123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116 |
- /*
- * 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 <new>
- #include "ZCABContainer.h"
- #include "ZCMAPIProp.h"
- #include <kopano/Trace.h>
- #include <mapiutil.h>
- #include <kopano/ECMemTable.h>
- #include <kopano/ECGuid.h>
- #include <kopano/ECInterfaceDefs.h>
- #include <kopano/ECDebug.h>
- #include <kopano/CommonUtil.h>
- #include <kopano/mapiext.h>
- #include <kopano/mapiguidext.h>
- #include <kopano/memory.hpp>
- #include <kopano/namedprops.h>
- #include <kopano/charset/convert.h>
- #include <kopano/mapi_ptr.h>
- #include <kopano/ECGetText.h>
- #include <kopano/EMSAbTag.h>
- #include <kopano/ECRestriction.h>
- #include <iostream>
- #include <kopano/Util.h>
- #include <kopano/stringutil.h>
- using namespace std;
- using namespace KCHL;
- ZCABContainer::ZCABContainer(std::vector<zcabFolderEntry> *lpFolders,
- IMAPIFolder *lpContacts, LPMAPISUP lpMAPISup, void *lpProvider,
- const char *szClassName) :
- ECUnknown(szClassName), m_lpFolders(lpFolders),
- m_lpContactFolder(lpContacts), m_lpMAPISup(lpMAPISup),
- m_lpProvider(lpProvider)
- {
- assert(!(lpFolders != NULL && lpContacts != NULL));
- if (m_lpMAPISup)
- m_lpMAPISup->AddRef();
- if (m_lpContactFolder)
- m_lpContactFolder->AddRef();
- }
- ZCABContainer::~ZCABContainer()
- {
- if (m_lpMAPISup)
- m_lpMAPISup->Release();
- if (m_lpContactFolder)
- m_lpContactFolder->Release();
- if (m_lpDistList)
- m_lpDistList->Release();
- }
- HRESULT ZCABContainer::QueryInterface(REFIID refiid, void **lppInterface)
- {
- if (m_lpDistList == NULL)
- REGISTER_INTERFACE2(ZCABContainer, this);
- else
- REGISTER_INTERFACE(IID_ZCDistList, this);
- REGISTER_INTERFACE2(ECUnknown, this);
- if (m_lpDistList == NULL)
- REGISTER_INTERFACE2(IABContainer, &this->m_xABContainer);
- else
- REGISTER_INTERFACE(IID_IDistList, &this->m_xABContainer);
- REGISTER_INTERFACE2(IMAPIProp, &this->m_xABContainer);
- REGISTER_INTERFACE2(IUnknown, &this->m_xABContainer);
- return MAPI_E_INTERFACE_NOT_SUPPORTED;
- }
- /**
- * Create a ZCABContainer as either the top level (lpFolders is set) or
- * as a subfolder (lpContacts is set).
- *
- * @param[in] lpFolders Only the top container has the list to the wanted Kopano Contacts Folders, NULL otherwise.
- * @param[in] lpContacts Create this object as wrapper for the lpContacts folder, NULL if
- * @param[in] lpMAPISup
- * @param[in] lpProvider
- * @param[out] lppABContainer The newly created ZCABContainer class
- *
- * @return
- */
- HRESULT ZCABContainer::Create(std::vector<zcabFolderEntry> *lpFolders, IMAPIFolder *lpContacts, LPMAPISUP lpMAPISup, void* lpProvider, ZCABContainer **lppABContainer)
- {
- auto lpABContainer = new(std::nothrow) ZCABContainer(lpFolders, lpContacts, lpMAPISup, lpProvider, "IABContainer");
- if (lpABContainer == nullptr)
- return MAPI_E_NOT_ENOUGH_MEMORY;
- auto ret = lpABContainer->QueryInterface(IID_ZCABContainer,
- reinterpret_cast<void **>(lppABContainer));
- if (ret != hrSuccess)
- delete lpABContainer;
- return ret;
- }
- HRESULT ZCABContainer::Create(IMessage *lpContact, ULONG cbEntryID, LPENTRYID lpEntryID, LPMAPISUP lpMAPISup, ZCABContainer **lppABContainer)
- {
- HRESULT hr = hrSuccess;
- object_ptr<ZCMAPIProp> lpDistList;
- auto lpABContainer = new(std::nothrow) ZCABContainer(NULL, NULL, lpMAPISup, NULL, "IABContainer");
- if (lpABContainer == nullptr) {
- hr = MAPI_E_NOT_ENOUGH_MEMORY;
- goto exit;
- }
- hr = ZCMAPIProp::Create(lpContact, cbEntryID, lpEntryID, &~lpDistList);
- if (hr != hrSuccess)
- goto exit;
- hr = lpDistList->QueryInterface(IID_IMAPIProp, (void **)&lpABContainer->m_lpDistList);
- if (hr != hrSuccess)
- goto exit;
- hr = lpABContainer->QueryInterface(IID_ZCDistList, (void **)lppABContainer);
- exit:
- if (hr != hrSuccess)
- delete lpABContainer;
- return hr;
- }
- // IMAPIContainer
- HRESULT ZCABContainer::MakeWrappedEntryID(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulObjType, ULONG ulOffset, ULONG *lpcbEntryID, LPENTRYID *lppEntryID)
- {
- cabEntryID *lpWrapped = NULL;
- ULONG cbWrapped = CbNewCABENTRYID(cbEntryID);
- HRESULT hr = MAPIAllocateBuffer(cbWrapped,
- reinterpret_cast<void **>(&lpWrapped));
- if (hr != hrSuccess)
- return hr;
- memset(lpWrapped, 0, cbWrapped);
- memcpy(&lpWrapped->muid, &MUIDZCSAB, sizeof(MAPIUID));
- lpWrapped->ulObjType = ulObjType;
- lpWrapped->ulOffset = ulOffset;
- memcpy(lpWrapped->origEntryID, lpEntryID, cbEntryID);
-
- *lpcbEntryID = cbWrapped;
- *lppEntryID = (LPENTRYID)lpWrapped;
- return hrSuccess;
- }
- HRESULT ZCABContainer::GetFolderContentsTable(ULONG ulFlags, LPMAPITABLE *lppTable)
- {
- HRESULT hr = hrSuccess;
- MAPITablePtr ptrContents;
- SRowSetPtr ptrRows;
- object_ptr<ECMemTable> lpTable;
- object_ptr<ECMemTableView> lpTableView;
- ULONG i, j = 0;
- ECAndRestriction resAnd;
- SPropValue sRestrictProp;
- #define I_NCOLS 11
- // data from the contact
- static constexpr const SizedSPropTagArray(I_NCOLS, inputCols) =
- {I_NCOLS, {PR_DISPLAY_NAME, PR_ADDRTYPE, PR_EMAIL_ADDRESS,
- PR_NORMALIZED_SUBJECT, PR_ENTRYID, PR_MESSAGE_CLASS,
- PR_ORIGINAL_DISPLAY_NAME, PR_PARENT_ENTRYID, PR_SOURCE_KEY,
- PR_PARENT_SOURCE_KEY, PR_CHANGE_KEY}};
- // I_MV_INDEX is dispidABPEmailList from mnNamedProps
- enum {I_DISPLAY_NAME = 0, I_ADDRTYPE, I_EMAIL_ADDRESS, I_NORMALIZED_SUBJECT, I_ENTRYID, I_MESSAGE_CLASS, I_ORIGINAL_DISPLAY_NAME,
- I_PARENT_ENTRYID, I_SOURCE_KEY, I_PARENT_SOURCE_KEY, I_CHANGE_KEY, I_MV_INDEX, I_NAMEDSTART};
- SPropTagArrayPtr ptrInputCols;
- #define O_NCOLS 21
- // data for the table
- static constexpr const SizedSPropTagArray(O_NCOLS, outputCols) =
- {O_NCOLS, {PR_DISPLAY_NAME, PR_ADDRTYPE, PR_EMAIL_ADDRESS,
- PR_NORMALIZED_SUBJECT, PR_ENTRYID, PR_DISPLAY_TYPE,
- PR_OBJECT_TYPE, PR_ORIGINAL_DISPLAY_NAME,
- PR_ZC_ORIGINAL_ENTRYID, PR_ZC_ORIGINAL_PARENT_ENTRYID,
- PR_ZC_ORIGINAL_SOURCE_KEY, PR_ZC_ORIGINAL_PARENT_SOURCE_KEY,
- PR_ZC_ORIGINAL_CHANGE_KEY, PR_SEARCH_KEY, PR_INSTANCE_KEY,
- PR_ROWID}};
- enum {O_DISPLAY_NAME = 0, O_ADDRTYPE, O_EMAIL_ADDRESS, O_NORMALIZED_SUBJECT, O_ENTRYID, O_DISPLAY_TYPE, O_OBJECT_TYPE, O_ORIGINAL_DISPLAY_NAME,
- O_ZC_ORIGINAL_ENTRYID, O_ZC_ORIGINAL_PARENT_ENTRYID, O_ZC_ORIGINAL_SOURCE_KEY, O_ZC_ORIGINAL_PARENT_SOURCE_KEY, O_ZC_ORIGINAL_CHANGE_KEY,
- O_SEARCH_KEY, O_INSTANCE_KEY, O_ROWID};
- SPropTagArrayPtr ptrOutputCols;
- SPropTagArrayPtr ptrContactCols;
- // named properties
- SPropTagArrayPtr ptrNameTags;
- KCHL::memory_ptr<MAPINAMEID *> lppNames;
- ULONG ulNames = (6 * 5) + 2;
- ULONG ulType = (ulFlags & MAPI_UNICODE) ? PT_UNICODE : PT_STRING8;
- MAPINAMEID mnNamedProps[(6 * 5) + 2] = {
- // index with MVI_FLAG
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidABPEmailList}},
- // MVI offset 0: email1 set
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail1DisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail1AddressType}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail1Address}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail1OriginalDisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail1OriginalEntryID}},
- // MVI offset 1: email2 set
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail2DisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail2AddressType}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail2Address}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail2OriginalDisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail2OriginalEntryID}},
- // MVI offset 2: email3 set
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail3DisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail3AddressType}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail3Address}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail3OriginalDisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidEmail3OriginalEntryID}},
- // MVI offset 3: business fax (fax2) set
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax2DisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax2AddressType}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax2Address}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax2OriginalDisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax2OriginalEntryID}},
- // MVI offset 4: home fax (fax3) set
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax3DisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax3AddressType}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax3Address}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax3OriginalDisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax3OriginalEntryID}},
- // MVI offset 5: primary fax (fax1) set
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax1DisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax1AddressType}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax1Address}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax1OriginalDisplayName}},
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidFax1OriginalEntryID}},
- // restriction
- {(LPGUID)&PSETID_Address, MNID_ID, {dispidABPArrayType}},
- };
- ulFlags = ulFlags & MAPI_UNICODE;
- hr = Util::HrCopyUnicodePropTagArray(ulFlags, inputCols, &~ptrInputCols);
- if (hr != hrSuccess)
- return hr;
- hr = Util::HrCopyUnicodePropTagArray(ulFlags, outputCols, &~ptrOutputCols);
- if (hr != hrSuccess)
- return hr;
- hr = ECMemTable::Create(ptrOutputCols, PR_ROWID, &~lpTable);
- if(hr != hrSuccess)
- return hr;
- // root container has no contents, on hierarchy entries
- if (m_lpContactFolder == NULL)
- goto done;
- hr = m_lpContactFolder->GetContentsTable(ulFlags | MAPI_DEFERRED_ERRORS, &~ptrContents);
- if (hr != hrSuccess)
- return hr;
- hr = MAPIAllocateBuffer(sizeof(LPMAPINAMEID) * ulNames, &~lppNames);
- if (hr != hrSuccess)
- return hr;
- for (i = 0; i < ulNames; ++i)
- lppNames[i] = &mnNamedProps[i];
- hr = m_lpContactFolder->GetIDsFromNames(ulNames, lppNames, MAPI_CREATE, &~ptrNameTags);
- if (FAILED(hr))
- return hr;
- // fix types
- ptrNameTags->aulPropTag[0] = CHANGE_PROP_TYPE(ptrNameTags->aulPropTag[0], PT_MV_LONG | MV_INSTANCE);
- for (i = 0; i < (ulNames - 2) / 5; ++i) {
- ptrNameTags->aulPropTag[1+ (i*5) + 0] = CHANGE_PROP_TYPE(ptrNameTags->aulPropTag[1+ (i*5) + 0], ulType);
- ptrNameTags->aulPropTag[1+ (i*5) + 1] = CHANGE_PROP_TYPE(ptrNameTags->aulPropTag[1+ (i*5) + 1], ulType);
- ptrNameTags->aulPropTag[1+ (i*5) + 2] = CHANGE_PROP_TYPE(ptrNameTags->aulPropTag[1+ (i*5) + 2], ulType);
- ptrNameTags->aulPropTag[1+ (i*5) + 3] = CHANGE_PROP_TYPE(ptrNameTags->aulPropTag[1+ (i*5) + 3], ulType);
- ptrNameTags->aulPropTag[1+ (i*5) + 4] = CHANGE_PROP_TYPE(ptrNameTags->aulPropTag[1+ (i*5) + 4], PT_BINARY);
- }
- ptrNameTags->aulPropTag[ulNames-1] = CHANGE_PROP_TYPE(ptrNameTags->aulPropTag[ulNames-1], PT_LONG);
- // add func HrCombinePropTagArrays(part1, part2, dest);
- hr = MAPIAllocateBuffer(CbNewSPropTagArray(ptrInputCols->cValues + ptrNameTags->cValues), &~ptrContactCols);
- if (hr != hrSuccess)
- return hr;
- j = 0;
- for (i = 0; i < ptrInputCols->cValues; ++i)
- ptrContactCols->aulPropTag[j++] = ptrInputCols->aulPropTag[i];
- for (i = 0; i < ptrNameTags->cValues; ++i)
- ptrContactCols->aulPropTag[j++] = ptrNameTags->aulPropTag[i];
- ptrContactCols->cValues = j;
- // the exists is extra compared to the outlook restriction
- // restrict: ( distlist || ( contact && exist(abparraytype) && abparraytype != 0 ) )
- sRestrictProp.ulPropTag = PR_MESSAGE_CLASS_A;
- sRestrictProp.Value.lpszA = const_cast<char *>("IPM.Contact");
- resAnd += ECContentRestriction(FL_PREFIX|FL_IGNORECASE, PR_MESSAGE_CLASS_A, &sRestrictProp, ECRestriction::Shallow);
- sRestrictProp.ulPropTag = ptrNameTags->aulPropTag[ulNames-1];
- sRestrictProp.Value.ul = 0;
- resAnd += ECExistRestriction(sRestrictProp.ulPropTag);
- resAnd += ECPropertyRestriction(RELOP_NE, sRestrictProp.ulPropTag, &sRestrictProp, ECRestriction::Shallow);
- sRestrictProp.ulPropTag = PR_MESSAGE_CLASS_A;
- sRestrictProp.Value.lpszA = const_cast<char *>("IPM.DistList");
- hr = ECOrRestriction(
- ECContentRestriction(FL_PREFIX | FL_IGNORECASE, PR_MESSAGE_CLASS_A, &sRestrictProp, ECRestriction::Cheap) +
- resAnd
- ).RestrictTable(ptrContents, TBL_BATCH);
- if (hr != hrSuccess)
- return hr;
- // set columns
- hr = ptrContents->SetColumns(ptrContactCols, TBL_BATCH);
- if (hr != hrSuccess)
- return hr;
- j = 0;
- while (true) {
- hr = ptrContents->QueryRows(256, 0, &ptrRows);
- if (hr != hrSuccess)
- return hr;
- if (ptrRows.empty())
- break;
- for (i = 0; i < ptrRows.size(); ++i) {
- ULONG ulOffset = 0;
- std::string strSearchKey;
- SPropValue lpColData[O_NCOLS];
- memset(lpColData, 0, sizeof(lpColData));
- if (ptrRows[i].lpProps[I_MV_INDEX].ulPropTag == (ptrNameTags->aulPropTag[0] & ~MVI_FLAG)) {
- // do not index outside named properties
- if (ptrRows[i].lpProps[I_MV_INDEX].Value.ul > 5)
- continue;
- ulOffset = ptrRows[i].lpProps[I_MV_INDEX].Value.ul * 5;
- }
- if (PROP_TYPE(ptrRows[i].lpProps[I_MESSAGE_CLASS].ulPropTag) == PT_ERROR)
- // no PR_MESSAGE_CLASS, unusable
- continue;
- if (
- ((ulFlags & MAPI_UNICODE) && wcscasecmp(ptrRows[i].lpProps[I_MESSAGE_CLASS].Value.lpszW, L"IPM.Contact") == 0) ||
- ((ulFlags & MAPI_UNICODE) == 0 && strcasecmp(ptrRows[i].lpProps[I_MESSAGE_CLASS].Value.lpszA, "IPM.Contact") == 0)
- )
- {
- lpColData[O_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
- lpColData[O_DISPLAY_TYPE].Value.ul = DT_MAILUSER;
- lpColData[O_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
- lpColData[O_OBJECT_TYPE].Value.ul = MAPI_MAILUSER;
- lpColData[O_ADDRTYPE].ulPropTag = CHANGE_PROP_TYPE(ptrOutputCols->aulPropTag[O_ADDRTYPE], PROP_TYPE(ptrRows[i].lpProps[I_NAMEDSTART + ulOffset + 1].ulPropTag));
- lpColData[O_ADDRTYPE].Value = ptrRows[i].lpProps[I_NAMEDSTART + ulOffset + 1].Value;
- } else if (
- ((ulFlags & MAPI_UNICODE) && wcscasecmp(ptrRows[i].lpProps[I_MESSAGE_CLASS].Value.lpszW, L"IPM.DistList") == 0) ||
- ((ulFlags & MAPI_UNICODE) == 0 && strcasecmp(ptrRows[i].lpProps[I_MESSAGE_CLASS].Value.lpszA, "IPM.DistList") == 0)
- )
- {
- lpColData[O_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
- lpColData[O_DISPLAY_TYPE].Value.ul = DT_PRIVATE_DISTLIST;
- lpColData[O_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
- lpColData[O_OBJECT_TYPE].Value.ul = MAPI_DISTLIST;
- lpColData[O_ADDRTYPE].ulPropTag = PR_ADDRTYPE_W;
- lpColData[O_ADDRTYPE].Value.lpszW = const_cast<wchar_t *>(L"MAPIPDL");
- } else {
- continue;
- }
- // devide by 5 since a block of properties on a contact is a set of 5 (see mnNamedProps above)
- memory_ptr<ENTRYID> wrapped_eid;
- hr = MakeWrappedEntryID(ptrRows[i].lpProps[I_ENTRYID].Value.bin.cb, (LPENTRYID)ptrRows[i].lpProps[I_ENTRYID].Value.bin.lpb,
- lpColData[O_OBJECT_TYPE].Value.ul, ulOffset/5,
- &lpColData[O_ENTRYID].Value.bin.cb, &~wrapped_eid);
- if (hr != hrSuccess)
- return hr;
- lpColData[O_ENTRYID].Value.bin.lpb = reinterpret_cast<BYTE *>(wrapped_eid.get());
- lpColData[O_ENTRYID].ulPropTag = PR_ENTRYID;
- ulOffset += I_NAMEDSTART;
- lpColData[O_DISPLAY_NAME].ulPropTag = CHANGE_PROP_TYPE(ptrOutputCols->aulPropTag[O_DISPLAY_NAME], PROP_TYPE(ptrRows[i].lpProps[ulOffset + 0].ulPropTag));
- if (PROP_TYPE(lpColData[O_DISPLAY_NAME].ulPropTag) == PT_ERROR)
- // Email#Display not available, fallback to normal PR_DISPLAY_NAME
- lpColData[O_DISPLAY_NAME] = ptrRows[i].lpProps[I_DISPLAY_NAME];
- else
- lpColData[O_DISPLAY_NAME].Value = ptrRows[i].lpProps[ulOffset + 0].Value;
- lpColData[O_EMAIL_ADDRESS].ulPropTag = CHANGE_PROP_TYPE(ptrOutputCols->aulPropTag[O_EMAIL_ADDRESS], PROP_TYPE(ptrRows[i].lpProps[ulOffset + 2].ulPropTag));
- if (PROP_TYPE(lpColData[O_EMAIL_ADDRESS].ulPropTag) == PT_ERROR)
- // Email#Address not available, fallback to normal PR_EMAIL_ADDRESS
- lpColData[O_EMAIL_ADDRESS] = ptrRows[i].lpProps[I_EMAIL_ADDRESS];
- else
- lpColData[O_EMAIL_ADDRESS].Value = ptrRows[i].lpProps[ulOffset + 2].Value;
- lpColData[O_NORMALIZED_SUBJECT].ulPropTag = CHANGE_PROP_TYPE(ptrOutputCols->aulPropTag[O_NORMALIZED_SUBJECT], PROP_TYPE(ptrRows[i].lpProps[ulOffset + 3].ulPropTag));
- if (PROP_TYPE(lpColData[O_NORMALIZED_SUBJECT].ulPropTag) == PT_ERROR)
- // Email#OriginalDisplayName not available, fallback to normal PR_NORMALIZED_SUBJECT
- lpColData[O_NORMALIZED_SUBJECT] = ptrRows[i].lpProps[I_NORMALIZED_SUBJECT];
- else
- lpColData[O_NORMALIZED_SUBJECT].Value = ptrRows[i].lpProps[ulOffset + 3].Value;
- lpColData[O_ORIGINAL_DISPLAY_NAME].ulPropTag = CHANGE_PROP_TYPE(ptrOutputCols->aulPropTag[O_ORIGINAL_DISPLAY_NAME], PROP_TYPE(ptrRows[i].lpProps[I_DISPLAY_NAME].ulPropTag));
- lpColData[O_ORIGINAL_DISPLAY_NAME].Value = ptrRows[i].lpProps[I_DISPLAY_NAME].Value;
- lpColData[O_ZC_ORIGINAL_ENTRYID].ulPropTag = CHANGE_PROP_TYPE(ptrOutputCols->aulPropTag[O_ZC_ORIGINAL_ENTRYID], PROP_TYPE(ptrRows[i].lpProps[I_ENTRYID].ulPropTag));
- lpColData[O_ZC_ORIGINAL_ENTRYID].Value = ptrRows[i].lpProps[I_ENTRYID].Value;
- lpColData[O_ZC_ORIGINAL_PARENT_ENTRYID].ulPropTag = CHANGE_PROP_TYPE(ptrOutputCols->aulPropTag[O_ZC_ORIGINAL_PARENT_ENTRYID], PROP_TYPE(ptrRows[i].lpProps[I_PARENT_ENTRYID].ulPropTag));
- lpColData[O_ZC_ORIGINAL_PARENT_ENTRYID].Value = ptrRows[i].lpProps[I_PARENT_ENTRYID].Value;
- lpColData[O_ZC_ORIGINAL_SOURCE_KEY].ulPropTag = CHANGE_PROP_TYPE(ptrOutputCols->aulPropTag[O_ZC_ORIGINAL_SOURCE_KEY], PROP_TYPE(ptrRows[i].lpProps[I_SOURCE_KEY].ulPropTag));
- lpColData[O_ZC_ORIGINAL_SOURCE_KEY].Value = ptrRows[i].lpProps[I_SOURCE_KEY].Value;
- lpColData[O_ZC_ORIGINAL_PARENT_SOURCE_KEY].ulPropTag = CHANGE_PROP_TYPE(ptrOutputCols->aulPropTag[O_ZC_ORIGINAL_PARENT_SOURCE_KEY], PROP_TYPE(ptrRows[i].lpProps[I_PARENT_SOURCE_KEY].ulPropTag));
- lpColData[O_ZC_ORIGINAL_PARENT_SOURCE_KEY].Value = ptrRows[i].lpProps[I_PARENT_SOURCE_KEY].Value;
- lpColData[O_ZC_ORIGINAL_CHANGE_KEY].ulPropTag = CHANGE_PROP_TYPE(ptrOutputCols->aulPropTag[O_ZC_ORIGINAL_CHANGE_KEY], PROP_TYPE(ptrRows[i].lpProps[I_CHANGE_KEY].ulPropTag));
- lpColData[O_ZC_ORIGINAL_CHANGE_KEY].Value = ptrRows[i].lpProps[I_CHANGE_KEY].Value;
- // @note, outlook seems to set the gab original search key (if possible, otherwise SMTP). The IMessage contact in the folder contains some unusable binary blob.
- if (PROP_TYPE(lpColData[O_ADDRTYPE].ulPropTag) == PT_STRING8 &&
- PROP_TYPE(lpColData[O_EMAIL_ADDRESS].ulPropTag) == PT_STRING8)
- strSearchKey = strToUpper(std::string(lpColData[O_ADDRTYPE].Value.lpszA) + ":" + lpColData[O_EMAIL_ADDRESS].Value.lpszA);
- else if (PROP_TYPE(lpColData[O_ADDRTYPE].ulPropTag) == PT_UNICODE &&
- PROP_TYPE(lpColData[O_EMAIL_ADDRESS].ulPropTag) == PT_UNICODE)
- strSearchKey = strToUpper(convert_to<std::string>(std::wstring(lpColData[O_ADDRTYPE].Value.lpszW) + L":" + lpColData[O_EMAIL_ADDRESS].Value.lpszW));
- else
- // eg. distlists
- hr = MAPI_E_NOT_FOUND;
- if (hr == hrSuccess) {
- lpColData[O_SEARCH_KEY].ulPropTag = PR_SEARCH_KEY;
- lpColData[O_SEARCH_KEY].Value.bin.cb = strSearchKey.length()+1;
- lpColData[O_SEARCH_KEY].Value.bin.lpb = (BYTE*)strSearchKey.data();
- } else {
- lpColData[O_SEARCH_KEY].ulPropTag = CHANGE_PROP_TYPE(PR_SEARCH_KEY, PT_ERROR);
- lpColData[O_SEARCH_KEY].Value.ul = MAPI_E_NOT_FOUND;
- }
- lpColData[O_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
- lpColData[O_INSTANCE_KEY].Value.bin.cb = sizeof(ULONG);
- lpColData[O_INSTANCE_KEY].Value.bin.lpb = (LPBYTE)&j;
- lpColData[O_ROWID].ulPropTag = PR_ROWID;
- lpColData[O_ROWID].Value.ul = j++;
- hr = lpTable->HrModifyRow(ECKeyTable::TABLE_ROW_ADD, NULL, lpColData, O_NCOLS);
- if (hr != hrSuccess)
- return hr;
- }
- }
-
- done:
- AddChild(lpTable);
- hr = lpTable->HrGetView(createLocaleFromName(nullptr), ulFlags, &~lpTableView);
- if(hr != hrSuccess)
- return hr;
- return lpTableView->QueryInterface(IID_IMAPITable,
- reinterpret_cast<void **>(lppTable));
- #undef TCOLS
- }
- HRESULT ZCABContainer::GetDistListContentsTable(ULONG ulFlags, LPMAPITABLE *lppTable)
- {
- HRESULT hr = hrSuccess;
- static constexpr const SizedSPropTagArray(13, sptaCols) =
- {13, {PR_NULL /* reserve for PR_ROWID */, PR_ADDRTYPE,
- PR_DISPLAY_NAME, PR_DISPLAY_TYPE, PR_EMAIL_ADDRESS, PR_ENTRYID,
- PR_INSTANCE_KEY, PR_OBJECT_TYPE, PR_RECORD_KEY, PR_SEARCH_KEY,
- PR_SEND_INTERNET_ENCODING, PR_SEND_RICH_INFO,
- PR_TRANSMITABLE_DISPLAY_NAME}};
- SPropTagArrayPtr ptrCols;
- object_ptr<ECMemTable> lpTable;
- object_ptr<ECMemTableView> lpTableView;
- SPropValuePtr ptrEntries;
- MAPIPropPtr ptrUser;
- ULONG ulObjType;
- ULONG cValues;
- SPropArrayPtr ptrProps;
- SPropValue sKey;
- KCHL::object_ptr<ZCMAPIProp> ptrZCMAPIProp;
- hr = Util::HrCopyUnicodePropTagArray(ulFlags, sptaCols, &~ptrCols);
- if (hr != hrSuccess)
- return hr;
- hr = ECMemTable::Create(ptrCols, PR_ROWID, &~lpTable);
- if(hr != hrSuccess)
- return hr;
- // getprops, open real contacts, make table
- hr = HrGetOneProp(m_lpDistList, 0x81051102, &~ptrEntries); // Members "entryids" named property, see data layout below
- if (hr != hrSuccess)
- return hr;
- sKey.ulPropTag = PR_ROWID;
- sKey.Value.ul = 0;
- for (ULONG i = 0; i < ptrEntries->Value.MVbin.cValues; ++i) {
- ULONG ulOffset = 0;
- BYTE cType = 0;
- // Wrapped entryids:
- // Flags: (ULONG) 0
- // Provider: (GUID) 0xC091ADD3519DCF11A4A900AA0047FAA4
- // Type: (BYTE) <value>, describes wrapped entryid
- // lower 4 bits:
- // 0x00 = OneOff (use addressbook)
- // 0x03 = Contact (use folder / session?)
- // 0x04 = PDL (use folder / session?)
- // 0x05 = GAB IMailUser (use addressbook)
- // 0x06 = GAB IDistList (use addressbook)
- // next 3 bits: if lower is 0x03
- // 0x00 = business fax, or oneoff entryid
- // 0x10 = home fax
- // 0x20 = primary fax
- // 0x30 = no contact data
- // 0x40 = email 1
- // 0x50 = email 2
- // 0x60 = email 3
- // top bit:
- // 0x80 default on, except for oneoff entryids
- // either WAB_GUID or ONE_OFF_MUID
- if (memcmp(ptrEntries->Value.MVbin.lpbin[i].lpb + sizeof(ULONG), (void*)&WAB_GUID, sizeof(GUID)) == 0) {
- // handle wrapped entryids
- ulOffset = sizeof(ULONG) + sizeof(GUID) + sizeof(BYTE);
- cType = ptrEntries->Value.MVbin.lpbin[i].lpb[sizeof(ULONG) + sizeof(GUID)];
- }
- hr = m_lpMAPISup->OpenEntry(ptrEntries->Value.MVbin.lpbin[i].cb - ulOffset, reinterpret_cast<ENTRYID *>(ptrEntries->Value.MVbin.lpbin[i].lpb + ulOffset), nullptr, 0, &ulObjType, &~ptrUser);
- if (hr != hrSuccess)
- continue;
- if ((cType & 0x80) && (cType & 0x0F) < 5 && (cType & 0x0F) > 0) {
- ULONG cbEntryID;
- EntryIdPtr ptrEntryID;
- SPropValuePtr ptrPropEntryID;
- ULONG ulObjOffset = 0;
- ULONG ulObjType = 0;
- hr = HrGetOneProp(ptrUser, PR_ENTRYID, &~ptrPropEntryID);
- if (hr != hrSuccess)
- return hr;
- if ((cType & 0x0F) == 3) {
- ulObjType = MAPI_MAILUSER;
- ulObjOffset = cType >> 4;
- } else
- ulObjType = MAPI_DISTLIST;
- hr = MakeWrappedEntryID(ptrPropEntryID->Value.bin.cb, (LPENTRYID)ptrPropEntryID->Value.bin.lpb, ulObjType, ulObjOffset, &cbEntryID, &~ptrEntryID);
- if (hr != hrSuccess)
- return hr;
- hr = ZCMAPIProp::Create(ptrUser, cbEntryID, ptrEntryID, &~ptrZCMAPIProp);
- if (hr != hrSuccess)
- return hr;
- hr = ptrZCMAPIProp->GetProps(ptrCols, 0, &cValues, &~ptrProps);
- if (FAILED(hr))
- continue;
- } else {
- hr = ptrUser->GetProps(ptrCols, 0, &cValues, &~ptrProps);
- if (FAILED(hr))
- continue;
- }
- ptrProps[0] = sKey;
- hr = lpTable->HrModifyRow(ECKeyTable::TABLE_ROW_ADD, NULL, ptrProps.get(), cValues);
- if (hr != hrSuccess)
- return hr;
- ++sKey.Value.ul;
- }
- AddChild(lpTable);
- hr = lpTable->HrGetView(createLocaleFromName(nullptr), ulFlags, &~lpTableView);
- if(hr != hrSuccess)
- return hr;
- return lpTableView->QueryInterface(IID_IMAPITable,
- reinterpret_cast<void **>(lppTable));
- }
- /**
- * Returns an addressbook contents table of the IPM.Contacts folder in m_lpContactFolder.
- *
- * @param[in] ulFlags MAPI_UNICODE for default unicode columns
- * @param[out] lppTable contents table of all items found in folder
- *
- * @return
- */
- HRESULT ZCABContainer::GetContentsTable(ULONG ulFlags, LPMAPITABLE *lppTable)
- {
- if (m_lpDistList)
- return GetDistListContentsTable(ulFlags, lppTable);
- return GetFolderContentsTable(ulFlags, lppTable);
- }
- /**
- * Can return 3 kinds of tables:
- * 1. Root Container, contains one entry: the provider container
- * 2. Provider Container, contains user folders
- * 3. CONVENIENT_DEPTH: 1 + 2
- *
- * @param[in] ulFlags MAPI_UNICODE | CONVENIENT_DEPTH
- * @param[out] lppTable root container table
- *
- * @return MAPI Error code
- */
- HRESULT ZCABContainer::GetHierarchyTable(ULONG ulFlags, LPMAPITABLE *lppTable)
- {
- HRESULT hr = hrSuccess;
- object_ptr<ECMemTable> lpTable;
- object_ptr<ECMemTableView> lpTableView;
- #define TCOLS 9
- SizedSPropTagArray(TCOLS, sptaCols) = {TCOLS, {PR_ENTRYID, PR_STORE_ENTRYID, PR_DISPLAY_NAME_W, PR_OBJECT_TYPE, PR_CONTAINER_FLAGS, PR_DISPLAY_TYPE, PR_AB_PROVIDER_ID, PR_DEPTH, PR_INSTANCE_KEY}};
- enum {XENTRYID = 0, STORE_ENTRYID, DISPLAY_NAME, OBJECT_TYPE, CONTAINER_FLAGS, DISPLAY_TYPE, AB_PROVIDER_ID, DEPTH, INSTANCE_KEY, ROWID};
- ULONG ulInstance = 0;
- SPropValue sProps[TCOLS + 1];
- convert_context converter;
- if ((ulFlags & MAPI_UNICODE) == 0)
- sptaCols.aulPropTag[DISPLAY_NAME] = PR_DISPLAY_NAME_A;
- hr = ECMemTable::Create(sptaCols, PR_ROWID, &~lpTable);
- if(hr != hrSuccess)
- return hr;
- /*
- 1. root container : m_lpFolders = NULL, m_lpContactFolder = NULL, m_lpDistList = NULL, m_lpProvider = ZCABLogon (one entry: provider)
- 2. provider container : m_lpFolders = data, m_lpContactFolder = NULL, m_lpDistList = NULL, m_lpProvider = ZCABLogon (N entries: folders)
- 3. contact folder : m_lpFolders = NULL, m_lpContactFolder = data, m_lpDistList = NULL, m_lpProvider = ZCABContainer from (2), (no hierarchy entries)
- 4. distlist : m_lpFolders = NULL, m_lpContactFolder = NULL, m_lpDistList = data, m_lpProvider = ZCABContainer from (3), (no hierarchy entries)
- when ulFlags contains CONVENIENT_DEPTH, (1) also contains (2)
- so we open (2) through the provider, which gives the m_lpFolders
- */
- if (m_lpFolders) {
- // create hierarchy with folders from user stores
- for (const auto &folder : *m_lpFolders) {
- std::string strName;
- KCHL::memory_ptr<cabEntryID> lpEntryID;
- ULONG cbEntryID = CbNewCABENTRYID(folder.cbFolder);
- hr = MAPIAllocateBuffer(cbEntryID, &~lpEntryID);
- if (hr != hrSuccess)
- return hr;
- memset(lpEntryID, 0, cbEntryID);
- memcpy(&lpEntryID->muid, &MUIDZCSAB, sizeof(MAPIUID));
- lpEntryID->ulObjType = MAPI_ABCONT;
- lpEntryID->ulOffset = 0;
- memcpy(lpEntryID->origEntryID, folder.lpFolder, folder.cbFolder);
- sProps[XENTRYID].ulPropTag = sptaCols.aulPropTag[XENTRYID];
- sProps[XENTRYID].Value.bin.cb = cbEntryID;
- sProps[XENTRYID].Value.bin.lpb = reinterpret_cast<BYTE *>(lpEntryID.get());
- sProps[STORE_ENTRYID].ulPropTag = CHANGE_PROP_TYPE(sptaCols.aulPropTag[STORE_ENTRYID], PT_ERROR);
- sProps[STORE_ENTRYID].Value.err = MAPI_E_NOT_FOUND;
- sProps[DISPLAY_NAME].ulPropTag = sptaCols.aulPropTag[DISPLAY_NAME];
- if ((ulFlags & MAPI_UNICODE) == 0) {
- sProps[DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME_A;
- strName = converter.convert_to<std::string>(folder.strwDisplayName);
- sProps[DISPLAY_NAME].Value.lpszA = (char*)strName.c_str();
- } else {
- sProps[DISPLAY_NAME].Value.lpszW = const_cast<wchar_t *>(folder.strwDisplayName.c_str());
- }
- sProps[OBJECT_TYPE].ulPropTag = sptaCols.aulPropTag[OBJECT_TYPE];
- sProps[OBJECT_TYPE].Value.ul = MAPI_ABCONT;
- sProps[CONTAINER_FLAGS].ulPropTag = sptaCols.aulPropTag[CONTAINER_FLAGS];
- sProps[CONTAINER_FLAGS].Value.ul = AB_RECIPIENTS | AB_UNMODIFIABLE | AB_UNICODE_OK;
- sProps[DISPLAY_TYPE].ulPropTag = sptaCols.aulPropTag[DISPLAY_TYPE];
- sProps[DISPLAY_TYPE].Value.ul = DT_NOT_SPECIFIC;
- sProps[AB_PROVIDER_ID].ulPropTag = sptaCols.aulPropTag[AB_PROVIDER_ID];
- sProps[AB_PROVIDER_ID].Value.bin.cb = sizeof(GUID);
- sProps[AB_PROVIDER_ID].Value.bin.lpb = (BYTE*)&MUIDZCSAB;
- sProps[DEPTH].ulPropTag = PR_DEPTH;
- sProps[DEPTH].Value.ul = (ulFlags & CONVENIENT_DEPTH) ? 1 : 0;
- sProps[INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
- sProps[INSTANCE_KEY].Value.bin.cb = sizeof(ULONG);
- sProps[INSTANCE_KEY].Value.bin.lpb = (LPBYTE)&ulInstance;
- sProps[ROWID].ulPropTag = PR_ROWID;
- sProps[ROWID].Value.ul = ulInstance;
- hr = lpTable->HrModifyRow(ECKeyTable::TABLE_ROW_ADD, NULL, sProps, TCOLS + 1);
- if (hr != hrSuccess)
- return hr;
- ++ulInstance;
- }
- } else if (!m_lpContactFolder) {
- // only if not using a contacts folder, which should make the contents table. so this would return an empty hierarchy table, which is true.
- // create toplevel hierarchy. one entry: "Kopano Contacts Folders"
- BYTE sEntryID[4 + sizeof(GUID)]; // minimum sized entryid. no extra info needed
- memset(sEntryID, 0, sizeof(sEntryID));
- memcpy(sEntryID + 4, &MUIDZCSAB, sizeof(GUID));
- sProps[XENTRYID].ulPropTag = sptaCols.aulPropTag[XENTRYID];
- sProps[XENTRYID].Value.bin.cb = sizeof(sEntryID);
- sProps[XENTRYID].Value.bin.lpb = sEntryID;
- sProps[STORE_ENTRYID].ulPropTag = CHANGE_PROP_TYPE(sptaCols.aulPropTag[STORE_ENTRYID], PT_ERROR);
- sProps[STORE_ENTRYID].Value.err = MAPI_E_NOT_FOUND;
- sProps[DISPLAY_NAME].ulPropTag = sptaCols.aulPropTag[DISPLAY_NAME];
- if ((ulFlags & MAPI_UNICODE) == 0) {
- sProps[DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME_A;
- sProps[DISPLAY_NAME].Value.lpszA = _A("Kopano Contacts Folders");
- } else {
- sProps[DISPLAY_NAME].Value.lpszW = _W("Kopano Contacts Folders");
- }
- sProps[OBJECT_TYPE].ulPropTag = sptaCols.aulPropTag[OBJECT_TYPE];
- sProps[OBJECT_TYPE].Value.ul = MAPI_ABCONT;
- // AB_SUBCONTAINERS flag causes this folder to be skipped in the IAddrBook::GetSearchPath()
- sProps[CONTAINER_FLAGS].ulPropTag = sptaCols.aulPropTag[CONTAINER_FLAGS];
- sProps[CONTAINER_FLAGS].Value.ul = AB_SUBCONTAINERS | AB_UNMODIFIABLE | AB_UNICODE_OK;
- sProps[DISPLAY_TYPE].ulPropTag = sptaCols.aulPropTag[DISPLAY_TYPE];
- sProps[DISPLAY_TYPE].Value.ul = DT_NOT_SPECIFIC;
- sProps[AB_PROVIDER_ID].ulPropTag = sptaCols.aulPropTag[AB_PROVIDER_ID];
- sProps[AB_PROVIDER_ID].Value.bin.cb = sizeof(GUID);
- sProps[AB_PROVIDER_ID].Value.bin.lpb = (BYTE*)&MUIDZCSAB;
- sProps[DEPTH].ulPropTag = PR_DEPTH;
- sProps[DEPTH].Value.ul = 0;
- sProps[INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
- sProps[INSTANCE_KEY].Value.bin.cb = sizeof(ULONG);
- sProps[INSTANCE_KEY].Value.bin.lpb = (LPBYTE)&ulInstance;
- sProps[ROWID].ulPropTag = PR_ROWID;
- sProps[ROWID].Value.ul = ulInstance++;
- hr = lpTable->HrModifyRow(ECKeyTable::TABLE_ROW_ADD, NULL, sProps, TCOLS + 1);
- if (hr != hrSuccess)
- return hr;
- if (ulFlags & CONVENIENT_DEPTH) {
- ABContainerPtr ptrContainer;
- ULONG ulObjType;
- MAPITablePtr ptrTable;
- SRowSetPtr ptrRows;
- hr = ((ZCABLogon*)m_lpProvider)->OpenEntry(sizeof(sEntryID), reinterpret_cast<ENTRYID *>(sEntryID), nullptr, 0, &ulObjType, &~ptrContainer);
- if (hr != hrSuccess)
- return hr;
- hr = ptrContainer->GetHierarchyTable(ulFlags, &~ptrTable);
- if (hr != hrSuccess)
- return hr;
- hr = ptrTable->QueryRows(-1, 0, &ptrRows);
- if (hr != hrSuccess)
- return hr;
- for (SRowSetPtr::size_type i = 0; i < ptrRows.size(); ++i) {
- // use PR_STORE_ENTRYID field to set instance key, since that is always MAPI_E_NOT_FOUND (see above)
- auto lpProp = PpropFindProp(ptrRows[i].lpProps, ptrRows[i].cValues, CHANGE_PROP_TYPE(PR_STORE_ENTRYID, PT_ERROR));
- if (lpProp == nullptr)
- continue;
- lpProp->ulPropTag = PR_ROWID;
- lpProp->Value.ul = ulInstance++;
- hr = lpTable->HrModifyRow(ECKeyTable::TABLE_ROW_ADD, NULL, ptrRows[i].lpProps, ptrRows[i].cValues);
- if (hr != hrSuccess)
- return hr;
- }
- }
- }
- AddChild(lpTable);
- hr = lpTable->HrGetView(createLocaleFromName(nullptr), ulFlags, &~lpTableView);
- if(hr != hrSuccess)
- return hr;
- return lpTableView->QueryInterface(IID_IMAPITable,
- reinterpret_cast<void **>(lppTable));
- #undef TCOLS
- }
- /**
- * Opens the contact from any given contact folder, and makes a ZCMAPIProp object for that contact.
- *
- * @param[in] cbEntryID wrapped contact entryid bytes
- * @param[in] lpEntryID
- * @param[in] lpInterface requested interface
- * @param[in] ulFlags unicode flags
- * @param[out] lpulObjType returned object type
- * @param[out] lppUnk returned object
- *
- * @return MAPI Error code
- */
- HRESULT ZCABContainer::OpenEntry(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulFlags, ULONG *lpulObjType, LPUNKNOWN *lppUnk)
- {
- HRESULT hr = hrSuccess;
- auto lpCABEntryID = reinterpret_cast<cabEntryID *>(lpEntryID);
- ULONG cbNewCABEntryID = CbNewCABENTRYID(0);
- ULONG cbFolder = 0;
- LPENTRYID lpFolder = NULL;
- ULONG ulObjType = 0;
- MAPIFolderPtr ptrContactFolder;
- object_ptr<ZCABContainer> lpZCABContacts;
- MessagePtr ptrContact;
- object_ptr<ZCMAPIProp> lpZCMAPIProp;
- if (cbEntryID < cbNewCABEntryID ||
- memcmp(&lpCABEntryID->muid, &MUIDZCSAB, sizeof(MAPIUID)) != 0)
- return MAPI_E_UNKNOWN_ENTRYID;
- if (m_lpDistList)
- // there is nothing to open from the distlist point of view
- // @todo, passthrough to IMAPISupport object?
- return MAPI_E_NO_SUPPORT;
- cbFolder = cbEntryID - cbNewCABEntryID;
- lpFolder = (LPENTRYID)((LPBYTE)lpEntryID + cbNewCABEntryID);
- if (lpCABEntryID->ulObjType == MAPI_ABCONT) {
- hr = m_lpMAPISup->OpenEntry(cbFolder, lpFolder, nullptr, 0, &ulObjType, &~ptrContactFolder);
- if (hr == MAPI_E_NOT_FOUND) {
- // the folder is most likely in a store that is not yet available through this MAPI session
- // try opening the store through the support object, and see if we can get it anyway
- MsgStorePtr ptrStore;
- MAPIGetSessionPtr ptrGetSession;
- MAPISessionPtr ptrSession;
- hr = m_lpMAPISup->QueryInterface(IID_IMAPIGetSession, &~ptrGetSession);
- if (hr != hrSuccess)
- return hr;
- hr = ptrGetSession->GetMAPISession(&~ptrSession);
- if (hr != hrSuccess)
- return hr;
- std::vector<zcabFolderEntry>::const_iterator i;
- // find the store of this folder
- for (i = m_lpFolders->cbegin();
- i != m_lpFolders->cend(); ++i) {
- ULONG res;
- if ((m_lpMAPISup->CompareEntryIDs(i->cbFolder, (LPENTRYID)i->lpFolder, cbFolder, lpFolder, 0, &res) == hrSuccess) && res == TRUE)
- break;
- }
- if (i == m_lpFolders->cend())
- return MAPI_E_NOT_FOUND;
- hr = ptrSession->OpenMsgStore(0, i->cbStore, reinterpret_cast<ENTRYID *>(i->lpStore), nullptr, 0, &~ptrStore);
- if (hr != hrSuccess)
- return hr;
- hr = ptrStore->OpenEntry(cbFolder, lpFolder, nullptr, 0, &ulObjType, &~ptrContactFolder);
- }
- if (hr != hrSuccess)
- return hr;
- hr = ZCABContainer::Create(nullptr, ptrContactFolder, m_lpMAPISup, m_lpProvider, &~lpZCABContacts);
- if (hr != hrSuccess)
- return hr;
- AddChild(lpZCABContacts);
- if (lpInterface)
- hr = lpZCABContacts->QueryInterface(*lpInterface, (void**)lppUnk);
- else
- hr = lpZCABContacts->QueryInterface(IID_IABContainer, (void**)lppUnk);
- } else if (lpCABEntryID->ulObjType == MAPI_DISTLIST) {
- // open the Original Message
- hr = m_lpMAPISup->OpenEntry(cbFolder, lpFolder, nullptr, 0, &ulObjType, &~ptrContact);
- if (hr != hrSuccess)
- return hr;
- hr = ZCABContainer::Create(ptrContact, cbEntryID, lpEntryID, m_lpMAPISup, &~lpZCABContacts);
- if (hr != hrSuccess)
- return hr;
- AddChild(lpZCABContacts);
- if (lpInterface)
- hr = lpZCABContacts->QueryInterface(*lpInterface, (void**)lppUnk);
- else
- hr = lpZCABContacts->QueryInterface(IID_IDistList, (void**)lppUnk);
- } else if (lpCABEntryID->ulObjType == MAPI_MAILUSER) {
- // open the Original Message
- hr = m_lpMAPISup->OpenEntry(cbFolder, lpFolder, nullptr, 0, &ulObjType, &~ptrContact);
- if (hr != hrSuccess)
- return hr;
- hr = ZCMAPIProp::Create(ptrContact, cbEntryID, lpEntryID, &~lpZCMAPIProp);
- if (hr != hrSuccess)
- return hr;
- AddChild(lpZCMAPIProp);
- if (lpInterface)
- hr = lpZCMAPIProp->QueryInterface(*lpInterface, (void**)lppUnk);
- else
- hr = lpZCMAPIProp->QueryInterface(IID_IMAPIProp, (void**)lppUnk);
- } else {
- return MAPI_E_UNKNOWN_ENTRYID;
- }
- *lpulObjType = lpCABEntryID->ulObjType;
- return hr;
- }
- HRESULT ZCABContainer::SetSearchCriteria(LPSRestriction lpRestriction, LPENTRYLIST lpContainerList, ULONG ulSearchFlags)
- {
- return MAPI_E_NO_SUPPORT;
- }
- HRESULT ZCABContainer::GetSearchCriteria(ULONG ulFlags, LPSRestriction *lppRestriction, LPENTRYLIST *lppContainerList, ULONG *lpulSearchState)
- {
- return MAPI_E_NO_SUPPORT;
- }
- // IABContainer
- HRESULT ZCABContainer::CreateEntry(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulCreateFlags, LPMAPIPROP* lppMAPIPropEntry)
- {
- return MAPI_E_NO_SUPPORT;
- }
- HRESULT ZCABContainer::CopyEntries(LPENTRYLIST lpEntries, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)
- {
- return MAPI_E_NO_SUPPORT;
- }
- HRESULT ZCABContainer::DeleteEntries(LPENTRYLIST lpEntries, ULONG ulFlags)
- {
- return MAPI_E_NO_SUPPORT;
- }
- /**
- * Resolve MAPI_UNRESOLVED items in lpAdrList and possebly add resolved
- *
- * @param[in] lpPropTagArray properties to be included in lpAdrList
- * @param[in] ulFlags EMS_AB_ADDRESS_LOOKUP | MAPI_UNICODE
- * @param[in,out] lpAdrList
- * @param[in,out] lpFlagList MAPI_AMBIGUOUS | MAPI_RESOLVED | MAPI_UNRESOLVED
- *
- * @return
- */
- HRESULT ZCABContainer::ResolveNames(const SPropTagArray *lpPropTagArray,
- ULONG ulFlags, LPADRLIST lpAdrList, LPFlagList lpFlagList)
- {
- HRESULT hr;
- // only columns we can set from our contents table
- static constexpr const SizedSPropTagArray(7, sptaDefault) =
- {7, {PR_ADDRTYPE_A, PR_DISPLAY_NAME_A, PR_DISPLAY_TYPE,
- PR_EMAIL_ADDRESS_A, PR_ENTRYID, PR_INSTANCE_KEY,
- PR_OBJECT_TYPE}};
- static constexpr const SizedSPropTagArray(7, sptaUnicode) =
- {7, {PR_ADDRTYPE_W, PR_DISPLAY_NAME_W, PR_DISPLAY_TYPE,
- PR_EMAIL_ADDRESS_W, PR_ENTRYID, PR_INSTANCE_KEY,
- PR_OBJECT_TYPE}};
- ULONG i;
- SRowSetPtr ptrRows;
- if (lpPropTagArray == NULL)
- lpPropTagArray = (ulFlags & MAPI_UNICODE) ? sptaUnicode : sptaDefault;
- // in this container table, find given PR_DISPLAY_NAME
- if (m_lpFolders) {
- // return MAPI_E_NO_SUPPORT ? since you should not query on this level
- // @todo search in all folders, loop over self, since we want this providers entry ids
- MAPITablePtr ptrHierarchy;
- if (m_lpFolders->empty())
- return hrSuccess;
- hr = this->GetHierarchyTable(0, &~ptrHierarchy);
- if (hr != hrSuccess)
- return hr;
- hr = ptrHierarchy->QueryRows(m_lpFolders->size(), 0, &ptrRows);
- if (hr != hrSuccess)
- return hr;
- for (i = 0; i < ptrRows.size(); ++i) {
- ABContainerPtr ptrContainer;
- auto lpEntryID = PCpropFindProp(ptrRows[i].lpProps, ptrRows[i].cValues, PR_ENTRYID);
- ULONG ulObjType;
- if (!lpEntryID)
- continue;
- // this? provider?
- hr = this->OpenEntry(lpEntryID->Value.bin.cb, reinterpret_cast<ENTRYID *>(lpEntryID->Value.bin.lpb), nullptr, 0, &ulObjType, &~ptrContainer);
- if (hr != hrSuccess)
- return hr;
- hr = ptrContainer->ResolveNames(lpPropTagArray, ulFlags, lpAdrList, lpFlagList);
- if (hr != hrSuccess)
- return hr;
- }
- } else if (m_lpContactFolder) {
- // only search within this folder and set entries in lpAdrList / lpFlagList
- MAPITablePtr ptrContents;
- std::set<ULONG> stProps;
- SPropTagArrayPtr ptrColumns;
- // make joint proptags
- std::copy(lpPropTagArray->aulPropTag, lpPropTagArray->aulPropTag + lpPropTagArray->cValues, std::inserter(stProps, stProps.begin()));
- for (i = 0; i < lpAdrList->aEntries[0].cValues; ++i)
- stProps.insert(lpAdrList->aEntries[0].rgPropVals[i].ulPropTag);
- hr = MAPIAllocateBuffer(CbNewSPropTagArray(stProps.size()), &~ptrColumns);
- if (hr != hrSuccess)
- return hr;
- ptrColumns->cValues = stProps.size();
- std::copy(stProps.begin(), stProps.end(), ptrColumns->aulPropTag);
- hr = this->GetContentsTable(ulFlags & MAPI_UNICODE, &~ptrContents);
- if (hr != hrSuccess)
- return hr;
- hr = ptrContents->SetColumns(ptrColumns, 0);
- if (hr != hrSuccess)
- return hr;
- for (i = 0; i < lpAdrList->cEntries; ++i) {
- auto lpDisplayNameA = PCpropFindProp(lpAdrList->aEntries[i].rgPropVals, lpAdrList->aEntries[i].cValues, PR_DISPLAY_NAME_A);
- auto lpDisplayNameW = PCpropFindProp(lpAdrList->aEntries[i].rgPropVals, lpAdrList->aEntries[i].cValues, PR_DISPLAY_NAME_W);
- if (!lpDisplayNameA && !lpDisplayNameW)
- continue;
- ULONG ulResFlag = (ulFlags & EMS_AB_ADDRESS_LOOKUP) ? FL_FULLSTRING : FL_PREFIX | FL_IGNORECASE;
- ULONG ulStringType = lpDisplayNameW ? PT_UNICODE : PT_STRING8;
- SPropValue sProp = lpDisplayNameW ? *lpDisplayNameW : *lpDisplayNameA;
- ECOrRestriction resFind;
- static const ULONG ulSearchTags[] = {PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_ORIGINAL_DISPLAY_NAME};
- for (size_t j = 0; j < ARRAY_SIZE(ulSearchTags); ++j) {
- sProp.ulPropTag = CHANGE_PROP_TYPE(ulSearchTags[j], ulStringType);
- resFind += ECContentRestriction(ulResFlag, CHANGE_PROP_TYPE(ulSearchTags[j], ulStringType), &sProp, ECRestriction::Cheap);
- }
- hr = resFind.RestrictTable(ptrContents, 0);
- if (hr != hrSuccess)
- return hr;
- hr = ptrContents->QueryRows(-1, MAPI_UNICODE, &ptrRows);
- if (hr != hrSuccess)
- return hr;
- if (ptrRows.size() == 1) {
- lpFlagList->ulFlag[i] = MAPI_RESOLVED;
- // release old row
- MAPIFreeBuffer(lpAdrList->aEntries[i].rgPropVals);
- lpAdrList->aEntries[i].rgPropVals = NULL;
- hr = Util::HrCopySRow((LPSRow)&lpAdrList->aEntries[i], &ptrRows[0], NULL);
- if (hr != hrSuccess)
- return hr;
- } else if (ptrRows.size() > 1) {
- lpFlagList->ulFlag[i] = MAPI_AMBIGUOUS;
- }
- }
- } else {
- // not supported within MAPI_DISTLIST container
- return MAPI_E_NO_SUPPORT;
- }
- return hrSuccess;
- }
- // IMAPIProp for m_lpDistList
- HRESULT ZCABContainer::GetProps(const SPropTagArray *lpPropTagArray,
- ULONG ulFlags, ULONG *lpcValues, SPropValue **lppPropArray)
- {
- if (m_lpDistList != NULL)
- return m_lpDistList->GetProps(lpPropTagArray, ulFlags, lpcValues, lppPropArray);
- return MAPI_E_NO_SUPPORT;
- }
- HRESULT ZCABContainer::GetPropList(ULONG ulFlags, LPSPropTagArray *lppPropTagArray)
- {
- if (m_lpDistList != NULL)
- return m_lpDistList->GetPropList(ulFlags, lppPropTagArray);
- return MAPI_E_NO_SUPPORT;
- }
- // Interface IUnknown
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, QueryInterface, (REFIID, refiid), (void**, lppInterface))
- DEF_ULONGMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, AddRef, (void))
- DEF_ULONGMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, Release, (void))
- // Interface IABContainer
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, CreateEntry, (ULONG, cbEntryID), (LPENTRYID, lpEntryID), (ULONG, ulCreateFlags), (LPMAPIPROP*, lppMAPIPropEntry))
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, CopyEntries, (LPENTRYLIST, lpEntries), (ULONG, ulUIParam), (LPMAPIPROGRESS, lpProgress), (ULONG, ulFlags))
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, DeleteEntries, (LPENTRYLIST, lpEntries), (ULONG, ulFlags))
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, ResolveNames, (const SPropTagArray *, lpPropTagArray), (ULONG, ulFlags), (LPADRLIST, lpAdrList), (LPFlagList, lpFlagList))
- // Interface IMAPIContainer
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, GetContentsTable, (ULONG, ulFlags), (LPMAPITABLE *, lppTable))
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, GetHierarchyTable, (ULONG, ulFlags), (LPMAPITABLE *, lppTable))
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, OpenEntry, (ULONG, cbEntryID), (LPENTRYID, lpEntryID), (LPCIID, lpInterface), (ULONG, ulFlags), (ULONG *, lpulObjType), (LPUNKNOWN *, lppUnk))
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, SetSearchCriteria, (LPSRestriction, lpRestriction), (LPENTRYLIST, lpContainerList), (ULONG, ulSearchFlags))
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, GetSearchCriteria, (ULONG, ulFlags), (LPSRestriction *, lppRestriction), (LPENTRYLIST *, lppContainerList), (ULONG *, lpulSearchState))
- // Interface IMAPIProp
- DEF_HRMETHOD_NOSUPPORT(TRACE_MAPI, ZCABContainer, ABContainer, GetLastError, (HRESULT, hError), (ULONG, ulFlags), (LPMAPIERROR *, lppMapiError))
- DEF_HRMETHOD_NOSUPPORT(TRACE_MAPI, ZCABContainer, ABContainer, SaveChanges, (ULONG, ulFlags))
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, GetProps, (const SPropTagArray *, lpPropTagArray), (ULONG, ulFlags), (ULONG *, lpcValues), (SPropValue **, lppPropArray))
- DEF_HRMETHOD1(TRACE_MAPI, ZCABContainer, ABContainer, GetPropList, (ULONG, ulFlags), (LPSPropTagArray *, lppPropTagArray))
- DEF_HRMETHOD_NOSUPPORT(TRACE_MAPI, ZCABContainer, ABContainer, OpenProperty, (ULONG, ulPropTag), (LPCIID, lpiid), (ULONG, ulInterfaceOptions), (ULONG, ulFlags), (LPUNKNOWN *, lppUnk))
- DEF_HRMETHOD_NOSUPPORT(TRACE_MAPI, ZCABContainer, ABContainer, SetProps, (ULONG, cValues), (const SPropValue *, lpPropArray), (SPropProblemArray **, lppProblems))
- DEF_HRMETHOD_NOSUPPORT(TRACE_MAPI, ZCABContainer, ABContainer, DeleteProps, (const SPropTagArray *, lpPropTagArray), (SPropProblemArray **, lppProblems))
- DEF_HRMETHOD_NOSUPPORT(TRACE_MAPI, ZCABContainer, ABContainer, CopyTo, (ULONG, ciidExclude), (LPCIID, rgiidExclude), (const SPropTagArray *, lpExcludeProps), (ULONG, ulUIParam), (LPMAPIPROGRESS, lpProgress), (LPCIID, lpInterface), (void *, lpDestObj), (ULONG, ulFlags), (SPropProblemArray **, lppProblems))
- DEF_HRMETHOD_NOSUPPORT(TRACE_MAPI, ZCABContainer, ABContainer, CopyProps, (const SPropTagArray *, lpIncludeProps), (ULONG, ulUIParam), (LPMAPIPROGRESS, lpProgress), (LPCIID, lpInterface), (void *, lpDestObj), (ULONG, ulFlags), (SPropProblemArray **, lppProblems))
- DEF_HRMETHOD_NOSUPPORT(TRACE_MAPI, ZCABContainer, ABContainer, GetNamesFromIDs, (LPSPropTagArray *, pptaga), (LPGUID, lpguid), (ULONG, ulFlags), (ULONG *, pcNames), (LPMAPINAMEID **, pppNames))
- DEF_HRMETHOD_NOSUPPORT(TRACE_MAPI, ZCABContainer, ABContainer, GetIDsFromNames, (ULONG, cNames), (LPMAPINAMEID *, ppNames), (ULONG, ulFlags), (LPSPropTagArray *, pptaga))
|