/* * 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 #ifdef WIN16 #include "mapi.h" #endif #include #include #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 #include #include #include #include #include #include #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); }