/////////////////////////////////////////////////////////////////////////////// /* File: action.cpp Description: Implements classes to handle actions associated with user notifications (email, popup dialog etc). CAction CActionEmail CActionPopup Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 07/01/97 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// #include #pragma hdrstop #include #include "action.h" #include "history.h" #include "stats.h" #include "resource.h" #include "mapisend.h" //----------------------------------------------------------------------------- // CActionEmail //----------------------------------------------------------------------------- #ifdef UNICODE # define EMAIL_UNICODE TRUE #else # define EMAIL_UNICODE FALSE #endif CActionEmail::CActionEmail( CMapiSession& MapiSession, // For sending message. LPMAPIFOLDER pMapiFolder, // For initializing message object. LPTSTR pszRecipientsTo, // Other recips on "To:" line. LPTSTR pszRecipientsCc, // Other recips on "Cc:" line. LPTSTR pszRecipientsBcc, // Other recips on "Bcc:" line. LPCTSTR pszSubject, // Message subject line. CMapiMessageBody& MsgBody // Message body text. ) : m_MapiSession(MapiSession), m_MapiRecipients(EMAIL_UNICODE), m_MapiMsg(pMapiFolder, MsgBody, pszSubject) { HRESULT hr; m_Mapi.Load(); // // NOTE: We hold a reference to a CMapiSession object. // The CMapiSession object doen't employ any reference // counting of it's own. This code assumes that the // lifetime of the referenced section object exceeds the // lifetime of the action object. LPSPropValue pProps = NULL; ULONG cbProps = 0; // // Get the address properties for the MAPI session user. // hr = m_MapiSession.GetSessionUser(&pProps, &cbProps); if (SUCCEEDED(hr)) { if (5 == cbProps) { SPropValue rgProp[5]; // // Get the string resource containing "NT Disk Quota Administrator". // It's a resource for localization. // // FEATURE: This currently doesn't work although the Exchange guys // tell me it should. Currently, the mail message always // arrives with the local user's name on the "From:" line. // It should read "NT Disk Quota Administrator". // Needs work. [brianau - 07/10/97] // CString strEmailFromName(g_hInstDll, IDS_EMAIL_FROM_NAME); // // Set the "PR_SENT_REPRESENTING_XXXX" props to the same // values as the "PR_SENDER_XXXX" props. // rgProp[0].ulPropTag = PR_SENT_REPRESENTING_ADDRTYPE; rgProp[0].Value.LPSZ = pProps[0].Value.LPSZ; rgProp[1].ulPropTag = PR_SENT_REPRESENTING_NAME; rgProp[1].Value.LPSZ = (LPTSTR)strEmailFromName; rgProp[2].ulPropTag = PR_SENT_REPRESENTING_EMAIL_ADDRESS; rgProp[2].Value.LPSZ = pProps[2].Value.LPSZ; rgProp[3].ulPropTag = PR_SENT_REPRESENTING_ENTRYID; rgProp[3].Value.bin.cb = pProps[3].Value.bin.cb; rgProp[3].Value.bin.lpb = pProps[3].Value.bin.lpb; rgProp[4].ulPropTag = PR_SENT_REPRESENTING_SEARCH_KEY; rgProp[4].Value.bin.cb = pProps[4].Value.bin.cb; rgProp[4].Value.bin.lpb = pProps[4].Value.bin.lpb; LPSPropProblemArray pProblems = NULL; // // Set the new properties. // hr = m_MapiMsg.SetProps(ARRAYSIZE(rgProp), rgProp, &pProblems); hr = m_MapiMsg.SaveChanges(KEEP_OPEN_READWRITE); // // Add the recipient to the list of recipients. // hr = m_MapiRecipients.AddRecipient(pProps[2].Value.LPSZ, MAPI_TO); } m_Mapi.FreeBuffer(pProps); } // // Each element of this array contains a pointer to a list of // recipient names (semicolon-delmited) and a recipient type // code. This allows us to process all of the recipients // in a single loop. // struct recip { LPTSTR pszName; DWORD dwType; } rgRecips[] = { { pszRecipientsTo, MAPI_TO }, { pszRecipientsCc, MAPI_CC }, { pszRecipientsBcc, MAPI_BCC }, }; for (INT i = 0; i < ARRAYSIZE(rgRecips); i++) { LPTSTR pszNext = rgRecips[i].pszName; LPCTSTR pszPrev = pszNext; // // Process the current list of recipient names until we reach // the terminating nul character. // while(TEXT('\0') != *pszPrev) { while((TEXT('\0') != *pszNext) && (TEXT(';') != *pszNext)) { // // Find the next semicolon or the terminating nul. // pszNext++; } if (TEXT('\0') != *pszNext) { // // Found a semicolon. Replace it with a nul and // skip ahead to the start of the next name. // *pszNext++ = TEXT('\0'); } // // Add the name of the recipient pointed to by pszPrev // using the type code associated with this list of recipients. // m_MapiRecipients.AddRecipient(pszPrev, rgRecips[i].dwType); pszPrev = pszNext; } } } CActionEmail::~CActionEmail( VOID ) { m_Mapi.Unload(); } // // Send the email and record the send operation in our history record. // HRESULT CActionEmail::DoAction( CHistory& history ) { HRESULT hr; // // Try sending the mail using the current ANSI/Unicode contents. // hr = m_MapiSession.Send(m_MapiRecipients, m_MapiMsg); if (MAPI_E_BAD_CHARWIDTH == hr) { // // Failed because the provider can't handle the character width. // Convert the address list to the opposite character width. // // FEATURE: Currently, we just convert the address list. We // should probably do the same thing with the message body // and subject line. // CMapiRecipients recipTemp(!m_MapiRecipients.IsUnicode()); recipTemp = m_MapiRecipients; // // Try to send again. // hr = m_MapiSession.Send(recipTemp, m_MapiMsg); } if (SUCCEEDED(hr)) { // // Record in the history log that we've sent email. // history.RecordEmailSent(); } return hr; } //----------------------------------------------------------------------------- // CActionPopup //----------------------------------------------------------------------------- UINT CActionPopup::m_idAutoCloseTimer = 1; UINT CActionPopup::m_uAutoCloseTimeout = 300000; // Timeout in 5 minutes. CActionPopup::CActionPopup( CStatisticsList& stats ) : m_stats(stats), m_hiconDialog(NULL), m_hwnd(NULL) { m_hiconDialog = LoadIcon(g_hInstDll, MAKEINTRESOURCE(IDI_QUOTA)); } CActionPopup::~CActionPopup( VOID ) { } typedef BOOL (WINAPI *LPFNINITCOMMONCONTROLSEX)(LPINITCOMMONCONTROLSEX); HRESULT CActionPopup::CreateAndRunPopup( HINSTANCE hInst, LPCTSTR pszDlgTemplate, HWND hwndParent ) { INT iResult = 1; // // Load and initialize comctl32.dll. // We need it for the listview control in the dialog. // m_hmodCOMCTL32 = ::LoadLibrary(TEXT("comctl32.dll")); if (NULL != m_hmodCOMCTL32) { LPFNINITCOMMONCONTROLSEX pfnInitCommonControlsEx = NULL; pfnInitCommonControlsEx = (LPFNINITCOMMONCONTROLSEX)::GetProcAddress(m_hmodCOMCTL32, "InitCommonControlsEx"); if (NULL != pfnInitCommonControlsEx) { INITCOMMONCONTROLSEX iccex; iccex.dwSize = sizeof(iccex); iccex.dwICC = ICC_LISTVIEW_CLASSES; if ((*pfnInitCommonControlsEx)(&iccex)) { iResult = DialogBoxParam(hInst, pszDlgTemplate, hwndParent, DlgProc, (LPARAM)this); } } } return (0 == iResult) ? NOERROR : E_FAIL; } HRESULT CActionPopup::DoAction( CHistory& history ) { HRESULT hr = E_FAIL; if (0 == CreateAndRunPopup(g_hInstDll, MAKEINTRESOURCE(IDD_QUOTA_POPUP), GetDesktopWindow())) { // // Record in the history log that we've popped up a dialog. // history.RecordDialogPoppedUp(); hr = NOERROR; } return hr; } /////////////////////////////////////////////////////////////////////////////// /* Function: CActionPopup::DlgProc [static] Description: Message procedure for the dialog. Arguments: Standard Win32 message proc arguments. Returns: Standard Win32 message proc return values. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 05/28/97 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// INT_PTR CALLBACK CActionPopup::DlgProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { // // Retrieve the dialog object's ptr from the window's userdata. // Place there in response to WM_INITDIALOG. // CActionPopup *pThis = (CActionPopup *)GetWindowLong(hwnd, GWL_USERDATA); switch(uMsg) { case WM_INITDIALOG: // // Store "this" ptr in window's userdata. // SetWindowLong(hwnd, GWL_USERDATA, (LONG)lParam); pThis = (CActionPopup *)lParam; // // Save the HWND in our object. We'll need it later. // pThis->m_hwnd = hwnd; return pThis->OnInitDialog(hwnd); case WM_DESTROY: return pThis->OnDestroy(hwnd); case WM_NCDESTROY: return pThis->OnNcDestroy(hwnd); case WM_TIMER: if (m_idAutoCloseTimer != wParam) break; // // Fall through to EndDialog... // DebugMsg(DM_ERROR, TEXT("CActionPopup::DlgProc - Dialog closed automatically.")); case WM_COMMAND: EndDialog(hwnd, 0); break; } return FALSE; } BOOL CActionPopup::OnInitDialog( HWND hwnd ) { BOOL bResult = TRUE; // // Set the quota icon. // SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)m_hiconDialog); SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)m_hiconDialog); // // Populate the listview with notification records. // InitializeList(GetDlgItem(hwnd, IDC_LIST_POPUP)); // // Set the timer that will automatically close the dialog after 2 minutes. // SetTimer(hwnd, m_idAutoCloseTimer, m_uAutoCloseTimeout, NULL); return bResult; } /////////////////////////////////////////////////////////////////////////////// /* Function: CActionPopup::OnDestroy Description: Arguments: hwnd - Dialog window handle. Returns: Always returns FALSE. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 07/01/97 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// BOOL CActionPopup::OnDestroy( HWND hwnd ) { KillTimer(hwnd, m_idAutoCloseTimer); return FALSE; } /////////////////////////////////////////////////////////////////////////////// /* Function: CActionPopup::OnNcDestroy Description: Arguments: hwnd - Dialog window handle. Returns: Always returns FALSE. Revision History: Date Description Programmer -------- --------------------------------------------------- ---------- 07/01/97 Initial creation. BrianAu */ /////////////////////////////////////////////////////////////////////////////// BOOL CActionPopup::OnNcDestroy( HWND hwnd ) { // // We no longer need comctl32. // Unload it. // if (NULL != m_hmodCOMCTL32) { FreeLibrary(m_hmodCOMCTL32); m_hmodCOMCTL32 = NULL; } return FALSE; } // // Creates the listview columns and populates the listview from // the statistics list object. // VOID CActionPopup::InitializeList( HWND hwndList ) { // // We want to base pixel units off of dialog units. // INT DialogBaseUnitsX = LOWORD(GetDialogBaseUnits()); #define PIXELSX(du) ((INT)((DialogBaseUnitsX * du) / 4)) // // Create the header titles. // CString strVolume(g_hInstDll, IDS_LVHDR_VOLUME); CString strUsed(g_hInstDll, IDS_LVHDR_USED); CString strWarning(g_hInstDll, IDS_LVHDR_WARNING); CString strLimit(g_hInstDll, IDS_LVHDR_LIMIT); #define LVCOLMASK (LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM) LV_COLUMN rgCols[] = { { LVCOLMASK, LVCFMT_LEFT, PIXELSX(70), strVolume, 0, 0 }, { LVCOLMASK, LVCFMT_LEFT, PIXELSX(60), strUsed, 0, 1 }, { LVCOLMASK, LVCFMT_LEFT, PIXELSX(50), strWarning, 0, 2 }, { LVCOLMASK, LVCFMT_LEFT, PIXELSX(50), strLimit, 0, 3 } }; // // Add the columns to the listview. // for (INT i = 0; i < ARRAYSIZE(rgCols); i++) { if (-1 == ListView_InsertColumn(hwndList, i, &rgCols[i])) { DebugMsg(DM_ERROR, TEXT("CActionPopup::InitializeList failed to add column %d"), i); } } // // How many statistics objects are there in the stats list? // INT cEntries = m_stats.Count(); // // This prevents the listview from having to extend itself each time we // add an item. // ListView_SetItemCount(hwndList, cEntries); // // Item struct for adding listview items and setting item text. // LV_ITEM item; item.mask = LVIF_TEXT; // // Scratch string for storing formatted column text. // CString str; // // For each row... // INT iRow = 0; for (INT iEntry = 0; iEntry < cEntries; iEntry++) { item.iItem = iRow; // // Retrieve the statistics object for this row. // const CStatistics *pStats = m_stats.GetEntry(iEntry); Assert(NULL != pStats); if (0 == iEntry) { // // First row. Get the user's display name and // format/set the header message. // str.Format(g_hInstDll, IDS_POPUP_HEADER); SetWindowText(GetDlgItem(m_hwnd, IDC_TXT_POPUP_HEADER), str); } if (pStats->IncludeInReport()) { // // For each column... // for (INT iCol = 0; iCol < ARRAYSIZE(rgCols); iCol++) { item.iSubItem = iCol; switch(iCol) { case 0: // // Location (volume display name) // item.pszText = pStats->GetVolumeDisplayName() ? (LPTSTR)((LPCTSTR)pStats->GetVolumeDisplayName()) : TEXT(""); break; case 1: { TCHAR szBytes[40]; TCHAR szBytesOver[40]; // // Quota Used // XBytes::FormatByteCountForDisplay(pStats->GetUserQuotaUsed().QuadPart, szBytes, ARRAYSIZE(szBytes)); __int64 diff = pStats->GetUserQuotaUsed().QuadPart - pStats->GetUserQuotaThreshold().QuadPart; if (0 > diff) { diff = 0; } XBytes::FormatByteCountForDisplay(diff, szBytesOver, ARRAYSIZE(szBytesOver)); str.Format(g_hInstDll, IDS_LVFMT_USED, szBytes, szBytesOver); item.pszText = (LPTSTR)str; break; } case 2: // // Warning Level // XBytes::FormatByteCountForDisplay(pStats->GetUserQuotaThreshold().QuadPart, str.GetBuffer(40), 40); item.pszText = (LPTSTR)str; break; case 3: // // Quota Limit. // XBytes::FormatByteCountForDisplay(pStats->GetUserQuotaLimit().QuadPart, str.GetBuffer(40), 40); item.pszText = (LPTSTR)str; break; default: break; } if (0 == iCol) { // // Add the item to the listview. // if (-1 == ListView_InsertItem(hwndList, &item)) { DebugMsg(DM_ERROR, TEXT("CActionPopup::InitializeList failed to add entry %d,%d"), iRow, iCol); } } else { // // Set the text for a listview column entry. // Note: There's no return value to check. // ListView_SetItemText(hwndList, iRow, iCol, (item.pszText)); } } iRow++; } } }