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

641 lines
19 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: action.cpp
  3. Description: Implements classes to handle actions associated
  4. with user notifications (email, popup dialog etc).
  5. CAction
  6. CActionEmail
  7. CActionPopup
  8. Revision History:
  9. Date Description Programmer
  10. -------- --------------------------------------------------- ----------
  11. 07/01/97 Initial creation. BrianAu
  12. */
  13. ///////////////////////////////////////////////////////////////////////////////
  14. #include <precomp.hxx>
  15. #pragma hdrstop
  16. #include <commctrl.h>
  17. #include "action.h"
  18. #include "history.h"
  19. #include "stats.h"
  20. #include "resource.h"
  21. #include "mapisend.h"
  22. //-----------------------------------------------------------------------------
  23. // CActionEmail
  24. //-----------------------------------------------------------------------------
  25. #ifdef UNICODE
  26. # define EMAIL_UNICODE TRUE
  27. #else
  28. # define EMAIL_UNICODE FALSE
  29. #endif
  30. CActionEmail::CActionEmail(
  31. CMapiSession& MapiSession, // For sending message.
  32. LPMAPIFOLDER pMapiFolder, // For initializing message object.
  33. LPTSTR pszRecipientsTo, // Other recips on "To:" line.
  34. LPTSTR pszRecipientsCc, // Other recips on "Cc:" line.
  35. LPTSTR pszRecipientsBcc, // Other recips on "Bcc:" line.
  36. LPCTSTR pszSubject, // Message subject line.
  37. CMapiMessageBody& MsgBody // Message body text.
  38. ) : m_MapiSession(MapiSession),
  39. m_MapiRecipients(EMAIL_UNICODE),
  40. m_MapiMsg(pMapiFolder, MsgBody, pszSubject)
  41. {
  42. HRESULT hr;
  43. m_Mapi.Load();
  44. //
  45. // NOTE: We hold a reference to a CMapiSession object.
  46. // The CMapiSession object doen't employ any reference
  47. // counting of it's own. This code assumes that the
  48. // lifetime of the referenced section object exceeds the
  49. // lifetime of the action object.
  50. LPSPropValue pProps = NULL;
  51. ULONG cbProps = 0;
  52. //
  53. // Get the address properties for the MAPI session user.
  54. //
  55. hr = m_MapiSession.GetSessionUser(&pProps, &cbProps);
  56. if (SUCCEEDED(hr))
  57. {
  58. if (5 == cbProps)
  59. {
  60. SPropValue rgProp[5];
  61. //
  62. // Get the string resource containing "NT Disk Quota Administrator".
  63. // It's a resource for localization.
  64. //
  65. // FEATURE: This currently doesn't work although the Exchange guys
  66. // tell me it should. Currently, the mail message always
  67. // arrives with the local user's name on the "From:" line.
  68. // It should read "NT Disk Quota Administrator".
  69. // Needs work. [brianau - 07/10/97]
  70. //
  71. CString strEmailFromName(g_hInstDll, IDS_EMAIL_FROM_NAME);
  72. //
  73. // Set the "PR_SENT_REPRESENTING_XXXX" props to the same
  74. // values as the "PR_SENDER_XXXX" props.
  75. //
  76. rgProp[0].ulPropTag = PR_SENT_REPRESENTING_ADDRTYPE;
  77. rgProp[0].Value.LPSZ = pProps[0].Value.LPSZ;
  78. rgProp[1].ulPropTag = PR_SENT_REPRESENTING_NAME;
  79. rgProp[1].Value.LPSZ = (LPTSTR)strEmailFromName;
  80. rgProp[2].ulPropTag = PR_SENT_REPRESENTING_EMAIL_ADDRESS;
  81. rgProp[2].Value.LPSZ = pProps[2].Value.LPSZ;
  82. rgProp[3].ulPropTag = PR_SENT_REPRESENTING_ENTRYID;
  83. rgProp[3].Value.bin.cb = pProps[3].Value.bin.cb;
  84. rgProp[3].Value.bin.lpb = pProps[3].Value.bin.lpb;
  85. rgProp[4].ulPropTag = PR_SENT_REPRESENTING_SEARCH_KEY;
  86. rgProp[4].Value.bin.cb = pProps[4].Value.bin.cb;
  87. rgProp[4].Value.bin.lpb = pProps[4].Value.bin.lpb;
  88. LPSPropProblemArray pProblems = NULL;
  89. //
  90. // Set the new properties.
  91. //
  92. hr = m_MapiMsg.SetProps(ARRAYSIZE(rgProp), rgProp, &pProblems);
  93. hr = m_MapiMsg.SaveChanges(KEEP_OPEN_READWRITE);
  94. //
  95. // Add the recipient to the list of recipients.
  96. //
  97. hr = m_MapiRecipients.AddRecipient(pProps[2].Value.LPSZ, MAPI_TO);
  98. }
  99. m_Mapi.FreeBuffer(pProps);
  100. }
  101. //
  102. // Each element of this array contains a pointer to a list of
  103. // recipient names (semicolon-delmited) and a recipient type
  104. // code. This allows us to process all of the recipients
  105. // in a single loop.
  106. //
  107. struct recip {
  108. LPTSTR pszName;
  109. DWORD dwType;
  110. } rgRecips[] = {
  111. { pszRecipientsTo, MAPI_TO },
  112. { pszRecipientsCc, MAPI_CC },
  113. { pszRecipientsBcc, MAPI_BCC },
  114. };
  115. for (INT i = 0; i < ARRAYSIZE(rgRecips); i++)
  116. {
  117. LPTSTR pszNext = rgRecips[i].pszName;
  118. LPCTSTR pszPrev = pszNext;
  119. //
  120. // Process the current list of recipient names until we reach
  121. // the terminating nul character.
  122. //
  123. while(TEXT('\0') != *pszPrev)
  124. {
  125. while((TEXT('\0') != *pszNext) && (TEXT(';') != *pszNext))
  126. {
  127. //
  128. // Find the next semicolon or the terminating nul.
  129. //
  130. pszNext++;
  131. }
  132. if (TEXT('\0') != *pszNext)
  133. {
  134. //
  135. // Found a semicolon. Replace it with a nul and
  136. // skip ahead to the start of the next name.
  137. //
  138. *pszNext++ = TEXT('\0');
  139. }
  140. //
  141. // Add the name of the recipient pointed to by pszPrev
  142. // using the type code associated with this list of recipients.
  143. //
  144. m_MapiRecipients.AddRecipient(pszPrev, rgRecips[i].dwType);
  145. pszPrev = pszNext;
  146. }
  147. }
  148. }
  149. CActionEmail::~CActionEmail(
  150. VOID
  151. )
  152. {
  153. m_Mapi.Unload();
  154. }
  155. //
  156. // Send the email and record the send operation in our history record.
  157. //
  158. HRESULT
  159. CActionEmail::DoAction(
  160. CHistory& history
  161. )
  162. {
  163. HRESULT hr;
  164. //
  165. // Try sending the mail using the current ANSI/Unicode contents.
  166. //
  167. hr = m_MapiSession.Send(m_MapiRecipients, m_MapiMsg);
  168. if (MAPI_E_BAD_CHARWIDTH == hr)
  169. {
  170. //
  171. // Failed because the provider can't handle the character width.
  172. // Convert the address list to the opposite character width.
  173. //
  174. // FEATURE: Currently, we just convert the address list. We
  175. // should probably do the same thing with the message body
  176. // and subject line.
  177. //
  178. CMapiRecipients recipTemp(!m_MapiRecipients.IsUnicode());
  179. recipTemp = m_MapiRecipients;
  180. //
  181. // Try to send again.
  182. //
  183. hr = m_MapiSession.Send(recipTemp, m_MapiMsg);
  184. }
  185. if (SUCCEEDED(hr))
  186. {
  187. //
  188. // Record in the history log that we've sent email.
  189. //
  190. history.RecordEmailSent();
  191. }
  192. return hr;
  193. }
  194. //-----------------------------------------------------------------------------
  195. // CActionPopup
  196. //-----------------------------------------------------------------------------
  197. UINT CActionPopup::m_idAutoCloseTimer = 1;
  198. UINT CActionPopup::m_uAutoCloseTimeout = 300000; // Timeout in 5 minutes.
  199. CActionPopup::CActionPopup(
  200. CStatisticsList& stats
  201. ) : m_stats(stats),
  202. m_hiconDialog(NULL),
  203. m_hwnd(NULL)
  204. {
  205. m_hiconDialog = LoadIcon(g_hInstDll, MAKEINTRESOURCE(IDI_QUOTA));
  206. }
  207. CActionPopup::~CActionPopup(
  208. VOID
  209. )
  210. {
  211. }
  212. typedef BOOL (WINAPI *LPFNINITCOMMONCONTROLSEX)(LPINITCOMMONCONTROLSEX);
  213. HRESULT
  214. CActionPopup::CreateAndRunPopup(
  215. HINSTANCE hInst,
  216. LPCTSTR pszDlgTemplate,
  217. HWND hwndParent
  218. )
  219. {
  220. INT iResult = 1;
  221. //
  222. // Load and initialize comctl32.dll.
  223. // We need it for the listview control in the dialog.
  224. //
  225. m_hmodCOMCTL32 = ::LoadLibrary(TEXT("comctl32.dll"));
  226. if (NULL != m_hmodCOMCTL32)
  227. {
  228. LPFNINITCOMMONCONTROLSEX pfnInitCommonControlsEx = NULL;
  229. pfnInitCommonControlsEx = (LPFNINITCOMMONCONTROLSEX)::GetProcAddress(m_hmodCOMCTL32, "InitCommonControlsEx");
  230. if (NULL != pfnInitCommonControlsEx)
  231. {
  232. INITCOMMONCONTROLSEX iccex;
  233. iccex.dwSize = sizeof(iccex);
  234. iccex.dwICC = ICC_LISTVIEW_CLASSES;
  235. if ((*pfnInitCommonControlsEx)(&iccex))
  236. {
  237. iResult = DialogBoxParam(hInst,
  238. pszDlgTemplate,
  239. hwndParent,
  240. DlgProc,
  241. (LPARAM)this);
  242. }
  243. }
  244. }
  245. return (0 == iResult) ? NOERROR : E_FAIL;
  246. }
  247. HRESULT
  248. CActionPopup::DoAction(
  249. CHistory& history
  250. )
  251. {
  252. HRESULT hr = E_FAIL;
  253. if (0 == CreateAndRunPopup(g_hInstDll,
  254. MAKEINTRESOURCE(IDD_QUOTA_POPUP),
  255. GetDesktopWindow()))
  256. {
  257. //
  258. // Record in the history log that we've popped up a dialog.
  259. //
  260. history.RecordDialogPoppedUp();
  261. hr = NOERROR;
  262. }
  263. return hr;
  264. }
  265. ///////////////////////////////////////////////////////////////////////////////
  266. /* Function: CActionPopup::DlgProc [static]
  267. Description: Message procedure for the dialog.
  268. Arguments: Standard Win32 message proc arguments.
  269. Returns: Standard Win32 message proc return values.
  270. Revision History:
  271. Date Description Programmer
  272. -------- --------------------------------------------------- ----------
  273. 05/28/97 Initial creation. BrianAu
  274. */
  275. ///////////////////////////////////////////////////////////////////////////////
  276. INT_PTR CALLBACK
  277. CActionPopup::DlgProc(
  278. HWND hwnd,
  279. UINT uMsg,
  280. WPARAM wParam,
  281. LPARAM lParam
  282. )
  283. {
  284. //
  285. // Retrieve the dialog object's ptr from the window's userdata.
  286. // Place there in response to WM_INITDIALOG.
  287. //
  288. CActionPopup *pThis = (CActionPopup *)GetWindowLong(hwnd, GWL_USERDATA);
  289. switch(uMsg)
  290. {
  291. case WM_INITDIALOG:
  292. //
  293. // Store "this" ptr in window's userdata.
  294. //
  295. SetWindowLong(hwnd, GWL_USERDATA, (LONG)lParam);
  296. pThis = (CActionPopup *)lParam;
  297. //
  298. // Save the HWND in our object. We'll need it later.
  299. //
  300. pThis->m_hwnd = hwnd;
  301. return pThis->OnInitDialog(hwnd);
  302. case WM_DESTROY:
  303. return pThis->OnDestroy(hwnd);
  304. case WM_NCDESTROY:
  305. return pThis->OnNcDestroy(hwnd);
  306. case WM_TIMER:
  307. if (m_idAutoCloseTimer != wParam)
  308. break;
  309. //
  310. // Fall through to EndDialog...
  311. //
  312. DebugMsg(DM_ERROR, TEXT("CActionPopup::DlgProc - Dialog closed automatically."));
  313. case WM_COMMAND:
  314. EndDialog(hwnd, 0);
  315. break;
  316. }
  317. return FALSE;
  318. }
  319. BOOL
  320. CActionPopup::OnInitDialog(
  321. HWND hwnd
  322. )
  323. {
  324. BOOL bResult = TRUE;
  325. //
  326. // Set the quota icon.
  327. //
  328. SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)m_hiconDialog);
  329. SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)m_hiconDialog);
  330. //
  331. // Populate the listview with notification records.
  332. //
  333. InitializeList(GetDlgItem(hwnd, IDC_LIST_POPUP));
  334. //
  335. // Set the timer that will automatically close the dialog after 2 minutes.
  336. //
  337. SetTimer(hwnd, m_idAutoCloseTimer, m_uAutoCloseTimeout, NULL);
  338. return bResult;
  339. }
  340. ///////////////////////////////////////////////////////////////////////////////
  341. /* Function: CActionPopup::OnDestroy
  342. Description:
  343. Arguments:
  344. hwnd - Dialog window handle.
  345. Returns: Always returns FALSE.
  346. Revision History:
  347. Date Description Programmer
  348. -------- --------------------------------------------------- ----------
  349. 07/01/97 Initial creation. BrianAu
  350. */
  351. ///////////////////////////////////////////////////////////////////////////////
  352. BOOL
  353. CActionPopup::OnDestroy(
  354. HWND hwnd
  355. )
  356. {
  357. KillTimer(hwnd, m_idAutoCloseTimer);
  358. return FALSE;
  359. }
  360. ///////////////////////////////////////////////////////////////////////////////
  361. /* Function: CActionPopup::OnNcDestroy
  362. Description:
  363. Arguments:
  364. hwnd - Dialog window handle.
  365. Returns: Always returns FALSE.
  366. Revision History:
  367. Date Description Programmer
  368. -------- --------------------------------------------------- ----------
  369. 07/01/97 Initial creation. BrianAu
  370. */
  371. ///////////////////////////////////////////////////////////////////////////////
  372. BOOL
  373. CActionPopup::OnNcDestroy(
  374. HWND hwnd
  375. )
  376. {
  377. //
  378. // We no longer need comctl32.
  379. // Unload it.
  380. //
  381. if (NULL != m_hmodCOMCTL32)
  382. {
  383. FreeLibrary(m_hmodCOMCTL32);
  384. m_hmodCOMCTL32 = NULL;
  385. }
  386. return FALSE;
  387. }
  388. //
  389. // Creates the listview columns and populates the listview from
  390. // the statistics list object.
  391. //
  392. VOID
  393. CActionPopup::InitializeList(
  394. HWND hwndList
  395. )
  396. {
  397. //
  398. // We want to base pixel units off of dialog units.
  399. //
  400. INT DialogBaseUnitsX = LOWORD(GetDialogBaseUnits());
  401. #define PIXELSX(du) ((INT)((DialogBaseUnitsX * du) / 4))
  402. //
  403. // Create the header titles.
  404. //
  405. CString strVolume(g_hInstDll, IDS_LVHDR_VOLUME);
  406. CString strUsed(g_hInstDll, IDS_LVHDR_USED);
  407. CString strWarning(g_hInstDll, IDS_LVHDR_WARNING);
  408. CString strLimit(g_hInstDll, IDS_LVHDR_LIMIT);
  409. #define LVCOLMASK (LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM)
  410. LV_COLUMN rgCols[] = {
  411. { LVCOLMASK, LVCFMT_LEFT, PIXELSX(70), strVolume, 0, 0 },
  412. { LVCOLMASK, LVCFMT_LEFT, PIXELSX(60), strUsed, 0, 1 },
  413. { LVCOLMASK, LVCFMT_LEFT, PIXELSX(50), strWarning, 0, 2 },
  414. { LVCOLMASK, LVCFMT_LEFT, PIXELSX(50), strLimit, 0, 3 }
  415. };
  416. //
  417. // Add the columns to the listview.
  418. //
  419. for (INT i = 0; i < ARRAYSIZE(rgCols); i++)
  420. {
  421. if (-1 == ListView_InsertColumn(hwndList, i, &rgCols[i]))
  422. {
  423. DebugMsg(DM_ERROR, TEXT("CActionPopup::InitializeList failed to add column %d"), i);
  424. }
  425. }
  426. //
  427. // How many statistics objects are there in the stats list?
  428. //
  429. INT cEntries = m_stats.Count();
  430. //
  431. // This prevents the listview from having to extend itself each time we
  432. // add an item.
  433. //
  434. ListView_SetItemCount(hwndList, cEntries);
  435. //
  436. // Item struct for adding listview items and setting item text.
  437. //
  438. LV_ITEM item;
  439. item.mask = LVIF_TEXT;
  440. //
  441. // Scratch string for storing formatted column text.
  442. //
  443. CString str;
  444. //
  445. // For each row...
  446. //
  447. INT iRow = 0;
  448. for (INT iEntry = 0; iEntry < cEntries; iEntry++)
  449. {
  450. item.iItem = iRow;
  451. //
  452. // Retrieve the statistics object for this row.
  453. //
  454. const CStatistics *pStats = m_stats.GetEntry(iEntry);
  455. Assert(NULL != pStats);
  456. if (0 == iEntry)
  457. {
  458. //
  459. // First row. Get the user's display name and
  460. // format/set the header message.
  461. //
  462. str.Format(g_hInstDll, IDS_POPUP_HEADER);
  463. SetWindowText(GetDlgItem(m_hwnd, IDC_TXT_POPUP_HEADER), str);
  464. }
  465. if (pStats->IncludeInReport())
  466. {
  467. //
  468. // For each column...
  469. //
  470. for (INT iCol = 0; iCol < ARRAYSIZE(rgCols); iCol++)
  471. {
  472. item.iSubItem = iCol;
  473. switch(iCol)
  474. {
  475. case 0:
  476. //
  477. // Location (volume display name)
  478. //
  479. item.pszText = pStats->GetVolumeDisplayName() ?
  480. (LPTSTR)((LPCTSTR)pStats->GetVolumeDisplayName()) :
  481. TEXT("");
  482. break;
  483. case 1:
  484. {
  485. TCHAR szBytes[40];
  486. TCHAR szBytesOver[40];
  487. //
  488. // Quota Used
  489. //
  490. XBytes::FormatByteCountForDisplay(pStats->GetUserQuotaUsed().QuadPart,
  491. szBytes, ARRAYSIZE(szBytes));
  492. __int64 diff = pStats->GetUserQuotaUsed().QuadPart - pStats->GetUserQuotaThreshold().QuadPart;
  493. if (0 > diff)
  494. {
  495. diff = 0;
  496. }
  497. XBytes::FormatByteCountForDisplay(diff, szBytesOver, ARRAYSIZE(szBytesOver));
  498. str.Format(g_hInstDll, IDS_LVFMT_USED, szBytes, szBytesOver);
  499. item.pszText = (LPTSTR)str;
  500. break;
  501. }
  502. case 2:
  503. //
  504. // Warning Level
  505. //
  506. XBytes::FormatByteCountForDisplay(pStats->GetUserQuotaThreshold().QuadPart,
  507. str.GetBuffer(40), 40);
  508. item.pszText = (LPTSTR)str;
  509. break;
  510. case 3:
  511. //
  512. // Quota Limit.
  513. //
  514. XBytes::FormatByteCountForDisplay(pStats->GetUserQuotaLimit().QuadPart,
  515. str.GetBuffer(40), 40);
  516. item.pszText = (LPTSTR)str;
  517. break;
  518. default:
  519. break;
  520. }
  521. if (0 == iCol)
  522. {
  523. //
  524. // Add the item to the listview.
  525. //
  526. if (-1 == ListView_InsertItem(hwndList, &item))
  527. {
  528. DebugMsg(DM_ERROR, TEXT("CActionPopup::InitializeList failed to add entry %d,%d"), iRow, iCol);
  529. }
  530. }
  531. else
  532. {
  533. //
  534. // Set the text for a listview column entry.
  535. // Note: There's no return value to check.
  536. //
  537. ListView_SetItemText(hwndList, iRow, iCol, (item.pszText));
  538. }
  539. }
  540. iRow++;
  541. }
  542. }
  543. }