642 lines
19 KiB
C++
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++;
|
|
}
|
|
}
|
|
}
|
|
|