ECGenericProp.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  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/lockhelper.hpp>
  19. #include <kopano/memory.hpp>
  20. #include <kopano/ECInterfaceDefs.h>
  21. #include <mapidefs.h>
  22. #include "WSTransport.h"
  23. #include "ECGenericProp.h"
  24. #include "kcore.hpp"
  25. #include "pcutil.hpp"
  26. #include "Mem.h"
  27. #include <kopano/Util.h>
  28. #include <kopano/ECGuid.h>
  29. #include <kopano/ECDebug.h>
  30. #include <kopano/charset/convert.h>
  31. #include "EntryPoint.h"
  32. ECGenericProp::ECGenericProp(void *lpProvider, ULONG ulObjType, BOOL fModify,
  33. const char *szClassName) :
  34. ECUnknown(szClassName)
  35. {
  36. this->ulObjType = ulObjType;
  37. this->fModify = fModify;
  38. this->lpProvider = lpProvider;
  39. this->HrAddPropHandlers(PR_EC_OBJECT, DefaultGetProp, DefaultSetPropComputed, (void*) this, FALSE, TRUE);
  40. this->HrAddPropHandlers(PR_NULL, DefaultGetProp, DefaultSetPropIgnore, (void*) this, FALSE, TRUE);
  41. this->HrAddPropHandlers(PR_OBJECT_TYPE, DefaultGetProp, DefaultSetPropComputed, (void*) this);
  42. this->HrAddPropHandlers(PR_ENTRYID, DefaultGetProp, DefaultSetPropComputed, (void*) this);
  43. }
  44. ECGenericProp::~ECGenericProp()
  45. {
  46. if (m_sMapiObject)
  47. FreeMapiObject(m_sMapiObject);
  48. if(lstProps) {
  49. for (auto &i : *lstProps)
  50. i.second.DeleteProperty();
  51. delete lstProps;
  52. }
  53. if(lpStorage)
  54. lpStorage->Release();
  55. MAPIFreeBuffer(m_lpEntryId);
  56. }
  57. HRESULT ECGenericProp::QueryInterface(REFIID refiid, void **lppInterface)
  58. {
  59. REGISTER_INTERFACE2(ECUnknown, this);
  60. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  61. }
  62. HRESULT ECGenericProp::SetProvider(void* lpProvider)
  63. {
  64. HRESULT hr = hrSuccess;
  65. assert(this->lpProvider == NULL);
  66. this->lpProvider = lpProvider;
  67. return hr;
  68. }
  69. HRESULT ECGenericProp::SetEntryId(ULONG cbEntryId, LPENTRYID lpEntryId)
  70. {
  71. assert(m_lpEntryId == NULL);
  72. return Util::HrCopyEntryId(cbEntryId, lpEntryId, &m_cbEntryId, &m_lpEntryId);
  73. }
  74. // Add a property handler. Usually called by a subclass
  75. HRESULT ECGenericProp::HrAddPropHandlers(ULONG ulPropTag, GetPropCallBack lpfnGetProp, SetPropCallBack lpfnSetProp, void *lpParam, BOOL fRemovable, BOOL fHidden)
  76. {
  77. HRESULT hr = hrSuccess;
  78. ECPropCallBackIterator iterCallBack;
  79. PROPCALLBACK sCallBack;
  80. // Check if the handler defines the right type, If Unicode you should never define a PT_STRING8 as handler!
  81. assert(PROP_TYPE(ulPropTag) == PT_STRING8 ||
  82. PROP_TYPE(ulPropTag) == PT_UNICODE ?
  83. PROP_TYPE(ulPropTag) == PT_TSTRING : true);
  84. // Only Support properties on ID, different types are not supported.
  85. iterCallBack = lstCallBack.find(PROP_ID(ulPropTag));
  86. if(iterCallBack != lstCallBack.end())
  87. lstCallBack.erase(iterCallBack);
  88. sCallBack.lpfnGetProp = lpfnGetProp;
  89. sCallBack.lpfnSetProp = lpfnSetProp;
  90. sCallBack.ulPropTag = ulPropTag;
  91. sCallBack.lpParam = lpParam;
  92. sCallBack.fRemovable = fRemovable;
  93. sCallBack.fHidden = fHidden;
  94. lstCallBack.insert(std::make_pair(PROP_ID(ulPropTag), sCallBack));
  95. dwLastError = hr;
  96. return hr;
  97. }
  98. // sets an actual value in memory
  99. HRESULT ECGenericProp::HrSetRealProp(const SPropValue *lpsPropValue)
  100. {
  101. HRESULT hr = hrSuccess;
  102. ECProperty* lpProperty = NULL;
  103. ECPropertyEntryIterator iterProps;
  104. ECPropertyEntryIterator iterPropsFound;
  105. ULONG ulPropId = 0;
  106. //FIXME: check the property structure -> lpsPropValue
  107. if (m_bLoading == FALSE && m_sMapiObject) {
  108. // Only reset instance id when we're being modified, not being reloaded
  109. HrSIEntryIDToID(m_sMapiObject->cbInstanceID, (LPBYTE)m_sMapiObject->lpInstanceID, NULL, NULL, (unsigned int *)&ulPropId);
  110. if (ulPropId == PROP_ID(lpsPropValue->ulPropTag))
  111. SetSingleInstanceId(0, NULL);
  112. }
  113. if(lstProps == NULL) {
  114. hr = HrLoadProps();
  115. if(hr != hrSuccess)
  116. goto exit;
  117. }
  118. iterPropsFound = lstProps->end();
  119. // Loop through all properties, get the first EXACT matching property, but delete ALL
  120. // other properties with this PROP_ID and the wrong type - this makes sure you can SetProps() with 0x60010003,
  121. // then with 0x60010102 and then with 0x60010040 for example.
  122. iterProps = lstProps->find(PROP_ID(lpsPropValue->ulPropTag));
  123. if (iterProps != lstProps->end()) {
  124. if (iterProps->second.GetPropTag() != lpsPropValue->ulPropTag) {
  125. // type is different, remove the property and insert a new item
  126. m_setDeletedProps.insert(lpsPropValue->ulPropTag);
  127. iterProps->second.DeleteProperty();
  128. lstProps->erase(iterProps);
  129. } else {
  130. iterPropsFound = iterProps;
  131. }
  132. }
  133. // Changing an existing property
  134. if(iterPropsFound != lstProps->end()) {
  135. iterPropsFound->second.HrSetProp(lpsPropValue);
  136. } else { // Add new property
  137. lpProperty = new ECProperty(lpsPropValue);
  138. if(lpProperty->GetLastError() != 0) {
  139. hr = lpProperty->GetLastError();
  140. goto exit;
  141. }
  142. ECPropertyEntry entry(lpProperty);
  143. lstProps->insert(std::make_pair(PROP_ID(lpsPropValue->ulPropTag), entry));
  144. }
  145. // Property is now added/modified and marked 'dirty' for saving
  146. exit:
  147. if (hr != hrSuccess)
  148. delete lpProperty;
  149. dwLastError = hr;
  150. return hr;
  151. }
  152. // Get an actual value from the property array and saves it to the given address. Any extra memory required
  153. // is allocated with MAPIAllocMore with lpBase as the base pointer
  154. //
  155. // Properties are always returned unless:
  156. //
  157. // 1) The underlying system didn't return them in the initial HrReadProps call, and as such are 'too large' and
  158. // the property has not been force-loaded with OpenProperty
  159. // or
  160. // 2) A MaxSize was specified and the property is larger than that size (normally 8k or so)
  161. HRESULT ECGenericProp::HrGetRealProp(ULONG ulPropTag, ULONG ulFlags, void *lpBase, LPSPropValue lpsPropValue, ULONG ulMaxSize)
  162. {
  163. HRESULT hr = hrSuccess;
  164. ECPropertyEntryIterator iterProps;
  165. if(lstProps == NULL || m_bReload == TRUE) {
  166. hr = HrLoadProps();
  167. if(hr != hrSuccess)
  168. goto exit;
  169. m_bReload = FALSE;
  170. }
  171. // Find the property in our list
  172. iterProps = lstProps->find(PROP_ID(ulPropTag));
  173. // Not found or property is not matching
  174. if(iterProps == lstProps->end() || !( PROP_TYPE(ulPropTag) == PT_UNSPECIFIED || PROP_TYPE(ulPropTag) == PROP_TYPE(iterProps->second.GetPropTag()) ||
  175. (((ulPropTag & MV_FLAG) == (iterProps->second.GetPropTag( ) & MV_FLAG)) && PROP_TYPE(ulPropTag&~MV_FLAG) == PT_STRING8 && PROP_TYPE(iterProps->second.GetPropTag()&~MV_FLAG) == PT_UNICODE) ))
  176. {
  177. lpsPropValue->ulPropTag = PROP_TAG(PT_ERROR,PROP_ID(ulPropTag));
  178. lpsPropValue->Value.err = MAPI_E_NOT_FOUND;
  179. hr = MAPI_W_ERRORS_RETURNED;
  180. goto exit;
  181. }
  182. if(!iterProps->second.FIsLoaded()) {
  183. lpsPropValue->ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(ulPropTag));
  184. lpsPropValue->Value.err = MAPI_E_NOT_ENOUGH_MEMORY;
  185. hr = MAPI_W_ERRORS_RETURNED;
  186. goto exit;
  187. // The load should have loaded into the value pointed to by iterProps, so we can use that now
  188. }
  189. // Check if a max. size was requested, if so, dont return unless smaller than max. size
  190. if (ulMaxSize != 0 && iterProps->second.GetProperty()->GetSize() > ulMaxSize) {
  191. lpsPropValue->ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(ulPropTag));
  192. lpsPropValue->Value.err = MAPI_E_NOT_ENOUGH_MEMORY;
  193. hr = MAPI_W_ERRORS_RETURNED;
  194. goto exit;
  195. }
  196. if (PROP_TYPE(ulPropTag) == PT_UNSPECIFIED) {
  197. if (PROP_TYPE(iterProps->second.GetPropTag()) == PT_UNICODE)
  198. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, ((ulFlags & MAPI_UNICODE) ? PT_UNICODE : PT_STRING8));
  199. else if (PROP_TYPE(iterProps->second.GetPropTag()) == PT_MV_UNICODE)
  200. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, ((ulFlags & MAPI_UNICODE) ? PT_MV_UNICODE : PT_MV_STRING8));
  201. else
  202. ulPropTag = iterProps->second.GetPropTag();
  203. }
  204. // Copy the property to its final destination, with base pointer for extra allocations, if required.
  205. iterProps->second.GetProperty()->CopyTo(lpsPropValue, lpBase, ulPropTag);
  206. exit:
  207. dwLastError = hr;
  208. return hr;
  209. }
  210. /**
  211. * Deletes a property from the internal system
  212. *
  213. * @param ulPropTag The requested ulPropTag to remove. Property type is ignored; only the property identifier is used.
  214. * @param fOverwriteRO Set to TRUE if the object is to be modified eventhough it's read-only. Currently unused! @todo parameter should be removed.
  215. *
  216. * @return MAPI error code
  217. * @retval hrSuccess PropTag is set to be removed during the next SaveChanges call
  218. * @retval MAPI_E_NOT_FOUND The PropTag is not found in the list (can be type mismatch too)
  219. */
  220. HRESULT ECGenericProp::HrDeleteRealProp(ULONG ulPropTag, BOOL fOverwriteRO)
  221. {
  222. HRESULT hr = hrSuccess;
  223. ECPropertyEntryIterator iterProps;
  224. if(lstProps == NULL) {
  225. hr = HrLoadProps();
  226. if(hr != hrSuccess)
  227. goto exit;
  228. }
  229. // Now find the real value
  230. iterProps = lstProps->find(PROP_ID(ulPropTag));
  231. if(iterProps == lstProps->end()) {
  232. // Couldn't find it!
  233. hr = MAPI_E_NOT_FOUND;
  234. goto exit;
  235. }
  236. m_setDeletedProps.insert(iterProps->second.GetPropTag());
  237. iterProps->second.DeleteProperty();
  238. lstProps->erase(iterProps);
  239. exit:
  240. dwLastError = hr;
  241. return hr;
  242. }
  243. // Default property handles
  244. HRESULT ECGenericProp::DefaultGetProp(ULONG ulPropTag, void* lpProvider, ULONG ulFlags, LPSPropValue lpsPropValue, void *lpParam, void *lpBase)
  245. {
  246. HRESULT hr = hrSuccess;
  247. auto lpProp = static_cast<ECGenericProp *>(lpParam);
  248. switch(PROP_ID(ulPropTag))
  249. {
  250. case PROP_ID(PR_ENTRYID):
  251. if (lpProp->m_cbEntryId == 0)
  252. return MAPI_E_NOT_FOUND;
  253. lpsPropValue->ulPropTag = PR_ENTRYID;
  254. lpsPropValue->Value.bin.cb = lpProp->m_cbEntryId;
  255. if (lpBase == NULL)
  256. assert(false);
  257. hr = ECAllocateMore(lpProp->m_cbEntryId, lpBase, reinterpret_cast<void **>(&lpsPropValue->Value.bin.lpb));
  258. if (hr != hrSuccess)
  259. return hr;
  260. memcpy(lpsPropValue->Value.bin.lpb, lpProp->m_lpEntryId, lpProp->m_cbEntryId);
  261. break;
  262. // Gives access to the actual ECUnknown underlying object
  263. case PROP_ID(PR_EC_OBJECT):
  264. /*
  265. * NOTE: we place the object pointer in lpszA to make sure it
  266. * is on the same offset as Value.x on 32-bit as 64-bit
  267. * machines.
  268. */
  269. lpsPropValue->ulPropTag = PR_EC_OBJECT;
  270. lpsPropValue->Value.lpszA = reinterpret_cast<char *>(static_cast<IECUnknown *>(lpProp));
  271. break;
  272. case PROP_ID(PR_NULL):
  273. // outlook with export contacts to csv (IMessage)(0x00000000) <- skip this one
  274. // Palm used PR_NULL (IMAPIFolder)(0x00000001)
  275. if (ulPropTag != PR_NULL)
  276. return MAPI_E_NOT_FOUND;
  277. lpsPropValue->ulPropTag = PR_NULL;
  278. memset(&lpsPropValue->Value, 0, sizeof(lpsPropValue->Value)); // make sure all bits, 32 or 64, are 0
  279. break;
  280. case PROP_ID(PR_OBJECT_TYPE):
  281. lpsPropValue->Value.l = lpProp->ulObjType;
  282. lpsPropValue->ulPropTag = PR_OBJECT_TYPE;
  283. break;
  284. default:
  285. return lpProp->HrGetRealProp(ulPropTag, ulFlags, lpBase, lpsPropValue);
  286. }
  287. return hr;
  288. }
  289. HRESULT ECGenericProp::DefaultGetPropGetReal(ULONG ulPropTag, void* lpProvider, ULONG ulFlags, LPSPropValue lpsPropValue, void *lpParam, void *lpBase)
  290. {
  291. auto lpProp = static_cast<ECGenericProp *>(lpParam);
  292. return lpProp->HrGetRealProp(ulPropTag, ulFlags, lpBase, lpsPropValue, lpProp->m_ulMaxPropSize);
  293. }
  294. HRESULT ECGenericProp::DefaultGetPropNotFound(ULONG ulPropTag, void* lpProvider, ULONG ulFlags, LPSPropValue lpsPropValue, void *lpParam, void *lpBase)
  295. {
  296. return MAPI_E_NOT_FOUND;
  297. }
  298. HRESULT ECGenericProp::DefaultSetPropSetReal(ULONG ulPropTag, void *lpProvider,
  299. const SPropValue *lpsPropValue, void *lpParam)
  300. {
  301. return static_cast<ECGenericProp *>(lpParam)->HrSetRealProp(lpsPropValue);
  302. }
  303. HRESULT ECGenericProp::DefaultSetPropComputed(ULONG tag, void *provider,
  304. const SPropValue *, void *)
  305. {
  306. return MAPI_E_COMPUTED;
  307. }
  308. HRESULT ECGenericProp::DefaultSetPropIgnore(ULONG tag, void *provider,
  309. const SPropValue *, void *)
  310. {
  311. return hrSuccess;
  312. }
  313. HRESULT ECGenericProp::TableRowGetProp(void* lpProvider, struct propVal *lpsPropValSrc, LPSPropValue lpsPropValDst, void **lpBase, ULONG ulType)
  314. {
  315. HRESULT hr = hrSuccess;
  316. switch(lpsPropValSrc->ulPropTag) {
  317. case PROP_TAG(PT_ERROR, PROP_ID(PR_NULL)):
  318. lpsPropValDst->Value.l = 0;
  319. lpsPropValDst->ulPropTag = PR_NULL;
  320. break;
  321. default:
  322. return MAPI_E_NOT_FOUND;
  323. }
  324. return hr;
  325. }
  326. // Sets all the properties 'clean', ie. un-dirty
  327. HRESULT ECGenericProp::HrSetClean()
  328. {
  329. HRESULT hr = hrSuccess;
  330. ECPropertyEntryIterator iterProps;
  331. // also remove deleted marked properties, since the object isn't reloaded from the server anymore
  332. for (iterProps = lstProps->begin(); iterProps != lstProps->end(); ++iterProps)
  333. iterProps->second.HrSetClean();
  334. m_setDeletedProps.clear();
  335. return hr;
  336. }
  337. HRESULT ECGenericProp::HrSaveChild(ULONG ulFlags, MAPIOBJECT *lpsMapiObject)
  338. {
  339. // ECMessage implements saving an attachment
  340. // ECAttach implements saving a sub-message
  341. return MAPI_E_INVALID_OBJECT;
  342. }
  343. HRESULT ECGenericProp::HrRemoveModifications(MAPIOBJECT *lpsMapiObject, ULONG ulPropTag)
  344. {
  345. HRESULT hr = hrSuccess;
  346. lpsMapiObject->lstDeleted.remove(ulPropTag);
  347. for (auto iterProps = lpsMapiObject->lstModified.begin();
  348. iterProps != lpsMapiObject->lstModified.end(); ++iterProps)
  349. if(iterProps->GetPropTag() == ulPropTag) {
  350. lpsMapiObject->lstModified.erase(iterProps);
  351. break;
  352. }
  353. return hr;
  354. }
  355. HRESULT ECGenericProp::GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR *lppMAPIError)
  356. {
  357. HRESULT hr = hrSuccess;
  358. ecmem_ptr<MAPIERROR> lpMapiError;
  359. KCHL::memory_ptr<TCHAR> lpszErrorMsg;
  360. hr = Util::HrMAPIErrorToText((hResult == hrSuccess)?MAPI_E_NO_ACCESS : hResult, &~lpszErrorMsg);
  361. if (hr != hrSuccess)
  362. return hr;
  363. hr = ECAllocateBuffer(sizeof(MAPIERROR), &~lpMapiError);
  364. if(hr != hrSuccess)
  365. return hr;
  366. if (ulFlags & MAPI_UNICODE) {
  367. std::wstring wstrErrorMsg = convert_to<std::wstring>(lpszErrorMsg.get());
  368. std::wstring wstrCompName = convert_to<std::wstring>(g_strProductName.c_str());
  369. if ((hr = MAPIAllocateMore(sizeof(std::wstring::value_type) * (wstrErrorMsg.size() + 1), lpMapiError, (void**)&lpMapiError->lpszError)) != hrSuccess)
  370. return hr;
  371. wcscpy((wchar_t*)lpMapiError->lpszError, wstrErrorMsg.c_str());
  372. if ((hr = MAPIAllocateMore(sizeof(std::wstring::value_type) * (wstrCompName.size() + 1), lpMapiError, (void**)&lpMapiError->lpszComponent)) != hrSuccess)
  373. return hr;
  374. wcscpy((wchar_t*)lpMapiError->lpszComponent, wstrCompName.c_str());
  375. } else {
  376. std::string strErrorMsg = convert_to<std::string>(lpszErrorMsg.get());
  377. std::string strCompName = convert_to<std::string>(g_strProductName.c_str());
  378. if ((hr = MAPIAllocateMore(strErrorMsg.size() + 1, lpMapiError, (void**)&lpMapiError->lpszError)) != hrSuccess)
  379. return hr;
  380. strcpy((char*)lpMapiError->lpszError, strErrorMsg.c_str());
  381. if ((hr = MAPIAllocateMore(strCompName.size() + 1, lpMapiError, (void**)&lpMapiError->lpszComponent)) != hrSuccess)
  382. return hr;
  383. strcpy((char*)lpMapiError->lpszComponent, strCompName.c_str());
  384. }
  385. lpMapiError->ulContext = 0;
  386. lpMapiError->ulLowLevelError= 0;
  387. lpMapiError->ulVersion = 0;
  388. *lppMAPIError = lpMapiError.release();
  389. return hrSuccess;
  390. }
  391. // Differential save of changed properties
  392. HRESULT ECGenericProp::SaveChanges(ULONG ulFlags)
  393. {
  394. HRESULT hr = hrSuccess;
  395. scoped_rlock l_obj(m_hMutexMAPIObject);
  396. if (!fModify) {
  397. hr = MAPI_E_NO_ACCESS;
  398. goto exit;
  399. }
  400. if (!m_sMapiObject || !lstProps) {
  401. hr = MAPI_E_CALL_FAILED;
  402. goto exit;
  403. }
  404. // no props -> succeed (no changes made)
  405. if(lstProps->empty())
  406. goto exit;
  407. if(lpStorage == NULL) {
  408. // no way to save our properties !
  409. hr = MAPI_E_NO_ACCESS;
  410. goto exit;
  411. }
  412. // Note: m_sMapiObject->lstProperties and m_sMapiObject->lstAvailable are empty
  413. // here, because they are cleared after HrLoadProps and SaveChanges
  414. // save into m_sMapiObject
  415. for (auto l : m_setDeletedProps) {
  416. // Make sure the property is not present in deleted/modified list
  417. HrRemoveModifications(m_sMapiObject, l);
  418. m_sMapiObject->lstDeleted.push_back(l);
  419. }
  420. for (auto &p : *lstProps) {
  421. // Property is dirty, so we have to save it
  422. if (p.second.FIsDirty()) {
  423. // Save in the 'modified' list
  424. // Make sure the property is not present in deleted/modified list
  425. HrRemoveModifications(m_sMapiObject, p.second.GetPropTag());
  426. // Save modified property
  427. m_sMapiObject->lstModified.push_back(*p.second.GetProperty());
  428. // Save in the normal properties list
  429. m_sMapiObject->lstProperties.push_back(*p.second.GetProperty());
  430. continue;
  431. }
  432. // Normal property: either non-loaded or loaded
  433. if (!p.second.FIsLoaded()) // skip pt_error anyway
  434. m_sMapiObject->lstAvailable.push_back(p.second.GetPropTag());
  435. else
  436. m_sMapiObject->lstProperties.push_back(*p.second.GetProperty());
  437. }
  438. m_sMapiObject->bChanged = true;
  439. // Our s_MapiObject now contains its full property list in lstProperties and lstAvailable,
  440. // and its modifications in lstModified and lstDeleted.
  441. // save to parent or server
  442. hr = lpStorage->HrSaveObject(this->ulObjFlags, m_sMapiObject);
  443. if (hr != hrSuccess)
  444. goto exit;
  445. // HrSaveObject() has appended any new properties in lstAvailable and lstProperties. We need to load the
  446. // new properties. The easiest way to do this is to simply load all properties. Note that in embedded objects
  447. // that save to ECParentStorage, the object will be untouched. The code below will do nothing.
  448. // Large properties received
  449. for (auto tag : m_sMapiObject->lstAvailable) {
  450. // ONLY if not present
  451. auto ip = lstProps->find(PROP_ID(tag));
  452. if (ip == lstProps->cend() || ip->second.GetPropTag() != tag) {
  453. ECPropertyEntry entry(tag);
  454. lstProps->insert(std::make_pair(PROP_ID(tag), entry));
  455. }
  456. }
  457. m_sMapiObject->lstAvailable.clear();
  458. // Normal properties with value
  459. for (const auto &pv : m_sMapiObject->lstProperties)
  460. // don't add any 'error' types ... (the storage object shouldn't really give us these anyway ..)
  461. if (PROP_TYPE(pv.GetPropTag()) != PT_ERROR) {
  462. SPropValue tmp = pv.GetMAPIPropValRef();
  463. HrSetRealProp(&tmp);
  464. }
  465. // Note that we currently don't support the server removing properties after the SaveObject call
  466. // We have loaded all properties, so clear the properties in the m_sMapiObject
  467. m_sMapiObject->lstProperties.clear();
  468. m_sMapiObject->lstAvailable.clear();
  469. // We are now in sync with the server again, so set everything as clean
  470. HrSetClean();
  471. fSaved = true;
  472. exit:
  473. if (hr == hrSuccess)
  474. // Unless the user requests to continue with modify access, switch
  475. // down to read-only access. This means that specifying neither of
  476. // the KEEP_OPEN flags means the same thing as KEEP_OPEN_READONLY.
  477. if (!(ulFlags & (KEEP_OPEN_READWRITE|FORCE_SAVE)))
  478. fModify = FALSE;
  479. return hr;
  480. }
  481. // Check if property is dirty (delete properties gives MAPI_E_NOT_FOUND)
  482. HRESULT ECGenericProp::IsPropDirty(ULONG ulPropTag, BOOL *lpbDirty)
  483. {
  484. ECPropertyEntryIterator iterProps;
  485. iterProps = lstProps->find(PROP_ID(ulPropTag));
  486. if (iterProps == lstProps->end() || (PROP_TYPE(ulPropTag) != PT_UNSPECIFIED && ulPropTag != iterProps->second.GetPropTag()))
  487. return MAPI_E_NOT_FOUND;
  488. *lpbDirty = iterProps->second.FIsDirty();
  489. return hrSuccess;
  490. }
  491. /**
  492. * Clears the 'dirty' flag for a property
  493. *
  494. * This means that during a save the property will not be sent to the server. The dirty flag will be set
  495. * again after a HrSetRealProp() again.
  496. *
  497. * @param[in] ulPropTag Property to mark un-dirty
  498. * @result HRESULT
  499. */
  500. HRESULT ECGenericProp::HrSetCleanProperty(ULONG ulPropTag)
  501. {
  502. ECPropertyEntryIterator iterProps;
  503. iterProps = lstProps->find(PROP_ID(ulPropTag));
  504. if (iterProps == lstProps->end() || (PROP_TYPE(ulPropTag) != PT_UNSPECIFIED && ulPropTag != iterProps->second.GetPropTag()))
  505. return MAPI_E_NOT_FOUND;
  506. iterProps->second.HrSetClean();
  507. return hrSuccess;
  508. }
  509. // Get the handler(s) for a given property tag
  510. HRESULT ECGenericProp::HrGetHandler(ULONG ulPropTag, SetPropCallBack *lpfnSetProp, GetPropCallBack *lpfnGetProp, void **lpParam)
  511. {
  512. HRESULT hr = hrSuccess;
  513. ECPropCallBackIterator iterCallBack;
  514. iterCallBack = lstCallBack.find(PROP_ID(ulPropTag));
  515. if(iterCallBack == lstCallBack.end() ||
  516. (ulPropTag != iterCallBack->second.ulPropTag && PROP_TYPE(ulPropTag) != PT_UNSPECIFIED &&
  517. !(PROP_TYPE(iterCallBack->second.ulPropTag) == PT_TSTRING && (PROP_TYPE(ulPropTag) == PT_STRING8 || PROP_TYPE(ulPropTag) == PT_UNICODE) )
  518. ) ) {
  519. hr = MAPI_E_NOT_FOUND;
  520. goto exit;
  521. }
  522. if(lpfnSetProp)
  523. *lpfnSetProp = iterCallBack->second.lpfnSetProp;
  524. if(lpfnGetProp)
  525. *lpfnGetProp = iterCallBack->second.lpfnGetProp;
  526. if(lpParam)
  527. *lpParam = iterCallBack->second.lpParam;
  528. exit:
  529. dwLastError = hr;
  530. return hr;
  531. }
  532. HRESULT ECGenericProp::HrSetPropStorage(IECPropStorage *lpStorage, BOOL fLoadProps)
  533. {
  534. HRESULT hr;
  535. SPropValue sPropValue;
  536. if(this->lpStorage)
  537. this->lpStorage->Release();
  538. this->lpStorage = lpStorage;
  539. if(lpStorage)
  540. lpStorage->AddRef();
  541. if(fLoadProps) {
  542. hr = HrLoadProps();
  543. if(hr != hrSuccess)
  544. return hr;
  545. if (HrGetRealProp(PR_OBJECT_TYPE, 0, NULL, &sPropValue, m_ulMaxPropSize) == hrSuccess &&
  546. // The server sent a PR_OBJECT_TYPE, check if it is correct
  547. this->ulObjType != sPropValue.Value.ul)
  548. // Return NOT FOUND because the entryid given was the incorrect type. This means
  549. // that the object was basically not found.
  550. return MAPI_E_NOT_FOUND;
  551. }
  552. return hrSuccess;
  553. }
  554. HRESULT ECGenericProp::HrLoadEmptyProps()
  555. {
  556. scoped_rlock lock(m_hMutexMAPIObject);
  557. assert(lstProps == NULL);
  558. assert(m_sMapiObject == NULL);
  559. lstProps = new ECPropertyEntryMap;
  560. AllocNewMapiObject(0, 0, ulObjType, &m_sMapiObject);
  561. return hrSuccess;
  562. }
  563. // Loads the properties of the saved message for use
  564. HRESULT ECGenericProp::HrLoadProps()
  565. {
  566. HRESULT hr = hrSuccess;
  567. if(lpStorage == NULL)
  568. return MAPI_E_CALL_FAILED;
  569. scoped_rlock lock(m_hMutexMAPIObject);
  570. if (lstProps != NULL && m_bReload == FALSE)
  571. goto exit; // already loaded
  572. m_bLoading = TRUE;
  573. if (m_sMapiObject != NULL) {
  574. // remove what we know, (scenario: keep open r/w, drop props, get all again causes to know the server changes, incl. the hierarchy id)
  575. FreeMapiObject(m_sMapiObject);
  576. m_sMapiObject = NULL;
  577. // only remove my own properties: keep recipients and attachment tables
  578. if (lstProps != NULL) {
  579. for (auto &p : *lstProps)
  580. p.second.DeleteProperty();
  581. lstProps->clear();
  582. }
  583. m_setDeletedProps.clear();
  584. }
  585. hr = lpStorage->HrLoadObject(&m_sMapiObject);
  586. if (hr != hrSuccess)
  587. goto exit;
  588. if (lstProps == NULL)
  589. lstProps = new ECPropertyEntryMap;
  590. // Add *all* the entries as with empty values; values for these properties will be
  591. // retrieved on-demand
  592. for (auto tag : m_sMapiObject->lstAvailable) {
  593. ECPropertyEntry entry(tag);
  594. lstProps->insert(std::make_pair(PROP_ID(tag), entry));
  595. }
  596. // Load properties
  597. for (const auto &pv : m_sMapiObject->lstProperties)
  598. // don't add any 'error' types ... (the storage object shouldn't really give us these anyway ..)
  599. if (PROP_TYPE(pv.GetPropTag()) != PT_ERROR) {
  600. SPropValue tmp = pv.GetMAPIPropValRef();
  601. HrSetRealProp(&tmp);
  602. }
  603. // remove copied proptags, subobjects are still present
  604. m_sMapiObject->lstAvailable.clear();
  605. m_sMapiObject->lstProperties.clear(); // pointers are now only present in lstProps (this removes memory usage!)
  606. // at this point: children still known, ulObjId and ulObjType too
  607. // Mark all properties now in memory as 'clean' (need not be saved)
  608. hr = HrSetClean();
  609. if(hr != hrSuccess)
  610. goto exit;
  611. // We just read the properties from the disk, so it is a 'saved' (ie on-disk) message
  612. fSaved = true;
  613. exit:
  614. dwLastError = hr;
  615. m_bReload = FALSE;
  616. m_bLoading = FALSE;
  617. return hr;
  618. }
  619. // Load a single (large) property from the storage
  620. HRESULT ECGenericProp::HrLoadProp(ULONG ulPropTag)
  621. {
  622. HRESULT hr = hrSuccess;
  623. ecmem_ptr<SPropValue> lpsPropVal;
  624. ECPropertyEntryIterator iterProps;
  625. if(lpStorage == NULL)
  626. return MAPI_E_CALL_FAILED;
  627. ulPropTag = NormalizePropTag(ulPropTag);
  628. scoped_rlock lock(m_hMutexMAPIObject);
  629. if(lstProps == NULL || m_bReload == TRUE) {
  630. hr = HrLoadProps();
  631. if(hr != hrSuccess)
  632. return hr;
  633. }
  634. iterProps = lstProps->find(PROP_ID(ulPropTag));
  635. if (iterProps == lstProps->end() ||
  636. (PROP_TYPE(ulPropTag) != PT_UNSPECIFIED &&
  637. PROP_TYPE(ulPropTag) != PROP_TYPE(iterProps->second.GetPropTag())))
  638. return MAPI_E_NOT_FOUND;
  639. // Don't load the data if it was already loaded
  640. if (iterProps->second.FIsLoaded())
  641. return MAPI_E_NOT_FOUND;
  642. // The property was not loaded yet, demand-load it now
  643. hr = lpStorage->HrLoadProp(m_sMapiObject->ulObjId, iterProps->second.GetPropTag(), &~lpsPropVal);
  644. if(hr != hrSuccess)
  645. return hr;
  646. hr = iterProps->second.HrSetProp(new ECProperty(lpsPropVal));
  647. if(hr != hrSuccess)
  648. return hr;
  649. // It's clean 'cause we just loaded it
  650. iterProps->second.HrSetClean();
  651. return hrSuccess;
  652. }
  653. HRESULT ECGenericProp::GetProps(const SPropTagArray *lpPropTagArray,
  654. ULONG ulFlags, ULONG *lpcValues, SPropValue **lppPropArray)
  655. {
  656. HRESULT hr = hrSuccess;
  657. HRESULT hrT = hrSuccess;
  658. ecmem_ptr<SPropTagArray> lpGetPropTagArray;
  659. GetPropCallBack lpfnGetProp = NULL;
  660. void* lpParam = NULL;
  661. ecmem_ptr<SPropValue> lpsPropValue;
  662. unsigned int i;
  663. //FIXME: check lpPropTagArray on PROP_TYPE()
  664. if((lpPropTagArray != NULL && lpPropTagArray->cValues == 0) || Util::ValidatePropTagArray(lpPropTagArray) == false)
  665. return MAPI_E_INVALID_PARAMETER;
  666. if (lpPropTagArray == NULL) {
  667. hr = GetPropList(ulFlags, &~lpGetPropTagArray);
  668. if(hr != hrSuccess)
  669. return hr;
  670. lpPropTagArray = lpGetPropTagArray.get();
  671. }
  672. hr = ECAllocateBuffer(sizeof(SPropValue) * lpPropTagArray->cValues, &~lpsPropValue);
  673. if (hr != hrSuccess)
  674. return hr;
  675. for (i = 0; i < lpPropTagArray->cValues; ++i) {
  676. if (HrGetHandler(lpPropTagArray->aulPropTag[i], NULL, &lpfnGetProp, &lpParam) == hrSuccess) {
  677. lpsPropValue[i].ulPropTag = lpPropTagArray->aulPropTag[i];
  678. hrT = lpfnGetProp(lpPropTagArray->aulPropTag[i], this->lpProvider, ulFlags, &lpsPropValue[i], lpParam, lpsPropValue);
  679. } else {
  680. hrT = HrGetRealProp(lpPropTagArray->aulPropTag[i], ulFlags, lpsPropValue, &lpsPropValue[i], m_ulMaxPropSize);
  681. if (hrT != hrSuccess && hrT != MAPI_E_NOT_FOUND &&
  682. hrT != MAPI_E_NOT_ENOUGH_MEMORY &&
  683. hrT != MAPI_W_ERRORS_RETURNED)
  684. return hrT;
  685. }
  686. if(HR_FAILED(hrT)) {
  687. lpsPropValue[i].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(lpPropTagArray->aulPropTag[i]));
  688. lpsPropValue[i].Value.err = hrT;
  689. hr = MAPI_W_ERRORS_RETURNED;
  690. } else if(hrT != hrSuccess) {
  691. hr = MAPI_W_ERRORS_RETURNED;
  692. }
  693. }
  694. *lppPropArray = lpsPropValue.release();
  695. *lpcValues = lpPropTagArray->cValues;
  696. return hr;
  697. }
  698. HRESULT ECGenericProp::GetPropList(ULONG ulFlags, LPSPropTagArray *lppPropTagArray)
  699. {
  700. HRESULT hr;
  701. ecmem_ptr<SPropTagArray> lpPropTagArray;
  702. int n = 0;
  703. ECPropCallBackIterator iterCallBack;
  704. ECPropertyEntryIterator iterProps;
  705. if(lstProps == NULL) {
  706. hr = HrLoadProps();
  707. if(hr != hrSuccess)
  708. return hr;
  709. }
  710. // The size of the property tag array is never larger than (static properties + generated properties)
  711. hr = ECAllocateBuffer(CbNewSPropTagArray(lstProps->size() + lstCallBack.size()),
  712. &~lpPropTagArray);
  713. if (hr != hrSuccess)
  714. return hr;
  715. // Some will overlap so we've actually allocated slightly too much memory
  716. // Add the callback types first
  717. for (iterCallBack = lstCallBack.begin();
  718. iterCallBack != lstCallBack.end(); ++iterCallBack) {
  719. // Don't add 'hidden' properties
  720. if(iterCallBack->second.fHidden)
  721. continue;
  722. // Check if the callback actually returns OK
  723. // a bit wasteful but fine for now.
  724. ecmem_ptr<SPropValue> lpsPropValue;
  725. HRESULT hrT = hrSuccess;
  726. ECAllocateBuffer(sizeof(SPropValue), &~lpsPropValue);
  727. hrT = iterCallBack->second.lpfnGetProp(iterCallBack->second.ulPropTag, this->lpProvider, ulFlags, lpsPropValue, this, lpsPropValue);
  728. if((!HR_FAILED(hrT) || hrT == MAPI_E_NOT_ENOUGH_MEMORY) && (PROP_TYPE(lpsPropValue->ulPropTag) != PT_ERROR || lpsPropValue->Value.err == MAPI_E_NOT_ENOUGH_MEMORY)) {
  729. ULONG ulPropTag = iterCallBack->second.ulPropTag;
  730. if (PROP_TYPE(ulPropTag) == PT_UNICODE ||
  731. PROP_TYPE(ulPropTag) == PT_STRING8)
  732. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, ((ulFlags & MAPI_UNICODE) ? PT_UNICODE : PT_STRING8));
  733. lpPropTagArray->aulPropTag[n++] = ulPropTag;
  734. }
  735. }
  736. // Then add the others, if not added yet
  737. for (iterProps = lstProps->begin(); iterProps != lstProps->end(); ++iterProps) {
  738. if(HrGetHandler(iterProps->second.GetPropTag(),NULL,NULL,NULL) != 0) {
  739. ULONG ulPropTag = iterProps->second.GetPropTag();
  740. if(!(ulFlags & MAPI_UNICODE)) {
  741. // Downgrade to ansi
  742. if(PROP_TYPE(ulPropTag) == PT_UNICODE)
  743. ulPropTag = PROP_TAG(PT_STRING8, PROP_ID(ulPropTag));
  744. else if(PROP_TYPE(ulPropTag) == PT_MV_UNICODE)
  745. ulPropTag = PROP_TAG(PT_MV_STRING8, PROP_ID(ulPropTag));
  746. }
  747. lpPropTagArray->aulPropTag[n++] = ulPropTag;
  748. }
  749. }
  750. lpPropTagArray->cValues = n;
  751. *lppPropTagArray = lpPropTagArray.release();
  752. return hrSuccess;
  753. }
  754. HRESULT ECGenericProp::OpenProperty(ULONG ulPropTag, LPCIID lpiid, ULONG ulInterfaceOptions, ULONG ulFlags, LPUNKNOWN *lppUnk)
  755. {
  756. return MAPI_E_NO_SUPPORT;
  757. }
  758. HRESULT ECGenericProp::SetProps(ULONG cValues, const SPropValue *lpPropArray,
  759. SPropProblemArray **lppProblems)
  760. {
  761. HRESULT hr = hrSuccess;
  762. HRESULT hrT = hrSuccess;
  763. ecmem_ptr<SPropProblemArray> lpProblems;
  764. int nProblem = 0;
  765. SetPropCallBack lpfnSetProp = NULL;
  766. void* lpParam = NULL;
  767. if (lpPropArray == nullptr)
  768. return MAPI_E_INVALID_PARAMETER;
  769. hr = ECAllocateBuffer(CbNewSPropProblemArray(cValues), &~lpProblems);
  770. if(hr != hrSuccess)
  771. return hr;
  772. for (unsigned int i = 0; i < cValues; ++i) {
  773. // Ignore the PR_NULL property tag and all properties with a type of PT_ERROR;
  774. // no changes and report no problems in the SPropProblemArray structure.
  775. if(PROP_TYPE(lpPropArray[i].ulPropTag) == PR_NULL ||
  776. PROP_TYPE(lpPropArray[i].ulPropTag) == PT_ERROR)
  777. continue;
  778. if (HrGetHandler(lpPropArray[i].ulPropTag, &lpfnSetProp, NULL, &lpParam) == hrSuccess)
  779. hrT = lpfnSetProp(lpPropArray[i].ulPropTag, this->lpProvider, &lpPropArray[i], lpParam);
  780. else
  781. hrT = HrSetRealProp(&lpPropArray[i]); // SC: TODO: this does a ref copy ?!
  782. if(hrT != hrSuccess) {
  783. lpProblems->aProblem[nProblem].scode = hrT;
  784. lpProblems->aProblem[nProblem].ulIndex = i;
  785. lpProblems->aProblem[nProblem].ulPropTag = lpPropArray[i].ulPropTag; // Hold here the real property
  786. ++nProblem;
  787. }
  788. }
  789. lpProblems->cProblem = nProblem;
  790. if (lppProblems != nullptr && nProblem != 0)
  791. *lppProblems = lpProblems.release();
  792. else if (lppProblems != nullptr)
  793. *lppProblems = NULL;
  794. return hrSuccess;
  795. }
  796. /**
  797. * Delete properties from the current object
  798. *
  799. * @param lpPropTagArray PropTagArray with properties to remove from the object. If a property from this list is not found, it will be added to the lppProblems array.
  800. * @param lppProblems An array of proptags that could not be removed from the object. Returns NULL if everything requested was removed. Can be NULL not to want the problem array.
  801. *
  802. * @remark Property types are ignored; only the property identifiers are used.
  803. *
  804. * @return MAPI error code
  805. * @retval hrSuccess 0 or more properties are set to be removed on SaveChanges
  806. * @retval MAPI_E_NO_ACCESS the object is read-only
  807. * @retval MAPI_E_NOT_ENOUGH_MEMORY unable to allocate memory to remove the problem array
  808. */
  809. HRESULT ECGenericProp::DeleteProps(const SPropTagArray *lpPropTagArray,
  810. SPropProblemArray **lppProblems)
  811. {
  812. ECRESULT er = erSuccess;
  813. HRESULT hr = hrSuccess;
  814. HRESULT hrT = hrSuccess;
  815. ECPropCallBackIterator iterCallBack;
  816. ecmem_ptr<SPropProblemArray> lpProblems;
  817. int nProblem = 0;
  818. if (lpPropTagArray == NULL)
  819. return MAPI_E_INVALID_PARAMETER;
  820. // over-allocate the problem array
  821. er = ECAllocateBuffer(CbNewSPropProblemArray(lpPropTagArray->cValues), &~lpProblems);
  822. if (er != erSuccess)
  823. return MAPI_E_NOT_ENOUGH_MEMORY;
  824. for (unsigned int i = 0; i < lpPropTagArray->cValues; ++i) {
  825. // See if it's computed
  826. iterCallBack = lstCallBack.find(PROP_ID(lpPropTagArray->aulPropTag[i]));
  827. // Ignore removable callbacks
  828. if(iterCallBack != lstCallBack.end() && !iterCallBack->second.fRemovable) {
  829. // This is a computed value
  830. lpProblems->aProblem[nProblem].scode = MAPI_E_COMPUTED;
  831. lpProblems->aProblem[nProblem].ulIndex = i;
  832. lpProblems->aProblem[nProblem].ulPropTag = lpPropTagArray->aulPropTag[i];
  833. ++nProblem;
  834. } else {
  835. hrT = HrDeleteRealProp(lpPropTagArray->aulPropTag[i],FALSE);
  836. if(hrT != hrSuccess) {
  837. // Add the error
  838. lpProblems->aProblem[nProblem].scode = hrT;
  839. lpProblems->aProblem[nProblem].ulIndex = i;
  840. lpProblems->aProblem[nProblem].ulPropTag = lpPropTagArray->aulPropTag[i];
  841. ++nProblem;
  842. }
  843. }
  844. }
  845. lpProblems->cProblem = nProblem;
  846. if(lppProblems && nProblem)
  847. *lppProblems = lpProblems.release();
  848. else if (lppProblems != nullptr)
  849. *lppProblems = NULL;
  850. return hr;
  851. }
  852. HRESULT ECGenericProp::CopyTo(ULONG ciidExclude, LPCIID rgiidExclude,
  853. const SPropTagArray *lpExcludeProps, ULONG ulUIParam,
  854. LPMAPIPROGRESS lpProgress, LPCIID lpInterface, void *lpDestObj,
  855. ULONG ulFlags, SPropProblemArray **lppProblems)
  856. {
  857. return MAPI_E_NO_SUPPORT;
  858. }
  859. HRESULT ECGenericProp::CopyProps(const SPropTagArray *, ULONG ui_param,
  860. LPMAPIPROGRESS, LPCIID intf, void *dest_obj, ULONG flags,
  861. SPropProblemArray **)
  862. {
  863. return MAPI_E_NO_SUPPORT;
  864. }
  865. HRESULT ECGenericProp::GetNamesFromIDs(LPSPropTagArray *lppPropTags, LPGUID lpPropSetGuid, ULONG ulFlags, ULONG *lpcPropNames, LPMAPINAMEID **lpppPropNames)
  866. {
  867. return MAPI_E_NO_SUPPORT;
  868. }
  869. HRESULT ECGenericProp::GetIDsFromNames(ULONG cPropNames, LPMAPINAMEID *lppPropNames, ULONG ulFlags, LPSPropTagArray *lppPropTags)
  870. {
  871. return MAPI_E_NO_SUPPORT;
  872. }
  873. // Interface IECSingleInstance
  874. HRESULT ECGenericProp::GetSingleInstanceId(ULONG *lpcbInstanceID, LPSIEID *lppInstanceID)
  875. {
  876. scoped_rlock lock(m_hMutexMAPIObject);
  877. if (m_sMapiObject == NULL)
  878. return MAPI_E_NOT_FOUND;
  879. if (lpcbInstanceID == NULL || lppInstanceID == NULL)
  880. return MAPI_E_INVALID_PARAMETER;
  881. return Util::HrCopyEntryId(m_sMapiObject->cbInstanceID,
  882. reinterpret_cast<ENTRYID *>(m_sMapiObject->lpInstanceID),
  883. lpcbInstanceID, reinterpret_cast<ENTRYID **>(lppInstanceID));
  884. }
  885. HRESULT ECGenericProp::SetSingleInstanceId(ULONG cbInstanceID, LPSIEID lpInstanceID)
  886. {
  887. scoped_rlock lock(m_hMutexMAPIObject);
  888. if (m_sMapiObject == NULL)
  889. return MAPI_E_NOT_FOUND;
  890. if (m_sMapiObject->lpInstanceID)
  891. ECFreeBuffer(m_sMapiObject->lpInstanceID);
  892. m_sMapiObject->lpInstanceID = NULL;
  893. m_sMapiObject->cbInstanceID = 0;
  894. m_sMapiObject->bChangedInstance = false;
  895. HRESULT hr = Util::HrCopyEntryId(cbInstanceID,
  896. reinterpret_cast<ENTRYID *>(lpInstanceID),
  897. &m_sMapiObject->cbInstanceID,
  898. reinterpret_cast<ENTRYID **>(&m_sMapiObject->lpInstanceID));
  899. if (hr != hrSuccess)
  900. return hr;
  901. m_sMapiObject->bChangedInstance = true;
  902. return hr;
  903. }
  904. // Interface IMAPIProp
  905. DEF_HRMETHOD0(ECGenericProp, MAPIProp, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  906. DEF_ULONGMETHOD0(ECGenericProp, MAPIProp, AddRef, (void))
  907. DEF_ULONGMETHOD0(ECGenericProp, MAPIProp, Release, (void))
  908. DEF_HRMETHOD0(ECGenericProp, MAPIProp, GetLastError, (HRESULT, hError), (ULONG, ulFlags), (LPMAPIERROR *, lppMapiError))
  909. DEF_HRMETHOD0(ECGenericProp, MAPIProp, SaveChanges, (ULONG, ulFlags))
  910. DEF_HRMETHOD0(ECGenericProp, MAPIProp, GetProps, (const SPropTagArray *, lpPropTagArray), (ULONG, ulFlags), (ULONG *, lpcValues), (SPropValue **, lppPropArray))
  911. DEF_HRMETHOD0(ECGenericProp, MAPIProp, GetPropList, (ULONG, ulFlags), (LPSPropTagArray *, lppPropTagArray))
  912. DEF_HRMETHOD0(ECGenericProp, MAPIProp, OpenProperty, (ULONG, ulPropTag), (LPCIID, lpiid), (ULONG, ulInterfaceOptions), (ULONG, ulFlags), (LPUNKNOWN *, lppUnk))
  913. DEF_HRMETHOD0(ECGenericProp, MAPIProp, SetProps, (ULONG, cValues), (const SPropValue *, lpPropArray), (SPropProblemArray **, lppProblems))
  914. DEF_HRMETHOD0(ECGenericProp, MAPIProp, DeleteProps, (const SPropTagArray *, lpPropTagArray), (SPropProblemArray **, lppProblems))
  915. DEF_HRMETHOD0(ECGenericProp, MAPIProp, CopyTo, (ULONG, ciidExclude), (LPCIID, rgiidExclude), (const SPropTagArray *, lpExcludeProps), (ULONG, ulUIParam), (LPMAPIPROGRESS, lpProgress), (LPCIID, lpInterface), (void *, lpDestObj), (ULONG, ulFlags), (SPropProblemArray **, lppProblems))
  916. DEF_HRMETHOD0(ECGenericProp, MAPIProp, CopyProps, (const SPropTagArray *, lpIncludeProps), (ULONG, ulUIParam), (LPMAPIPROGRESS, lpProgress), (LPCIID, lpInterface), (void *, lpDestObj), (ULONG, ulFlags), (SPropProblemArray **, lppProblems))
  917. DEF_HRMETHOD0(ECGenericProp, MAPIProp, GetNamesFromIDs, (LPSPropTagArray *, pptaga), (LPGUID, lpguid), (ULONG, ulFlags), (ULONG *, pcNames), (LPMAPINAMEID **, pppNames))
  918. DEF_HRMETHOD0(ECGenericProp, MAPIProp, GetIDsFromNames, (ULONG, cNames), (LPMAPINAMEID *, ppNames), (ULONG, ulFlags), (LPSPropTagArray *, pptaga))
  919. // Proxy routines for IECSingleInstance
  920. DEF_HRMETHOD1(TRACE_MAPI, ECGenericProp, ECSingleInstance, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  921. DEF_ULONGMETHOD1(TRACE_MAPI, ECGenericProp, ECSingleInstance, AddRef, (void))
  922. DEF_ULONGMETHOD1(TRACE_MAPI, ECGenericProp, ECSingleInstance, Release, (void))
  923. HRESULT __stdcall ECGenericProp::xECSingleInstance::GetSingleInstanceId(ULONG *lpcbInstanceID, LPENTRYID *lppInstanceID)
  924. {
  925. TRACE_MAPI(TRACE_ENTRY, "IECSingleInstance::GetSingleInstanceId", "");
  926. METHOD_PROLOGUE_(ECGenericProp , ECSingleInstance);
  927. HRESULT hr = pThis->GetSingleInstanceId(lpcbInstanceID, (LPSIEID *)lppInstanceID);
  928. TRACE_MAPI(TRACE_RETURN, "IECSingleInstance::GetSingleInstanceId", "%s", GetMAPIErrorDescription(hr).c_str());
  929. return hr;
  930. }
  931. HRESULT __stdcall ECGenericProp::xECSingleInstance::SetSingleInstanceId(ULONG cbInstanceID, LPENTRYID lpInstanceID)
  932. {
  933. TRACE_MAPI(TRACE_ENTRY, "IECSingleInstance::SetSingleInstanceId", "");
  934. METHOD_PROLOGUE_(ECGenericProp , ECSingleInstance);
  935. HRESULT hr = pThis->SetSingleInstanceId(cbInstanceID, (LPSIEID)lpInstanceID);
  936. TRACE_MAPI(TRACE_RETURN, "IECSingleInstance::SetSingleInstanceId", "%s", GetMAPIErrorDescription(hr).c_str());
  937. return hr;
  938. }