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.
 
 
 
 
 
 

1352 lines
43 KiB

/*
* m s g p r o p . c p p
*
* Purpose:
* Implements propsheet for a msg
*
* Owner:
* brettm.
*
* History:
* Feb '95: Stolen from Capone Sources - brettm
*
* Copyright (C) Microsoft Corp. 1993, 1994.
*/
#include <pch.hxx>
#ifdef WIN16
#include "mapi.h"
#endif
#include <resource.h>
#include <richedit.h>
#include "goptions.h"
#include "mimeole.h"
#include "mimeutil.h"
#include "msgprop.h"
#include "addrobj.h"
#include "mpropdlg.h"
#ifndef WIN16
#include "mapi.h"
#endif
#include "ipab.h"
#include <secutil.h>
#include <seclabel.h>
#include <certs.h>
#include <demand.h>
#include <strconst.h>
#include <shlwapi.h>
#include <shlwapip.h>
#include "instance.h"
#include "conman.h"
#include "shared.h"
#include "htmlhelp.h"
/*
* m a c r o s and c o n s t a n t s
*
*/
#define KILOBYTE 1024L
#define PROP_ERROR(prop) (PROP_TYPE(prop.ulPropTag) == PT_ERROR)
#ifdef WIN16
#ifndef GetLastError
#define GetLastError() ((DWORD)-1)
#endif
#endif //!WIN16
#ifdef WIN16
#define SET_DIALOG_SECURITY(hwnd, value) SetProp32(hwnd, s_cszDlgSec, (LPVOID)value)
#define GET_DIALOG_SECURITY(hwnd) GetProp32(hwnd, s_cszDlgSec)
#define CLEAR_DIALOG_SECURITY(hwnd) RemoveProp32(hwnd, s_cszDlgSec);
#else
#define SET_DIALOG_SECURITY(hwnd, value) SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)value)
#define GET_DIALOG_SECURITY(hwnd) GetWindowLongPtr(hwnd, DWLP_USER);
#define CLEAR_DIALOG_SECURITY(hwnd) SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)NULL)
#endif
/*
* s t r u c t u r e s
*
*/
struct DLGSECURITYtag
{
PCX509CERT pSenderCert;
PCCERT_CONTEXT pEncSenderCert;
PCCERT_CONTEXT pEncryptionCert;
THUMBBLOB tbSenderThumbprint;
BLOB blSymCaps;
FILETIME ftSigningTime;
HCERTSTORE hcMsg;
};
typedef struct DLGSECURITYtag DLGSECURITY;
typedef DLGSECURITY *PDLGSECURITY;
typedef const DLGSECURITY *PCDLGSECURITY;
/*
* c l a s s e s
*
*/
class CMsgProps
{
public:
CMsgProps();
~CMsgProps();
HRESULT HrDoProps(PMSGPROP pmp);
static INT_PTR CALLBACK GeneralPageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK DetailsPageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK SecurityPageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK EncryptionPageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void InitGeneralPage();
void InitDetailsPage(HWND hwnd);
void InitSecurityPage(HWND hwnd);
private:
HIMAGELIST m_himl;
HWND m_hwndGen;
HWND m_hwndGenSource;
PMSGPROP m_pmp;
};
// Function declarations ////////////////////////////////////////
// msg source dialog is modeless, so it can't be in the CProps dialog.
/*
* p r o t o t y p e s
*
*/
void SecurityOnWMCreate(HWND hwnd, LPARAM lParam);
INT_PTR CALLBACK ViewSecCertDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
/*
* f u n c t i o n s
*
*/
//
// FUNCTION: HrMsgProperties()
//
// PURPOSE: Displays the property sheet for the specified message.
//
// PARAMETERS:
// [in] pmp - Information needed to identify the message.
//
HRESULT HrMsgProperties(PMSGPROP pmp)
{
CMsgProps *pMsgProp = 0;
HRESULT hr;
TraceCall("HrMsgProperties");
// Create the property sheet object
pMsgProp = new CMsgProps();
if (!pMsgProp)
return E_OUTOFMEMORY;
// Tell the object to do it's thing. This won't go away until the
// property sheet is dismissed.
hr = pMsgProp->HrDoProps(pmp);
// Free the object
if (pMsgProp)
delete pMsgProp;
return hr;
}
CMsgProps::CMsgProps()
{
m_himl = 0;
m_hwndGen = 0;
m_hwndGenSource = 0;
m_pmp = NULL;
}
CMsgProps::~CMsgProps()
{
}
//
// FUNCTION: CMsgProps::HrDoProps()
//
// PURPOSE: Initializes the structures used to create the prop sheet
// and then displays the sheet.
//
// PARAMETERS:
// [in] pmp - Information needed to identify the message.
//
// RETURN VALUE:
// HRESULT
//
HRESULT CMsgProps::HrDoProps(PMSGPROP pmp)
{
PROPSHEETHEADER psh;
PROPSHEETPAGE psp[3];
BOOL fApply = FALSE;
HRESULT hr;
LPTSTR pszSubject = NULL;
LPTSTR pszFree = NULL;
TCHAR rgch[256] = "";
TraceCall("CMsgProps::HrDoProps");
// Zero init the prop sheet structures
ZeroMemory(&psh, sizeof(psh));
ZeroMemory(&psp, sizeof(psp));
// Double check that we have the information we need to do this.
if (pmp == NULL || (pmp->pMsg == NULL && pmp->pNoMsgData == NULL))
return E_INVALIDARG;
Assert(pmp->hwndParent);
// Stash this pointer
m_pmp = pmp;
// Page zero is the general tab
psp[0].dwSize = sizeof(PROPSHEETPAGE);
psp[0].dwFlags = PSP_USETITLE;
psp[0].hInstance = g_hLocRes;
psp[0].pszTemplate = MAKEINTRESOURCE(iddMsgProp_General);
psp[0].pfnDlgProc = GeneralPageProc;
psp[0].pszTitle = MAKEINTRESOURCE(idsPropPageGeneral);
psp[0].lParam = (LPARAM) this;
// Increment the number of pages
psh.nPages++;
// If the message is not unsent, then we also display the "Details" tab.
if (!(pmp->dwFlags & ARF_UNSENT) || (pmp->dwFlags & ARF_SUBMITTED))
{
psp[psh.nPages].dwSize = sizeof(PROPSHEETPAGE);
psp[psh.nPages].dwFlags = PSP_USETITLE;
psp[psh.nPages].hInstance = g_hLocRes;
psp[psh.nPages].pszTemplate = MAKEINTRESOURCE(iddMsgProp_Details);
psp[psh.nPages].pfnDlgProc = DetailsPageProc;
psp[psh.nPages].pszTitle = MAKEINTRESOURCE(idsPropPageDetails);
psp[psh.nPages].lParam = (LPARAM) this;
// If the caller wanted this to be the first page the user
// sees, set it to be the start page.
if (MP_DETAILS == pmp->mpStartPage)
psh.nStartPage = psh.nPages;
// Increment the number of pages
psh.nPages++;
}
// If the message is secure, add the security pages
if (pmp->fSecure && (!(pmp->dwFlags & ARF_UNSENT) || (pmp->dwFlags & ARF_SUBMITTED)))
{
psp[psh.nPages].dwSize = sizeof(PROPSHEETPAGE);
psp[psh.nPages].dwFlags = PSP_USETITLE;
psp[psh.nPages].hInstance = g_hLocRes;
psp[psh.nPages].pszTemplate = MAKEINTRESOURCE(iddMsgProp_Security_Msg);
psp[psh.nPages].pfnDlgProc = SecurityPageProc;
psp[psh.nPages].pszTitle = MAKEINTRESOURCE(idsPropPageSecurity);
psp[psh.nPages].lParam = (LPARAM) this;
// If the caller wanted this to be the first page the user
// sees, set it to be the start page.
if (MP_SECURITY == pmp->mpStartPage)
psh.nStartPage = psh.nPages;
// Increment the number of pages
psh.nPages++;
}
// Property sheet header information
psh.dwSize = sizeof(PROPSHEETHEADER);
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEPAGELANG | ((fApply) ? 0 : PSH_NOAPPLYNOW);
psh.hwndParent = pmp->hwndParent;
psh.hInstance = g_hLocRes;
// The title of the property sheet is the same as the subject. So now we
// need to get the subject from either the message or message info.
if (pmp->pMsg)
{
// Get the subject from the message
if (SUCCEEDED(MimeOleGetBodyPropA(pmp->pMsg, HBODY_ROOT,
PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS,
&pszSubject)))
{
// We'll need to free this string later
pszFree = pszSubject;
}
}
else
{
AssertSz(pmp->pNoMsgData, "CMsgProp::HrDoProps() - Need to provide either a Message or Message Info");
pszSubject = (LPTSTR) pmp->pNoMsgData->pszSubject;
}
// If there was no subject on the message, set the title to be "No Subject"
if (!pszSubject || !*pszSubject)
{
LoadString(g_hLocRes, idsNoSubject, rgch, sizeof(rgch));
pszSubject = rgch;
}
// Clean up the subject string before we use it. Tabs look like pretty bad.
ConvertTabsToSpaces(pszSubject);
// Set the subject as the property sheet title.
psh.pszCaption = pszSubject;
// Provide the array of pages. The number was set along the way.
psh.ppsp = (LPCPROPSHEETPAGE) &psp;
// Invoke the property sheet.
PropertySheet(&psh);
// If this is valid, then we need to free the string.
SafeMemFree(pszFree);
return (S_OK);
}
//
// FUNCTION: CMsgProps::GeneralPageProc()
//
// PURPOSE: Callback for the General tab dialog.
//
INT_PTR CALLBACK CMsgProps::GeneralPageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
CMsgProps *pThis = 0;
switch(msg)
{
case WM_INITDIALOG:
{
// Grab the object's this pointer from the init info
pThis = (CMsgProps *) ((PROPSHEETPAGE *)lParam)->lParam;
// Stash the window handle for this dialog in the class
pThis->m_hwndGen = hwnd;
// Initialize the page
pThis->InitGeneralPage();
return TRUE;
}
case WM_NOTIFY:
{
switch(((NMHDR FAR *)lParam)->code)
{
// We're going to do the default thing for all of these notifications
case PSN_APPLY:
case PSN_KILLACTIVE:
case PSN_SETACTIVE:
{
SetDlgMsgResult(hwnd, WM_NOTIFY, FALSE);
return TRUE;
}
}
break;
}
}
return FALSE;
}
enum
{
freeSubject = 0,
freeFrom,
freeMax
};
//
// FUNCTION: CMsgProps::InitGeneralPage()
//
// PURPOSE: Set's the values for the "General" tab in the message
// property sheet.
//
void CMsgProps::InitGeneralPage()
{
HWND hwnd;
char rgch[256],
rgchFmt[256];
char *psz = NULL;
PROPVARIANT rVariant;
LPMIMEMESSAGE pMsg = m_pmp->pMsg;
IMSGPRIORITY Pri = IMSG_PRI_NORMAL;
int ids;
BOOL fMime;
LPSTR rgszFree[freeMax]={0};
WCHAR wszDate[CCHMAX_STRINGRES];
TraceCall("CMsgProps::InitGeneralPage");
// [SBAILEY]: Raid-2440: ATTACH: Attachments field in Properties dialog innacurate when looked at from the listview.
if (m_pmp->fFromListView)
{
// Too hard to get these counts write from the listview because to really compute the attachment
// counts correctly, we have to render the message in trident. Since we are time contrained,
// we are going to simply remove the attachement count from the listview message properties. But
// since the counts are correct from message note properties, we will show the attachment counts from there.
ShowWindow(GetDlgItem(m_hwndGen, IDC_ATTACHMENTS_STATIC), SW_HIDE);
ShowWindow(GetDlgItem(m_hwndGen, IDC_ATTACHMENTS), SW_HIDE);
}
// If this is a news message, we hide the "Recieved:" and "Priority" fields
if (m_pmp->type == MSGPROPTYPE_NEWS)
{
RECT rc, rcLabel;
// Get the position of the priority field
GetWindowRect(GetDlgItem(m_hwndGen, IDC_PRIORITY), &rc);
MapWindowPoints(NULL, m_hwndGen, (LPPOINT) &rc, 2);
// Get the position of the priority label
GetWindowRect(GetDlgItem(m_hwndGen, IDC_PRIORITY_STATIC), &rcLabel);
MapWindowPoints(NULL, m_hwndGen, (LPPOINT) &rcLabel, 2);
// Hide the unused fields
ShowWindow(GetDlgItem(m_hwndGen, IDC_PRIORITY_STATIC), SW_HIDE);
ShowWindow(GetDlgItem(m_hwndGen, IDC_PRIORITY), SW_HIDE);
ShowWindow(GetDlgItem(m_hwndGen, idcStatic1), SW_HIDE);
ShowWindow(GetDlgItem(m_hwndGen, IDC_RECEIVED_STATIC), SW_HIDE);
ShowWindow(GetDlgItem(m_hwndGen, IDC_RECEIVED), SW_HIDE);
// Move the sent fields up to where the priority fields were
SetWindowPos(GetDlgItem(m_hwndGen, IDC_SENT_STATIC), NULL, rcLabel.left,
rcLabel.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
SetWindowPos(GetDlgItem(m_hwndGen, IDC_SENT), NULL, rc.left, rc.top, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
// Figure out the correct image for this message
int idIcon;
if (m_pmp->type == MSGPROPTYPE_MAIL)
{
if (m_pmp->dwFlags & ARF_UNSENT)
idIcon = idiMsgPropUnSent;
else
idIcon = idiMsgPropSent;
}
else
{
if (m_pmp->dwFlags & ARF_UNSENT)
idIcon = idiArtPropUnpost;
else
idIcon = idiArtPropPost;
}
// Set the image on the property sheet
HICON hIcon = LoadIcon(g_hLocRes, MAKEINTRESOURCE(idIcon));
SendDlgItemMessage(m_hwndGen, IDC_FOLDER_IMAGE, STM_SETIMAGE, IMAGE_ICON, (LPARAM) hIcon);
// Subject
if (pMsg)
{
// If we have a message object, then we need to get the subject from the message
if (SUCCEEDED(MimeOleGetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT),
NOFLAGS, &psz)))
{
// Make sure we free this later, eh?
rgszFree[freeSubject] = psz;
}
}
else
{
Assert(m_pmp->pNoMsgData);
psz = (LPTSTR) m_pmp->pNoMsgData->pszSubject;
}
// If the message doesn't have a subject, then substitute "(No Subject)"
if (!psz || !*psz)
{
LoadString(g_hLocRes, idsNoSubject, rgch, sizeof(rgch));
psz = rgch;
}
// Set the subject on the dialog
SetDlgItemText(m_hwndGen, IDC_MSGSUBJECT, psz);
// From
if (pMsg)
{
// Get the "From" line
if (S_OK == pMsg->GetAddressFormat(IAT_FROM, AFT_DISPLAY_BOTH, &psz))
{
// We'll need to free this later
rgszFree[freeFrom] = psz;
// Set the name on the control
SetDlgItemText(m_hwndGen, IDC_MSGFROM, psz);
}
}
else
{
// Check to see if the caller provided this information
if (m_pmp->pNoMsgData && m_pmp->pNoMsgData->pszFrom)
{
SetDlgItemText(m_hwndGen, IDC_MSGFROM, m_pmp->pNoMsgData->pszFrom);
}
}
// Type (News or Mail)
if (m_pmp->type == MSGPROPTYPE_MAIL)
LoadString(g_hLocRes, idsMailMessage, rgch, ARRAYSIZE(rgch));
else
LoadString(g_hLocRes, idsNewsMessage, rgch, ARRAYSIZE(rgch));
SetDlgItemText(m_hwndGen, IDC_TYPE, rgch);
// Location
if (m_pmp->dwFlags & ARF_UNSENT)
{
LoadString(g_hLocRes, idsUnderComp, rgch, ARRAYSIZE(rgchFmt));
SetDlgItemText(m_hwndGen, IDC_MSGFOLDER, rgch);
}
else
SetDlgItemText(m_hwndGen, IDC_MSGFOLDER, m_pmp->szFolderName);
// Size
ULONG ulSize;
if (pMsg)
{
pMsg->GetMessageSize(&ulSize, 0);
if (0 == ulSize)
{
// see if the message has the userprop for uncached size
rVariant.vt = VT_UI4;
if (SUCCEEDED(pMsg->GetProp(PIDTOSTR(PID_ATT_UNCACHEDSIZE), 0, &rVariant)))
ulSize = rVariant.ulVal;
}
AthFormatSizeK(ulSize, rgch, ARRAYSIZE(rgch));
}
else if (m_pmp->pNoMsgData && m_pmp->pNoMsgData->ulSize)
{
AthFormatSizeK(m_pmp->pNoMsgData->ulSize, rgch, ARRAYSIZE(rgch));
}
else
{
LoadString(g_hLocRes, idsUnderComp, rgch, ARRAYSIZE(rgchFmt));
}
SetDlgItemText(m_hwndGen, IDC_MSGSIZE, rgch);
// Attachments
ULONG cAttachments = 0;
if (pMsg)
{
GetAttachmentCount(pMsg, &cAttachments);
}
else if (m_pmp->pNoMsgData)
{
cAttachments = m_pmp->pNoMsgData->cAttachments;
SetDlgItemInt(m_hwndGen, IDC_ATTACHMENTS, cAttachments, FALSE);
}
if (cAttachments)
{
SetDlgItemInt(m_hwndGen, IDC_ATTACHMENTS, cAttachments, FALSE);
}
else
{
LoadString(g_hLocRes, idsPropAttachNone, rgch, sizeof(rgch));
SetDlgItemText(m_hwndGen, IDC_ATTACHMENTS, rgch);
}
// Priority
// Get the priority from the message
rVariant.vt = VT_UI4;
Pri = IMSG_PRI_NORMAL;
if (pMsg && SUCCEEDED(pMsg->GetProp(PIDTOSTR(PID_ATT_PRIORITY), 0, &rVariant)))
Pri = (IMSGPRIORITY) rVariant.ulVal;
else
{
Assert(m_pmp->pNoMsgData);
Pri = m_pmp->pNoMsgData->Pri;
}
// Map the priority to a string
switch (Pri)
{
case IMSG_PRI_LOW:
ids = idsPriLow;
break;
case IMSG_PRI_HIGH:
ids = idsPriHigh;
break;
default:
ids = idsPriNormal;
}
// Set the string on the dialog
LoadString(g_hLocRes, ids, rgch, ARRAYSIZE(rgch));
SetDlgItemText(m_hwndGen, IDC_PRIORITY, rgch);
// Sent
if (pMsg)
{
*wszDate = 0;
rVariant.vt = VT_FILETIME;
pMsg->GetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &rVariant);
AthFileTimeToDateTimeW(&rVariant.filetime, wszDate, ARRAYSIZE(wszDate), DTM_NOSECONDS);
SetDlgItemTextWrapW(m_hwndGen, IDC_SENT, wszDate);
}
else if (m_pmp->dwFlags & ARF_UNSENT)
{
LoadString(g_hLocRes, idsUnderComp, rgch, ARRAYSIZE(rgchFmt));
SetDlgItemText(m_hwndGen, IDC_SENT, rgch);
}
else
{
SetDlgItemText(m_hwndGen, IDC_SENT, m_pmp->pNoMsgData->pszSent);
}
// Recieved
if (pMsg)
{
*wszDate = 0;
rVariant.vt = VT_FILETIME;
pMsg->GetProp(PIDTOSTR(PID_ATT_RECVTIME), 0, &rVariant);
AthFileTimeToDateTimeW(&rVariant.filetime, wszDate, ARRAYSIZE(wszDate), DTM_NOSECONDS);
SetDlgItemTextWrapW(m_hwndGen, IDC_RECEIVED, wszDate);
}
else if (m_pmp->dwFlags & ARF_UNSENT)
{
LoadString(g_hLocRes, idsUnderComp, rgch, ARRAYSIZE(rgchFmt));
SetDlgItemText(m_hwndGen, IDC_RECEIVED, rgch);
}
// Free the string table
for (register int i=0; i < freeMax; i++)
if (rgszFree[i])
MemFree(rgszFree[i]);
}
void CMsgProps::InitDetailsPage(HWND hwnd)
{
LPSTREAM pstm;
BODYOFFSETS rOffset;
char *psz;
int cch;
Assert(m_pmp);
Assert(m_pmp->pMsg);
// fill in the headers...
if(m_pmp->pMsg->GetMessageSource(&pstm, 0)==S_OK)
{
HrRewindStream(pstm);
m_pmp->pMsg->GetBodyOffsets(HBODY_ROOT, &rOffset);
cch=rOffset.cbBodyStart;
if(MemAlloc((LPVOID *)&psz, cch+1))
{
if(!pstm->Read(psz, cch, NULL))
{
psz[cch]=0; // null term this
SetDlgItemText(hwnd, idcTxtHeaders, psz);
}
MemFree(psz);
}
ReleaseObj(pstm);
}
else
EnableWindow(GetDlgItem(hwnd, idbMsgSource), FALSE);
if (!m_pmp->fSecure || !m_pmp->pSecureMsg)
ShowWindow(GetDlgItem(hwnd, idbSecMsgSource), SW_HIDE);
}
INT_PTR CALLBACK CMsgProps::DetailsPageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
CMsgProps *pmprop=0;
switch(msg)
{
case WM_INITDIALOG:
pmprop=(CMsgProps *) ((PROPSHEETPAGE *)lParam)->lParam;
SetDlgThisPtr(hwnd, (LPARAM)pmprop);
Assert(pmprop);
pmprop->InitDetailsPage(hwnd);
return TRUE;
case WM_COMMAND:
pmprop=(CMsgProps *)GetDlgThisPtr(hwnd);
if(GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
{
if (GET_WM_COMMAND_ID(wParam, lParam)==idbMsgSource)
{
MimeEditViewSource(pmprop->m_pmp->hwndParent, pmprop->m_pmp->pMsg);
return(FALSE);
}
else if (GET_WM_COMMAND_ID(wParam, lParam)==idbSecMsgSource)
{
MimeEditViewSource(pmprop->m_pmp->hwndParent, pmprop->m_pmp->pSecureMsg);
return(FALSE);
}
}
else if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_SETFOCUS) {
if (GET_WM_COMMAND_ID(wParam, lParam) == idcTxtHeaders) {
// Remove the selection!
SendDlgItemMessage(hwnd, idcTxtHeaders, EM_SETSEL, -1, -1);
// fall through to default processing.
}
}
return TRUE;
case WM_NOTIFY:
switch(((NMHDR FAR *)lParam)->code)
{
pmprop=(CMsgProps *)GetDlgThisPtr(hwnd);
case PSN_APPLY:
case PSN_KILLACTIVE:
case PSN_SETACTIVE:
return TRUE;
}
break;
case WM_CLOSE:
{
PostMessage(GetParent(hwnd), WM_CLOSE, 0, 0);
break;
}
}
return FALSE;
}
#ifdef WIN16
static const char s_cszDlgSec[] = "PDLGSECUTIRY";
#endif
INT_PTR CALLBACK CMsgProps::SecurityPageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
PMSGPROP pMsgProp = (PMSGPROP)0;
DLGSECURITY *pDlgSec;
switch(msg)
{
case WM_INITDIALOG:
{
CMsgProps *pmprop;
pmprop=(CMsgProps *) ((PROPSHEETPAGE *)lParam)->lParam;
SetWndThisPtr(hwnd, (LPARAM)pmprop->m_pmp);
if (pmprop)
pmprop->InitSecurityPage(hwnd);
}
return TRUE;
case WM_COMMAND:
if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
{
switch(GET_WM_COMMAND_ID(wParam, lParam))
{
case idcAddCert:
pDlgSec = (PDLGSECURITY)GET_DIALOG_SECURITY(hwnd);
pMsgProp = (PMSGPROP)GetWndThisPtr(hwnd);
// Get thumbprint into WAB and cert into AddressBook CAPI store
// cert goes to store first so CAPI details page can find it
if (pDlgSec && pMsgProp)
{
if (SUCCEEDED(HrAddSenderCertToWab(hwnd,
pMsgProp->pMsg,
pMsgProp->lpWabal,
&pDlgSec->tbSenderThumbprint,
&pDlgSec->blSymCaps,
pDlgSec->ftSigningTime,
WFF_CREATE | WFF_SHOWUI)))
{
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaMail),
MAKEINTRESOURCEW(idsSenderCertAdded), NULL, MB_ICONINFORMATION | MB_OK);
}
}
return(FALSE);
case idcVerifySig:
pDlgSec = (PDLGSECURITY)GET_DIALOG_SECURITY(hwnd);
if (CommonUI_ViewSigningCertificate(hwnd, pDlgSec->pSenderCert, pDlgSec->hcMsg))
MessageBeep(MB_OK);
return(FALSE);
case idcViewCerts:
pMsgProp = (PMSGPROP)GetWndThisPtr(hwnd);
return (DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddMsgProp_Sec_ViewCert),
hwnd, ViewSecCertDlgProc, (LPARAM) (pMsgProp)) == IDOK);
case idcCertHelp:
OEHtmlHelp(hwnd, c_szCtxHelpFileHTMLCtx, HH_DISPLAY_TOPIC, (DWORD_PTR)(LPCSTR)"mail_overview_send_secure_messages.htm");
return(FALSE);
default:
break;
}
}
return TRUE;
case WM_DESTROY:
pDlgSec = (PDLGSECURITY)GET_DIALOG_SECURITY(hwnd);
if (pDlgSec)
{
if (pDlgSec->pSenderCert)
CertFreeCertificateContext(pDlgSec->pSenderCert);
if (pDlgSec->pEncSenderCert)
CertFreeCertificateContext(pDlgSec->pEncSenderCert);
if (pDlgSec->pEncryptionCert)
CertFreeCertificateContext(pDlgSec->pEncryptionCert);
if (pDlgSec->tbSenderThumbprint.pBlobData)
MemFree(pDlgSec->tbSenderThumbprint.pBlobData);
if (pDlgSec->hcMsg) {
if (! CertCloseStore(pDlgSec->hcMsg, 0)) {
DOUTL(DOUTL_CRYPT, "CertCloseStore (message store) failed");
}
pDlgSec->hcMsg = NULL;
}
MemFree(pDlgSec);
CLEAR_DIALOG_SECURITY(hwnd);
}
return NULL;
case WM_NOTIFY:
switch(((NMHDR FAR *)lParam)->code)
{
case PSN_APPLY:
case PSN_KILLACTIVE:
case PSN_SETACTIVE:
return TRUE;
}
break;
}
return FALSE;
}
void CMsgProps::InitSecurityPage(HWND hwnd)
{
DWORD cb;
DWORD i;
HRESULT hr;
TCHAR szYes[CCHMAX_STRINGRES/4],
szNo[CCHMAX_STRINGRES/4],
szMaybe[CCHMAX_STRINGRES/4],
szNA[CCHMAX_STRINGRES/4];
HWND hwndCtrl;
DLGSECURITY *pDlgSec;
IMimeBody *pBody;
PROPVARIANT var;
ULONG secType, ulROVal;
BOOL fNoEncAlg = TRUE;
LPTSTR sz;
LPMIMEMESSAGE pMsg = m_pmp->pMsg;
PCCERT_CONTEXT pccert = NULL;
TCHAR szTmp[CCHMAX_STRINGRES];
HBODY hBody = NULL;
SECSTATE SecState ={0};
// We need these to set the statics
LoadString(g_hLocRes, idsOui, szYes, ARRAYSIZE(szYes));
LoadString(g_hLocRes, idsNon, szNo, ARRAYSIZE(szNo));
LoadString(g_hLocRes, idsMaybe, szMaybe, ARRAYSIZE(szMaybe));
LoadString(g_hLocRes, idsNotApplicable, szNA, ARRAYSIZE(szNA));
if(FAILED(HrGetSecurityState(m_pmp->pMsg, &SecState, &hBody)))
return;
CleanupSECSTATE(&SecState);
if (FAILED(m_pmp->pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (void **)&pBody)))
return;
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_TYPE, &var)))
secType = var.ulVal;
// Set up storage for the other security info that
// we care about
if (MemAlloc((LPVOID *)&pDlgSec, sizeof(*pDlgSec)))
{
memset(pDlgSec, 0, sizeof(*pDlgSec));
#ifdef _WIN64
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE_64, &var)))
{
pDlgSec->hcMsg = (HCERTSTORE)(var.pulVal); // Closed in WM_DESTROY
}
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING_64, &var)))
{
// we don't have to dupe the pDlgSec cert because we won't free
// the var's.
pDlgSec->pSenderCert = (PCCERT_CONTEXT)(var.pulVal);
}
#else // !_WIN64
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE, &var)))
{
pDlgSec->hcMsg = (HCERTSTORE) var.ulVal; // Closed in WM_DESTROY
}
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING, &var)))
{
// we don't have to dupe the pDlgSec cert because we won't free
// the var's.
pDlgSec->pSenderCert = (PCCERT_CONTEXT) var.ulVal;
}
#endif // _WIN64
hr = GetSigningCert(m_pmp->pMsg, &pccert,
&pDlgSec->tbSenderThumbprint, &pDlgSec->blSymCaps,
&pDlgSec->ftSigningTime);
if (FAILED(hr) && (hr != MIME_E_SECURITY_NOCERT))
{
SUCCEEDED(hr);
}
}
SET_DIALOG_SECURITY(hwnd, (LPARAM)pDlgSec);
// we use the same dlgproc for sent items and recd items
// so use if statements to check for existance of all
// non-common controls
// set up the statics based on the message's info
if(IsSigned(secType))
{
LPSTR szCertEmail = SzGetCertificateEmailAddress(pccert);
SetDlgItemText(hwnd, idcStaticDigSign, szCertEmail);
MemFree(szCertEmail);
SetDlgItemText(hwnd, idcStaticRevoked,
(LPCTSTR)(((DwGetOption(OPT_REVOKE_CHECK) != 0) && !g_pConMan->IsGlobalOffline() && CheckCDPinCert(pMsg))
? szYes
: szNo));
}
else
{
SetDlgItemText(hwnd, idcStaticDigSign, szNA);
SetDlgItemText(hwnd, idcStaticRevoked, szNA);
}
SetDlgItemText(hwnd, idcStaticEncrypt,
(LPCTSTR)(IsEncrypted(secType)
? szYes
: szNo));
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_RO_MSG_VALIDITY, &var)))
ulROVal = var.ulVal;
else
ulROVal = MSV_INVALID|MSV_UNVERIFIABLE;
#ifdef SMIME_V3
if(!IsSMIME3Supported())
{
LoadString(g_hLocRes, idsRecUnknown, szTmp, ARRAYSIZE(szTmp));
SendMessage(GetDlgItem(hwnd, idcRetRecReq), WM_SETTEXT, 0, LPARAM(LPCTSTR(szTmp)));
}
else
{
if(FPresentPolicyRegInfo())
{
if ((hwndCtrl = GetDlgItem(hwnd, idcSecLabelText)) && IsSigned(secType))
{
LPWSTR pwStr = NULL;
// Set Label text
if((hr = HrGetLabelString(m_pmp->pMsg, &pwStr)) == S_OK)
{
SetWindowTextWrapW(hwndCtrl, pwStr);
SafeMemFree(pwStr);
}
else
SendMessage(hwndCtrl, WM_SETTEXT, 0, LPARAM(LPCTSTR(SUCCEEDED(hr) ? szYes : szNo)));
}
}
// Check receipt request
if ((hwndCtrl = GetDlgItem(hwnd, idcRetRecReq)))
{
if (!IsSigned(secType))
sz = szNA;
else
{
PSMIME_RECEIPT pSecReceipt = NULL;
if(CheckDecodedForReceipt(m_pmp->pMsg, &pSecReceipt) == S_OK)
sz = szNA;
else
sz = (secType & MST_RECEIPT_REQUEST) ? szYes : szNo;
SafeMemFree(pSecReceipt);
}
SendMessage(hwndCtrl, WM_SETTEXT, 0, LPARAM(LPCTSTR(sz)));
}
}
#endif // SMIME_V3
////////
// begin sign dependent block
if (!IsSigned(secType))
sz = szNA;
if ((hwndCtrl = GetDlgItem(hwnd, idcStaticAlter)))
{
if (IsSigned(secType))
{
sz = (MSV_SIGNATURE_MASK & ulROVal)
? (MSV_BADSIGNATURE & ulROVal)
? szNo
: szMaybe
: ((pccert != NULL) ? szYes : szMaybe);
}
SendMessage(hwndCtrl, WM_SETTEXT, 0, LPARAM(LPCTSTR(sz)));
}
if ((hwndCtrl = GetDlgItem(hwnd, idcStaticTrust)) &&
SUCCEEDED(pBody->GetOption(OID_SECURITY_USER_VALIDITY, &var)))
{
if (IsSigned(secType))
{
sz = (ATHSEC_TRUSTSTATEMASK & var.ulVal)
? ((ATHSEC_NOTRUSTNOTTRUSTED & var.ulVal) || (ulROVal & MSV_EXPIRED_SIGNINGCERT))
? szNo
: szMaybe
: szYes;
}
SendMessage(hwndCtrl, WM_SETTEXT, 0, LPARAM(LPCTSTR(sz)));
}
if((hwndCtrl = GetDlgItem(hwnd, idcStaticRevStatus)) && IsSigned(secType))
{
if((DwGetOption(OPT_REVOKE_CHECK) != 0) && !g_pConMan->IsGlobalOffline() && CheckCDPinCert(pMsg))
{
if(var.ulVal & ATHSEC_NOTRUSTREVOKED)
LoadString(g_hLocRes, idsWrnSecurityCertRevoked, szTmp, ARRAYSIZE(szTmp));
else if(var.ulVal & ATHSEC_NOTRUSTREVFAIL)
LoadString(g_hLocRes, idsWrnSecurityRevFail, szTmp, ARRAYSIZE(szTmp));
else
LoadString(g_hLocRes, idsOkSecurityCertRevoked, szTmp, ARRAYSIZE(szTmp));
}
else if((DwGetOption(OPT_REVOKE_CHECK) != 0) && !g_pConMan->IsGlobalOffline() && !CheckCDPinCert(pMsg))
LoadString(g_hLocRes, idsWrnSecurityNoCDP, szTmp, ARRAYSIZE(szTmp));
else if((DwGetOption(OPT_REVOKE_CHECK) != 0) && g_pConMan->IsGlobalOffline())
LoadString(g_hLocRes, idsRevokationOffline, szTmp, ARRAYSIZE(szTmp));
else if(DwGetOption(OPT_REVOKE_CHECK) == 0)
LoadString(g_hLocRes, idsRevokationTurnedOff, szTmp, ARRAYSIZE(szTmp));
SendMessage(hwndCtrl, WM_SETTEXT, 0, LPARAM(LPCTSTR(szTmp)));
}
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_INCLUDED, &var)))
{
if (IsSigned(secType))
sz = (var.boolVal == TRUE) ? szYes : szNo;
SetDlgItemText(hwnd, idcStaticCertInc, LPCTSTR(sz));
}
// end signing dependent block
////////
if (IsEncrypted(secType) && SUCCEEDED(pBody->GetOption(OID_SECURITY_ALG_BULK, &var)))
{
Assert(var.vt == VT_BLOB);
if (var.vt == VT_BLOB && var.blob.cbSize && var.blob.pBlobData)
{
LPCTSTR pszProtocol = NULL;
// Convert the SYMCAPS blob to an "encrypted using" string
if (SUCCEEDED(MimeOleAlgNameFromSMimeCap(var.blob.pBlobData, var.blob.cbSize,
&pszProtocol)))
{ // Note: returns a static string. Don't free it.
if (pszProtocol)
{
SendMessage(GetDlgItem(hwnd, idcStaticEncAlg), WM_SETTEXT, 0, (LPARAM)pszProtocol);
fNoEncAlg = FALSE;
}
}
// Free the data
MemFree(var.blob.pBlobData);
}
}
if (fNoEncAlg)
{
SendMessage(GetDlgItem(hwnd, idcStaticEncAlg), WM_SETTEXT, 0,
LPARAM(LPCTSTR(szNA)));
}
if (pccert != NULL)
CertFreeCertificateContext(pccert);
ReleaseObj(pBody);
return;
}
INT_PTR CALLBACK ViewSecCertDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LPMIMEMESSAGE pMsg = NULL;
IMimeBody *pBody;
PROPVARIANT var;
DLGSECURITY *pDlgSec;
ULONG secType, ulROVal;
HWND hwndCtrl = NULL;
PMSGPROP pMsgProp = (PMSGPROP)0;
HRESULT hr = S_OK;
TCHAR szTmp[CCHMAX_STRINGRES];
HBODY hBody = NULL;
HBODY hInerBody = NULL;
SECSTATE SecState ={0};
switch (message)
{
case WM_INITDIALOG:
TCHAR szNA[CCHMAX_STRINGRES/4];
SetWndThisPtr(hwnd, lParam);
CenterDialog(hwnd);
pMsgProp = (PMSGPROP) lParam;
pMsg = pMsgProp->pMsg;
LoadString(g_hLocRes, idsNotApplicable, szNA, ARRAYSIZE(szNA));
if(FAILED(HrGetSecurityState(pMsgProp->pMsg, &SecState, &hBody)))
return FALSE;
if(FAILED(HrGetInnerLayer(pMsgProp->pMsg, &hInerBody)))
return FALSE;
if((!IsSignTrusted(&SecState) || !IsEncryptionOK(&SecState)) && (hBody != hInerBody))
EnableWindow(GetDlgItem(hwnd, idcAddCert), FALSE);
CleanupSECSTATE(&SecState);
if (FAILED(pMsgProp->pMsg->BindToObject(hBody ? hBody : HBODY_ROOT, IID_IMimeBody, (void **)&pBody)))
return FALSE;
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_TYPE, &var)))
secType = var.ulVal;
// Set up storage for the other security info that
// we care about
if (MemAlloc((LPVOID *)&pDlgSec, sizeof(*pDlgSec)))
{
memset(pDlgSec, 0, sizeof(*pDlgSec));
#ifdef _WIN64
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE_64, &var)))
{
pDlgSec->hcMsg = (HCERTSTORE)(var.pulVal); // Closed in WM_DESTROY
}
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING_64, &var)))
{
// we don't have to dupe the pDlgSec cert because we won't free
// the var's.
pDlgSec->pSenderCert = (PCCERT_CONTEXT)(var.pulVal);
}
#else // !_WIN64
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_HCERTSTORE, &var)))
{
pDlgSec->hcMsg = (HCERTSTORE) var.ulVal; // Closed in WM_DESTROY
}
if (SUCCEEDED(pBody->GetOption(OID_SECURITY_CERT_SIGNING, &var)))
{
// we don't have to dupe the pDlgSec cert because we won't free
// the var's.
pDlgSec->pSenderCert = (PCCERT_CONTEXT) var.ulVal;
}
#endif // _WIN64
hr = GetSignerEncryptionCert(pMsgProp->pMsg, &pDlgSec->pEncSenderCert,
&pDlgSec->tbSenderThumbprint, &pDlgSec->blSymCaps,
&pDlgSec->ftSigningTime);
if (FAILED(hr) && (hr != MIME_E_SECURITY_NOCERT))
{
SUCCEEDED(hr);
}
}
if(IsEncrypted(secType))
{
#ifdef _WIN64
if (SUCCEEDED(hr = pBody->GetOption(OID_SECURITY_CERT_DECRYPTION_64, &var)))
{
Assert(VT_UI8 == var.vt);
if ((PCCERT_CONTEXT)(var.pulVal))
pDlgSec->pEncryptionCert = (PCCERT_CONTEXT)(var.pulVal);
}
#else // !_WIN64
if (SUCCEEDED(hr = pBody->GetOption(OID_SECURITY_CERT_DECRYPTION, &var)))
{
Assert(VT_UI4 == var.vt);
if (*(PCCERT_CONTEXT *)(&(var.uhVal)))
pDlgSec->pEncryptionCert = *(PCCERT_CONTEXT *)(&(var.uhVal));
}
#endif // _WIN64
}
else
pDlgSec->pEncryptionCert = NULL;
SET_DIALOG_SECURITY(hwnd, (LPARAM)pDlgSec);
if (pDlgSec->pEncSenderCert == NULL)
{
// Disable Add to Address Book button
if ((hwndCtrl = GetDlgItem(hwnd, idcAddCert)))
EnableWindow(hwndCtrl, FALSE);
// Disable View sender's encrypt cert.
if ((hwndCtrl = GetDlgItem(hwnd, idcSendersEncryptionCert)))
EnableWindow(hwndCtrl, FALSE);
LoadString(g_hLocRes, idsEncrCertNotIncluded, szTmp, ARRAYSIZE(szTmp));
SetDlgItemText(hwnd, idcStaticSendersCert, LPCTSTR(szTmp));
}
//
if (pDlgSec->pSenderCert == NULL)
{
if ((hwndCtrl = GetDlgItem(hwnd, idcVerifySig)))
EnableWindow(hwndCtrl, FALSE);
LoadString(g_hLocRes, idsSignCertNotIncl, szTmp, ARRAYSIZE(szTmp));
SetDlgItemText(hwnd, idcStaticSigningCert, LPCTSTR(szTmp));
}
if(pDlgSec->pEncryptionCert == NULL)
{
if ((hwndCtrl = GetDlgItem(hwnd, idcViewEncrytionCert)))
EnableWindow(hwndCtrl, FALSE);
if(IsEncrypted(secType))
LoadString(g_hLocRes, idsEncrCertNotFoundOnPC, szTmp, ARRAYSIZE(szTmp));
else
LoadString(g_hLocRes, idsMsgWasNotEncrypted, szTmp, ARRAYSIZE(szTmp));
SetDlgItemText(hwnd, idcStaticEncryptionCert, LPCTSTR(szTmp));
}
if(pDlgSec->blSymCaps.cbSize > 0)
{
// Convert the SYMCAPS blob to an "encrypted using" string
LPCTSTR pszProtocol = NULL;
if (SUCCEEDED(MimeOleAlgNameFromSMimeCap(pDlgSec->blSymCaps.pBlobData, pDlgSec->blSymCaps.cbSize,
&pszProtocol)))
{ // Note: returns a static string. Don't free it.
if (pszProtocol)
SetDlgItemText(hwnd, idcStaticEncryptAlgorithm, LPCTSTR(pszProtocol));
}
}
else
SetDlgItemText(hwnd, idcStaticEncryptAlgorithm, LPCTSTR(szNA));
if(pBody)
ReleaseObj(pBody);
break;
case WM_COMMAND:
pDlgSec = (PDLGSECURITY)GET_DIALOG_SECURITY(hwnd);
pMsgProp = (PMSGPROP)GetWndThisPtr(hwnd);
pMsg = pMsgProp->pMsg;
switch (LOWORD(wParam))
{
case idcAddCert:
// Get thumbprint into WAB and cert into AddressBook CAPI store
// cert goes to store first so CAPI details page can find it
if (pDlgSec && pMsgProp)
{
if (SUCCEEDED(HrAddSenderCertToWab(hwnd,
pMsgProp->pMsg,
pMsgProp->lpWabal,
&pDlgSec->tbSenderThumbprint,
&pDlgSec->blSymCaps,
pDlgSec->ftSigningTime,
WFF_CREATE | WFF_SHOWUI)))
{
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaMail),
MAKEINTRESOURCEW(idsSenderCertAdded), NULL, MB_ICONINFORMATION | MB_OK);
}
}
break;
case idcVerifySig:
if (CommonUI_ViewSigningCertificate(hwnd, pDlgSec->pSenderCert, pDlgSec->hcMsg))
MessageBeep(MB_OK);
return(FALSE);
case idcViewEncrytionCert:
if (CommonUI_ViewSigningCertificate(hwnd, pDlgSec->pEncryptionCert, pDlgSec->hcMsg))
MessageBeep(MB_OK);
return(FALSE);
case idcSendersEncryptionCert:
if (CommonUI_ViewSigningCertificate(hwnd, pDlgSec->pEncSenderCert, pDlgSec->hcMsg))
MessageBeep(MB_OK);
return(FALSE);
case IDOK:
case IDCANCEL:
EndDialog(hwnd, LOWORD(wParam));
return(TRUE);
}
break; // wm_command
case WM_CLOSE:
SendMessage(hwnd, WM_COMMAND, IDCANCEL, 0L);
return (TRUE);
case WM_DESTROY:
pDlgSec = (PDLGSECURITY)GET_DIALOG_SECURITY(hwnd);
if (pDlgSec)
{
if (pDlgSec->pSenderCert)
CertFreeCertificateContext(pDlgSec->pSenderCert);
if (pDlgSec->pEncSenderCert)
CertFreeCertificateContext(pDlgSec->pEncSenderCert);
if (pDlgSec->pEncryptionCert)
CertFreeCertificateContext(pDlgSec->pEncryptionCert);
if (pDlgSec->tbSenderThumbprint.pBlobData)
MemFree(pDlgSec->tbSenderThumbprint.pBlobData);
if (pDlgSec->hcMsg)
{
if (! CertCloseStore(pDlgSec->hcMsg, 0))
{
DOUTL(DOUTL_CRYPT, "CertCloseStore (message store) failed");
}
pDlgSec->hcMsg = NULL;
}
MemFree(pDlgSec);
CLEAR_DIALOG_SECURITY(hwnd);
}
} // message switch
return(FALSE);
}