#include "pch.hxx" #include "msgsite.h" #include "secutil.h" #include "mailutil.h" #include "conman.h" #include "newfldr.h" #include "storutil.h" #include "msoeobj.h" #include "regutil.h" #include "mapiutil.h" #include "browser.h" #include "receipts.h" #include "shlwapip.h" #include "msoert.h" // **************************************** COEMsgSite::COEMsgSite() { m_pMsg = NULL; m_pOrigMsg = NULL; m_pStoreCB = NULL; m_pMsgTable = NULL; m_pListSelect = NULL; m_pCBMsgFolder = NULL; m_fCBCopy = FALSE; m_fCBSavedInDrafts = FALSE; m_fCBSaveInFolderAndDelOrig = FALSE; m_fGotNewID = FALSE; m_fHeaderOnly = FALSE; m_fValidMessage = FALSE; m_fNeedToLoadMsg = TRUE; m_fHaveCBMessageID = TRUE; m_fThreadingEnabled = FALSE; m_fReloadMessageFlag = TRUE; m_dwArfFlags = 0; m_dwMSAction = MSA_IDLE; m_dwCMFState = CMF_UNINITED; m_dwOrigFolderIsImap = OFIMAP_UNDEFINED; m_cRef = 1; m_FolderID = FOLDERID_INVALID; m_CBFolderID = FOLDERID_INVALID; m_MessageID = 0; m_CBMessageID = 0; m_NewMessageID = 0; *m_rgwchFileName = 0; m_pFolderReleaseOnComplete = NULL; m_dwMDNFlags = 0; if (!!DwGetOption(OPT_MDN_SEND_REQUEST)) m_dwMDNFlags |= MDN_REQUEST; } // **************************************** COEMsgSite::~COEMsgSite() { Assert(!m_pMsg); Assert(!m_pOrigMsg); Assert(!m_pMsgTable); Assert(!m_pStoreCB); Assert(!m_pListSelect); AssertSz(!m_pCBMsgFolder, "Who missed freeing this?"); ReleaseObj(m_pFolderReleaseOnComplete); } // **************************************** HRESULT COEMsgSite::QueryInterface(REFIID riid, LPVOID FAR *lplpObj) { if(!lplpObj) return E_INVALIDARG; *lplpObj = NULL; if (IsEqualIID(riid, IID_IUnknown)) *lplpObj = (LPVOID)this; else return E_NOINTERFACE; AddRef(); return NOERROR; } // **************************************** ULONG COEMsgSite::AddRef() { return ++m_cRef; } // **************************************** ULONG COEMsgSite::Release() { if(--m_cRef==0) { delete this; return 0; } return m_cRef; } // **************************************** BOOL COEMsgSite::ThreadingEnabled(void) { BOOL fEnabled = FALSE; FOLDERSORTINFO SortInfo; Assert(OEMSIT_MSG_TABLE == m_dwInitType); if (SUCCEEDED(m_pMsgTable->GetSortInfo(&SortInfo))) fEnabled = SortInfo.fThreaded; return fEnabled; } // **************************************** HRESULT COEMsgSite::Init(INIT_MSGSITE_STRUCT *pInitStruct) { // WARNING!!! pStoreCB will not have been setup by this point. // Use it in this function only if you are sure things will work. // For instance, the hwnd will not get setup yet so GetCallbackHwnd // will not work appropriatly. Assert(pInitStruct); HRESULT hr = S_OK; m_dwInitType = pInitStruct->dwInitType; m_fValidMessage = TRUE; switch (m_dwInitType) { case OEMSIT_MSG_TABLE: { Assert (m_pMsgTable==NULL); ReplaceInterface(m_pMsgTable, pInitStruct->initTable.pMsgTable); if (m_pMsgTable) m_pMsgTable->ConnectionAddRef(); ReplaceInterface(m_pListSelect, pInitStruct->initTable.pListSelect); hr = m_pMsgTable->GetRowMessageId(pInitStruct->initTable.rowIndex, &m_MessageID); if (FAILED(hr)) break; m_FolderID = pInitStruct->folderID; m_fThreadingEnabled = ThreadingEnabled(); break; } case OEMSIT_STORE: AssertSz(FALSE, "Can't init using the store..."); hr = E_UNEXPECTED; break; case OEMSIT_FAT: StrCpyNW(m_rgwchFileName, pInitStruct->pwszFile, ARRAYSIZE(m_rgwchFileName)); break; case OEMSIT_MSG: m_FolderID = pInitStruct->folderID; ReplaceInterface(m_pMsg, pInitStruct->pMsg); break; case OEMSIT_VIRGIN: m_FolderID = pInitStruct->folderID; break; default: hr = E_UNEXPECTED; break; } /* ~~~ Took this out of mailnote.cpp HrInit(pcni) code. How do we get this to work??? ~~~ It is suppose to notify us if a folder has been deleted. In that case, we would ~~~ need to convert the msgSite to a msg based msgsite. if (m_pMsgTable) m_pMsgTable->Advise(GetCallbackHwnd()); if (FAILED(hr = CreateNotify(&m_pFldrDelNotify)) || FAILED(hr = m_pFldrDelNotify->Initialize((TCHAR *)c_szFolderDelNotify)) || FAILED(hr = m_pFldrDelNotify->Register(GetCallbackHwnd(), g_hwndInit, FALSE))) goto error; */ return hr; } // **************************************** HRESULT COEMsgSite::GetStatusFlags(DWORD *pdwFlags) { DWORD dwNewFlags = OEMSF_CAN_COPY | OEMSF_CAN_SAVE; if (!!(m_dwMDNFlags & MDN_REQUEST)) { dwNewFlags |= OEMSF_MDN_REQUEST; } switch (m_dwInitType) { case OEMSIT_MSG_TABLE: case OEMSIT_STORE: { FOLDERTYPE folderType = GetFolderType(m_FolderID); dwNewFlags |= OEMSF_CAN_MARK | OEMSF_FROM_STORE; // GetMessageFlags is fairly intensive to be called as often as GetStatusFlags // is called. Since this flag really only matters at load time, we will only go // and get the value after a load from store. Otherwise, we will use the // cached value from m_fSecUI. if (m_fReloadMessageFlag) { m_dwArfFlags = 0; GetMessageFlags(&m_dwArfFlags); m_fReloadMessageFlag = FALSE; } if (0 == (m_dwArfFlags & ARF_READ)) dwNewFlags |= OEMSF_UNREAD; // If we came from a store and we are a new folder, then can't delete if (FOLDER_NEWS != folderType) { dwNewFlags |= OEMSF_CAN_MOVE; if (0 == (m_dwArfFlags & ARF_ENDANGERED)) dwNewFlags |= OEMSF_CAN_DELETE; if ((FOLDER_HTTPMAIL == folderType) || (FOLDER_IMAP == folderType)) dwNewFlags |= OEMSF_RULESNOTENABLED; } if (OEMSIT_MSG_TABLE == m_dwInitType) { dwNewFlags |= OEMSF_CAN_NEXT|OEMSF_CAN_PREV; if (m_fThreadingEnabled) dwNewFlags |= OEMSF_THREADING_ENABLED; } if (m_dwArfFlags & ARF_UNSENT) { // If we are table based, need to do extra checking for IMAP message in find folder if (OEMSIT_MSG_TABLE == m_dwInitType) { if (OFIMAP_UNDEFINED == m_dwOrigFolderIsImap) { FOLDERINFO fi; if (SUCCEEDED(g_pStore->GetFolderInfo(m_FolderID, &fi))) { // If is a find folder, check to see if message is IMAP if (FOLDER_FINDRESULTS & (fi.dwFlags)) { // Get original folder for this message (ie, not the find folder) IMessageFolder *pMsgFolder = NULL; if (SUCCEEDED(g_pStore->OpenFolder(m_FolderID, NULL, NOFLAGS, &pMsgFolder))) { // If original folder type is IMAP, then don't set unsent flag FOLDERID folderID; if (SUCCEEDED(pMsgFolder->GetMessageFolderId(m_MessageID, &folderID))) { FOLDERTYPE origFolderType = GetFolderType(folderID); if (FOLDER_IMAP != origFolderType) { m_dwOrigFolderIsImap = OFIMAP_FALSE; dwNewFlags |= OEMSF_UNSENT; } else m_dwOrigFolderIsImap = OFIMAP_TRUE; } pMsgFolder->Release(); } } else dwNewFlags |= OEMSF_UNSENT; g_pStore->FreeRecord(&fi); } } else if (OFIMAP_FALSE == m_dwOrigFolderIsImap) dwNewFlags |= OEMSF_UNSENT; } else dwNewFlags |= OEMSF_UNSENT; } if (0 == (m_dwArfFlags & ARF_NOSECUI)) dwNewFlags |= OEMSF_SEC_UI_ENABLED; if (m_dwArfFlags & ARF_NEWSMSG) dwNewFlags |= OEMSF_BASEISNEWS; break; } case OEMSIT_FAT: { LPWSTR pwszUnsent = NULL, pwszExt = PathFindExtensionW(m_rgwchFileName); dwNewFlags |= OEMSF_CAN_DELETE | OEMSF_CAN_MOVE | OEMSF_SEC_UI_ENABLED; dwNewFlags |= OEMSF_FROM_FAT; if (SUCCEEDED(MimeOleGetBodyPropW(m_pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_XUNSENT), NOFLAGS, &pwszUnsent))) { if (FALSE == FIsEmptyW(pwszUnsent)) dwNewFlags |= OEMSF_UNSENT; SafeMemFree(pwszUnsent); } if (0 == StrCmpW(pwszExt, c_wszNwsExt)) dwNewFlags |= OEMSF_BASEISNEWS; break; } case OEMSIT_MSG: dwNewFlags |= OEMSF_FROM_MSG; break; case OEMSIT_VIRGIN: dwNewFlags |= OEMSF_VIRGIN | OEMSF_UNSENT; break; } *pdwFlags = dwNewFlags; return S_OK; } // **************************************** HRESULT COEMsgSite::DeleteFromStore(DELETEMESSAGEFLAGS dwFlags) { HRESULT hr; AssertSz(!m_pCBMsgFolder, "Someone forgot to release this baby."); Assert(m_pStoreCB); hr = g_pStore->OpenFolder(m_FolderID, NULL, NOFLAGS, &m_pCBMsgFolder); if (SUCCEEDED(hr)) { MESSAGEIDLIST list; FOLDERINFO fi; list.cMsgs = 1; list.prgidMsg = &m_MessageID; hr = m_pCBMsgFolder->DeleteMessages(dwFlags, &list, NULL, m_pStoreCB); if (E_PENDING != hr) SafeRelease(m_pCBMsgFolder); } return hr; } // **************************************** HRESULT COEMsgSite::DeleteFromMsgTable(DELETEMESSAGEFLAGS dwFlags) { HRESULT hr; ROWINDEX iRow = -1, iNewRow = -1; AssertSz(m_pMsgTable, "How can you be OEMSIT_MSG_TABLE and not have a table"); m_fGotNewID = FALSE; hr = m_pMsgTable->GetRowIndex(m_MessageID, &iRow); if (FAILED(hr)) goto Exit; if (SUCCEEDED(m_pMsgTable->GetNextRow(iRow, GETNEXT_NEXT, ROWMSG_ALL, 0, &iNewRow)) && SUCCEEDED(m_pMsgTable->GetRowMessageId(iNewRow, &m_NewMessageID))) m_fGotNewID = TRUE; hr = m_pMsgTable->DeleteRows(dwFlags, 1, &iRow, FALSE, m_pStoreCB); if (FAILED(hr) && (E_PENDING != hr)) AthMessageBoxW(GetCallbackHwnd(), MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsErrDeleteMsg), NULL, MB_OK); Exit: return hr; } // **************************************** HRESULT COEMsgSite::Delete(DELETEMESSAGEFLAGS dwFlags) { HRESULT hr; m_dwMSAction = MSA_DELETE; switch (m_dwInitType) { case OEMSIT_MSG_TABLE: hr = DeleteFromMsgTable(dwFlags); break; case OEMSIT_STORE: hr = DeleteFromStore(dwFlags); m_fValidMessage = FALSE; break; case OEMSIT_FAT: DeleteFileWrapW(m_rgwchFileName); m_fValidMessage = FALSE; m_dwMSAction = MSA_IDLE; break; // With these two, there is nothing to delete. case OEMSIT_MSG: case OEMSIT_VIRGIN: hr = S_OK; break; default: AssertSz(FALSE, "Weren't prepared to handle this initType"); hr = E_UNEXPECTED; break; } return hr; } // **************************************** HRESULT COEMsgSite::DoNextPrev(BOOL fNext, DWORD dwFlags) { HRESULT hr; if (OEMSIT_MSG_TABLE == m_dwInitType) { ROWMESSAGETYPE tyMsg; ROWINDEX iRow = 0, iNewRow = 0; MESSAGEID idNewMark; GETNEXTFLAGS dwNextFlags = 0; GETNEXTTYPE tyDir = fNext?GETNEXT_NEXT:GETNEXT_PREVIOUS; AssertSz(m_pMsgTable, "How can you be OEMSIT_MSG_TABLE and not have a table"); hr = m_pMsgTable->GetRowIndex(m_MessageID, &iRow); if (FAILED(hr)) goto Exit; if (dwFlags&OENF_SKIPMAIL) tyMsg = ROWMSG_MAIL; else if (dwFlags&OENF_SKIPNEWS) tyMsg = ROWMSG_NEWS; else tyMsg = ROWMSG_ALL; if (dwFlags&OENF_UNREAD) dwNextFlags |= GETNEXT_UNREAD; if (dwFlags&OENF_THREAD) dwNextFlags |= GETNEXT_THREAD; hr = m_pMsgTable->GetNextRow(iRow, tyDir, tyMsg, dwNextFlags, &iNewRow); if (FAILED(hr)) goto Exit; hr = m_pMsgTable->GetRowMessageId(iNewRow, &idNewMark); if (FAILED(hr)) goto Exit; if (m_pListSelect) m_pListSelect->SetActiveRow(iNewRow); m_MessageID = idNewMark; m_fNeedToLoadMsg = TRUE; } else hr = E_UNEXPECTED; Exit: AssertSz(E_PENDING != hr, "COEMsgSite::DoNextPrev not setup to handle E_PENDING."); return hr; } // **************************************** HRESULT COEMsgSite::DoCopyMoveFromMsgToFldr(IMimeMessage *pMsg, BOOL fUnSent) { HRESULT hr = E_UNEXPECTED; if (m_fCBCopy) { hr = m_pCBMsgFolder->SaveMessage(NULL, SAVE_MESSAGE_GENID, fUnSent?ARF_UNSENT:NOFLAGS, 0, pMsg, m_pStoreCB); if (SUCCEEDED(hr)) { m_dwCMFState = CMF_MSG_TO_FOLDER; OnComplete(SOT_COPYMOVE_MESSAGE, S_OK); } } else AssertSz(FALSE, "Can't move a message based on a message. Only copy."); return hr; } // **************************************** HRESULT COEMsgSite::DoCopyMoveFromStoreToFldr(BOOL fUnSent) { HRESULT hr; MESSAGEID msgID = 0; hr = SaveMessageInFolder(m_pStoreCB, m_pCBMsgFolder, m_pMsg, fUnSent?ARF_UNSENT:NOFLAGS, &msgID, TRUE); if (SUCCEEDED(hr)) { m_dwCMFState = CMF_STORE_TO_FOLDER; OnComplete(SOT_COPYMOVE_MESSAGE, S_OK); } return hr; } // **************************************** HRESULT COEMsgSite::DoCopyMoveFromTableToFldr(void) { HRESULT hr; IMessageFolder *pSrcFolder = NULL; MESSAGEIDLIST rMsgIDList; LPMESSAGEINFO pMsgInfo; ROWINDEX iRow, iNewRow; MESSAGEID msgID; FOLDERID folderID = 0; Assert(m_pStoreCB); m_fGotNewID = FALSE; if (m_pFolderReleaseOnComplete != NULL) return E_FAIL; hr = g_pStore->OpenFolder(m_FolderID, NULL, NOFLAGS, &pSrcFolder); if (FAILED(hr)) goto Exit; hr = m_pMsgTable->GetRowIndex(m_MessageID, &iRow); if (FAILED(hr)) goto Exit; // If we are moving, then we need to get the next item in the list if (!m_fCBCopy && SUCCEEDED(m_pMsgTable->GetNextRow(iRow, GETNEXT_NEXT, ROWMSG_ALL, 0, &iNewRow)) && SUCCEEDED(m_pMsgTable->GetRowMessageId(iNewRow, &m_NewMessageID))) m_fGotNewID = TRUE; hr = m_pMsgTable->GetRow(iRow, &pMsgInfo); if (FAILED(hr)) goto Exit; msgID = pMsgInfo->idMessage; m_pMsgTable->ReleaseRow(pMsgInfo); rMsgIDList.cAllocated = 0; rMsgIDList.cMsgs = 1; rMsgIDList.prgidMsg = &msgID; if (SUCCEEDED(m_pCBMsgFolder->GetFolderId(&folderID))) { m_CBFolderID = folderID; m_CBMessageID = msgID; } else { m_CBFolderID = FOLDERID_INVALID; m_dwInitType = OEMSIT_MSG; } hr = pSrcFolder->CopyMessages(m_pCBMsgFolder, m_fCBCopy?0:COPY_MESSAGE_MOVE, &rMsgIDList, NULL, NULL, m_pStoreCB); if (SUCCEEDED(hr)) { m_dwCMFState = CMF_TABLE_TO_FOLDER; OnComplete(SOT_COPYMOVE_MESSAGE, S_OK); } if (hr == E_PENDING) { ReplaceInterface(m_pFolderReleaseOnComplete, pSrcFolder); SafeRelease(pSrcFolder); } Exit: ReleaseObj(pSrcFolder); return hr; } // **************************************** HRESULT COEMsgSite::DoCopyMoveFromFATToFldr(BOOL fUnSent) { IMimeMessage *pMsg = NULL; HRESULT hr = S_OK; // Need original message, because m_pMsg is without security... hr = HrCreateMessage(&pMsg); if (FAILED(hr)) return hr; hr = HrLoadMsgFromFileW(pMsg, m_rgwchFileName); hr = SaveMessageInFolder(m_pStoreCB, m_pCBMsgFolder, pMsg, fUnSent?ARF_UNSENT:NOFLAGS, &m_CBMessageID, TRUE); if (SUCCEEDED(hr)) { m_fHaveCBMessageID = TRUE; m_dwCMFState = CMF_FAT_TO_FOLDER; OnComplete(SOT_COPYMOVE_MESSAGE, S_OK); } SafeRelease(pMsg); return hr; } // **************************************** HRESULT COEMsgSite::DoCopyMoveToFolder(BOOL fCopy, IMimeMessage *pMsg, BOOL fUnSent) { HRESULT hr; FOLDERID newFolderID; Assert(m_pStoreCB); AssertSz(NULL == m_pCBMsgFolder, "Someone forgot to release the folder"); m_fCBCopy = fCopy; m_dwMSAction = MSA_COPYMOVE; hr = SelectFolderDialog(GetCallbackHwnd(), SFD_SELECTFOLDER, m_FolderID, FD_DISABLESERVERS | TREEVIEW_NONEWS | (m_fCBCopy?FD_COPYFLAGS:FD_MOVEFLAGS), MAKEINTRESOURCE(m_fCBCopy?idsCopy:idsMove), MAKEINTRESOURCE(m_fCBCopy?idsCopyCaption:idsMoveCaption), &newFolderID); // Only want to do the copy if: // 1- The new folder is not invalid // 2- Can open the needed folder if (SUCCEEDED(hr) && (newFolderID != FOLDERID_INVALID) && SUCCEEDED(hr = g_pStore->OpenFolder(newFolderID, NULL, NOFLAGS, &m_pCBMsgFolder))) { if (pMsg) hr = DoCopyMoveFromMsgToFldr(pMsg, fUnSent); else switch (m_dwInitType) { case OEMSIT_MSG_TABLE: hr = DoCopyMoveFromTableToFldr(); break; case OEMSIT_STORE: hr = DoCopyMoveFromStoreToFldr(fUnSent); break; case OEMSIT_FAT: hr = DoCopyMoveFromFATToFldr(fUnSent); break; case OEMSIT_VIRGIN: case OEMSIT_MSG: hr = DoCopyMoveFromMsgToFldr(m_pMsg, fUnSent); break; } if (E_PENDING != hr) SafeRelease(m_pCBMsgFolder); } if (FAILED(hr) && (E_PENDING != hr) && (hrUserCancel != hr)) AthErrorMessageW(GetCallbackHwnd(), MAKEINTRESOURCEW(idsAthenaNews), MAKEINTRESOURCEW(idsCantSaveMsg), hr); return hr; } // **************************************** HRESULT COEMsgSite::Save(IMimeMessage *pMsg, DWORD dwFlags, IImnAccount *pAcct) { HRESULT hr; WORD wMessageFlags = 0; ACCTTYPE acctType = ACCT_MAIL; AssertSz(!m_pCBMsgFolder, "Someone forgot to release this baby."); m_fCBSaveInFolderAndDelOrig = !!(dwFlags & OESF_SAVE_IN_ORIG_FOLDER); m_fCBSavedInDrafts = FALSE; m_dwMSAction = MSA_SAVE; pAcct->GetAccountType(&acctType); if (ACCT_NEWS == acctType) wMessageFlags |= ARF_NEWSMSG; if (dwFlags & OESF_UNSENT) wMessageFlags |= ARF_UNSENT; if (dwFlags & OESF_READ) wMessageFlags |= ARF_READ; // Decide if want to save to drafts or some other folder if ((OEMSIT_MSG_TABLE == m_dwInitType) && m_fCBSaveInFolderAndDelOrig) { m_CBFolderID = m_FolderID; hr = g_pStore->OpenFolder(m_FolderID, NULL, NOFLAGS, &m_pCBMsgFolder); } else { FOLDERID idStore; m_fCBSavedInDrafts = TRUE; // Find store ID of account in the header // If have problems getting the special folder on the server, then use // the local store drafts. if (dwFlags & OESF_FORCE_LOCAL_DRAFT) idStore = FOLDERID_LOCAL_STORE; else { IImnAccount *pSaveAcct = NULL; if (ACCT_NEWS == acctType) GetDefaultAccount(ACCT_MAIL, &pSaveAcct); else ReplaceInterface(pSaveAcct, pAcct); if (pSaveAcct) { DWORD dw = 0; CHAR szAcctId[CCHMAX_ACCOUNT_NAME]; hr = pSaveAcct->GetPropSz(AP_ACCOUNT_ID, szAcctId, ARRAYSIZE(szAcctId)); if (SUCCEEDED(hr)) hr = g_pStore->FindServerId(szAcctId, &idStore); pSaveAcct->Release(); } else hr = E_FAIL; if (FAILED(hr)) idStore = FOLDERID_LOCAL_STORE; } hr = g_pStore->OpenSpecialFolder(idStore, NULL, FOLDER_DRAFT, &m_pCBMsgFolder); // If failed opening special folder and we weren't trying local folders, try // using local folders now. if (FAILED(hr) && (idStore != FOLDERID_LOCAL_STORE)) hr = g_pStore->OpenSpecialFolder(FOLDERID_LOCAL_STORE, NULL, FOLDER_DRAFT, &m_pCBMsgFolder); if (SUCCEEDED(hr)) { m_CBFolderID = FOLDERID_INVALID; m_pCBMsgFolder->GetFolderId(&m_CBFolderID); } } if (FAILED(hr)) goto Exit; m_CBMessageID = m_MessageID; // Save message to the folder hr = SaveMessageInFolder(m_pStoreCB, m_pCBMsgFolder, pMsg, wMessageFlags, &m_CBMessageID, TRUE); if (SUCCEEDED(hr)) m_fHaveCBMessageID = TRUE; else if (E_PENDING == hr) { ReplaceInterface(m_pMsg, pMsg); m_fHaveCBMessageID = FALSE; } Exit: if (E_PENDING != hr) SafeRelease(m_pCBMsgFolder); if (FAILED(hr) && (hrUserCancel != hr) && (E_PENDING != hr)) { int idsErr = ((MIME_E_URL_NOTFOUND == hr) ? idsErrSaveDownloadFail : idsCantSaveMsg); AthMessageBoxW(GetCallbackHwnd(), MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsCantSaveMsg), NULL, MB_OK); } return hr; } // **************************************** // Use to split this function into one for news and one for mail. Don't think that // we need to do that anymore. If there is any difference, that should probably // be moved into the message mangling phase. I can't see anything else that would // be different. #ifdef SMIME_V3 HRESULT COEMsgSite::SendMsg(IMimeMessage *pMsg, BOOL fSendImmediately, BOOL fMail, IHeaderSite *pHeaderSite) #else HRESULT COEMsgSite::SendMsg(IMimeMessage *pMsg, BOOL fSendImmediately, BOOL fMail) #endif // SMIME_V3 { HRESULT hr; // Figure out whether we need to request for MDNs. Doing it here skips processing it in smapi. if (fMail && (!!(m_dwMDNFlags & MDN_REQUEST)) && (!IsMDN(pMsg))) { LPWSTR pwsz = NULL; if (SUCCEEDED(MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_FROM), NOFLAGS, &pwsz))) { MimeOleSetBodyPropW(pMsg, HBODY_ROOT, STR_HDR_DISP_NOTIFICATION_TO, NOFLAGS, pwsz); MemFree(pwsz); } } // Account should already be setup in the message by this time. if (IsSecure(pMsg)) #ifdef SMIME_V3 hr = SendSecureMailToOutBox(m_pStoreCB, pMsg, fSendImmediately, FALSE, fMail, pHeaderSite); #else hr = SendSecureMailToOutBox(m_pStoreCB, pMsg, fSendImmediately, FALSE, fMail); #endif // SMIME_V3 else hr = SendMailToOutBox(m_pStoreCB, pMsg, fSendImmediately, FALSE, fMail); return hr; } // **************************************** BOOL COEMsgSite::NeedToSendNews(IMimePropertySet *pPropSet) { MIMEPROPINFO mimePropInfo; AssertSz(pPropSet, "A property set needs to be passed in."); if (SUCCEEDED(pPropSet->GetPropInfo(PIDTOSTR(PID_HDR_NEWSGROUPS), &mimePropInfo))) return TRUE; if (SUCCEEDED(pPropSet->GetPropInfo(PIDTOSTR(PID_HDR_FOLLOWUPTO), &mimePropInfo))) return TRUE; return FALSE; } // **************************************** BOOL COEMsgSite::NeedToSendMail(IMimePropertySet *pPropSet) { MIMEPROPINFO mimePropInfo; AssertSz(pPropSet, "A property set needs to be passed in."); if (SUCCEEDED(pPropSet->GetPropInfo(PIDTOSTR(PID_HDR_TO), &mimePropInfo))) return TRUE; if (SUCCEEDED(pPropSet->GetPropInfo(PIDTOSTR(PID_HDR_CC), &mimePropInfo))) return TRUE; if (SUCCEEDED(pPropSet->GetPropInfo(PIDTOSTR(PID_HDR_BCC), &mimePropInfo))) return TRUE; return FALSE; } // **************************************** HRESULT COEMsgSite::ClearHeaders(ULONG cNames, LPCSTR *prgszName, IMimePropertySet *pPropSet) { HRESULT hr = S_OK; for (ULONG i = 0; i < cNames; i++) pPropSet->DeleteProp(*prgszName++); return S_OK; } // **************************************** #ifdef SMIME_V3 HRESULT COEMsgSite::SendToOutbox(IMimeMessage *pMsg, BOOL fSendImmediate, IHeaderSite *pHeaderSite) #else HRESULT COEMsgSite::SendToOutbox(IMimeMessage *pMsg, BOOL fSendImmediate) #endif // SMIME_V3 { HRESULT hr; BOOL fSendMail, fSendNews, fSendBoth; IMimePropertySet *pPropSet = NULL, *pTempPropSet = NULL; PROPVARIANT var; IImnAccount *pAccount = NULL; ACCTTYPE acctType; IMimeMessage *pTempMsg = NULL; LPCSTR rgszMailOnlyHeaders[] = { PIDTOSTR(PID_HDR_TO), PIDTOSTR(PID_HDR_CC), PIDTOSTR(PID_HDR_BCC), PIDTOSTR(PID_HDR_XPRI), PIDTOSTR(PID_HDR_XMSPRI), PIDTOSTR(PID_HDR_APPARTO), PIDTOSTR(PID_HDR_COMMENT), PIDTOSTR(PID_HDR_SENDER), PIDTOSTR(PID_HDR_XMAILER), PIDTOSTR(PID_HDR_RECEIVED), PIDTOSTR(PID_HDR_DISP_NOTIFICATION_TO) }; LPCSTR rgszNewsOnlyHeaders[] = { PIDTOSTR(PID_HDR_NEWSGROUPS), PIDTOSTR(PID_HDR_PATH), PIDTOSTR(PID_HDR_FOLLOWUPTO), PIDTOSTR(PID_HDR_EXPIRES), PIDTOSTR(PID_HDR_REFS), PIDTOSTR(PID_HDR_DISTRIB), PIDTOSTR(PID_HDR_ORG), PIDTOSTR(PID_HDR_KEYWORDS), PIDTOSTR(PID_HDR_SUMMARY), PIDTOSTR(PID_HDR_APPROVED), PIDTOSTR(PID_HDR_LINES), PIDTOSTR(PID_HDR_XREF), PIDTOSTR(PID_HDR_CONTROL) }; // Common headers between mail and news that can be left where they are // PID_HDR_FROM PID_HDR_DATE PID_HDR_SUBJECT PID_HDR_MESSAGEID // PID_HDR_REPLYTO PID_HDR_CNTTYPE PID_HDR_CNTXFER PID_HDR_CNTDESC // PID_HDR_CNTDISP PID_HDR_CNTBASE PID_HDR_CNTLOC PID_HDR_CNTID // PID_HDR_MIMEVER PID_HDR_ENCODING PID_HDR_ENCRYPTED m_dwMSAction = MSA_SEND; hr = pMsg->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pPropSet); if(FAILED(hr)) return hr; fSendMail = NeedToSendMail(pPropSet); fSendNews = NeedToSendNews(pPropSet); fSendBoth = fSendMail && fSendNews; PropVariantInit(&var); if((!fSendMail) && (!fSendNews)) { hr = hrNoRecipients; goto Exit; } var.vt = VT_LPSTR; hr = pMsg->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var); if (FAILED(hr)) goto Exit; hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, var.pszVal, &pAccount); if (FAILED(hr)) goto Exit; hr = pAccount->GetAccountType(&acctType); if (FAILED(hr)) goto Exit; if (fSendBoth) { hr = HrDupeMsg(pMsg, &pTempMsg); if (FAILED(hr)) goto Exit; hr = pTempMsg->BindToObject(HBODY_ROOT, IID_IMimePropertySet, (LPVOID *)&pTempPropSet); if(FAILED(hr)) return hr; hr = ClearHeaders(ARRAYSIZE(rgszMailOnlyHeaders), rgszMailOnlyHeaders, pPropSet); if (FAILED(hr)) goto Exit; hr = ClearHeaders(ARRAYSIZE(rgszNewsOnlyHeaders), rgszNewsOnlyHeaders, pTempPropSet); if (FAILED(hr)) goto Exit; } // If going to do both news and mail, then must send news first. The spooler will // block and say it is busy if we send mail first. If we send mail second, then // the spooler has a special flag that says when you are done being busy, send // any mail that you have in your outbox. if (fSendNews) { if (ACCT_MAIL == acctType) { IImnAccount *pTempAccount = NULL; if (SUCCEEDED(GetDefaultAccount(ACCT_NEWS, &pTempAccount))) { HrSetAccountByAccount(pMsg, pTempAccount); pTempAccount->Release(); } } #ifdef SMIME_V3 hr = SendMsg(pMsg, fSendImmediate, FALSE, pHeaderSite); #else hr = SendMsg(pMsg, fSendImmediate, FALSE); #endif // SMIME_V3 if (FAILED(hr) && (E_PENDING != hr)) goto Exit; // Tell the user this is being sent to the server but might not appear // right away. if (fSendImmediate && !g_pConMan->IsGlobalOffline()) DoDontShowMeAgainDlg(GetCallbackHwnd(), c_szDSSendNews, MAKEINTRESOURCE(idsPostNews), MAKEINTRESOURCE(idsPostSentToServer), MB_OK); if (fSendBoth) pMsg = pTempMsg; } if (fSendMail) { if (ACCT_NEWS == acctType) { //If we are not the smapi client forward it to whoever it is. if (!FIsDefaultMailConfiged()) { hr = NewsUtil_ReFwdByMapi(GetCallbackHwnd(), pMsg, MSGTYPE_CC); goto Exit; } IImnAccount *pTempAccount = NULL; if (SUCCEEDED(GetDefaultAccount(ACCT_MAIL, &pTempAccount))) { HrSetAccountByAccount(pMsg, pTempAccount); pTempAccount->Release(); } } #ifdef SMIME_V3 hr = SendMsg(pMsg, fSendImmediate, TRUE, pHeaderSite); #else hr = SendMsg(pMsg, fSendImmediate, TRUE); #endif // SMIME_V3 } Exit: SafeMemFree(var.pszVal); ReleaseObj(pAccount); ReleaseObj(pPropSet); ReleaseObj(pTempPropSet); ReleaseObj(pTempMsg); return hr; } // **************************************** HRESULT COEMsgSite::GetLocation(LPWSTR rgwchLocation, DWORD cchSize) { FOLDERINFO fi; LPWSTR pwszName = NULL; HRESULT hr = S_OK; BOOL fFreeFolder = FALSE; switch (m_dwInitType) { case OEMSIT_MSG_TABLE: case OEMSIT_STORE: if (SUCCEEDED(g_pStore->GetFolderInfo(m_FolderID, &fi))) { Assert(fi.pszName); fFreeFolder = TRUE; IF_NULLEXIT(pwszName = PszToUnicode(CP_ACP, fi.pszName)); StrCpyNW(rgwchLocation, pwszName, cchSize); } else *rgwchLocation = 0; break; case OEMSIT_FAT: StrCpyNW(rgwchLocation, m_rgwchFileName, cchSize); break; case OEMSIT_MSG: case OEMSIT_VIRGIN: *rgwchLocation = 0; break; } exit: if (fFreeFolder) g_pStore->FreeRecord(&fi); MemFree(pwszName); return hr; } // **************************************** HRESULT COEMsgSite::MarkMessage(MARK_TYPE dwType, APPLYCHILDRENTYPE dwApplyType) { HRESULT hr = E_FAIL; if (OEMSIT_MSG_TABLE == m_dwInitType) { ROWINDEX iRow = 0; hr = m_pMsgTable->GetRowIndex(m_MessageID, &iRow); if (SUCCEEDED(hr)) hr = m_pMsgTable->Mark(&iRow, 1, dwApplyType, dwType, m_pStoreCB); } return hr; } // **************************************** HRESULT COEMsgSite::GetMessageFlags(MESSAGEFLAGS *pdwFlags) { HRESULT hr = S_OK; *pdwFlags = 0; if (!m_pMsgTable) { hr = E_FAIL; goto Exit; } if (OEMSIT_MSG_TABLE == m_dwInitType) { ROWINDEX iRow = 0; LPMESSAGEINFO pMsgInfo; hr = m_pMsgTable->GetRowIndex(m_MessageID, &iRow); if (FAILED(hr)) goto Exit; hr = m_pMsgTable->GetRow(iRow, &pMsgInfo); if (FAILED(hr)) goto Exit; *pdwFlags = pMsgInfo->dwFlags; m_pMsgTable->ReleaseRow(pMsgInfo); } Exit: return hr; } // **************************************** HRESULT COEMsgSite::GetDefaultAccount(ACCTTYPE acctType, IImnAccount **ppAcct) { HRESULT hr = E_FAIL, hr2; LPMESSAGEINFO pMsgInfo = NULL; ROWINDEX iRow; DWORD dwFlags = 0; Assert(ppAcct); if(OEMSIT_MSG_TABLE == m_dwInitType) { if (ACCT_MAIL == acctType) { IF_FAILEXIT(GetMessageFlags(&dwFlags)); if (!!(dwFlags & ARF_NEWSMSG)) goto exit; } IF_FAILEXIT(hr = m_pMsgTable->GetRowIndex(m_MessageID, &iRow)); IF_FAILEXIT(hr = m_pMsgTable->GetRow(iRow, &pMsgInfo)); IF_FAILEXIT(hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pMsgInfo->pszAcctId, ppAcct)); } exit: if(FAILED(hr)) hr = g_pAcctMan->GetDefaultAccount(acctType, ppAcct); if(pMsgInfo) { // We don't want to mask hr, so we'll just test an alternative HRESULT hr2 = m_pMsgTable->ReleaseRow(pMsgInfo); if(FAILED(hr2)) TraceResult(hr2); } return hr; } // **************************************** HRESULT COEMsgSite::LoadMessageFromStore(void) { HRESULT hr; IMessageFolder *pMsgFolder = NULL; hr = g_pStore->OpenFolder(m_FolderID, NULL, NOFLAGS, &pMsgFolder); if (SUCCEEDED(hr)) { IMimeMessage *pMsg = NULL; //Can only get into this state in a drafts message, so don't need worry about security hr = pMsgFolder->OpenMessage(m_MessageID, 0/* OPEN_MESSAGE_SECURE*/, &pMsg, NULL); if (SUCCEEDED(hr)) { ReplaceInterface(m_pMsg, pMsg); pMsg->Release(); } pMsgFolder->Release(); } return hr; } // **************************************** HRESULT COEMsgSite::LoadMessageFromRow(IMimeMessage **ppMsg, ROWINDEX row) { HRESULT hr; LPMESSAGEINFO pInfo; AssertSz(!(*ppMsg), "We create a message in this function."); hr = m_pMsgTable->GetRow(row, &pInfo); if (SUCCEEDED(hr)) { m_dwMSAction = MSA_GET_MESSAGE; hr = CreateMessageFromInfo(pInfo, ppMsg, m_FolderID); m_fHeaderOnly = TRUE; // now we wait until the message has downloaded and reload in // OnComplete m_pMsgTable->ReleaseRow(pInfo); } return hr; } // **************************************** HRESULT COEMsgSite::LoadMessageFromTable(BOOL fGetOriginal, HRESULT *phr) { IMimeMessage *pMsg = NULL; BOOL fOffline=FALSE; ROWINDEX rowIndex = 0; HRESULT hr, tempHr = S_OK; hr = m_pMsgTable->GetRowIndex(m_MessageID, &rowIndex); if (FAILED(hr)) goto Exit; m_fHeaderOnly = FALSE; hr = m_pMsgTable->OpenMessage(rowIndex, (fGetOriginal ? OPEN_MESSAGE_SECURE : 0), &pMsg, m_pStoreCB); if (FAILED(hr) || hr == STORE_S_ALREADYPENDING) { tempHr = hr; hr = LoadMessageFromRow(&pMsg, rowIndex); if (SUCCEEDED(hr)) { switch (tempHr) { case E_NOT_ONLINE: hr = HR_S_OFFLINE; break; case STORE_S_ALREADYPENDING: case E_PENDING: { LPMESSAGEINFO pmiMsgInfo; // Save the MsgID of msg we're trying to load. This way if user quickly loads // several msgs into note, we won't re-enter MSA_IDLE until the desired msg loads if (SUCCEEDED(m_pMsgTable->GetRow(rowIndex, &pmiMsgInfo))) { m_MessageID = pmiMsgInfo->idMessage; m_pMsgTable->ReleaseRow(pmiMsgInfo); } else m_MessageID = 0; // This means show the next msg we get! tempHr = S_OK; break; } } } if (FAILED(hr)) goto Exit; } else { m_dwArfFlags = 0; GetMessageFlags(&m_dwArfFlags); } *phr = tempHr; ReplaceInterface(m_pMsg, pMsg); Exit: ReleaseObj(pMsg); return hr; } // **************************************** HRESULT COEMsgSite::LoadMessageFromFAT(BOOL fGetOriginal, HRESULT *phr) { IMimeMessage *pMsg = NULL; HRESULT hr; hr = HrCreateMessage(&pMsg); if (FAILED(hr)) return hr; //bobn: We need to make sure we know the default charset HGetDefaultCharset(NULL); hr = HrLoadMsgFromFileW(pMsg, m_rgwchFileName); if (SUCCEEDED(hr)) { if(!fGetOriginal) *phr = HandleSecurity(NULL, pMsg); //if (SUCCEEDED(hr)) ReplaceInterface(m_pMsg, pMsg); } SafeRelease(pMsg); return hr; } // **************************************** HRESULT COEMsgSite::GetFolderID(FOLDERID *folderID) { Assert(folderID); *folderID = m_FolderID; return S_OK; } // **************************************** HRESULT COEMsgSite::SetAccountInfo(void) { HRESULT hr = S_OK; FOLDERINFO fi; PROPVARIANT var; // Check to see if need an account in the message. var.vt = VT_LPSTR; if (FAILED(m_pMsg->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var)) || !(var.pszVal)) { if (FOLDERID_INVALID != m_FolderID) { hr = g_pStore->GetFolderInfo(m_FolderID, &fi); if (SUCCEEDED(hr)) { // Set account based upon the folder ID passed down if (FOLDER_LOCAL != fi.tyFolder) { char szAcctId[CCHMAX_ACCOUNT_NAME]; IImnAccount *pAcct = NULL; if (SUCCEEDED(GetFolderAccountId(&fi, szAcctId, ARRAYSIZE(szAcctId))) && SUCCEEDED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, szAcctId, &pAcct))) { HrSetAccountByAccount(m_pMsg, pAcct); pAcct->Release(); } // If not a server node, set the newgroup if ((FOLDER_NEWS == fi.tyFolder) && (0 == (FOLDER_SERVER & fi.dwFlags))) hr = MimeOleSetBodyPropA(m_pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_NEWSGROUPS), NOFLAGS, fi.pszName); } g_pStore->FreeRecord(&fi); } } } else SafeMemFree(var.pszVal); return hr; } // **************************************** HRESULT COEMsgSite::CreateMsgWithAccountInfo(void) { HRESULT hr; SafeRelease(m_pMsg); hr = HrCreateMessage(&m_pMsg); if (SUCCEEDED(hr)) { if(g_hDefaultCharsetForMail) m_pMsg->SetCharset(g_hDefaultCharsetForMail, CSET_APPLY_ALL); hr = SetAccountInfo(); } return hr; } // **************************************** HRESULT COEMsgSite::GetMessage(IMimeMessage **ppMsg, BOOL *pfCompleteMsg, DWORD dwMessageFlags, HRESULT *phr) { HRESULT hr = S_OK; BOOL fGetOriginal = (OEGM_ORIGINAL & dwMessageFlags); if (!m_fValidMessage) return E_FAIL; *phr = S_OK; if (m_fNeedToLoadMsg || fGetOriginal) { switch (m_dwInitType) { case OEMSIT_MSG_TABLE: hr = LoadMessageFromTable(fGetOriginal, phr); break; case OEMSIT_STORE: hr = LoadMessageFromStore(); break; case OEMSIT_FAT: hr = LoadMessageFromFAT(fGetOriginal, phr); break; case OEMSIT_MSG: hr = SetAccountInfo(); break; case OEMSIT_VIRGIN: hr = CreateMsgWithAccountInfo(); break; } m_fNeedToLoadMsg = FALSE; } if (SUCCEEDED(hr) && !m_fHeaderOnly && (OEGM_AS_ATTACH &dwMessageFlags)) { IMimeMessage *pMsgFwd = NULL; PROPVARIANT var; hr = HrCreateMessage(&pMsgFwd); if (SUCCEEDED(hr)) hr = pMsgFwd->AttachObject(IID_IMimeMessage, (LPVOID)m_pMsg, NULL); var.vt = VT_LPSTR; if (SUCCEEDED(m_pMsg->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var))) { pMsgFwd->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var); } if (SUCCEEDED(hr)) { ReplaceInterface(m_pMsg, pMsgFwd); pMsgFwd->Release(); m_dwInitType = OEMSIT_MSG; } } if (fGetOriginal) m_fReloadMessageFlag = TRUE; if (SUCCEEDED(hr)) { ReplaceInterface((*ppMsg), m_pMsg); *pfCompleteMsg = !m_fHeaderOnly; m_fNeedToLoadMsg = !!m_fHeaderOnly; if (!m_pMsg) hr = E_FAIL; } return hr; } // ************************* BOOL COEMsgSite::FCanConnect() { IImnAccount *pAcct = NULL; HRESULT hr; BOOL fRet = TRUE; hr = GetDefaultAccount(ACCT_MAIL, &pAcct); if (SUCCEEDED(hr)) { hr = g_pConMan->CanConnect(pAcct); pAcct->Release(); } fRet = (S_OK == hr); return(fRet); } // **************************************** HWND COEMsgSite::GetCallbackHwnd() { HWND hwnd; Assert(m_pStoreCB); if (SUCCEEDED(m_pStoreCB->GetParentWindow(0, &hwnd))) return hwnd; return 0; } // **************************************** HRESULT COEMsgSite::Close(void) { SafeRelease(m_pMsg); SafeRelease(m_pOrigMsg); if (m_pMsgTable) { m_pMsgTable->ConnectionRelease(); m_pMsgTable->Release(); m_pMsgTable = NULL; } SafeRelease(m_pStoreCB); SafeRelease(m_pListSelect); return S_OK; } // **************************************** HRESULT COEMsgSite::SetStoreCallback(IStoreCallback *pStoreCB) { ReplaceInterface(m_pStoreCB, pStoreCB); return S_OK; } // **************************************** HRESULT COEMsgSite::SwitchLanguage(HCHARSET hOldCharset, HCHARSET hNewCharset) { DWORD dwCodePage = 0; INETCSETINFO CsetInfo; BOOL fSaveLang = TRUE; ROWINDEX iRow = 0; HRESULT hr = S_OK; if (OEMSIT_MSG_TABLE != m_dwInitType) goto Exit; if (FAILED(m_pMsgTable->GetRowIndex(m_MessageID, &iRow))) goto Exit; #if 0 if (SUCCEEDED(m_pMsgTable->GetLanguage(iRow, &dwCodePage))) { DWORD dwFlag ; m_pMsg->GetFlags(&dwFlag); // for tagged message only if ((dwFlag & IMF_CSETTAGGED) && !dwCodePage ) fSaveLang = TRUE; // was !IntlCharsetMapLanguageCheck(hOldCharset, hNewCharset); We have } #endif // save language change to message store if (fSaveLang) { MimeOleGetCharsetInfo(hNewCharset, &CsetInfo); dwCodePage = CsetInfo.cpiInternet; // Get index again incase user changed row during dialog if (FAILED(m_pMsgTable->GetRowIndex(m_MessageID, &iRow))) goto Exit; hr = m_pMsgTable->SetLanguage(1, &iRow, dwCodePage); if (FAILED(hr)) AthMessageBoxW( GetCallbackHwnd(), MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW((hr == hrIncomplete)?idsViewLangMimeDBBad:idsErrViewLanguage), NULL, MB_OK|MB_ICONEXCLAMATION); } Exit: return hr; } // **************************************** HRESULT COEMsgSite::OnComplete(STOREOPERATIONTYPE tyOperation, HRESULT hrComplete, STOREOPERATIONTYPE *ptyNewOp) { // Action wasn't inited in MsgSite if (MSA_IDLE == m_dwMSAction) return S_OK; if (ptyNewOp) *ptyNewOp = SOT_INVALID; switch (tyOperation) { case SOT_GET_MESSAGE: HandleGetMessage(hrComplete); break; case SOT_DELETING_MESSAGES: HandleDelete(hrComplete); break; case SOT_PUT_MESSAGE: HandlePut(hrComplete, ptyNewOp); break; case SOT_COPYMOVE_MESSAGE: HandleCopyMove(hrComplete); SafeRelease(m_pFolderReleaseOnComplete); break; #ifdef DEBUG default: AssertSz(!m_pCBMsgFolder, "How did we get here with a CBMsgFolder"); #endif } return S_OK; } // **************************************** HRESULT COEMsgSite::UpdateCallbackInfo(LPSTOREOPERATIONINFO pOpInfo) { if (pOpInfo->idMessage != MESSAGEID_INVALID) { m_fHaveCBMessageID = TRUE; m_CBMessageID = pOpInfo->idMessage; } return S_OK; } // **************************************** // Need to handle MSA_SAVE, MSA_SEND, MSA_COPYMOVE void COEMsgSite::HandlePut(HRESULT hr, STOREOPERATIONTYPE *ptyNewOp) { // If is COPYMOVE, simply redirect to proper function if (MSA_COPYMOVE == m_dwMSAction) { HandleCopyMove(hr); if (ptyNewOp) *ptyNewOp = SOT_PUT_MESSAGE; return; } SafeRelease(m_pCBMsgFolder); if (FAILED(hr)) goto Exit; switch (m_dwMSAction) { case MSA_SAVE: { // Decide whether need to delete old message or not switch (m_dwInitType) { case OEMSIT_MSG_TABLE: { if (m_fCBSaveInFolderAndDelOrig) { ROWINDEX iRow = 0; hr = m_pMsgTable->GetRowIndex(m_MessageID, &iRow); if (SUCCEEDED(hr)) hr = m_pMsgTable->DeleteRows( DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT | DELETE_MESSAGE_MAYIGNORENOTRASH, 1, &iRow, FALSE, m_pStoreCB); if (SUCCEEDED(hr)) OnComplete(SOT_DELETING_MESSAGES, S_OK); else if ((E_PENDING == hr) && ptyNewOp) *ptyNewOp = SOT_DELETING_MESSAGES; } else { m_dwInitType = OEMSIT_STORE; m_fThreadingEnabled = FALSE; m_FolderID = m_CBFolderID; } m_MessageID = m_CBMessageID; if (!m_fHaveCBMessageID) { m_dwInitType = OEMSIT_MSG; } break; } // Always delete since our message was in drafts and is being saved to drafts case OEMSIT_STORE: { hr = DeleteFromStore( DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT | DELETE_MESSAGE_MAYIGNORENOTRASH); if ((E_PENDING == hr) && ptyNewOp) *ptyNewOp = SOT_DELETING_MESSAGES; else if (SUCCEEDED(hr)) OnComplete(SOT_DELETING_MESSAGES, S_OK); break; } case OEMSIT_FAT: case OEMSIT_MSG: case OEMSIT_VIRGIN: // This folder id should always be drafts. m_FolderID = m_CBFolderID; if ((FOLDERID_INVALID != m_FolderID) && m_fHaveCBMessageID) { m_MessageID = m_CBMessageID; m_dwInitType = OEMSIT_STORE; m_fThreadingEnabled = FALSE; } else m_dwInitType = OEMSIT_MSG; break; } if (m_fCBSavedInDrafts) DoDontShowMeAgainDlg(GetCallbackHwnd(), c_szDSSavedInSavedItems, MAKEINTRESOURCE(idsSavedMessage), MAKEINTRESOURCE(idsSavedInDrafts), MB_OK); break; } // Don't do anything with send. Just be happy that it worked. case MSA_SEND: break; default: AssertSz(FALSE, "Didn't expect to get PUT with other MsgSite action."); } Exit: if (hr != E_PENDING) m_dwMSAction = MSA_IDLE; } void COEMsgSite::HandleGetMessage(HRESULT hr) { if (SUCCEEDED(hr)) { HRESULT tempHr; LoadMessageFromTable(TRUE, &tempHr); AssertSz(SUCCEEDED(tempHr), "If hr succeeded, tempHr should have as well."); m_fHeaderOnly = FALSE; Notify(OEMSN_UPDATE_PREVIEW); SetFocus(GetCallbackHwnd()); } // Success or failure, we've loaded the target msg. Go to idle m_dwMSAction = MSA_IDLE; } HRESULT COEMsgSite::Notify(DWORD dwNotifyID) { HRESULT hr = S_OK; switch (dwNotifyID) { case OEMSN_UPDATE_PREVIEW: { if ((OEMSIT_MSG_TABLE == m_dwInitType) && (0 != m_MessageID)) { ROWINDEX iRow = 0; if (SUCCEEDED(m_pMsgTable->GetRowIndex(m_MessageID, &iRow))) m_pListSelect->SetActiveRow(iRow); } break; } case OEMSN_TOGGLE_READRCPT_REQ: { if (!!(m_dwMDNFlags & MDN_REQUEST)) { m_dwMDNFlags = m_dwMDNFlags & (~MDN_REQUEST); } else { m_dwMDNFlags |= MDN_REQUEST; } break; } case OEMSN_PROCESS_READRCPT_REQ: { ROWINDEX rowIndex = 0; if ((OEMSIT_MSG_TABLE == m_dwInitType) && (0 != m_MessageID)) { IF_FAILEXIT(hr = m_pMsgTable->GetRowIndex(m_MessageID, &rowIndex)); if (!(m_dwArfFlags & ARF_READ)) { IF_FAILEXIT(hr = ProcessReturnReceipts(m_pMsgTable, m_pStoreCB, rowIndex, READRECEIPT, m_FolderID, m_pMsg)); } } break; } } exit: return hr; } // **************************************** // Need to handle MSA_DELETE, MSA_COPYMOVE, and MSA_SAVE void COEMsgSite::HandleDelete(HRESULT hr) { AssertSz((MSA_DELETE == m_dwMSAction) || (MSA_COPYMOVE == m_dwMSAction) || (MSA_SAVE == m_dwMSAction), "Didn't expect to get DELETE with other MsgSite action."); SafeRelease(m_pCBMsgFolder); // If came from COPYMOVE, then don't do anything here. if (FAILED(hr)) goto exit; if (MSA_COPYMOVE == m_dwMSAction) { m_FolderID = m_CBFolderID; m_MessageID = m_CBMessageID; } else if (MSA_SAVE == m_dwMSAction) { m_FolderID = m_CBFolderID; m_MessageID = m_CBMessageID; if (m_pListSelect && (OEMSIT_MSG_TABLE == m_dwInitType)) { ROWINDEX iRow = 0; if (SUCCEEDED(m_pMsgTable->GetRowIndex(m_MessageID, &iRow))) m_pListSelect->SetActiveRow(iRow); } } // Then this must be a straight delete else switch (m_dwInitType) { case OEMSIT_MSG_TABLE: if (m_fGotNewID) { m_MessageID = m_NewMessageID; m_fNeedToLoadMsg = TRUE; if (m_pListSelect) { ROWINDEX iRow = 0; if (SUCCEEDED(m_pMsgTable->GetRowIndex(m_MessageID, &iRow))) m_pListSelect->SetActiveRow(iRow); } } else { m_fValidMessage = FALSE; } break; // Do nothing if from store case OEMSIT_STORE: break; } exit: // If doing copy move, I expect SOT_DELETING_MESSAGES to be called before SOT_COPYMOVE_MESSAGE m_dwMSAction = MSA_IDLE; } // **************************************** // Need to handle MSA_COPYMOVE void COEMsgSite::HandleCopyMove(HRESULT hr) { AssertSz(MSA_COPYMOVE == m_dwMSAction, "Didn't expect to get COPYMOVE with other MsgSite action."); SafeRelease(m_pCBMsgFolder); if (FAILED(hr) || m_fCBCopy) goto Exit; switch (m_dwCMFState) { case CMF_MSG_TO_FOLDER: // Don't need to worry about anything break; case CMF_TABLE_TO_FOLDER: { // If we are moving and there is a valid bookmark to go to, then set up the note to have the next message if (m_fGotNewID) { m_MessageID = m_NewMessageID; m_fNeedToLoadMsg = TRUE; } else m_fValidMessage = FALSE; break; } case CMF_STORE_TO_FOLDER: { FOLDERID folderID; MESSAGEIDLIST rMsgIDList; Assert(m_pStoreCB); rMsgIDList.cAllocated = 0; rMsgIDList.cMsgs = 1; rMsgIDList.prgidMsg = &m_MessageID; hr = g_pStore->OpenFolder(m_FolderID, NULL, NOFLAGS, &m_pCBMsgFolder); if (FAILED(hr)) goto Exit; // Don't really care if this works. hr = m_pCBMsgFolder->DeleteMessages( DELETE_MESSAGE_NOTRASHCAN | DELETE_MESSAGE_NOPROMPT | DELETE_MESSAGE_MAYIGNORENOTRASH, &rMsgIDList, NULL, m_pStoreCB); AssertSz(E_PENDING != hr, "Didn't expect E_PENDING here.") if (SUCCEEDED(hr)) OnComplete(SOT_DELETING_MESSAGES, S_OK); break; } case CMF_FAT_TO_FOLDER: { DeleteFileWrapW(m_rgwchFileName); // Need to shut down the note. m_fValidMessage = FALSE; break; } } Exit: // I expect SOT_DELETING_MESSAGES to be called before SOT_COPYMOVE_MESSAGE m_dwMSAction = MSA_IDLE; m_dwCMFState = CMF_UNINITED; }