123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786 |
- /*
- * Copyright 2005 - 2016 Zarafa and its licensors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- #include <kopano/platform.h>
- #include <memory>
- #include <new>
- #include <utility>
- #include <mapix.h>
- #include <mapiutil.h>
- #include "StoreHelper.h"
- using namespace std;
- #include <kopano/mapi_ptr.h>
- #include <kopano/mapiguidext.h>
- #include <kopano/archiver-common.h>
- #include <kopano/ECRestriction.h>
- namespace KC { namespace helpers {
- /**
- * The version of the current search folder restrictions. The version is the same
- * for all three folders, so if one restriction changes, they all get a new version.
- *
- * version 1: The search used as in V1 of the archiver.
- * version 2: Check if the original source key and current sourcekey match when stubbed equals true.
- */
- #define ARCHIVE_SEARCH_VERSION 2
- const StoreHelper::search_folder_info_t StoreHelper::s_infoSearchFolders[] = {
- {_T("Archive"), _T("This folder contains messages that are eligible for archiving"), &StoreHelper::SetupSearchArchiveFolder},
- {_T("Delete"), _T("This folder contains messages that are eligible for deletion"), &StoreHelper::SetupSearchDeleteFolder},
- {_T("Stub"), _T("This folder contains messages that are eligible for stubbing"), &StoreHelper::SetupSearchStubFolder}
- };
- /**
- * Create a new StoreHelper object.
- *
- * @param[in] ptrMsgStore
- * A MsgStorePtr that points to the message store for which to
- * create a StoreHelper.
- * @param[out] lpptrStoreHelper
- * Pointer to a StoreHelperPtr that will be assigned the address
- * of the new StoreHelper object.
- */
- HRESULT StoreHelper::Create(MsgStorePtr &ptrMsgStore, StoreHelperPtr *lpptrStoreHelper)
- {
- HRESULT hr;
- StoreHelperPtr ptrStoreHelper(new(std::nothrow) StoreHelper(ptrMsgStore));
- if (ptrStoreHelper == nullptr)
- return MAPI_E_NOT_ENOUGH_MEMORY;
- hr = ptrStoreHelper->Init();
- if (hr != hrSuccess)
- return hr;
-
- *lpptrStoreHelper = std::move(ptrStoreHelper);
- return hrSuccess;
- }
- /**
- * Constructor.
- */
- StoreHelper::StoreHelper(MsgStorePtr &ptrMsgStore)
- : MAPIPropHelper(ptrMsgStore.as<MAPIPropPtr>())
- , m_ptrMsgStore(ptrMsgStore), __propmap(8)
- { }
- /**
- * Initialize a StoreHelper object.
- */
- HRESULT StoreHelper::Init()
- {
- HRESULT hr;
-
- hr = MAPIPropHelper::Init();
- if (hr != hrSuccess)
- goto exitpm;
-
- PROPMAP_INIT_NAMED_ID(ARCHIVE_STORE_ENTRYIDS, PT_MV_BINARY, PSETID_Archive, dispidStoreEntryIds)
- PROPMAP_INIT_NAMED_ID(ARCHIVE_ITEM_ENTRYIDS, PT_MV_BINARY, PSETID_Archive, dispidItemEntryIds)
- PROPMAP_INIT_NAMED_ID(ORIGINAL_SOURCEKEY, PT_BINARY, PSETID_Archive, dispidOrigSourceKey)
- PROPMAP_INIT_NAMED_ID(SEARCH_FOLDER_ENTRYIDS, PT_MV_BINARY, PSETID_Archive, dispidSearchFolderEntryIds)
- PROPMAP_INIT_NAMED_ID(STUBBED, PT_BOOLEAN, PSETID_Archive, dispidStubbed)
- PROPMAP_INIT_NAMED_ID(DIRTY, PT_BOOLEAN, PSETID_Archive, dispidDirty)
- PROPMAP_INIT_NAMED_ID(FLAGS, PT_LONG, PSETID_Archive, dispidFlags)
- PROPMAP_INIT_NAMED_ID(VERSION, PT_LONG, PSETID_Archive, dispidVersion)
- PROPMAP_INIT(m_ptrMsgStore)
- exitpm:
- return hr;
- }
- /**
- * Open or optionaly create a folder by name from the IPM subtree.
- *
- * @param[in] strFolder
- * The name of the folder to open or create.
- * @param[in] bCreate
- * Set to true to create the folder if it doesn't exist.
- * @param[out] lppFolder
- * Pointer to a IMapiFolder pointer that will be assigned the address
- * of the returned folderd.
- */
- HRESULT StoreHelper::GetFolder(const tstring &strFolder, bool bCreate, LPMAPIFOLDER *lppFolder)
- {
- HRESULT hr;
- MAPIFolderPtr ptrIpmSubtree;
- MAPIFolderPtr ptrFolder;
-
- hr = GetIpmSubtree(&~ptrIpmSubtree);
- if (hr != hrSuccess)
- return hr;
- hr = GetSubFolder(ptrIpmSubtree, strFolder, bCreate, &~ptrFolder);
- if (hr != hrSuccess)
- return hr;
-
- return ptrFolder->QueryInterface(IID_IMAPIFolder,
- reinterpret_cast<LPVOID *>(lppFolder));
- }
- /**
- * Create or reinitialize the searchfolders used by the archiver. The search folders
- * need to be updated whenever the set of attached archives for a store change.
- */
- HRESULT StoreHelper::UpdateSearchFolders()
- {
- HRESULT hr;
- MAPIFolderPtr ptrSearchArchiveFolder;
- MAPIFolderPtr ptrSearchDeleteFolder;
- MAPIFolderPtr ptrSearchStubFolder;
- SPropValuePtr ptrSearchArchiveEntryId;
- SPropValuePtr ptrSearchDeleteEntryId;
- SPropValuePtr ptrSearchStubEntryId;
- SPropValuePtr ptrPropValue;
- hr = CreateSearchFolders(&~ptrSearchArchiveFolder, &~ptrSearchDeleteFolder, &~ptrSearchStubFolder);
- if (hr != hrSuccess)
- return hr;
-
- assert(ptrSearchArchiveFolder);
- assert(ptrSearchDeleteFolder);
- assert(ptrSearchStubFolder);
- hr = HrGetOneProp(ptrSearchArchiveFolder, PR_ENTRYID, &~ptrSearchArchiveEntryId);
- if (hr != hrSuccess)
- return hr;
- hr = HrGetOneProp(ptrSearchDeleteFolder, PR_ENTRYID, &~ptrSearchDeleteEntryId);
- if (hr != hrSuccess)
- return hr;
- hr = HrGetOneProp(ptrSearchStubFolder, PR_ENTRYID, &~ptrSearchStubEntryId);
- if (hr != hrSuccess)
- return hr;
- hr = MAPIAllocateBuffer(sizeof(SPropValue), &~ptrPropValue);
- if (hr != hrSuccess)
- return hr;
-
- ptrPropValue->ulPropTag = PROP_SEARCH_FOLDER_ENTRYIDS;
- ptrPropValue->Value.MVbin.cValues = 3;
-
- hr = MAPIAllocateMore(3 * sizeof(*ptrPropValue->Value.MVbin.lpbin), ptrPropValue, (LPVOID*)&ptrPropValue->Value.MVbin.lpbin);
- if (hr != hrSuccess)
- return hr;
-
- ptrPropValue->Value.MVbin.lpbin[0].cb = ptrSearchArchiveEntryId->Value.bin.cb;
- ptrPropValue->Value.MVbin.lpbin[0].lpb = ptrSearchArchiveEntryId->Value.bin.lpb;
- ptrPropValue->Value.MVbin.lpbin[1].cb = ptrSearchDeleteEntryId->Value.bin.cb;
- ptrPropValue->Value.MVbin.lpbin[1].lpb = ptrSearchDeleteEntryId->Value.bin.lpb;
- ptrPropValue->Value.MVbin.lpbin[2].cb = ptrSearchStubEntryId->Value.bin.cb;
- ptrPropValue->Value.MVbin.lpbin[2].lpb = ptrSearchStubEntryId->Value.bin.lpb;
-
- hr = HrSetOneProp(m_ptrMsgStore, ptrPropValue);
- if (hr != hrSuccess)
- return hr;
- return hrSuccess;
- }
- /**
- * Get the IPM subtree.
- *
- * @param[out] lppFolder
- * Pointer to an IMAPIFolder pointer that will be assigned the
- * address of the returned folder.
- */
- HRESULT StoreHelper::GetIpmSubtree(LPMAPIFOLDER *lppFolder)
- {
- HRESULT hr;
- SPropValuePtr ptrPropValue;
- ULONG ulType = 0;
- if (!m_ptrIpmSubtree) {
- hr = HrGetOneProp(m_ptrMsgStore, PR_IPM_SUBTREE_ENTRYID, &~ptrPropValue);
- if (hr != hrSuccess)
- return hr;
- hr = m_ptrMsgStore->OpenEntry(ptrPropValue->Value.bin.cb, reinterpret_cast<ENTRYID *>(ptrPropValue->Value.bin.lpb), &m_ptrIpmSubtree.iid(), MAPI_BEST_ACCESS|fMapiDeferredErrors, &ulType, &~m_ptrIpmSubtree);
- if (hr != hrSuccess)
- return hr;
- }
-
- return m_ptrIpmSubtree->QueryInterface(IID_IMAPIFolder,
- reinterpret_cast<LPVOID *>(lppFolder));
- }
- /**
- * Get the three search folders that are created with StoreHelper::UpdateSearchFolders.
- *
- * @param[out] lppSearchArchiveFolder
- * Pointer to an IMAPIFolder pointer that will be assigned the
- * address of the searcholder containing the messages that are eligible
- * for archiving. These are basically unarchived messages that are not
- * flagged to be never archived.
- * @param[out] lppSearchDeleteFolder
- * Pointer to an IMAPIFolder pointer that will be assigned the
- * address of the searcholder containing the messages that are eligible
- * for deletion. These are basically archived messages that are not flagged
- * to be never deleted.
- * @param[out] lppSearchStubFolder
- * Pointer to an IMAPIFolder pointer that will be assigned the
- * address of the searcholder containing the messages that are eligible
- * for stubbing. These are basically all non-stubbed, archived messages that
- * are not flagged to be never stubbed.
- */
- HRESULT StoreHelper::GetSearchFolders(LPMAPIFOLDER *lppSearchArchiveFolder, LPMAPIFOLDER *lppSearchDeleteFolder, LPMAPIFOLDER *lppSearchStubFolder)
- {
- HRESULT hr;
- SPropValuePtr ptrPropValue;
- MAPIFolderPtr ptrSearchArchiveFolder;
- MAPIFolderPtr ptrSearchDeleteFolder;
- MAPIFolderPtr ptrSearchStubFolder; // subset of SearchDeleteFolder.
- ULONG ulType = 0;
- bool bUpdateRef = false;
-
- hr = HrGetOneProp(m_ptrMsgStore, PROP_SEARCH_FOLDER_ENTRYIDS, &~ptrPropValue);
- if (hr != hrSuccess && hr != MAPI_E_NOT_FOUND)
- return hr;
-
- if (hr == hrSuccess && ptrPropValue->Value.MVbin.cValues == 3) {
- hr = m_ptrMsgStore->OpenEntry(ptrPropValue->Value.MVbin.lpbin[0].cb, reinterpret_cast<ENTRYID *>(ptrPropValue->Value.MVbin.lpbin[0].lpb), &ptrSearchArchiveFolder.iid(), fMapiDeferredErrors|MAPI_BEST_ACCESS, &ulType, &~ptrSearchArchiveFolder);
- if (hr == hrSuccess)
- hr = CheckAndUpdateSearchFolder(ptrSearchArchiveFolder, esfArchive);
- else if (hr == MAPI_E_NOT_FOUND) {
- bUpdateRef = true;
- hr = CreateSearchFolder(esfArchive, &~ptrSearchArchiveFolder);
- }
- if (hr != hrSuccess)
- return hr;
- hr = m_ptrMsgStore->OpenEntry(ptrPropValue->Value.MVbin.lpbin[1].cb, reinterpret_cast<ENTRYID *>(ptrPropValue->Value.MVbin.lpbin[1].lpb), &ptrSearchDeleteFolder.iid(), fMapiDeferredErrors|MAPI_BEST_ACCESS, &ulType, &~ptrSearchDeleteFolder);
- if (hr == hrSuccess)
- hr = CheckAndUpdateSearchFolder(ptrSearchDeleteFolder, esfDelete);
- else if (hr == MAPI_E_NOT_FOUND) {
- bUpdateRef = true;
- hr = CreateSearchFolder(esfDelete, &~ptrSearchDeleteFolder);
- }
- if (hr != hrSuccess)
- return hr;
- hr = m_ptrMsgStore->OpenEntry(ptrPropValue->Value.MVbin.lpbin[2].cb, reinterpret_cast<ENTRYID *>(ptrPropValue->Value.MVbin.lpbin[2].lpb), &ptrSearchStubFolder.iid(), fMapiDeferredErrors|MAPI_BEST_ACCESS, &ulType, &~ptrSearchStubFolder);
- if (hr == hrSuccess)
- hr = CheckAndUpdateSearchFolder(ptrSearchStubFolder, esfStub);
- else if (hr == MAPI_E_NOT_FOUND) {
- bUpdateRef = true;
- hr = CreateSearchFolder(esfStub, &~ptrSearchStubFolder);
- }
- if (hr != hrSuccess)
- return hr;
- } else {
- bUpdateRef = true;
- hr = CreateSearchFolders(&~ptrSearchArchiveFolder, &~ptrSearchDeleteFolder, &~ptrSearchStubFolder);
- if (hr != hrSuccess)
- return hr;
- }
- if (bUpdateRef) {
- SPropValuePtr ptrSearchArchiveEntryId;
- SPropValuePtr ptrSearchDeleteEntryId;
- SPropValuePtr ptrSearchStubEntryId;
- assert(ptrSearchArchiveFolder);
- assert(ptrSearchDeleteFolder);
- assert(ptrSearchStubFolder);
- hr = HrGetOneProp(ptrSearchArchiveFolder, PR_ENTRYID, &~ptrSearchArchiveEntryId);
- if (hr != hrSuccess)
- return hr;
- hr = HrGetOneProp(ptrSearchDeleteFolder, PR_ENTRYID, &~ptrSearchDeleteEntryId);
- if (hr != hrSuccess)
- return hr;
- hr = HrGetOneProp(ptrSearchStubFolder, PR_ENTRYID, &~ptrSearchStubEntryId);
- if (hr != hrSuccess)
- return hr;
- hr = MAPIAllocateBuffer(sizeof(SPropValue), &~ptrPropValue);
- if (hr != hrSuccess)
- return hr;
-
- ptrPropValue->ulPropTag = PROP_SEARCH_FOLDER_ENTRYIDS;
- ptrPropValue->Value.MVbin.cValues = 3;
-
- hr = MAPIAllocateMore(3 * sizeof(*ptrPropValue->Value.MVbin.lpbin), ptrPropValue, (LPVOID*)&ptrPropValue->Value.MVbin.lpbin);
- if (hr != hrSuccess)
- return hr;
-
- ptrPropValue->Value.MVbin.lpbin[0].cb = ptrSearchArchiveEntryId->Value.bin.cb;
- ptrPropValue->Value.MVbin.lpbin[0].lpb = ptrSearchArchiveEntryId->Value.bin.lpb;
- ptrPropValue->Value.MVbin.lpbin[1].cb = ptrSearchDeleteEntryId->Value.bin.cb;
- ptrPropValue->Value.MVbin.lpbin[1].lpb = ptrSearchDeleteEntryId->Value.bin.lpb;
- ptrPropValue->Value.MVbin.lpbin[2].cb = ptrSearchStubEntryId->Value.bin.cb;
- ptrPropValue->Value.MVbin.lpbin[2].lpb = ptrSearchStubEntryId->Value.bin.lpb;
-
- hr = HrSetOneProp(m_ptrMsgStore, ptrPropValue);
- if (hr != hrSuccess)
- return hr;
- }
-
- hr = ptrSearchArchiveFolder->QueryInterface(IID_IMAPIFolder, (LPVOID*)lppSearchArchiveFolder);
- if (hr != hrSuccess)
- return hr;
- hr = ptrSearchDeleteFolder->QueryInterface(IID_IMAPIFolder, (LPVOID*)lppSearchDeleteFolder);
- if (hr != hrSuccess)
- return hr;
-
- return ptrSearchStubFolder->QueryInterface(IID_IMAPIFolder,
- reinterpret_cast<LPVOID *>(lppSearchStubFolder));
- }
- /**
- * Open or create a subfolder by name from another folder.
- *
- * @param[in] ptrFolder
- * MAPIFolderPtr that points to the folder from which a subfolder
- * will be opened.
- * @param[in] strFolder
- * The name of the subfolder to open or create.
- * @param[in] bCreate
- * Set to true to create the subfolder if it doesn't exist.
- * @param[out] lppFolder
- * Pointer to an IMAPIFolder pointer that will be assigned the
- * address of the returned folder.
- */
- HRESULT StoreHelper::GetSubFolder(MAPIFolderPtr &ptrFolder, const tstring &strFolder, bool bCreate, LPMAPIFOLDER *lppFolder)
- {
- HRESULT hr;
- MAPITablePtr ptrTable;
- SRowSetPtr ptrRowSet;
- MAPIFolderPtr ptrSubFolder;
- ULONG ulType = 0;
- static constexpr const SizedSPropTagArray(1, sptaFolderProps) = {1, {PR_ENTRYID}};
- SPropValue sResPropValue = {0};
-
- sResPropValue.ulPropTag = PR_DISPLAY_NAME;
- sResPropValue.Value.LPSZ = (LPTSTR)strFolder.c_str();
-
- hr = ptrFolder->GetHierarchyTable(fMapiDeferredErrors, &~ptrTable);
- if (hr != hrSuccess)
- return hr;
- hr = ptrTable->SetColumns(sptaFolderProps, TBL_BATCH);
- if (hr != hrSuccess)
- return hr;
- hr = ECPropertyRestriction(RELOP_EQ, PR_DISPLAY_NAME, &sResPropValue, ECRestriction::Cheap)
- .FindRowIn(ptrTable, BOOKMARK_BEGINNING, 0);
- if (hr == hrSuccess) {
- hr = ptrTable->QueryRows(1, TBL_NOADVANCE, &ptrRowSet);
- if (hr != hrSuccess)
- return hr;
- if (ptrRowSet.size() != 1)
- return MAPI_E_NOT_FOUND;
- hr = m_ptrMsgStore->OpenEntry(ptrRowSet[0].lpProps[0].Value.bin.cb, reinterpret_cast<ENTRYID *>(ptrRowSet[0].lpProps[0].Value.bin.lpb), &ptrSubFolder.iid(), MAPI_BEST_ACCESS, &ulType, &~ptrSubFolder);
- } else if (hr == MAPI_E_NOT_FOUND && bCreate == true) {
- hr = ptrFolder->CreateFolder(FOLDER_GENERIC, (LPTSTR)strFolder.c_str(), nullptr, &ptrSubFolder.iid(), fMapiUnicode, &~ptrSubFolder);
- if (hr != hrSuccess)
- return hr;
- // Maybe set some class thingy!
- }
- if (hr != hrSuccess)
- return hr;
-
- return ptrSubFolder->QueryInterface(IID_IMAPIFolder,
- reinterpret_cast<LPVOID *>(lppFolder));
- }
- HRESULT StoreHelper::CheckAndUpdateSearchFolder(LPMAPIFOLDER lpSearchFolder, eSearchFolder esfWhich)
- {
- HRESULT hr;
- SPropValuePtr ptrVersion;
- if (lpSearchFolder == NULL)
- return MAPI_E_INVALID_PARAMETER;
- hr = HrGetOneProp(lpSearchFolder, PROP_VERSION, &~ptrVersion);
- if (hr != hrSuccess && hr != MAPI_E_NOT_FOUND)
- return hr;
- if (hr == hrSuccess && ptrVersion->Value.ul == ARCHIVE_SEARCH_VERSION)
- return hr;
- return (this->*s_infoSearchFolders[esfWhich].fnSetup)(lpSearchFolder, NULL, NULL);
- }
- HRESULT StoreHelper::CreateSearchFolder(eSearchFolder esfWhich, LPMAPIFOLDER *lppSearchFolder)
- {
- HRESULT hr;
- ULONG ulType = 0;
- MAPIFolderPtr ptrRootContainer;
- MAPIFolderPtr ptrArchiveSearchRoot;
- if (lppSearchFolder == NULL)
- return MAPI_E_INVALID_PARAMETER;
- hr = m_ptrMsgStore->OpenEntry(0, nullptr, &ptrRootContainer.iid(), MAPI_BEST_ACCESS | fMapiDeferredErrors, &ulType, &~ptrRootContainer);
- if (hr != hrSuccess)
- return hr;
- hr = ptrRootContainer->CreateFolder(FOLDER_GENERIC, (LPTSTR)"Zarafa-Archive-Search-Root", nullptr, &ptrArchiveSearchRoot.iid(), fMapiDeferredErrors | OPEN_IF_EXISTS, &~ptrArchiveSearchRoot);
- if (hr != hrSuccess)
- return hr;
- return DoCreateSearchFolder(ptrArchiveSearchRoot, esfWhich, lppSearchFolder);
- }
- HRESULT StoreHelper::CreateSearchFolders(LPMAPIFOLDER *lppSearchArchiveFolder, LPMAPIFOLDER *lppSearchDeleteFolder, LPMAPIFOLDER *lppSearchStubFolder)
- {
- HRESULT hr;
- ULONG ulType = 0;
- MAPIFolderPtr ptrRootContainer;
- MAPIFolderPtr ptrArchiveSearchRoot;
- bool bWithErrors = false;
- if (lppSearchArchiveFolder == NULL || lppSearchDeleteFolder == NULL ||
- lppSearchStubFolder == NULL)
- return MAPI_E_INVALID_PARAMETER;
- hr = m_ptrMsgStore->OpenEntry(0, nullptr, &ptrRootContainer.iid(), MAPI_BEST_ACCESS | fMapiDeferredErrors, &ulType, &~ptrRootContainer);
- if (hr != hrSuccess)
- return hr;
- hr = ptrRootContainer->CreateFolder(FOLDER_GENERIC, (LPTSTR)"Zarafa-Archive-Search-Root", nullptr, &ptrArchiveSearchRoot.iid(), fMapiDeferredErrors | OPEN_IF_EXISTS, &~ptrArchiveSearchRoot);
- if (hr != hrSuccess)
- return hr;
- // Create the common restrictions here and pass them through DoCreateSearchFolder
- hr = DoCreateSearchFolder(ptrArchiveSearchRoot, esfArchive, lppSearchArchiveFolder);
- if (hr != hrSuccess)
- bWithErrors = true;
- hr = DoCreateSearchFolder(ptrArchiveSearchRoot, esfDelete, lppSearchDeleteFolder);
- if (hr != hrSuccess)
- bWithErrors = true;
- hr = DoCreateSearchFolder(ptrArchiveSearchRoot, esfStub, lppSearchStubFolder);
- if (hr != hrSuccess)
- bWithErrors = true;
- return bWithErrors ? MAPI_W_ERRORS_RETURNED : hrSuccess;
- }
- HRESULT StoreHelper::DoCreateSearchFolder(LPMAPIFOLDER lpParent, eSearchFolder esfWhich, LPMAPIFOLDER *lppSearchFolder)
- {
- HRESULT hr;
- MAPIFolderPtr ptrSearchFolder;
- if (lpParent == NULL || lppSearchFolder == NULL)
- return MAPI_E_INVALID_PARAMETER;
- hr = lpParent->CreateFolder(FOLDER_SEARCH, (LPTSTR)s_infoSearchFolders[esfWhich].lpszName, (LPTSTR)s_infoSearchFolders[esfWhich].lpszDescription, &ptrSearchFolder.iid(), OPEN_IF_EXISTS | fMapiUnicode, &~ptrSearchFolder);
- if (hr != hrSuccess)
- return hr;
- hr = (this->*s_infoSearchFolders[esfWhich].fnSetup)(ptrSearchFolder, NULL, NULL);
- if (hr != hrSuccess)
- return hr;
- return ptrSearchFolder->QueryInterface(IID_IMAPIFolder,
- reinterpret_cast<LPVOID *>(lppSearchFolder));
- }
- HRESULT StoreHelper::SetupSearchArchiveFolder(LPMAPIFOLDER lpSearchFolder, const ECRestriction *lpresClassCheck, const ECRestriction *lpresArchiveCheck)
- {
- HRESULT hr;
- ECOrRestriction resClassCheck;
- ECAndRestriction resArchiveCheck;
- MAPIFolderPtr ptrIpmSubtree;
- SPropValuePtr ptrPropEntryId;
- SPropValue sPropStubbed;
- EntryListPtr ptrEntryList;
- ECAndRestriction resArchiveFolder;
- SRestrictionPtr ptrRestriction;
- SPropValue sPropVersion;
- if (lpSearchFolder == NULL)
- return MAPI_E_INVALID_PARAMETER;
- if (!lpresClassCheck) {
- hr = GetClassCheckRestriction(&resClassCheck);
- if (hr != hrSuccess)
- return hr;
- lpresClassCheck = &resClassCheck;
- }
- if (!lpresArchiveCheck) {
- hr = GetArchiveCheckRestriction(&resArchiveCheck);
- if (hr != hrSuccess)
- return hr;
- lpresArchiveCheck = &resArchiveCheck;
- }
- hr = GetIpmSubtree(&~ptrIpmSubtree);
- if (hr != hrSuccess)
- return hr;
- hr = HrGetOneProp(ptrIpmSubtree, PR_ENTRYID, &~ptrPropEntryId);
- if (hr != hrSuccess)
- return hr;
- hr = MAPIAllocateBuffer(sizeof(ENTRYLIST), &~ptrEntryList);
- if (hr != hrSuccess)
- return hr;
- ptrEntryList->cValues = 1;
-
- hr = MAPIAllocateMore(sizeof(SBinary), ptrEntryList, (LPVOID*)&ptrEntryList->lpbin);
- if (hr != hrSuccess)
- return hr;
- ptrEntryList->lpbin[0].cb = ptrPropEntryId->Value.bin.cb;
- ptrEntryList->lpbin[0].lpb = ptrPropEntryId->Value.bin.lpb;
- sPropStubbed.ulPropTag = PROP_STUBBED; sPropStubbed.Value.b = 1;
- // Create/Update the search folder that tracks unarchived message that are not flagged to be never archived
- resArchiveFolder +=
- *lpresClassCheck +
- ECNotRestriction(
- ECAndRestriction(
- ECExistRestriction(PROP_STUBBED) +
- ECPropertyRestriction(RELOP_EQ, PROP_STUBBED, &sPropStubbed, ECRestriction::Cheap) +
- // The prop stub is only valid if the stub was not copied.
- ECExistRestriction(PROP_ORIGINAL_SOURCEKEY) +
- ECComparePropsRestriction(RELOP_EQ, PROP_ORIGINAL_SOURCEKEY, PR_SOURCE_KEY)
- )
- ) +
- ECNotRestriction(
- ECAndRestriction(
- ECExistRestriction(PROP_FLAGS) +
- ECBitMaskRestriction(BMR_NEZ, PROP_FLAGS, ARCH_NEVER_ARCHIVE)
- )
- ) +
- ECNotRestriction(*lpresArchiveCheck);
- hr = resArchiveFolder.CreateMAPIRestriction(&~ptrRestriction, ECRestriction::Cheap);
- if (hr != hrSuccess)
- return hr;
- // Set the search criteria
- hr = lpSearchFolder->SetSearchCriteria(ptrRestriction, ptrEntryList, BACKGROUND_SEARCH|RECURSIVE_SEARCH);
- if (hr != hrSuccess)
- return hr;
- sPropVersion.ulPropTag = PROP_VERSION;
- sPropVersion.Value.ul = ARCHIVE_SEARCH_VERSION;
- return HrSetOneProp(lpSearchFolder, &sPropVersion);
- }
- HRESULT StoreHelper::SetupSearchDeleteFolder(LPMAPIFOLDER lpSearchFolder, const ECRestriction *lpresClassCheck, const ECRestriction *lpresArchiveCheck)
- {
- HRESULT hr;
- ECOrRestriction resClassCheck;
- ECAndRestriction resArchiveCheck;
- MAPIFolderPtr ptrIpmSubtree;
- SPropValuePtr ptrPropEntryId;
- EntryListPtr ptrEntryList;
- ECAndRestriction resDeleteFolder;
- SRestrictionPtr ptrRestriction;
- SPropValue sPropVersion;
- if (lpSearchFolder == NULL)
- return MAPI_E_INVALID_PARAMETER;
- if (!lpresClassCheck) {
- hr = GetClassCheckRestriction(&resClassCheck);
- if (hr != hrSuccess)
- return hr;
- lpresClassCheck = &resClassCheck;
- }
- if (!lpresArchiveCheck) {
- hr = GetArchiveCheckRestriction(&resArchiveCheck);
- if (hr != hrSuccess)
- return hr;
- lpresArchiveCheck = &resArchiveCheck;
- }
- hr = GetIpmSubtree(&~ptrIpmSubtree);
- if (hr != hrSuccess)
- return hr;
- hr = HrGetOneProp(ptrIpmSubtree, PR_ENTRYID, &~ptrPropEntryId);
- if (hr != hrSuccess)
- return hr;
- hr = MAPIAllocateBuffer(sizeof(ENTRYLIST), &~ptrEntryList);
- if (hr != hrSuccess)
- return hr;
- ptrEntryList->cValues = 1;
-
- hr = MAPIAllocateMore(sizeof(SBinary), ptrEntryList, (LPVOID*)&ptrEntryList->lpbin);
- if (hr != hrSuccess)
- return hr;
- ptrEntryList->lpbin[0].cb = ptrPropEntryId->Value.bin.cb;
- ptrEntryList->lpbin[0].lpb = ptrPropEntryId->Value.bin.lpb;
- // Create/Update the search folder that tracks all archived message that are not flagged to be never deleted or never stubbed
- resDeleteFolder +=
- *lpresClassCheck +
- ECNotRestriction(
- ECAndRestriction(
- ECExistRestriction(PROP_FLAGS) +
- ECBitMaskRestriction(BMR_NEZ, PROP_FLAGS, ARCH_NEVER_DELETE)
- )
- ) +
- *lpresArchiveCheck;
- hr = resDeleteFolder.CreateMAPIRestriction(&~ptrRestriction, ECRestriction::Cheap);
- if (hr != hrSuccess)
- return hr;
- // Set the search criteria
- hr = lpSearchFolder->SetSearchCriteria(ptrRestriction, ptrEntryList, BACKGROUND_SEARCH|RECURSIVE_SEARCH);
- if (hr != hrSuccess)
- return hr;
- sPropVersion.ulPropTag = PROP_VERSION;
- sPropVersion.Value.ul = ARCHIVE_SEARCH_VERSION;
- return HrSetOneProp(lpSearchFolder, &sPropVersion);
- }
- HRESULT StoreHelper::SetupSearchStubFolder(LPMAPIFOLDER lpSearchFolder, const ECRestriction* /*lpresClassCheck*/, const ECRestriction *lpresArchiveCheck)
- {
- HRESULT hr;
- ECAndRestriction resArchiveCheck;
- MAPIFolderPtr ptrIpmSubtree;
- SPropValuePtr ptrPropEntryId;
- SPropValue sPropStubbed;
- SPropValue sPropMsgClass[2];
- EntryListPtr ptrEntryList;
- ECAndRestriction resStubFolder;
- SRestrictionPtr ptrRestriction;
- SPropValue sPropVersion;
- if (lpSearchFolder == NULL)
- return MAPI_E_INVALID_PARAMETER;
- if (!lpresArchiveCheck) {
- hr = GetArchiveCheckRestriction(&resArchiveCheck);
- if (hr != hrSuccess)
- return hr;
- lpresArchiveCheck = &resArchiveCheck;
- }
- hr = GetIpmSubtree(&~ptrIpmSubtree);
- if (hr != hrSuccess)
- return hr;
- hr = HrGetOneProp(ptrIpmSubtree, PR_ENTRYID, &~ptrPropEntryId);
- if (hr != hrSuccess)
- return hr;
- hr = MAPIAllocateBuffer(sizeof(ENTRYLIST), &~ptrEntryList);
- if (hr != hrSuccess)
- return hr;
- ptrEntryList->cValues = 1;
-
- hr = MAPIAllocateMore(sizeof(SBinary), ptrEntryList, (LPVOID*)&ptrEntryList->lpbin);
- if (hr != hrSuccess)
- return hr;
- ptrEntryList->lpbin[0].cb = ptrPropEntryId->Value.bin.cb;
- ptrEntryList->lpbin[0].lpb = ptrPropEntryId->Value.bin.lpb;
- sPropStubbed.ulPropTag = PROP_STUBBED;
- sPropStubbed.Value.b = 1;
- sPropMsgClass[0].ulPropTag = PR_MESSAGE_CLASS;
- sPropMsgClass[0].Value.LPSZ = const_cast<TCHAR *>(_T("IPM.Note"));
- sPropMsgClass[1].ulPropTag = PR_MESSAGE_CLASS;
- sPropMsgClass[1].Value.LPSZ = const_cast<TCHAR *>(_T("IPM.Note.")); // RES_CONTENT w FL_PREFIX
- // Create/Update the search folder that tracks non-stubbed archived message that are not flagged to be never stubbed.
- resStubFolder +=
- ECOrRestriction(
- ECPropertyRestriction(RELOP_EQ, PR_MESSAGE_CLASS, &sPropMsgClass[0], ECRestriction::Cheap) +
- ECContentRestriction(FL_PREFIX, PR_MESSAGE_CLASS, &sPropMsgClass[1], ECRestriction::Cheap)
- ) +
- ECNotRestriction(
- ECAndRestriction(
- ECExistRestriction(PROP_STUBBED) +
- ECPropertyRestriction(RELOP_EQ, PROP_STUBBED, &sPropStubbed, ECRestriction::Cheap)
- )
- ) +
- ECNotRestriction(
- ECAndRestriction(
- ECExistRestriction(PROP_FLAGS) +
- ECBitMaskRestriction(BMR_NEZ, PROP_FLAGS, ARCH_NEVER_STUB)
- )
- ) +
- *lpresArchiveCheck;
- hr = resStubFolder.CreateMAPIRestriction(&~ptrRestriction, ECRestriction::Cheap);
- if (hr != hrSuccess)
- return hr;
- // Set the search criteria
- hr = lpSearchFolder->SetSearchCriteria(ptrRestriction, ptrEntryList, BACKGROUND_SEARCH|RECURSIVE_SEARCH);
- if (hr != hrSuccess)
- return hr;
- sPropVersion.ulPropTag = PROP_VERSION;
- sPropVersion.Value.ul = ARCHIVE_SEARCH_VERSION;
- return HrSetOneProp(lpSearchFolder, &sPropVersion);
- }
- HRESULT StoreHelper::GetClassCheckRestriction(ECOrRestriction *lpresClassCheck)
- {
- SPropValue sPropMsgClass[9];
- ECOrRestriction resClassCheck;
- sPropMsgClass[0].ulPropTag = PR_MESSAGE_CLASS;
- sPropMsgClass[0].Value.LPSZ = const_cast<TCHAR *>(_T("IPM.Note"));
- sPropMsgClass[1].ulPropTag = PR_MESSAGE_CLASS;
- sPropMsgClass[1].Value.LPSZ = const_cast<TCHAR *>(_T("IPM.Note.")); // RES_CONTENT w FL_PREFIX
- sPropMsgClass[2].ulPropTag = PR_MESSAGE_CLASS;
- sPropMsgClass[2].Value.LPSZ = const_cast<TCHAR *>(_T("IPM.Schedule.Meeting.Request"));
- sPropMsgClass[3].ulPropTag = PR_MESSAGE_CLASS;
- sPropMsgClass[3].Value.LPSZ = const_cast<TCHAR *>(_T("IPM.Schedule.Meeting.Resp.Pos"));
- sPropMsgClass[4].ulPropTag = PR_MESSAGE_CLASS;
- sPropMsgClass[4].Value.LPSZ = const_cast<TCHAR *>(_T("IPM.Schedule.Meeting.Resp.Neg"));
- sPropMsgClass[5].ulPropTag = PR_MESSAGE_CLASS;
- sPropMsgClass[5].Value.LPSZ = const_cast<TCHAR *>(_T("IPM.Schedule.Meeting.Resp.Tent"));
- sPropMsgClass[6].ulPropTag = PR_MESSAGE_CLASS;
- sPropMsgClass[6].Value.LPSZ = const_cast<TCHAR *>(_T("IPM.Schedule.Meeting.Canceled"));
- sPropMsgClass[7].ulPropTag = PR_MESSAGE_CLASS;
- sPropMsgClass[7].Value.LPSZ = const_cast<TCHAR *>(_T("Report.IPM.Note.NDR"));
- sPropMsgClass[8].ulPropTag = PR_MESSAGE_CLASS;
- sPropMsgClass[8].Value.LPSZ = const_cast<TCHAR *>(_T("Report.IPM.Note.IPNRN"));
- // Build the message class restriction.
- resClassCheck +=
- ECPropertyRestriction(RELOP_EQ, PR_MESSAGE_CLASS, &sPropMsgClass[0], ECRestriction::Shallow) +
- ECContentRestriction(FL_PREFIX, PR_MESSAGE_CLASS, &sPropMsgClass[1], ECRestriction::Shallow) +
- ECPropertyRestriction(RELOP_EQ, PR_MESSAGE_CLASS, &sPropMsgClass[2], ECRestriction::Shallow) +
- ECPropertyRestriction(RELOP_EQ, PR_MESSAGE_CLASS, &sPropMsgClass[3], ECRestriction::Shallow) +
- ECPropertyRestriction(RELOP_EQ, PR_MESSAGE_CLASS, &sPropMsgClass[4], ECRestriction::Shallow) +
- ECPropertyRestriction(RELOP_EQ, PR_MESSAGE_CLASS, &sPropMsgClass[5], ECRestriction::Shallow) +
- ECPropertyRestriction(RELOP_EQ, PR_MESSAGE_CLASS, &sPropMsgClass[6], ECRestriction::Shallow) +
- ECPropertyRestriction(RELOP_EQ, PR_MESSAGE_CLASS, &sPropMsgClass[7], ECRestriction::Shallow) +
- ECPropertyRestriction(RELOP_EQ, PR_MESSAGE_CLASS, &sPropMsgClass[8], ECRestriction::Shallow);
- *lpresClassCheck = std::move(resClassCheck);
- return hrSuccess;
- }
- HRESULT StoreHelper::GetArchiveCheckRestriction(ECAndRestriction *lpresArchiveCheck)
- {
- HRESULT hr;
- SPropValue sPropDirty = {0};
- ObjectEntryList lstArchives;
- ECAndRestriction resArchiveCheck;
- sPropDirty.ulPropTag = PROP_DIRTY;
- sPropDirty.Value.b = 1;
- resArchiveCheck +=
- ECAndRestriction(
- ECExistRestriction(PROP_ORIGINAL_SOURCEKEY) +
- ECComparePropsRestriction(RELOP_EQ, PROP_ORIGINAL_SOURCEKEY, PR_SOURCE_KEY)
- ) +
- ECNotRestriction(
- ECAndRestriction(
- ECExistRestriction(PROP_DIRTY) +
- ECPropertyRestriction(RELOP_EQ, PROP_DIRTY, &sPropDirty, ECRestriction::Shallow)
- )
- );
- hr = GetArchiveList(&lstArchives);
- if (hr != hrSuccess)
- return hr;
- // Build the restriction that checks that the message has been archived to all archives.
- resArchiveCheck += ECExistRestriction(PROP_ARCHIVE_STORE_ENTRYIDS);
- for (const auto &arc : lstArchives) {
- SPropValue sPropFolderEntryId;
- sPropFolderEntryId.ulPropTag = (PROP_ARCHIVE_STORE_ENTRYIDS & ~MV_FLAG);
- sPropFolderEntryId.Value.bin.cb = arc.sStoreEntryId.size();
- sPropFolderEntryId.Value.bin.lpb = arc.sStoreEntryId;
- resArchiveCheck += ECPropertyRestriction(RELOP_EQ, PROP_ARCHIVE_STORE_ENTRYIDS, &sPropFolderEntryId, ECRestriction::Full);
- }
- *lpresArchiveCheck = std::move(resArchiveCheck);
- return hrSuccess;
- }
- }} /* namespace */
|