ECMAPIProp.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/platform.h>
  18. #include <kopano/ECInterfaceDefs.h>
  19. #include <kopano/memory.hpp>
  20. #include <mapidefs.h>
  21. #include <mapicode.h>
  22. #include <mapitags.h>
  23. #include <mapiguid.h>
  24. #include <mapiutil.h>
  25. #include "kcore.hpp"
  26. #include <kopano/ECGuid.h>
  27. #include <kopano/ECDefs.h>
  28. #include "ECMsgStore.h"
  29. #include "ECMAPIProp.h"
  30. #include "ECMemStream.h"
  31. #include "Mem.h"
  32. #include <kopano/Util.h>
  33. #include <kopano/ECDebug.h>
  34. #include <kopano/mapiext.h>
  35. #include <kopano/CommonUtil.h>
  36. #include <kopano/mapi_ptr.h>
  37. #include "pcutil.hpp"
  38. #include <sstream>
  39. using namespace KCHL;
  40. struct STREAMDATA {
  41. ULONG ulPropTag;
  42. ECMAPIProp *lpProp;
  43. };
  44. static struct rights ECPermToRightsCheap(const ECPERMISSION &p)
  45. {
  46. struct rights r = {0, p.ulType, p.ulRights, p.ulState};
  47. r.sUserId.__size = p.sUserId.cb;
  48. r.sUserId.__ptr = p.sUserId.lpb;
  49. return r;
  50. }
  51. static ECPERMISSION RightsToECPermCheap(const struct rights r)
  52. {
  53. ECPERMISSION p = {r.ulType, r.ulRights, RIGHT_NEW}; // Force to new
  54. p.sUserId.cb = r.sUserId.__size;
  55. p.sUserId.lpb = r.sUserId.__ptr;
  56. return p;
  57. }
  58. class FindUser {
  59. public:
  60. FindUser(const ECENTRYID &sEntryID): m_sEntryID(sEntryID) {}
  61. bool operator()(const ECPERMISSION &sPermission) const {
  62. return CompareABEID(m_sEntryID.cb, (LPENTRYID)m_sEntryID.lpb, sPermission.sUserId.cb, (LPENTRYID)sPermission.sUserId.lpb);
  63. }
  64. private:
  65. const ECENTRYID &m_sEntryID;
  66. };
  67. ECMAPIProp::ECMAPIProp(void *lpProvider, ULONG ulObjType, BOOL fModify,
  68. ECMAPIProp *lpRoot, const char *szClassName) :
  69. ECGenericProp(lpProvider, ulObjType, fModify, szClassName)
  70. {
  71. TRACE_MAPI(TRACE_ENTRY, "ECMAPIProp::ECMAPIProp","");
  72. this->HrAddPropHandlers(PR_STORE_ENTRYID, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
  73. this->HrAddPropHandlers(PR_STORE_RECORD_KEY, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
  74. this->HrAddPropHandlers(PR_STORE_SUPPORT_MASK, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
  75. this->HrAddPropHandlers(PR_STORE_UNICODE_MASK, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
  76. this->HrAddPropHandlers(PR_MAPPING_SIGNATURE, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
  77. this->HrAddPropHandlers(PR_PARENT_ENTRYID, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
  78. this->HrAddPropHandlers(PR_MDB_PROVIDER, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
  79. this->HrAddPropHandlers(PR_LAST_MODIFICATION_TIME, DefaultMAPIGetProp, DefaultSetPropSetReal, (void*) this);
  80. this->HrAddPropHandlers(PR_CREATION_TIME, DefaultMAPIGetProp, DefaultSetPropIgnore, (void*) this);
  81. this->HrAddPropHandlers(PR_ACCESS_LEVEL, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
  82. this->HrAddPropHandlers(PR_PARENT_SOURCE_KEY, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
  83. this->HrAddPropHandlers(PR_RECORD_KEY, DefaultGetPropGetReal, DefaultSetPropComputed, (void*) this);
  84. this->HrAddPropHandlers(PR_EC_SERVER_UID, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this);
  85. this->HrAddPropHandlers(PR_EC_HIERARCHYID, DefaultMAPIGetProp, DefaultSetPropComputed, (void*) this, FALSE, TRUE);
  86. // ICS system
  87. this->HrAddPropHandlers(PR_SOURCE_KEY, DefaultMAPIGetProp ,SetPropHandler, (void*) this, FALSE, FALSE);
  88. // Used for loadsim
  89. this->HrAddPropHandlers(0x664B0014/*PR_REPLICA_VERSION*/, DefaultMAPIGetProp ,DefaultSetPropIgnore, (void*) this, FALSE, FALSE);
  90. // Track 'root object'. This is the object that was opened via OpenEntry or OpenMsgStore, so normally
  91. // lpRoot == this, but in the case of attachments and submessages it points to the top-level message
  92. if(lpRoot)
  93. m_lpRoot = lpRoot;
  94. else
  95. m_lpRoot = this;
  96. }
  97. ECMAPIProp::~ECMAPIProp()
  98. {
  99. TRACE_MAPI(TRACE_ENTRY, "ECMAPIProp::~ECMAPIProp","");
  100. MAPIFreeBuffer(m_lpParentID);
  101. }
  102. HRESULT ECMAPIProp::QueryInterface(REFIID refiid, void **lppInterface)
  103. {
  104. REGISTER_INTERFACE2(ECMAPIProp, this);
  105. REGISTER_INTERFACE2(ECUnknown, this);
  106. REGISTER_INTERFACE2(IMAPIProp, &this->m_xMAPIProp);
  107. REGISTER_INTERFACE2(IUnknown, &this->m_xMAPIProp);
  108. REGISTER_INTERFACE2(IECSecurity, &this->m_xECSecurity);
  109. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  110. }
  111. ECMsgStore* ECMAPIProp::GetMsgStore()
  112. {
  113. return (ECMsgStore*)lpProvider;
  114. }
  115. // Loads the properties of the saved message for use
  116. HRESULT ECMAPIProp::HrLoadProps()
  117. {
  118. return dwLastError = ECGenericProp::HrLoadProps();
  119. }
  120. HRESULT ECMAPIProp::SetICSObject(BOOL bICSObject)
  121. {
  122. m_bICSObject = bICSObject;
  123. return hrSuccess;
  124. }
  125. BOOL ECMAPIProp::IsICSObject()
  126. {
  127. return m_bICSObject;
  128. }
  129. // Property handles
  130. HRESULT ECMAPIProp::DefaultMAPIGetProp(ULONG ulPropTag, void* lpProvider, ULONG ulFlags, LPSPropValue lpsPropValue, void *lpParam, void *lpBase)
  131. {
  132. HRESULT hr = hrSuccess;
  133. auto lpMsgStore = static_cast<ECMsgStore *>(lpProvider);
  134. auto lpProp = static_cast<ECMAPIProp *>(lpParam);
  135. switch(PROP_ID(ulPropTag)) {
  136. case PROP_ID(PR_SOURCE_KEY):
  137. hr = lpProp->HrGetRealProp(PR_SOURCE_KEY, ulFlags, lpBase, lpsPropValue);
  138. if(hr != hrSuccess)
  139. return hr;
  140. break;
  141. case PROP_ID(0x664B0014):
  142. // Used for loadsim
  143. lpsPropValue->ulPropTag = 0x664B0014;//PR_REPLICA_VERSION;
  144. lpsPropValue->Value.li.QuadPart = 1688871835664386LL;
  145. break;
  146. case PROP_ID(PR_MAPPING_SIGNATURE):
  147. // get the mapping signature from the store
  148. if (lpMsgStore == NULL || lpMsgStore->HrGetRealProp(PR_MAPPING_SIGNATURE, ulFlags, lpBase, lpsPropValue) != hrSuccess)
  149. hr = MAPI_E_NOT_FOUND;
  150. break;
  151. case PROP_ID(PR_STORE_RECORD_KEY):
  152. lpsPropValue->ulPropTag = PR_STORE_RECORD_KEY;
  153. lpsPropValue->Value.bin.cb = sizeof(MAPIUID);
  154. hr = ECAllocateMore(sizeof(MAPIUID), lpBase, reinterpret_cast<void **>(&lpsPropValue->Value.bin.lpb));
  155. if (hr != hrSuccess)
  156. break;
  157. memcpy(lpsPropValue->Value.bin.lpb, &lpProp->GetMsgStore()->GetStoreGuid(), sizeof(MAPIUID));
  158. break;
  159. case PROP_ID(PR_STORE_SUPPORT_MASK):
  160. case PROP_ID(PR_STORE_UNICODE_MASK):
  161. if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_PUBLIC_GUID))
  162. lpsPropValue->Value.l = EC_SUPPORTMASK_PUBLIC;
  163. else if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_DELEGATE_GUID))
  164. lpsPropValue->Value.l = EC_SUPPORTMASK_DELEGATE;
  165. else if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_ARCHIVE_GUID))
  166. lpsPropValue->Value.l = EC_SUPPORTMASK_ARCHIVE;
  167. else
  168. lpsPropValue->Value.l = EC_SUPPORTMASK_PRIVATE;
  169. if(lpMsgStore->m_ulClientVersion == CLIENT_VERSION_OLK2000)
  170. lpsPropValue->Value.l &=~STORE_HTML_OK; // Remove the flag, other way outlook 2000 crashed
  171. // No real unicode support in outlook 2000 and xp
  172. if (lpMsgStore->m_ulClientVersion <= CLIENT_VERSION_OLK2002)
  173. lpsPropValue->Value.l &=~ STORE_UNICODE_OK;
  174. lpsPropValue->ulPropTag = CHANGE_PROP_TYPE(ulPropTag,PT_LONG);
  175. break;
  176. case PROP_ID(PR_STORE_ENTRYID): {
  177. lpsPropValue->ulPropTag = PR_STORE_ENTRYID;
  178. ULONG cbWrapped = 0;
  179. memory_ptr<ENTRYID> lpWrapped;
  180. hr = lpProp->GetMsgStore()->GetWrappedStoreEntryID(&cbWrapped, &~lpWrapped);
  181. if(hr == hrSuccess) {
  182. hr = ECAllocateMore(cbWrapped, lpBase, reinterpret_cast<void **>(&lpsPropValue->Value.bin.lpb));
  183. if (hr != hrSuccess)
  184. break;
  185. memcpy(lpsPropValue->Value.bin.lpb, lpWrapped, cbWrapped);
  186. lpsPropValue->Value.bin.cb = cbWrapped;
  187. }
  188. break;
  189. }
  190. case PROP_ID(PR_MDB_PROVIDER):
  191. hr = ECAllocateMore(sizeof(MAPIUID),lpBase, reinterpret_cast<void **>(&lpsPropValue->Value.bin.lpb));
  192. if (hr != hrSuccess)
  193. break;
  194. memcpy(lpsPropValue->Value.bin.lpb, &lpMsgStore->m_guidMDB_Provider, sizeof(MAPIUID));
  195. lpsPropValue->Value.bin.cb = sizeof(MAPIUID);
  196. lpsPropValue->ulPropTag = PR_MDB_PROVIDER;
  197. break;
  198. case PROP_ID(PR_ACCESS_LEVEL):
  199. if(lpProp->HrGetRealProp(PR_ACCESS_LEVEL, ulFlags, lpBase, lpsPropValue) != erSuccess)
  200. {
  201. lpsPropValue->Value.l = lpProp->fModify ? MAPI_MODIFY : 0;
  202. //lpsPropValue->Value.l = 0;
  203. lpsPropValue->ulPropTag = PR_ACCESS_LEVEL;
  204. }
  205. break;
  206. case PROP_ID(PR_PARENT_ENTRYID):
  207. lpsPropValue->ulPropTag = PR_PARENT_ENTRYID;
  208. if (lpProp->m_lpParentID != NULL) {
  209. hr = ECAllocateMore(lpProp->m_cbParentID, lpBase, reinterpret_cast<void **>(&lpsPropValue->Value.bin.lpb));
  210. if (hr != hrSuccess)
  211. break;
  212. memcpy(lpsPropValue->Value.bin.lpb, lpProp->m_lpParentID, lpProp->m_cbParentID);
  213. lpsPropValue->Value.bin.cb = lpProp->m_cbParentID;
  214. } else {
  215. hr = lpProp->HrGetRealProp(PR_PARENT_ENTRYID, ulFlags, lpBase, lpsPropValue);
  216. }
  217. break;
  218. case PROP_ID(PR_EC_SERVER_UID): {
  219. lpsPropValue->ulPropTag = PR_EC_SERVER_UID;
  220. GUID sServerGuid = {0};
  221. hr = ((ECMAPIProp*)lpParam)->m_lpRoot->GetMsgStore()->lpTransport->GetServerGUID(&sServerGuid);
  222. if (hr == hrSuccess)
  223. hr = ECAllocateMore(sizeof(GUID), lpBase, (LPVOID*)&lpsPropValue->Value.bin.lpb);
  224. if (hr == hrSuccess) {
  225. memcpy(lpsPropValue->Value.bin.lpb, &sServerGuid, sizeof(GUID));
  226. lpsPropValue->Value.bin.cb = sizeof(GUID);
  227. }
  228. break;
  229. }
  230. case PROP_ID(PR_EC_HIERARCHYID):
  231. if (lpProp->m_sMapiObject == NULL) {
  232. hr = lpProp->HrLoadProps();
  233. if (hr != hrSuccess)
  234. return hr;
  235. }
  236. if (lpProp->m_sMapiObject->ulObjId > 0) {
  237. lpsPropValue->ulPropTag = ulPropTag;
  238. lpsPropValue->Value.ul = lpProp->m_sMapiObject->ulObjId;
  239. } else {
  240. hr = MAPI_E_NOT_FOUND;
  241. }
  242. break;
  243. default:
  244. hr = lpProp->HrGetRealProp(ulPropTag, ulFlags, lpBase, lpsPropValue);
  245. break;
  246. }
  247. return hr;
  248. }
  249. HRESULT ECMAPIProp::SetPropHandler(ULONG ulPropTag, void *lpProvider,
  250. const SPropValue *lpsPropValue, void *lpParam)
  251. {
  252. HRESULT hr = hrSuccess;
  253. auto lpProp = static_cast<ECMAPIProp *>(lpParam);
  254. switch(ulPropTag) {
  255. case PR_SOURCE_KEY:
  256. if (lpProp->IsICSObject())
  257. hr = lpProp->HrSetRealProp(lpsPropValue);
  258. else
  259. hr = hrSuccess; // ignore the property
  260. break;
  261. default:
  262. hr = MAPI_E_NOT_FOUND;
  263. break;
  264. }
  265. return hr;
  266. }
  267. HRESULT ECMAPIProp::TableRowGetProp(void* lpProvider, struct propVal *lpsPropValSrc, LPSPropValue lpsPropValDst, void **lpBase, ULONG ulType)
  268. {
  269. HRESULT hr = hrSuccess;
  270. auto lpMsgStore = static_cast<ECMsgStore *>(lpProvider);
  271. switch(lpsPropValSrc->ulPropTag) {
  272. case PR_STORE_ENTRYID:
  273. {
  274. ULONG cbWrapped = 0;
  275. memory_ptr<ENTRYID> lpWrapped;
  276. // if we know, we are a spooler or a store than we can switch the function for 'speed-up'
  277. // hr = lpMsgStore->GetWrappedStoreEntryID(&cbWrapped, &lpWrapped);
  278. hr = lpMsgStore->GetWrappedServerStoreEntryID(lpsPropValSrc->Value.bin->__size, lpsPropValSrc->Value.bin->__ptr, &cbWrapped, &~lpWrapped);
  279. if (hr != hrSuccess)
  280. return hr;
  281. hr = ECAllocateMore(cbWrapped, lpBase, reinterpret_cast<void **>(&lpsPropValDst->Value.bin.lpb));
  282. if (hr != hrSuccess)
  283. return hr;
  284. memcpy(lpsPropValDst->Value.bin.lpb, lpWrapped, cbWrapped);
  285. lpsPropValDst->Value.bin.cb = cbWrapped;
  286. lpsPropValDst->ulPropTag = PROP_TAG(PT_BINARY,PROP_ID(lpsPropValSrc->ulPropTag));
  287. break;
  288. }
  289. case PROP_TAG(PT_ERROR,PROP_ID(PR_DISPLAY_TYPE)):
  290. lpsPropValDst->Value.l = DT_FOLDER; // FIXME, may be a search folder
  291. lpsPropValDst->ulPropTag = PR_DISPLAY_TYPE;
  292. break;
  293. case PROP_TAG(PT_ERROR,PROP_ID(PR_STORE_SUPPORT_MASK)):
  294. case PROP_TAG(PT_ERROR,PROP_ID(PR_STORE_UNICODE_MASK)):
  295. if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_PUBLIC_GUID))
  296. lpsPropValDst->Value.l = EC_SUPPORTMASK_PUBLIC;
  297. else if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_DELEGATE_GUID))
  298. lpsPropValDst->Value.l = EC_SUPPORTMASK_DELEGATE;
  299. else if (CompareMDBProvider(&lpMsgStore->m_guidMDB_Provider, &KOPANO_STORE_ARCHIVE_GUID))
  300. lpsPropValDst->Value.l = EC_SUPPORTMASK_ARCHIVE;
  301. else
  302. lpsPropValDst->Value.l = EC_SUPPORTMASK_PRIVATE;
  303. if (lpMsgStore->m_ulClientVersion == CLIENT_VERSION_OLK2000)
  304. lpsPropValDst->Value.l &=~STORE_HTML_OK; // Remove the flag, other way outlook 2000 crashed
  305. // No real unicode support in outlook 2000 and xp
  306. if (lpMsgStore->m_ulClientVersion <= CLIENT_VERSION_OLK2002)
  307. lpsPropValDst->Value.l &=~ STORE_UNICODE_OK;
  308. lpsPropValDst->ulPropTag = CHANGE_PROP_TYPE(lpsPropValSrc->ulPropTag, PT_LONG);
  309. break;
  310. case PROP_TAG(PT_ERROR,PROP_ID(PR_STORE_RECORD_KEY)):
  311. // Reset type to binary
  312. lpsPropValDst->ulPropTag = PROP_TAG(PT_BINARY,PROP_ID(lpsPropValSrc->ulPropTag));
  313. hr = ECAllocateMore(sizeof(MAPIUID), lpBase, reinterpret_cast<void **>(&lpsPropValDst->Value.bin.lpb));
  314. if (hr != hrSuccess)
  315. break;
  316. memcpy(lpsPropValDst->Value.bin.lpb, &lpMsgStore->GetStoreGuid(), sizeof(MAPIUID));
  317. lpsPropValDst->Value.bin.cb = sizeof(MAPIUID);
  318. break;
  319. case PROP_TAG(PT_ERROR,PROP_ID(PR_MDB_PROVIDER)):
  320. lpsPropValDst->ulPropTag = PROP_TAG(PT_BINARY,PROP_ID(lpsPropValSrc->ulPropTag));
  321. hr = ECAllocateMore(sizeof(MAPIUID), lpBase, reinterpret_cast<void **>(&lpsPropValDst->Value.bin.lpb));
  322. if (hr != hrSuccess)
  323. break;
  324. memcpy(lpsPropValDst->Value.bin.lpb, &lpMsgStore->m_guidMDB_Provider, sizeof(MAPIUID));
  325. lpsPropValDst->Value.bin.cb = sizeof(MAPIUID);
  326. break;
  327. default:
  328. return MAPI_E_NOT_FOUND;
  329. }
  330. return hr;
  331. }
  332. // FIXME openproperty on computed value is illegal
  333. HRESULT ECMAPIProp::OpenProperty(ULONG ulPropTag, LPCIID lpiid, ULONG ulInterfaceOptions, ULONG ulFlags, LPUNKNOWN *lppUnk)
  334. {
  335. HRESULT hr = hrSuccess;
  336. ECMemStream *lpStream = NULL;
  337. ecmem_ptr<SPropValue> lpsPropValue;
  338. STREAMDATA *lpStreamData = NULL;
  339. if((ulFlags&MAPI_CREATE && !(ulFlags&MAPI_MODIFY)) || lpiid == NULL)
  340. return MAPI_E_INVALID_PARAMETER;
  341. // Only support certain property types
  342. if (PROP_TYPE(ulPropTag) != PT_BINARY &&
  343. PROP_TYPE(ulPropTag) != PT_UNICODE &&
  344. PROP_TYPE(ulPropTag) != PT_STRING8)
  345. return MAPI_E_INVALID_PARAMETER;
  346. if (*lpiid != IID_IStream && *lpiid != IID_IStorage)
  347. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  348. if (PROP_TYPE(ulPropTag) != PT_STRING8 &&
  349. PROP_TYPE(ulPropTag) != PT_BINARY &&
  350. PROP_TYPE(ulPropTag) != PT_UNICODE)
  351. return MAPI_E_NOT_FOUND;
  352. if (*lpiid == IID_IStream && this->lstProps == NULL &&
  353. PROP_TYPE(ulPropTag) == PT_BINARY && !(ulFlags & MAPI_MODIFY) &&
  354. // Shortcut: don't load entire object if only one property is being requested for read-only. HrLoadProp() will return
  355. // without querying the server if the server does not support this capability (introduced in 6.20.8). Main reason is
  356. // calendar loading time with large recursive entries in outlook XP.
  357. // If HrLoadProp failed, just fallback to the 'normal' way of loading properties.
  358. this->lpStorage->HrLoadProp(0, ulPropTag, &~lpsPropValue) == erSuccess) {
  359. lpStreamData = new STREAMDATA; // is freed by HrStreamCleanup, called by ECMemStream on refcount == 0
  360. lpStreamData->ulPropTag = ulPropTag;
  361. lpStreamData->lpProp = this;
  362. hr = ECMemStream::Create((char*)lpsPropValue->Value.bin.lpb, lpsPropValue->Value.bin.cb, ulInterfaceOptions,
  363. NULL, ECMAPIProp::HrStreamCleanup, (void *)lpStreamData, &lpStream);
  364. if (hr != hrSuccess)
  365. return hr;
  366. lpStream->QueryInterface(IID_IStream, (void **)lppUnk);
  367. AddChild(lpStream);
  368. lpStream->Release();
  369. return hr;
  370. }
  371. if (ulFlags & MAPI_MODIFY)
  372. ulInterfaceOptions |= STGM_WRITE;
  373. // IStream requested for a property
  374. hr = ECAllocateBuffer(sizeof(SPropValue), &~lpsPropValue);
  375. if (hr != hrSuccess)
  376. return hr;
  377. // Yank the property in from disk if it wasn't loaded yet
  378. HrLoadProp(ulPropTag);
  379. // For MAPI_CREATE, reset (or create) the property now
  380. if (ulFlags & MAPI_CREATE) {
  381. if (!this->fModify)
  382. return MAPI_E_NO_ACCESS;
  383. SPropValue sProp;
  384. sProp.ulPropTag = ulPropTag;
  385. if (PROP_TYPE(ulPropTag) == PT_BINARY) {
  386. sProp.Value.bin.cb = 0;
  387. sProp.Value.bin.lpb = NULL;
  388. } else {
  389. // Handles lpszA and lpszW since they are the same field in the union
  390. sProp.Value.lpszW = const_cast<wchar_t *>(L"");
  391. }
  392. hr = HrSetRealProp(&sProp);
  393. if (hr != hrSuccess)
  394. return hr;
  395. }
  396. hr = HrGetRealProp(ulPropTag, ulFlags, lpsPropValue, lpsPropValue);
  397. if (hr != hrSuccess)
  398. // Promote warnings from GetProps to error
  399. return MAPI_E_NOT_FOUND;
  400. lpStreamData = new STREAMDATA; // is freed by HrStreamCleanup, called by ECMemStream on refcount == 0
  401. lpStreamData->ulPropTag = ulPropTag;
  402. lpStreamData->lpProp = this;
  403. if (ulFlags & MAPI_CREATE) {
  404. hr = ECMemStream::Create(NULL, 0, ulInterfaceOptions,
  405. ECMAPIProp::HrStreamCommit, ECMAPIProp::HrStreamCleanup, (void *)lpStreamData, &lpStream);
  406. } else {
  407. switch (PROP_TYPE(lpsPropValue->ulPropTag)) {
  408. case PT_STRING8:
  409. hr = ECMemStream::Create(lpsPropValue->Value.lpszA, strlen(lpsPropValue->Value.lpszA), ulInterfaceOptions,
  410. ECMAPIProp::HrStreamCommit, ECMAPIProp::HrStreamCleanup, (void *)lpStreamData, &lpStream);
  411. break;
  412. case PT_UNICODE:
  413. hr = ECMemStream::Create((char*)lpsPropValue->Value.lpszW, wcslen(lpsPropValue->Value.lpszW)*sizeof(WCHAR), ulInterfaceOptions,
  414. ECMAPIProp::HrStreamCommit, ECMAPIProp::HrStreamCleanup, (void *)lpStreamData, &lpStream);
  415. break;
  416. case PT_BINARY:
  417. hr = ECMemStream::Create((char *)lpsPropValue->Value.bin.lpb, lpsPropValue->Value.bin.cb, ulInterfaceOptions,
  418. ECMAPIProp::HrStreamCommit, ECMAPIProp::HrStreamCleanup, (void *)lpStreamData, &lpStream);
  419. break;
  420. default:
  421. assert(false);
  422. hr = MAPI_E_NOT_FOUND;
  423. delete lpStreamData;
  424. break;
  425. }
  426. }
  427. if (hr != hrSuccess)
  428. return hr;
  429. if (*lpiid == IID_IStorage) { //*lpiid == IID_IStreamDocfile ||
  430. //FIXME: Unknown what to do with flag STGSTRM_CURRENT
  431. hr = GetMsgStore()->lpSupport->IStorageFromStream((LPUNKNOWN)&lpStream->m_xStream, NULL, ((ulFlags &MAPI_MODIFY)?STGSTRM_MODIFY : 0) | ((ulFlags & MAPI_CREATE)?STGSTRM_CREATE:0), (LPSTORAGE*)lppUnk);
  432. if (hr != hrSuccess)
  433. return hr;
  434. } else
  435. hr = lpStream->QueryInterface(*lpiid, (void **)lppUnk);
  436. // Release our copy
  437. lpStream->Release();
  438. if(hr != hrSuccess)
  439. return hr;
  440. AddChild(lpStream);
  441. return hrSuccess;
  442. }
  443. HRESULT ECMAPIProp::SaveChanges(ULONG ulFlags)
  444. {
  445. HRESULT hr = hrSuccess;
  446. object_ptr<WSMAPIPropStorage> lpMAPIPropStorage;
  447. if (lpStorage == nullptr)
  448. return MAPI_E_NOT_FOUND;
  449. if (!fModify)
  450. return MAPI_E_NO_ACCESS;
  451. // only folders and main messages have a syncid, attachments and msg-in-msg don't
  452. if (lpStorage->QueryInterface(IID_WSMAPIPropStorage, &~lpMAPIPropStorage) == hrSuccess) {
  453. hr = lpMAPIPropStorage->HrSetSyncId(m_ulSyncId);
  454. if(hr != hrSuccess)
  455. return hr;
  456. }
  457. return ECGenericProp::SaveChanges(ulFlags);
  458. }
  459. HRESULT ECMAPIProp::HrSaveChild(ULONG ulFlags, MAPIOBJECT *lpsMapiObject) {
  460. // ECMessage implements saving an attachment
  461. // ECAttach implements saving a sub-message
  462. return MAPI_E_INVALID_OBJECT;
  463. }
  464. HRESULT ECMAPIProp::GetSerializedACLData(LPVOID lpBase, LPSPropValue lpsPropValue)
  465. {
  466. HRESULT hr = hrSuccess;
  467. ECSecurityPtr ptrSecurity;
  468. ULONG cPerms = 0;
  469. ECPermissionPtr ptrPerms;
  470. struct soap soap;
  471. std::ostringstream os;
  472. struct rightsArray rights;
  473. std::string strAclData;
  474. hr = QueryInterface(IID_IECSecurity, &~ptrSecurity);
  475. if (hr != hrSuccess)
  476. goto exit;
  477. hr = ptrSecurity->GetPermissionRules(ACCESS_TYPE_GRANT, &cPerms, &~ptrPerms);
  478. if (hr != hrSuccess)
  479. goto exit;
  480. rights.__size = cPerms;
  481. rights.__ptr = s_alloc<struct rights>(&soap, cPerms);
  482. std::transform(ptrPerms.get(), ptrPerms + cPerms, rights.__ptr, &ECPermToRightsCheap);
  483. soap_set_omode(&soap, SOAP_C_UTFSTRING);
  484. soap_begin(&soap);
  485. soap.os = &os;
  486. soap_serialize_rightsArray(&soap, &rights);
  487. soap_begin_send(&soap);
  488. soap_put_rightsArray(&soap, &rights, "rights", "rightsArray");
  489. soap_end_send(&soap);
  490. strAclData = os.str();
  491. lpsPropValue->Value.bin.cb = strAclData.size();
  492. hr = MAPIAllocateMore(lpsPropValue->Value.bin.cb, lpBase, (LPVOID*)&lpsPropValue->Value.bin.lpb);
  493. if (hr != hrSuccess)
  494. goto exit;
  495. memcpy(lpsPropValue->Value.bin.lpb, strAclData.data(), lpsPropValue->Value.bin.cb);
  496. exit:
  497. soap_destroy(&soap);
  498. soap_end(&soap); // clean up allocated temporaries
  499. return hr;
  500. }
  501. HRESULT ECMAPIProp::SetSerializedACLData(const SPropValue *lpsPropValue)
  502. {
  503. HRESULT hr = hrSuccess;
  504. ECPermissionPtr ptrPerms;
  505. struct soap soap;
  506. struct rightsArray rights;
  507. std::string strAclData;
  508. if (lpsPropValue == NULL || PROP_TYPE(lpsPropValue->ulPropTag) != PT_BINARY) {
  509. hr = MAPI_E_INVALID_PARAMETER;
  510. goto exit;
  511. }
  512. {
  513. std::istringstream is(std::string((char*)lpsPropValue->Value.bin.lpb, lpsPropValue->Value.bin.cb));
  514. soap.is = &is;
  515. soap_set_imode(&soap, SOAP_C_UTFSTRING);
  516. soap_begin(&soap);
  517. if (soap_begin_recv(&soap) != 0) {
  518. hr = MAPI_E_NETWORK_FAILURE;
  519. goto exit;
  520. }
  521. if (!soap_get_rightsArray(&soap, &rights, "rights", "rightsArray")) {
  522. hr = MAPI_E_CORRUPT_DATA;
  523. goto exit;
  524. }
  525. if (soap_end_recv(&soap) != 0) {
  526. hr = MAPI_E_NETWORK_ERROR;
  527. goto exit;
  528. }
  529. }
  530. hr = MAPIAllocateBuffer(rights.__size * sizeof(ECPERMISSION), &~ptrPerms);
  531. if (hr != hrSuccess)
  532. goto exit;
  533. std::transform(rights.__ptr, rights.__ptr + rights.__size, ptrPerms.get(), &RightsToECPermCheap);
  534. hr = UpdateACLs(rights.__size, ptrPerms);
  535. exit:
  536. soap_destroy(&soap);
  537. soap_end(&soap); // clean up allocated temporaries
  538. return hr;
  539. }
  540. HRESULT ECMAPIProp::UpdateACLs(ULONG cNewPerms, ECPERMISSION *lpNewPerms)
  541. {
  542. HRESULT hr;
  543. ECSecurityPtr ptrSecurity;
  544. ULONG cPerms = 0;
  545. ECPermissionArrayPtr ptrPerms;
  546. ULONG cSparePerms = 0;
  547. ECPermissionPtr ptrTmpPerms;
  548. ECPERMISSION *lpPermissions = NULL;
  549. hr = QueryInterface(IID_IECSecurity, &~ptrSecurity);
  550. if (hr != hrSuccess)
  551. return hr;
  552. hr = ptrSecurity->GetPermissionRules(ACCESS_TYPE_GRANT, &cPerms, &~ptrPerms);
  553. if (hr != hrSuccess)
  554. return hr;
  555. // Since we want to replace the current ACL with a new one, we need to mark
  556. // each existing item as deleted, and add all new ones as new.
  557. // But there can also be overlap, where some items are left unchanged, and
  558. // other modified.
  559. for (ULONG i = 0; i < cPerms; ++i) {
  560. ECPERMISSION *lpMatch = std::find_if(lpNewPerms, lpNewPerms + cNewPerms, FindUser(ptrPerms[i].sUserId));
  561. if (lpMatch == lpNewPerms + cNewPerms) {
  562. // Not in new set, so delete
  563. ptrPerms[i].ulState = RIGHT_DELETED;
  564. continue;
  565. }
  566. // Found an entry in the new set, check if it's different
  567. if (ptrPerms[i].ulRights == lpMatch->ulRights &&
  568. ptrPerms[i].ulType == lpMatch->ulType)
  569. {
  570. // Nothing changes, remove from set.
  571. if (i < (cPerms - 1))
  572. std::swap(ptrPerms[i], ptrPerms[cPerms - 1]);
  573. --cPerms;
  574. --i;
  575. ++cSparePerms;
  576. } else {
  577. ptrPerms[i].ulRights = lpMatch->ulRights;
  578. ptrPerms[i].ulType = lpMatch->ulType;
  579. ptrPerms[i].ulState = RIGHT_MODIFY;
  580. }
  581. // Remove from list of new permissions
  582. if (lpMatch != &lpNewPerms[cNewPerms - 1])
  583. std::swap(*lpMatch, lpNewPerms[cNewPerms - 1]);
  584. --cNewPerms;
  585. }
  586. // Now see if there are still some new ACL's left. If enough spare space is available
  587. // we'll reuse the ptrPerms storage. If not we'll reallocate the whole array.
  588. lpPermissions = ptrPerms.get();
  589. if (cNewPerms > 0) {
  590. if (cNewPerms <= cSparePerms) {
  591. memcpy(&ptrPerms[cPerms], lpNewPerms, cNewPerms * sizeof(ECPERMISSION));
  592. } else if (cPerms == 0) {
  593. lpPermissions = lpNewPerms;
  594. } else {
  595. hr = MAPIAllocateBuffer((cPerms + cNewPerms) * sizeof(ECPERMISSION), &~ptrTmpPerms);
  596. if (hr != hrSuccess)
  597. return hr;
  598. memcpy(ptrTmpPerms, ptrPerms, cPerms * sizeof(ECPERMISSION));
  599. memcpy(ptrTmpPerms + cPerms, lpNewPerms, cNewPerms * sizeof(ECPERMISSION));
  600. lpPermissions = ptrTmpPerms;
  601. }
  602. }
  603. if (cPerms + cNewPerms > 0)
  604. hr = ptrSecurity->SetPermissionRules(cPerms + cNewPerms, lpPermissions);
  605. return hrSuccess;
  606. }
  607. HRESULT ECMAPIProp::CopyTo(ULONG ciidExclude, LPCIID rgiidExclude,
  608. const SPropTagArray *lpExcludeProps, ULONG ulUIParam,
  609. LPMAPIPROGRESS lpProgress, LPCIID lpInterface, void *lpDestObj,
  610. ULONG ulFlags, SPropProblemArray **lppProblems)
  611. {
  612. return Util::DoCopyTo(&IID_IMAPIProp, &this->m_xMAPIProp, ciidExclude, rgiidExclude, lpExcludeProps, ulUIParam, lpProgress, lpInterface, lpDestObj, ulFlags, lppProblems);
  613. }
  614. HRESULT ECMAPIProp::CopyProps(const SPropTagArray *lpIncludeProps,
  615. ULONG ulUIParam, LPMAPIPROGRESS lpProgress, LPCIID lpInterface,
  616. void *lpDestObj, ULONG ulFlags, SPropProblemArray **lppProblems)
  617. {
  618. return Util::DoCopyProps(&IID_IMAPIProp, &this->m_xMAPIProp, lpIncludeProps, ulUIParam, lpProgress, lpInterface, lpDestObj, ulFlags, lppProblems);
  619. }
  620. // Pass call off to lpMsgStore
  621. HRESULT ECMAPIProp::GetNamesFromIDs(LPSPropTagArray *lppPropTags, LPGUID lpPropSetGuid, ULONG ulFlags, ULONG *lpcPropNames, LPMAPINAMEID **lpppPropNames)
  622. {
  623. return this->GetMsgStore()->lpNamedProp->GetNamesFromIDs(lppPropTags, lpPropSetGuid, ulFlags, lpcPropNames, lpppPropNames);
  624. }
  625. HRESULT ECMAPIProp::GetIDsFromNames(ULONG cPropNames, LPMAPINAMEID *lppPropNames, ULONG ulFlags, LPSPropTagArray *lppPropTags)
  626. {
  627. return this->GetMsgStore()->lpNamedProp->GetIDsFromNames(cPropNames, lppPropNames, ulFlags, lppPropTags);
  628. }
  629. // Stream functions
  630. HRESULT ECMAPIProp::HrStreamCommit(IStream *lpStream, void *lpData)
  631. {
  632. HRESULT hr = hrSuccess;
  633. auto lpStreamData = static_cast<STREAMDATA *>(lpData);
  634. char *buffer = NULL;
  635. ecmem_ptr<SPropValue> lpPropValue;
  636. STATSTG sStat;
  637. ULONG ulSize = 0;
  638. object_ptr<ECMemStream> lpECStream;
  639. hr = ECAllocateBuffer(sizeof(SPropValue), &~lpPropValue);
  640. if(hr != hrSuccess)
  641. return hr;
  642. hr = lpStream->Stat(&sStat, 0);
  643. if(hr != hrSuccess)
  644. return hr;
  645. if(PROP_TYPE(lpStreamData->ulPropTag) == PT_STRING8) {
  646. hr = ECAllocateMore((ULONG)sStat.cbSize.QuadPart+1, lpPropValue, (void **)&buffer);
  647. if(hr != hrSuccess)
  648. return hr;
  649. // read the data into the buffer
  650. hr = lpStream->Read(buffer, (ULONG)sStat.cbSize.QuadPart, &ulSize);
  651. } else if(PROP_TYPE(lpStreamData->ulPropTag) == PT_UNICODE) {
  652. hr = ECAllocateMore((ULONG)sStat.cbSize.QuadPart+sizeof(WCHAR), lpPropValue, (void **)&buffer);
  653. if(hr != hrSuccess)
  654. return hr;
  655. // read the data into the buffer
  656. hr = lpStream->Read(buffer, (ULONG)sStat.cbSize.QuadPart, &ulSize);
  657. } else{
  658. hr = lpStream->QueryInterface(IID_ECMemStream, &~lpECStream);
  659. if(hr != hrSuccess)
  660. return hr;
  661. ulSize = (ULONG)sStat.cbSize.QuadPart;
  662. buffer = lpECStream->GetBuffer();
  663. }
  664. lpPropValue->ulPropTag = lpStreamData->ulPropTag;
  665. switch(PROP_TYPE(lpStreamData->ulPropTag)) {
  666. case PT_STRING8:
  667. buffer[ulSize] = 0;
  668. lpPropValue->Value.lpszA = buffer;
  669. break;
  670. case PT_UNICODE:
  671. memset(&buffer[ulSize], 0, sizeof(wchar_t));
  672. lpPropValue->Value.lpszW = (WCHAR *)buffer;
  673. break;
  674. case PT_BINARY:
  675. lpPropValue->Value.bin.cb = ulSize;
  676. lpPropValue->Value.bin.lpb = (unsigned char *)buffer;
  677. break;
  678. }
  679. hr = lpStreamData->lpProp->HrSetRealProp(lpPropValue);
  680. if (hr != hrSuccess)
  681. return hr;
  682. // on a non transacted object SaveChanges is required
  683. if (!lpStreamData->lpProp->isTransactedObject)
  684. hr = lpStreamData->lpProp->ECGenericProp::SaveChanges(KEEP_OPEN_READWRITE);
  685. return hr;
  686. }
  687. HRESULT ECMAPIProp::HrStreamCleanup(void *lpData)
  688. {
  689. delete static_cast<STREAMDATA *>(lpData);
  690. return hrSuccess;
  691. }
  692. HRESULT ECMAPIProp::HrSetSyncId(ULONG ulSyncId)
  693. {
  694. HRESULT hr = hrSuccess;
  695. object_ptr<WSMAPIPropStorage> lpMAPIPropStorage;
  696. if (lpStorage != nullptr && lpStorage->QueryInterface(IID_WSMAPIPropStorage, &~lpMAPIPropStorage) == hrSuccess) {
  697. hr = lpMAPIPropStorage->HrSetSyncId(ulSyncId);
  698. if(hr != hrSuccess)
  699. return hr;
  700. }
  701. m_ulSyncId = ulSyncId;
  702. return hrSuccess;
  703. }
  704. // Security functions
  705. HRESULT ECMAPIProp::GetPermissionRules(int ulType, ULONG *lpcPermissions,
  706. ECPERMISSION **lppECPermissions)
  707. {
  708. if (m_lpEntryId == NULL)
  709. return MAPI_E_NO_ACCESS;
  710. return this->GetMsgStore()->lpTransport->HrGetPermissionRules(ulType, m_cbEntryId, m_lpEntryId, lpcPermissions, lppECPermissions);
  711. }
  712. HRESULT ECMAPIProp::SetPermissionRules(ULONG cPermissions,
  713. ECPERMISSION *lpECPermissions)
  714. {
  715. if (m_lpEntryId == NULL)
  716. return MAPI_E_NO_ACCESS;
  717. return this->GetMsgStore()->lpTransport->HrSetPermissionRules(m_cbEntryId, m_lpEntryId, cPermissions, lpECPermissions);
  718. }
  719. HRESULT ECMAPIProp::GetOwner(ULONG *lpcbOwner, LPENTRYID *lppOwner)
  720. {
  721. if (lpcbOwner == NULL || lppOwner == NULL)
  722. return MAPI_E_INVALID_PARAMETER;
  723. if (m_lpEntryId == NULL)
  724. return MAPI_E_NO_ACCESS;
  725. return GetMsgStore()->lpTransport->HrGetOwner(m_cbEntryId, m_lpEntryId, lpcbOwner, lppOwner);
  726. }
  727. HRESULT ECMAPIProp::GetUserList(ULONG cbCompanyId, LPENTRYID lpCompanyId,
  728. ULONG ulFlags, ULONG *lpcUsers, ECUSER **lppsUsers)
  729. {
  730. return GetMsgStore()->lpTransport->HrGetUserList(cbCompanyId, lpCompanyId, ulFlags, lpcUsers, lppsUsers);
  731. }
  732. HRESULT ECMAPIProp::GetGroupList(ULONG cbCompanyId, LPENTRYID lpCompanyId,
  733. ULONG ulFlags, ULONG *lpcGroups, ECGROUP **lppsGroups)
  734. {
  735. return GetMsgStore()->lpTransport->HrGetGroupList(cbCompanyId, lpCompanyId, ulFlags, lpcGroups, lppsGroups);
  736. }
  737. HRESULT ECMAPIProp::GetCompanyList(ULONG ulFlags, ULONG *lpcCompanies,
  738. ECCOMPANY **lppsCompanies)
  739. {
  740. return GetMsgStore()->lpTransport->HrGetCompanyList(ulFlags, lpcCompanies, lppsCompanies);
  741. }
  742. HRESULT ECMAPIProp::SetParentID(ULONG cbParentID, LPENTRYID lpParentID)
  743. {
  744. HRESULT hr;
  745. assert(m_lpParentID == NULL);
  746. if (lpParentID == NULL || cbParentID == 0)
  747. return MAPI_E_INVALID_PARAMETER;
  748. hr = MAPIAllocateBuffer(cbParentID, (void**)&m_lpParentID);
  749. if (hr != hrSuccess)
  750. return hr;
  751. m_cbParentID = cbParentID;
  752. memcpy(m_lpParentID, lpParentID, cbParentID);
  753. return hrSuccess;
  754. }
  755. // Interface IMAPIProp
  756. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  757. DEF_ULONGMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, AddRef, (void))
  758. DEF_ULONGMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, Release, (void))
  759. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, GetLastError, (HRESULT, hError), (ULONG, ulFlags), (LPMAPIERROR *, lppMapiError))
  760. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, SaveChanges, (ULONG, ulFlags))
  761. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, GetProps, (const SPropTagArray *, lpPropTagArray), (ULONG, ulFlags), (ULONG *, lpcValues), (SPropValue **, lppPropArray))
  762. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, GetPropList, (ULONG, ulFlags), (LPSPropTagArray *, lppPropTagArray))
  763. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, OpenProperty, (ULONG, ulPropTag), (LPCIID, lpiid), (ULONG, ulInterfaceOptions), (ULONG, ulFlags), (LPUNKNOWN *, lppUnk))
  764. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, SetProps, (ULONG, cValues), (const SPropValue *, lpPropArray), (SPropProblemArray **, lppProblems))
  765. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, DeleteProps, (const SPropTagArray *, lpPropTagArray), (SPropProblemArray **, lppProblems))
  766. 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))
  767. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, CopyProps, (const SPropTagArray *, lpIncludeProps), (ULONG, ulUIParam), (LPMAPIPROGRESS, lpProgress), (LPCIID, lpInterface), (void *, lpDestObj), (ULONG, ulFlags), (SPropProblemArray **, lppProblems))
  768. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, GetNamesFromIDs, (LPSPropTagArray *, pptaga), (LPGUID, lpguid), (ULONG, ulFlags), (ULONG *, pcNames), (LPMAPINAMEID **, pppNames))
  769. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, MAPIProp, GetIDsFromNames, (ULONG, cNames), (LPMAPINAMEID *, ppNames), (ULONG, ulFlags), (LPSPropTagArray *, pptaga))
  770. // Interface ECSecurity
  771. DEF_HRMETHOD0(ECMAPIProp, ECSecurity, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  772. DEF_ULONGMETHOD0(ECMAPIProp, ECSecurity, AddRef, (void))
  773. DEF_ULONGMETHOD0(ECMAPIProp, ECSecurity, Release, (void))
  774. DEF_HRMETHOD0(ECMAPIProp, ECSecurity, GetOwner, (ULONG *, lpcbOwner), (LPENTRYID *, lppOwner))
  775. DEF_HRMETHOD0(ECMAPIProp, ECSecurity, GetUserList, (ULONG, cbCompanyId), (LPENTRYID, lpCompanyId), (ULONG, ulFlags), (ULONG *, lpcUsers), (ECUSER **, lpsUsers))
  776. DEF_HRMETHOD0(ECMAPIProp, ECSecurity, GetGroupList, (ULONG, cbCompanyId), (LPENTRYID, lpCompanyId), (ULONG, ulFlags), (ULONG *, lpcGroups), (ECGROUP **, lppsGroups))
  777. DEF_HRMETHOD0(ECMAPIProp, ECSecurity, GetCompanyList, (ULONG, ulFlags), (ULONG *, lpcCompanies), (ECCOMPANY **, lppsCompanies))
  778. DEF_HRMETHOD0(ECMAPIProp, ECSecurity, GetPermissionRules, (int, ulType), (ULONG *, lpcPermissions), (ECPERMISSION **, lppECPermissions))
  779. DEF_HRMETHOD1(TRACE_MAPI, ECMAPIProp, ECSecurity, SetPermissionRules, (ULONG, cPermissions), (ECPERMISSION *, lpECPermissions))