123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903 |
- /*
- * 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 <kopano/ECInterfaceDefs.h>
- #include <kopano/memory.hpp>
- #include <mapidefs.h>
- #include <mapicode.h>
- #include <mapitags.h>
- #include <mapiguid.h>
- #include <mapiutil.h>
- #include "kcore.hpp"
- #include <kopano/ECGuid.h>
- #include <kopano/ECDefs.h>
- #include "ECMsgStore.h"
- #include "ECMAPIProp.h"
- #include "ECMemStream.h"
- #include "Mem.h"
- #include <kopano/Util.h>
- #include <kopano/ECDebug.h>
- #include <kopano/mapiext.h>
- #include <kopano/CommonUtil.h>
- #include <kopano/mapi_ptr.h>
- #include "pcutil.hpp"
- #include <sstream>
- using namespace KCHL;
- struct STREAMDATA {
- ULONG ulPropTag;
- ECMAPIProp *lpProp;
- };
- static struct rights ECPermToRightsCheap(const ECPERMISSION &p)
- {
- struct rights r = {0, p.ulType, p.ulRights, p.ulState};
- r.sUserId.__size = p.sUserId.cb;
- r.sUserId.__ptr = p.sUserId.lpb;
- return r;
- }
- static ECPERMISSION RightsToECPermCheap(const struct rights r)
- {
- ECPERMISSION p = {r.ulType, r.ulRights, RIGHT_NEW}; // Force to new
- p.sUserId.cb = r.sUserId.__size;
- p.sUserId.lpb = r.sUserId.__ptr;
- return p;
- }
- class FindUser {
- public:
- FindUser(const ECENTRYID &sEntryID): m_sEntryID(sEntryID) {}
- bool operator()(const ECPERMISSION &sPermission) const {
- return CompareABEID(m_sEntryID.cb, (LPENTRYID)m_sEntryID.lpb, sPermission.sUserId.cb, (LPENTRYID)sPermission.sUserId.lpb);
- }
- private:
- const ECENTRYID &m_sEntryID;
- };
- ECMAPIProp::ECMAPIProp(void *lpProvider, ULONG ulObjType, BOOL fModify,
- ECMAPIProp *lpRoot, const char *szClassName) :
- ECGenericProp(lpProvider, ulObjType, fModify, szClassName)
- {
- TRACE_MAPI(TRACE_ENTRY, "ECMAPIProp::ECMAPIProp","");
-
- this->HrAddPropHandlers(PR_STORE_ENTRYID, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
- this->HrAddPropHandlers(PR_STORE_RECORD_KEY, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
- this->HrAddPropHandlers(PR_STORE_SUPPORT_MASK, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
- this->HrAddPropHandlers(PR_STORE_UNICODE_MASK, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
- this->HrAddPropHandlers(PR_MAPPING_SIGNATURE, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
- this->HrAddPropHandlers(PR_PARENT_ENTRYID, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
- this->HrAddPropHandlers(PR_MDB_PROVIDER, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
- this->HrAddPropHandlers(PR_LAST_MODIFICATION_TIME, DefaultMAPIGetProp, DefaultSetPropSetReal, (void*) this);
- this->HrAddPropHandlers(PR_CREATION_TIME, DefaultMAPIGetProp, DefaultSetPropIgnore, (void*) this);
- this->HrAddPropHandlers(PR_ACCESS_LEVEL, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
- this->HrAddPropHandlers(PR_PARENT_SOURCE_KEY, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
- this->HrAddPropHandlers(PR_RECORD_KEY, DefaultGetPropGetReal, DefaultSetPropComputed, (void*) this);
- this->HrAddPropHandlers(PR_EC_SERVER_UID, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
- this->HrAddPropHandlers(PR_EC_HIERARCHYID, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this, FALSE, TRUE);
- // ICS system
- this->HrAddPropHandlers(PR_SOURCE_KEY, DefaultMAPIGetProp ,SetPropHandler, (void*) this, FALSE, FALSE);
- // Used for loadsim
- this->HrAddPropHandlers(0x664B0014/*PR_REPLICA_VERSION*/, DefaultMAPIGetProp ,DefaultSetPropIgnore, (void*) this, FALSE, FALSE);
- // Track 'root object'. This is the object that was opened via OpenEntry or OpenMsgStore, so normally
- // lpRoot == this, but in the case of attachments and submessages it points to the top-level message
- if(lpRoot)
- m_lpRoot = lpRoot;
- else
- m_lpRoot = this;
- }
- ECMAPIProp::~ECMAPIProp()
- {
- TRACE_MAPI(TRACE_ENTRY, "ECMAPIProp::~ECMAPIProp","");
- MAPIFreeBuffer(m_lpParentID);
- }
- HRESULT ECMAPIProp::QueryInterface(REFIID refiid, void **lppInterface)
- {
- REGISTER_INTERFACE2(ECMAPIProp, this);
- REGISTER_INTERFACE2(ECUnknown, this);
- REGISTER_INTERFACE2(IMAPIProp, &this->m_xMAPIProp);
- REGISTER_INTERFACE2(IUnknown, &this->m_xMAPIProp);
- REGISTER_INTERFACE2(IECSecurity, &this->m_xECSecurity);
- return MAPI_E_INTERFACE_NOT_SUPPORTED;
- }
- ECMsgStore* ECMAPIProp::GetMsgStore()
- {
- return (ECMsgStore*)lpProvider;
- }
- // Loads the properties of the saved message for use
- HRESULT ECMAPIProp::HrLoadProps()
- {
- return dwLastError = ECGenericProp::HrLoadProps();
- }
- HRESULT ECMAPIProp::SetICSObject(BOOL bICSObject)
- {
- m_bICSObject = bICSObject;
- return hrSuccess;
- }
- BOOL ECMAPIProp::IsICSObject()
- {
- return m_bICSObject;
- }
- // Property handles
- HRESULT ECMAPIProp::DefaultMAPIGetProp(ULONG ulPropTag, void* lpProvider, ULONG ulFlags, LPSPropValue lpsPropValue, void *lpParam, void *lpBase)
- {
- HRESULT hr = hrSuccess;
- auto lpMsgStore = static_cast<ECMsgStore *>(lpProvider);
- auto lpProp = static_cast<ECMAPIProp *>(lpParam);
- switch(PROP_ID(ulPropTag)) {
- case PROP_ID(PR_SOURCE_KEY):
- hr = lpProp->HrGetRealProp(PR_SOURCE_KEY, ulFlags, lpBase, lpsPropValue);
- if(hr != hrSuccess)
- return hr;
- break;
-
- case PROP_ID(0x664B0014):
- // Used for loadsim
- lpsPropValue->ulPropTag = 0x664B0014;//PR_REPLICA_VERSION;
- lpsPropValue->Value.li.QuadPart = 1688871835664386LL;
- break;
-
- case PROP_ID(PR_MAPPING_SIGNATURE):
- // get the mapping signature from the store
- if (lpMsgStore == NULL || lpMsgStore->HrGetRealProp(PR_MAPPING_SIGNATURE, ulFlags, lpBase, lpsPropValue) != hrSuccess)
- hr = MAPI_E_NOT_FOUND;
- break;
- case PROP_ID(PR_STORE_RECORD_KEY):
- lpsPropValue->ulPropTag = PR_STORE_RECORD_KEY;
- lpsPropValue->Value.bin.cb = sizeof(MAPIUID);
- hr = ECAllocateMore(sizeof(MAPIUID), lpBase, reinterpret_cast<void **>(&lpsPropValue->Value.bin.lpb));
- if (hr != hrSuccess)
- break;
- memcpy(lpsPropValue->Value.bin.lpb, &lpProp->GetMsgStore()->GetStoreGuid(), sizeof(MAPIUID));
- break;
- case PROP_ID(PR_STORE_SUPPORT_MASK):
- case PROP_ID(PR_STORE_UNICODE_MASK):
- if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_PUBLIC_GUID))
- lpsPropValue->Value.l = EC_SUPPORTMASK_PUBLIC;
- else if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_DELEGATE_GUID))
- lpsPropValue->Value.l = EC_SUPPORTMASK_DELEGATE;
- else if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_ARCHIVE_GUID))
- lpsPropValue->Value.l = EC_SUPPORTMASK_ARCHIVE;
- else
- lpsPropValue->Value.l = EC_SUPPORTMASK_PRIVATE;
- if(lpMsgStore->m_ulClientVersion == CLIENT_VERSION_OLK2000)
- lpsPropValue->Value.l &=~STORE_HTML_OK; // Remove the flag, other way outlook 2000 crashed
- // No real unicode support in outlook 2000 and xp
- if (lpMsgStore->m_ulClientVersion <= CLIENT_VERSION_OLK2002)
- lpsPropValue->Value.l &=~ STORE_UNICODE_OK;
- lpsPropValue->ulPropTag = CHANGE_PROP_TYPE(ulPropTag,PT_LONG);
- break;
- case PROP_ID(PR_STORE_ENTRYID): {
- lpsPropValue->ulPropTag = PR_STORE_ENTRYID;
- ULONG cbWrapped = 0;
- memory_ptr<ENTRYID> lpWrapped;
- hr = lpProp->GetMsgStore()->GetWrappedStoreEntryID(&cbWrapped, &~lpWrapped);
- if(hr == hrSuccess) {
- hr = ECAllocateMore(cbWrapped, lpBase, reinterpret_cast<void **>(&lpsPropValue->Value.bin.lpb));
- if (hr != hrSuccess)
- break;
- memcpy(lpsPropValue->Value.bin.lpb, lpWrapped, cbWrapped);
- lpsPropValue->Value.bin.cb = cbWrapped;
- }
- break;
- }
- case PROP_ID(PR_MDB_PROVIDER):
- hr = ECAllocateMore(sizeof(MAPIUID),lpBase, reinterpret_cast<void **>(&lpsPropValue->Value.bin.lpb));
- if (hr != hrSuccess)
- break;
- memcpy(lpsPropValue->Value.bin.lpb, &lpMsgStore->m_guidMDB_Provider, sizeof(MAPIUID));
- lpsPropValue->Value.bin.cb = sizeof(MAPIUID);
- lpsPropValue->ulPropTag = PR_MDB_PROVIDER;
- break;
- case PROP_ID(PR_ACCESS_LEVEL):
- if(lpProp->HrGetRealProp(PR_ACCESS_LEVEL, ulFlags, lpBase, lpsPropValue) != erSuccess)
- {
- lpsPropValue->Value.l = lpProp->fModify ? MAPI_MODIFY : 0;
- //lpsPropValue->Value.l = 0;
- lpsPropValue->ulPropTag = PR_ACCESS_LEVEL;
- }
- break;
- case PROP_ID(PR_PARENT_ENTRYID):
- lpsPropValue->ulPropTag = PR_PARENT_ENTRYID;
- if (lpProp->m_lpParentID != NULL) {
- hr = ECAllocateMore(lpProp->m_cbParentID, lpBase, reinterpret_cast<void **>(&lpsPropValue->Value.bin.lpb));
- if (hr != hrSuccess)
- break;
- memcpy(lpsPropValue->Value.bin.lpb, lpProp->m_lpParentID, lpProp->m_cbParentID);
- lpsPropValue->Value.bin.cb = lpProp->m_cbParentID;
- } else {
- hr = lpProp->HrGetRealProp(PR_PARENT_ENTRYID, ulFlags, lpBase, lpsPropValue);
- }
- break;
- case PROP_ID(PR_EC_SERVER_UID): {
- lpsPropValue->ulPropTag = PR_EC_SERVER_UID;
- GUID sServerGuid = {0};
- hr = ((ECMAPIProp*)lpParam)->m_lpRoot->GetMsgStore()->lpTransport->GetServerGUID(&sServerGuid);
- if (hr == hrSuccess)
- hr = ECAllocateMore(sizeof(GUID), lpBase, (LPVOID*)&lpsPropValue->Value.bin.lpb);
- if (hr == hrSuccess) {
- memcpy(lpsPropValue->Value.bin.lpb, &sServerGuid, sizeof(GUID));
- lpsPropValue->Value.bin.cb = sizeof(GUID);
- }
- break;
- }
- case PROP_ID(PR_EC_HIERARCHYID):
- if (lpProp->m_sMapiObject == NULL) {
- hr = lpProp->HrLoadProps();
- if (hr != hrSuccess)
- return hr;
- }
- if (lpProp->m_sMapiObject->ulObjId > 0) {
- lpsPropValue->ulPropTag = ulPropTag;
- lpsPropValue->Value.ul = lpProp->m_sMapiObject->ulObjId;
- } else {
- hr = MAPI_E_NOT_FOUND;
- }
- break;
- default:
- hr = lpProp->HrGetRealProp(ulPropTag, ulFlags, lpBase, lpsPropValue);
- break;
- }
- return hr;
- }
- HRESULT ECMAPIProp::SetPropHandler(ULONG ulPropTag, void *lpProvider,
- const SPropValue *lpsPropValue, void *lpParam)
- {
- HRESULT hr = hrSuccess;
- auto lpProp = static_cast<ECMAPIProp *>(lpParam);
- switch(ulPropTag) {
- case PR_SOURCE_KEY:
- if (lpProp->IsICSObject())
- hr = lpProp->HrSetRealProp(lpsPropValue);
- else
- hr = hrSuccess; // ignore the property
- break;
- default:
- hr = MAPI_E_NOT_FOUND;
- break;
- }
- return hr;
- }
- HRESULT ECMAPIProp::TableRowGetProp(void* lpProvider, struct propVal *lpsPropValSrc, LPSPropValue lpsPropValDst, void **lpBase, ULONG ulType)
- {
- HRESULT hr = hrSuccess;
- auto lpMsgStore = static_cast<ECMsgStore *>(lpProvider);
- switch(lpsPropValSrc->ulPropTag) {
- case PR_STORE_ENTRYID:
- {
- ULONG cbWrapped = 0;
- memory_ptr<ENTRYID> lpWrapped;
- // if we know, we are a spooler or a store than we can switch the function for 'speed-up'
- // hr = lpMsgStore->GetWrappedStoreEntryID(&cbWrapped, &lpWrapped);
- hr = lpMsgStore->GetWrappedServerStoreEntryID(lpsPropValSrc->Value.bin->__size, lpsPropValSrc->Value.bin->__ptr, &cbWrapped, &~lpWrapped);
- if (hr != hrSuccess)
- return hr;
- hr = ECAllocateMore(cbWrapped, lpBase, reinterpret_cast<void **>(&lpsPropValDst->Value.bin.lpb));
- if (hr != hrSuccess)
- return hr;
- memcpy(lpsPropValDst->Value.bin.lpb, lpWrapped, cbWrapped);
- lpsPropValDst->Value.bin.cb = cbWrapped;
- lpsPropValDst->ulPropTag = PROP_TAG(PT_BINARY,PROP_ID(lpsPropValSrc->ulPropTag));
- break;
- }
- case PROP_TAG(PT_ERROR,PROP_ID(PR_DISPLAY_TYPE)):
- lpsPropValDst->Value.l = DT_FOLDER; // FIXME, may be a search folder
- lpsPropValDst->ulPropTag = PR_DISPLAY_TYPE;
- break;
- case PROP_TAG(PT_ERROR,PROP_ID(PR_STORE_SUPPORT_MASK)):
- case PROP_TAG(PT_ERROR,PROP_ID(PR_STORE_UNICODE_MASK)):
- if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_PUBLIC_GUID))
- lpsPropValDst->Value.l = EC_SUPPORTMASK_PUBLIC;
- else if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_DELEGATE_GUID))
- lpsPropValDst->Value.l = EC_SUPPORTMASK_DELEGATE;
- else if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_ARCHIVE_GUID))
- lpsPropValDst->Value.l = EC_SUPPORTMASK_ARCHIVE;
- else
- lpsPropValDst->Value.l = EC_SUPPORTMASK_PRIVATE;
- if (lpMsgStore->m_ulClientVersion == CLIENT_VERSION_OLK2000)
- lpsPropValDst->Value.l &=~STORE_HTML_OK; // Remove the flag, other way outlook 2000 crashed
- // No real unicode support in outlook 2000 and xp
- if (lpMsgStore->m_ulClientVersion <= CLIENT_VERSION_OLK2002)
- lpsPropValDst->Value.l &=~ STORE_UNICODE_OK;
- lpsPropValDst->ulPropTag = CHANGE_PROP_TYPE(lpsPropValSrc->ulPropTag, PT_LONG);
- break;
- case PROP_TAG(PT_ERROR,PROP_ID(PR_STORE_RECORD_KEY)):
- // Reset type to binary
- lpsPropValDst->ulPropTag = PROP_TAG(PT_BINARY,PROP_ID(lpsPropValSrc->ulPropTag));
- hr = ECAllocateMore(sizeof(MAPIUID), lpBase, reinterpret_cast<void **>(&lpsPropValDst->Value.bin.lpb));
- if (hr != hrSuccess)
- break;
- memcpy(lpsPropValDst->Value.bin.lpb, &lpMsgStore->GetStoreGuid(), sizeof(MAPIUID));
- lpsPropValDst->Value.bin.cb = sizeof(MAPIUID);
- break;
- case PROP_TAG(PT_ERROR,PROP_ID(PR_MDB_PROVIDER)):
- lpsPropValDst->ulPropTag = PROP_TAG(PT_BINARY,PROP_ID(lpsPropValSrc->ulPropTag));
- hr = ECAllocateMore(sizeof(MAPIUID), lpBase, reinterpret_cast<void **>(&lpsPropValDst->Value.bin.lpb));
- if (hr != hrSuccess)
- break;
- memcpy(lpsPropValDst->Value.bin.lpb, &lpMsgStore->m_guidMDB_Provider, sizeof(MAPIUID));
- lpsPropValDst->Value.bin.cb = sizeof(MAPIUID);
- break;
- default:
- return MAPI_E_NOT_FOUND;
- }
- return hr;
- }
- // FIXME openproperty on computed value is illegal
- HRESULT ECMAPIProp::OpenProperty(ULONG ulPropTag, LPCIID lpiid, ULONG ulInterfaceOptions, ULONG ulFlags, LPUNKNOWN *lppUnk)
- {
- HRESULT hr = hrSuccess;
- ECMemStream *lpStream = NULL;
- ecmem_ptr<SPropValue> lpsPropValue;
- STREAMDATA *lpStreamData = NULL;
- if((ulFlags&MAPI_CREATE && !(ulFlags&MAPI_MODIFY)) || lpiid == NULL)
- return MAPI_E_INVALID_PARAMETER;
-
- // Only support certain property types
- if (PROP_TYPE(ulPropTag) != PT_BINARY &&
- PROP_TYPE(ulPropTag) != PT_UNICODE &&
- PROP_TYPE(ulPropTag) != PT_STRING8)
- return MAPI_E_INVALID_PARAMETER;
- if (*lpiid != IID_IStream && *lpiid != IID_IStorage)
- return MAPI_E_INTERFACE_NOT_SUPPORTED;
- if (PROP_TYPE(ulPropTag) != PT_STRING8 &&
- PROP_TYPE(ulPropTag) != PT_BINARY &&
- PROP_TYPE(ulPropTag) != PT_UNICODE)
- return MAPI_E_NOT_FOUND;
- if (*lpiid == IID_IStream && this->lstProps == NULL &&
- PROP_TYPE(ulPropTag) == PT_BINARY && !(ulFlags & MAPI_MODIFY) &&
- // Shortcut: don't load entire object if only one property is being requested for read-only. HrLoadProp() will return
- // without querying the server if the server does not support this capability (introduced in 6.20.8). Main reason is
- // calendar loading time with large recursive entries in outlook XP.
- // If HrLoadProp failed, just fallback to the 'normal' way of loading properties.
- this->lpStorage->HrLoadProp(0, ulPropTag, &~lpsPropValue) == erSuccess) {
- lpStreamData = new STREAMDATA; // is freed by HrStreamCleanup, called by ECMemStream on refcount == 0
- lpStreamData->ulPropTag = ulPropTag;
- lpStreamData->lpProp = this;
- hr = ECMemStream::Create((char*)lpsPropValue->Value.bin.lpb, lpsPropValue->Value.bin.cb, ulInterfaceOptions,
- NULL, ECMAPIProp::HrStreamCleanup, (void *)lpStreamData, &lpStream);
- if (hr != hrSuccess)
- return hr;
- lpStream->QueryInterface(IID_IStream, (void **)lppUnk);
- AddChild(lpStream);
- lpStream->Release();
- return hr;
- }
- if (ulFlags & MAPI_MODIFY)
- ulInterfaceOptions |= STGM_WRITE;
- // IStream requested for a property
- hr = ECAllocateBuffer(sizeof(SPropValue), &~lpsPropValue);
- if (hr != hrSuccess)
- return hr;
- // Yank the property in from disk if it wasn't loaded yet
- HrLoadProp(ulPropTag);
- // For MAPI_CREATE, reset (or create) the property now
- if (ulFlags & MAPI_CREATE) {
- if (!this->fModify)
- return MAPI_E_NO_ACCESS;
- SPropValue sProp;
- sProp.ulPropTag = ulPropTag;
- if (PROP_TYPE(ulPropTag) == PT_BINARY) {
- sProp.Value.bin.cb = 0;
- sProp.Value.bin.lpb = NULL;
- } else {
- // Handles lpszA and lpszW since they are the same field in the union
- sProp.Value.lpszW = const_cast<wchar_t *>(L"");
- }
- hr = HrSetRealProp(&sProp);
- if (hr != hrSuccess)
- return hr;
- }
- hr = HrGetRealProp(ulPropTag, ulFlags, lpsPropValue, lpsPropValue);
- if (hr != hrSuccess)
- // Promote warnings from GetProps to error
- return MAPI_E_NOT_FOUND;
- lpStreamData = new STREAMDATA; // is freed by HrStreamCleanup, called by ECMemStream on refcount == 0
- lpStreamData->ulPropTag = ulPropTag;
- lpStreamData->lpProp = this;
- if (ulFlags & MAPI_CREATE) {
- hr = ECMemStream::Create(NULL, 0, ulInterfaceOptions,
- ECMAPIProp::HrStreamCommit, ECMAPIProp::HrStreamCleanup, (void *)lpStreamData, &lpStream);
- } else {
- switch (PROP_TYPE(lpsPropValue->ulPropTag)) {
- case PT_STRING8:
- hr = ECMemStream::Create(lpsPropValue->Value.lpszA, strlen(lpsPropValue->Value.lpszA), ulInterfaceOptions,
- ECMAPIProp::HrStreamCommit, ECMAPIProp::HrStreamCleanup, (void *)lpStreamData, &lpStream);
- break;
- case PT_UNICODE:
- hr = ECMemStream::Create((char*)lpsPropValue->Value.lpszW, wcslen(lpsPropValue->Value.lpszW)*sizeof(WCHAR), ulInterfaceOptions,
- ECMAPIProp::HrStreamCommit, ECMAPIProp::HrStreamCleanup, (void *)lpStreamData, &lpStream);
- break;
- case PT_BINARY:
- hr = ECMemStream::Create((char *)lpsPropValue->Value.bin.lpb, lpsPropValue->Value.bin.cb, ulInterfaceOptions,
- ECMAPIProp::HrStreamCommit, ECMAPIProp::HrStreamCleanup, (void *)lpStreamData, &lpStream);
- break;
- default:
- assert(false);
- hr = MAPI_E_NOT_FOUND;
- delete lpStreamData;
- break;
- }
- }
- if (hr != hrSuccess)
- return hr;
- if (*lpiid == IID_IStorage) { //*lpiid == IID_IStreamDocfile ||
- //FIXME: Unknown what to do with flag STGSTRM_CURRENT
- hr = GetMsgStore()->lpSupport->IStorageFromStream((LPUNKNOWN)&lpStream->m_xStream, NULL, ((ulFlags &MAPI_MODIFY)?STGSTRM_MODIFY : 0) | ((ulFlags & MAPI_CREATE)?STGSTRM_CREATE:0), (LPSTORAGE*)lppUnk);
- if (hr != hrSuccess)
- return hr;
- } else
- hr = lpStream->QueryInterface(*lpiid, (void **)lppUnk);
- // Release our copy
- lpStream->Release();
- if(hr != hrSuccess)
- return hr;
- AddChild(lpStream);
- return hrSuccess;
- }
- HRESULT ECMAPIProp::SaveChanges(ULONG ulFlags)
- {
- HRESULT hr = hrSuccess;
- object_ptr<WSMAPIPropStorage> lpMAPIPropStorage;
-
- if (lpStorage == nullptr)
- return MAPI_E_NOT_FOUND;
- if (!fModify)
- return MAPI_E_NO_ACCESS;
- // only folders and main messages have a syncid, attachments and msg-in-msg don't
- if (lpStorage->QueryInterface(IID_WSMAPIPropStorage, &~lpMAPIPropStorage) == hrSuccess) {
- hr = lpMAPIPropStorage->HrSetSyncId(m_ulSyncId);
- if(hr != hrSuccess)
- return hr;
- }
- return ECGenericProp::SaveChanges(ulFlags);
- }
- HRESULT ECMAPIProp::HrSaveChild(ULONG ulFlags, MAPIOBJECT *lpsMapiObject) {
- // ECMessage implements saving an attachment
- // ECAttach implements saving a sub-message
- return MAPI_E_INVALID_OBJECT;
- }
- HRESULT ECMAPIProp::GetSerializedACLData(LPVOID lpBase, LPSPropValue lpsPropValue)
- {
- HRESULT hr = hrSuccess;
- ECSecurityPtr ptrSecurity;
- ULONG cPerms = 0;
- ECPermissionPtr ptrPerms;
- struct soap soap;
- std::ostringstream os;
- struct rightsArray rights;
- std::string strAclData;
- hr = QueryInterface(IID_IECSecurity, &~ptrSecurity);
- if (hr != hrSuccess)
- goto exit;
- hr = ptrSecurity->GetPermissionRules(ACCESS_TYPE_GRANT, &cPerms, &~ptrPerms);
- if (hr != hrSuccess)
- goto exit;
- rights.__size = cPerms;
- rights.__ptr = s_alloc<struct rights>(&soap, cPerms);
- std::transform(ptrPerms.get(), ptrPerms + cPerms, rights.__ptr, &ECPermToRightsCheap);
- soap_set_omode(&soap, SOAP_C_UTFSTRING);
- soap_begin(&soap);
- soap.os = &os;
- soap_serialize_rightsArray(&soap, &rights);
- soap_begin_send(&soap);
- soap_put_rightsArray(&soap, &rights, "rights", "rightsArray");
- soap_end_send(&soap);
- strAclData = os.str();
- lpsPropValue->Value.bin.cb = strAclData.size();
- hr = MAPIAllocateMore(lpsPropValue->Value.bin.cb, lpBase, (LPVOID*)&lpsPropValue->Value.bin.lpb);
- if (hr != hrSuccess)
- goto exit;
- memcpy(lpsPropValue->Value.bin.lpb, strAclData.data(), lpsPropValue->Value.bin.cb);
- exit:
- soap_destroy(&soap);
- soap_end(&soap); // clean up allocated temporaries
-
- return hr;
- }
- HRESULT ECMAPIProp::SetSerializedACLData(const SPropValue *lpsPropValue)
- {
- HRESULT hr = hrSuccess;
- ECPermissionPtr ptrPerms;
- struct soap soap;
- struct rightsArray rights;
- std::string strAclData;
- if (lpsPropValue == NULL || PROP_TYPE(lpsPropValue->ulPropTag) != PT_BINARY) {
- hr = MAPI_E_INVALID_PARAMETER;
- goto exit;
- }
- {
- std::istringstream is(std::string((char*)lpsPropValue->Value.bin.lpb, lpsPropValue->Value.bin.cb));
- soap.is = &is;
- soap_set_imode(&soap, SOAP_C_UTFSTRING);
- soap_begin(&soap);
- if (soap_begin_recv(&soap) != 0) {
- hr = MAPI_E_NETWORK_FAILURE;
- goto exit;
- }
- if (!soap_get_rightsArray(&soap, &rights, "rights", "rightsArray")) {
- hr = MAPI_E_CORRUPT_DATA;
- goto exit;
- }
- if (soap_end_recv(&soap) != 0) {
- hr = MAPI_E_NETWORK_ERROR;
- goto exit;
- }
- }
- hr = MAPIAllocateBuffer(rights.__size * sizeof(ECPERMISSION), &~ptrPerms);
- if (hr != hrSuccess)
- goto exit;
- std::transform(rights.__ptr, rights.__ptr + rights.__size, ptrPerms.get(), &RightsToECPermCheap);
- hr = UpdateACLs(rights.__size, ptrPerms);
- exit:
- soap_destroy(&soap);
- soap_end(&soap); // clean up allocated temporaries
- return hr;
- }
- HRESULT ECMAPIProp::UpdateACLs(ULONG cNewPerms, ECPERMISSION *lpNewPerms)
- {
- HRESULT hr;
- ECSecurityPtr ptrSecurity;
- ULONG cPerms = 0;
- ECPermissionArrayPtr ptrPerms;
- ULONG cSparePerms = 0;
- ECPermissionPtr ptrTmpPerms;
- ECPERMISSION *lpPermissions = NULL;
- hr = QueryInterface(IID_IECSecurity, &~ptrSecurity);
- if (hr != hrSuccess)
- return hr;
- hr = ptrSecurity->GetPermissionRules(ACCESS_TYPE_GRANT, &cPerms, &~ptrPerms);
- if (hr != hrSuccess)
- return hr;
- // Since we want to replace the current ACL with a new one, we need to mark
- // each existing item as deleted, and add all new ones as new.
- // But there can also be overlap, where some items are left unchanged, and
- // other modified.
- for (ULONG i = 0; i < cPerms; ++i) {
- ECPERMISSION *lpMatch = std::find_if(lpNewPerms, lpNewPerms + cNewPerms, FindUser(ptrPerms[i].sUserId));
- if (lpMatch == lpNewPerms + cNewPerms) {
- // Not in new set, so delete
- ptrPerms[i].ulState = RIGHT_DELETED;
- continue;
- }
- // Found an entry in the new set, check if it's different
- if (ptrPerms[i].ulRights == lpMatch->ulRights &&
- ptrPerms[i].ulType == lpMatch->ulType)
- {
- // Nothing changes, remove from set.
- if (i < (cPerms - 1))
- std::swap(ptrPerms[i], ptrPerms[cPerms - 1]);
- --cPerms;
- --i;
- ++cSparePerms;
- } else {
- ptrPerms[i].ulRights = lpMatch->ulRights;
- ptrPerms[i].ulType = lpMatch->ulType;
- ptrPerms[i].ulState = RIGHT_MODIFY;
- }
- // Remove from list of new permissions
- if (lpMatch != &lpNewPerms[cNewPerms - 1])
- std::swap(*lpMatch, lpNewPerms[cNewPerms - 1]);
- --cNewPerms;
- }
- // Now see if there are still some new ACL's left. If enough spare space is available
- // we'll reuse the ptrPerms storage. If not we'll reallocate the whole array.
- lpPermissions = ptrPerms.get();
- if (cNewPerms > 0) {
- if (cNewPerms <= cSparePerms) {
- memcpy(&ptrPerms[cPerms], lpNewPerms, cNewPerms * sizeof(ECPERMISSION));
- } else if (cPerms == 0) {
- lpPermissions = lpNewPerms;
- } else {
- hr = MAPIAllocateBuffer((cPerms + cNewPerms) * sizeof(ECPERMISSION), &~ptrTmpPerms);
- if (hr != hrSuccess)
- return hr;
- memcpy(ptrTmpPerms, ptrPerms, cPerms * sizeof(ECPERMISSION));
- memcpy(ptrTmpPerms + cPerms, lpNewPerms, cNewPerms * sizeof(ECPERMISSION));
- lpPermissions = ptrTmpPerms;
- }
- }
- if (cPerms + cNewPerms > 0)
- hr = ptrSecurity->SetPermissionRules(cPerms + cNewPerms, lpPermissions);
- return hrSuccess;
- }
- HRESULT ECMAPIProp::CopyTo(ULONG ciidExclude, LPCIID rgiidExclude,
- const SPropTagArray *lpExcludeProps, ULONG ulUIParam,
- LPMAPIPROGRESS lpProgress, LPCIID lpInterface, void *lpDestObj,
- ULONG ulFlags, SPropProblemArray **lppProblems)
- {
- return Util::DoCopyTo(&IID_IMAPIProp, &this->m_xMAPIProp, ciidExclude, rgiidExclude, lpExcludeProps, ulUIParam, lpProgress, lpInterface, lpDestObj, ulFlags, lppProblems);
- }
- HRESULT ECMAPIProp::CopyProps(const SPropTagArray *lpIncludeProps,
- ULONG ulUIParam, LPMAPIPROGRESS lpProgress, LPCIID lpInterface,
- void *lpDestObj, ULONG ulFlags, SPropProblemArray **lppProblems)
- {
- return Util::DoCopyProps(&IID_IMAPIProp, &this->m_xMAPIProp, lpIncludeProps, ulUIParam, lpProgress, lpInterface, lpDestObj, ulFlags, lppProblems);
- }
- // Pass call off to lpMsgStore
- HRESULT ECMAPIProp::GetNamesFromIDs(LPSPropTagArray *lppPropTags, LPGUID lpPropSetGuid, ULONG ulFlags, ULONG *lpcPropNames, LPMAPINAMEID **lpppPropNames)
- {
- return this->GetMsgStore()->lpNamedProp->GetNamesFromIDs(lppPropTags, lpPropSetGuid, ulFlags, lpcPropNames, lpppPropNames);
- }
- HRESULT ECMAPIProp::GetIDsFromNames(ULONG cPropNames, LPMAPINAMEID *lppPropNames, ULONG ulFlags, LPSPropTagArray *lppPropTags)
- {
- return this->GetMsgStore()->lpNamedProp->GetIDsFromNames(cPropNames, lppPropNames, ulFlags, lppPropTags);
- }
- // Stream functions
- HRESULT ECMAPIProp::HrStreamCommit(IStream *lpStream, void *lpData)
- {
- HRESULT hr = hrSuccess;
- auto lpStreamData = static_cast<STREAMDATA *>(lpData);
- char *buffer = NULL;
- ecmem_ptr<SPropValue> lpPropValue;
- STATSTG sStat;
- ULONG ulSize = 0;
- object_ptr<ECMemStream> lpECStream;
- hr = ECAllocateBuffer(sizeof(SPropValue), &~lpPropValue);
- if(hr != hrSuccess)
- return hr;
- hr = lpStream->Stat(&sStat, 0);
- if(hr != hrSuccess)
- return hr;
- if(PROP_TYPE(lpStreamData->ulPropTag) == PT_STRING8) {
- hr = ECAllocateMore((ULONG)sStat.cbSize.QuadPart+1, lpPropValue, (void **)&buffer);
-
- if(hr != hrSuccess)
- return hr;
- // read the data into the buffer
- hr = lpStream->Read(buffer, (ULONG)sStat.cbSize.QuadPart, &ulSize);
- } else if(PROP_TYPE(lpStreamData->ulPropTag) == PT_UNICODE) {
- hr = ECAllocateMore((ULONG)sStat.cbSize.QuadPart+sizeof(WCHAR), lpPropValue, (void **)&buffer);
-
- if(hr != hrSuccess)
- return hr;
- // read the data into the buffer
- hr = lpStream->Read(buffer, (ULONG)sStat.cbSize.QuadPart, &ulSize);
- } else{
- hr = lpStream->QueryInterface(IID_ECMemStream, &~lpECStream);
- if(hr != hrSuccess)
- return hr;
- ulSize = (ULONG)sStat.cbSize.QuadPart;
- buffer = lpECStream->GetBuffer();
- }
- lpPropValue->ulPropTag = lpStreamData->ulPropTag;
- switch(PROP_TYPE(lpStreamData->ulPropTag)) {
- case PT_STRING8:
- buffer[ulSize] = 0;
- lpPropValue->Value.lpszA = buffer;
- break;
- case PT_UNICODE:
- memset(&buffer[ulSize], 0, sizeof(wchar_t));
- lpPropValue->Value.lpszW = (WCHAR *)buffer;
- break;
- case PT_BINARY:
- lpPropValue->Value.bin.cb = ulSize;
- lpPropValue->Value.bin.lpb = (unsigned char *)buffer;
- break;
- }
- hr = lpStreamData->lpProp->HrSetRealProp(lpPropValue);
- if (hr != hrSuccess)
- return hr;
- // on a non transacted object SaveChanges is required
- if (!lpStreamData->lpProp->isTransactedObject)
- hr = lpStreamData->lpProp->ECGenericProp::SaveChanges(KEEP_OPEN_READWRITE);
- return hr;
- }
- HRESULT ECMAPIProp::HrStreamCleanup(void *lpData)
- {
- delete static_cast<STREAMDATA *>(lpData);
- return hrSuccess;
- }
- HRESULT ECMAPIProp::HrSetSyncId(ULONG ulSyncId)
- {
- HRESULT hr = hrSuccess;
- object_ptr<WSMAPIPropStorage> lpMAPIPropStorage;
-
- if (lpStorage != nullptr && lpStorage->QueryInterface(IID_WSMAPIPropStorage, &~lpMAPIPropStorage) == hrSuccess) {
- hr = lpMAPIPropStorage->HrSetSyncId(ulSyncId);
- if(hr != hrSuccess)
- return hr;
- }
- m_ulSyncId = ulSyncId;
- return hrSuccess;
- }
- // Security functions
- HRESULT ECMAPIProp::GetPermissionRules(int ulType, ULONG *lpcPermissions,
- ECPERMISSION **lppECPermissions)
- {
- if (m_lpEntryId == NULL)
- return MAPI_E_NO_ACCESS;
- return this->GetMsgStore()->lpTransport->HrGetPermissionRules(ulType, m_cbEntryId, m_lpEntryId, lpcPermissions, lppECPermissions);
- }
- HRESULT ECMAPIProp::SetPermissionRules(ULONG cPermissions,
- ECPERMISSION *lpECPermissions)
- {
- if (m_lpEntryId == NULL)
- return MAPI_E_NO_ACCESS;
- return this->GetMsgStore()->lpTransport->HrSetPermissionRules(m_cbEntryId, m_lpEntryId, cPermissions, lpECPermissions);
- }
- HRESULT ECMAPIProp::GetOwner(ULONG *lpcbOwner, LPENTRYID *lppOwner)
- {
- if (lpcbOwner == NULL || lppOwner == NULL)
- return MAPI_E_INVALID_PARAMETER;
- if (m_lpEntryId == NULL)
- return MAPI_E_NO_ACCESS;
- return GetMsgStore()->lpTransport->HrGetOwner(m_cbEntryId, m_lpEntryId, lpcbOwner, lppOwner);
- }
- HRESULT ECMAPIProp::GetUserList(ULONG cbCompanyId, LPENTRYID lpCompanyId,
- ULONG ulFlags, ULONG *lpcUsers, ECUSER **lppsUsers)
- {
- return GetMsgStore()->lpTransport->HrGetUserList(cbCompanyId, lpCompanyId, ulFlags, lpcUsers, lppsUsers);
- }
- HRESULT ECMAPIProp::GetGroupList(ULONG cbCompanyId, LPENTRYID lpCompanyId,
- ULONG ulFlags, ULONG *lpcGroups, ECGROUP **lppsGroups)
- {
- return GetMsgStore()->lpTransport->HrGetGroupList(cbCompanyId, lpCompanyId, ulFlags, lpcGroups, lppsGroups);
- }
- HRESULT ECMAPIProp::GetCompanyList(ULONG ulFlags, ULONG *lpcCompanies,
- ECCOMPANY **lppsCompanies)
- {
- return GetMsgStore()->lpTransport->HrGetCompanyList(ulFlags, lpcCompanies, lppsCompanies);
- }
- HRESULT ECMAPIProp::SetParentID(ULONG cbParentID, LPENTRYID lpParentID)
- {
- HRESULT hr;
- assert(m_lpParentID == NULL);
- if (lpParentID == NULL || cbParentID == 0)
- return MAPI_E_INVALID_PARAMETER;
- hr = MAPIAllocateBuffer(cbParentID, (void**)&m_lpParentID);
- if (hr != hrSuccess)
- return hr;
- m_cbParentID = cbParentID;
- memcpy(m_lpParentID, lpParentID, cbParentID);
- return hrSuccess;
- }
- // Interface IMAPIProp
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, QueryInterface, (REFIID, refiid), (void **, lppInterface))
- DEF_ULONGMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, AddRef, (void))
- DEF_ULONGMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, Release, (void))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, GetLastError, (HRESULT, hError), (ULONG, ulFlags), (LPMAPIERROR *, lppMapiError))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, SaveChanges, (ULONG, ulFlags))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, GetProps, (const SPropTagArray *, lpPropTagArray), (ULONG, ulFlags), (ULONG *, lpcValues), (SPropValue **, lppPropArray))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, GetPropList, (ULONG, ulFlags), (LPSPropTagArray *, lppPropTagArray))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, OpenProperty, (ULONG, ulPropTag), (LPCIID, lpiid), (ULONG, ulInterfaceOptions), (ULONG, ulFlags), (LPUNKNOWN *, lppUnk))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, SetProps, (ULONG, cValues), (const SPropValue *, lpPropArray), (SPropProblemArray **, lppProblems))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, DeleteProps, (const SPropTagArray *, lpPropTagArray), (SPropProblemArray **, lppProblems))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, CopyTo, (ULONG, ciidExclude), (LPCIID, rgiidExclude), (const SPropTagArray *, lpExcludeProps), (ULONG, ulUIParam), (LPMAPIPROGRESS, lpProgress), (LPCIID, lpInterface), (void *, lpDestObj), (ULONG, ulFlags), (SPropProblemArray **, lppProblems))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, CopyProps, (const SPropTagArray *, lpIncludeProps), (ULONG, ulUIParam), (LPMAPIPROGRESS, lpProgress), (LPCIID, lpInterface), (void *, lpDestObj), (ULONG, ulFlags), (SPropProblemArray **, lppProblems))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, GetNamesFromIDs, (LPSPropTagArray *, pptaga), (LPGUID, lpguid), (ULONG, ulFlags), (ULONG *, pcNames), (LPMAPINAMEID **, pppNames))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, GetIDsFromNames, (ULONG, cNames), (LPMAPINAMEID *, ppNames), (ULONG, ulFlags), (LPSPropTagArray *, pptaga))
- // Interface ECSecurity
- DEF_HRMETHOD0(ECMAPIProp, ECSecurity, QueryInterface, (REFIID, refiid), (void **, lppInterface))
- DEF_ULONGMETHOD0(ECMAPIProp, ECSecurity, AddRef, (void))
- DEF_ULONGMETHOD0(ECMAPIProp, ECSecurity, Release, (void))
- DEF_HRMETHOD0(ECMAPIProp, ECSecurity, GetOwner, (ULONG *, lpcbOwner), (LPENTRYID *, lppOwner))
- DEF_HRMETHOD0(ECMAPIProp, ECSecurity, GetUserList, (ULONG, cbCompanyId), (LPENTRYID, lpCompanyId), (ULONG, ulFlags), (ULONG *, lpcUsers), (ECUSER **, lpsUsers))
- DEF_HRMETHOD0(ECMAPIProp, ECSecurity, GetGroupList, (ULONG, cbCompanyId), (LPENTRYID, lpCompanyId), (ULONG, ulFlags), (ULONG *, lpcGroups), (ECGROUP **, lppsGroups))
- DEF_HRMETHOD0(ECMAPIProp, ECSecurity, GetCompanyList, (ULONG, ulFlags), (ULONG *, lpcCompanies), (ECCOMPANY **, lppsCompanies))
- DEF_HRMETHOD0(ECMAPIProp, ECSecurity, GetPermissionRules, (int, ulType), (ULONG *, lpcPermissions), (ECPERMISSION **, lppECPermissions))
- DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, ECSecurity, SetPermissionRules, (ULONG, cPermissions), (ECPERMISSION *, lpECPermissions))
|