windows-nt/Source/XPSP1/NT/shell/osshell/dskquota/watchdog/action.cpp
2020-09-26 16:20:57 +08:00

642 lines
19 KiB
C++

///////////////////////////////////////////////////////////////////////////////
/* 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 <precomp.hxx>
#pragma hdrstop
#include <commctrl.h>
#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++;
}
}
}