ECMsgStorePublic.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  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 <new>
  18. #include <kopano/platform.h>
  19. #include <kopano/memory.hpp>
  20. #include "ECMsgStorePublic.h"
  21. #include "ECMAPIFolder.h"
  22. #include <kopano/CommonUtil.h>
  23. #include <kopano/Util.h>
  24. #include "ClientUtil.h"
  25. #include "pcutil.hpp"
  26. #include <kopano/ECGetText.h>
  27. #include <kopano/mapiext.h>
  28. #include <mapiutil.h>
  29. #include "ECMAPIFolderPublic.h"
  30. #include <kopano/ECGuid.h>
  31. using namespace std;
  32. using namespace KCHL;
  33. ECMsgStorePublic::ECMsgStorePublic(char *lpszProfname, LPMAPISUP lpSupport, WSTransport *lpTransport, BOOL fModify, ULONG ulProfileFlags, BOOL fIsSpooler, BOOL bOfflineStore) :
  34. ECMsgStore(lpszProfname, lpSupport, lpTransport, fModify, ulProfileFlags, fIsSpooler, false, bOfflineStore)
  35. {
  36. TRACE_MAPI(TRACE_ENTRY, "ECMsgStorePublic::ECMsgStorePublic","");
  37. HrAddPropHandlers(PR_IPM_SUBTREE_ENTRYID, GetPropHandler, DefaultSetPropComputed, (void*) this, FALSE, FALSE);
  38. HrAddPropHandlers(PR_IPM_PUBLIC_FOLDERS_ENTRYID, GetPropHandler, DefaultSetPropComputed, (void*) this, FALSE, FALSE);
  39. HrAddPropHandlers(PR_IPM_FAVORITES_ENTRYID, GetPropHandler, DefaultSetPropComputed, (void*) this, FALSE, FALSE);
  40. HrAddPropHandlers(PR_EC_PUBLIC_IPM_SUBTREE_ENTRYID, GetPropHandler, SetPropHandler, (void*) this, FALSE, TRUE);
  41. TRACE_MAPI(TRACE_RETURN, "ECMsgStorePublic::ECMsgStorePublic","");
  42. }
  43. ECMsgStorePublic::~ECMsgStorePublic(void)
  44. {
  45. TRACE_MAPI(TRACE_ENTRY, "ECMsgStorePublic::~ECMsgStorePublic","");
  46. if (m_lpDefaultMsgStore)
  47. m_lpDefaultMsgStore->Release();
  48. if (m_lpIPMSubTree)
  49. m_lpIPMSubTree->Release();
  50. MAPIFreeBuffer(m_lpIPMSubTreeID);
  51. MAPIFreeBuffer(m_lpIPMFavoritesID);
  52. MAPIFreeBuffer(m_lpIPMPublicFoldersID);
  53. TRACE_MAPI(TRACE_RETURN, "~ECMsgStorePublic::ECMsgStorePublic","");
  54. }
  55. HRESULT ECMsgStorePublic::Create(char *lpszProfname, LPMAPISUP lpSupport, WSTransport *lpTransport, BOOL fModify, ULONG ulProfileFlags, BOOL fIsSpooler, BOOL bOfflineStore, ECMsgStore **lppECMsgStore) {
  56. HRESULT hr = hrSuccess;
  57. auto lpStore = new(std::nothrow) ECMsgStorePublic(lpszProfname,
  58. lpSupport, lpTransport, fModify, ulProfileFlags,
  59. fIsSpooler, bOfflineStore);
  60. if (lpStore == nullptr)
  61. return MAPI_E_NOT_ENOUGH_MEMORY;
  62. hr = lpStore->QueryInterface(IID_ECMsgStore, (void **)lppECMsgStore);
  63. if(hr != hrSuccess)
  64. delete lpStore;
  65. return hr;
  66. }
  67. HRESULT ECMsgStorePublic::QueryInterface(REFIID refiid, void **lppInterface)
  68. {
  69. return ECMsgStore::QueryInterface(refiid, lppInterface);
  70. }
  71. HRESULT ECMsgStorePublic::GetPropHandler(ULONG ulPropTag, void* lpProvider, ULONG ulFlags, LPSPropValue lpsPropValue, void *lpParam, void *lpBase)
  72. {
  73. HRESULT hr = hrSuccess;
  74. auto lpStore = static_cast<ECMsgStorePublic *>(lpParam);
  75. switch(ulPropTag) {
  76. case PR_IPM_SUBTREE_ENTRYID:
  77. return ::GetPublicEntryId(ePE_IPMSubtree, lpStore->GetStoreGuid(), lpBase, &lpsPropValue->Value.bin.cb, (LPENTRYID*)&lpsPropValue->Value.bin.lpb);
  78. case PR_IPM_PUBLIC_FOLDERS_ENTRYID:
  79. return ::GetPublicEntryId(ePE_PublicFolders, lpStore->GetStoreGuid(), lpBase, &lpsPropValue->Value.bin.cb, (LPENTRYID*)&lpsPropValue->Value.bin.lpb);
  80. case PR_IPM_FAVORITES_ENTRYID:
  81. return ::GetPublicEntryId(ePE_Favorites, lpStore->GetStoreGuid(), lpBase, &lpsPropValue->Value.bin.cb, (LPENTRYID*)&lpsPropValue->Value.bin.lpb);
  82. case PR_EC_PUBLIC_IPM_SUBTREE_ENTRYID:
  83. hr = lpStore->HrGetRealProp(PR_IPM_SUBTREE_ENTRYID, ulFlags, lpBase, lpsPropValue);
  84. if (hr == hrSuccess)
  85. lpsPropValue->ulPropTag = PR_EC_PUBLIC_IPM_SUBTREE_ENTRYID;
  86. return hr;
  87. default:
  88. return MAPI_E_NOT_FOUND;
  89. }
  90. }
  91. HRESULT ECMsgStorePublic::SetPropHandler(ULONG ulPropTag, void *lpProvider,
  92. const SPropValue *lpsPropValue, void *lpParam)
  93. {
  94. SPropValue sPropValue;
  95. auto lpStore = static_cast<ECMsgStorePublic *>(lpParam);
  96. switch(ulPropTag) {
  97. case PR_EC_PUBLIC_IPM_SUBTREE_ENTRYID:
  98. sPropValue.ulPropTag = PR_IPM_SUBTREE_ENTRYID;
  99. sPropValue.Value = lpsPropValue->Value; // Cheap copy
  100. return lpStore->HrSetRealProp(&sPropValue);
  101. default:
  102. return MAPI_E_NOT_FOUND;
  103. }
  104. }
  105. HRESULT ECMsgStorePublic::SetEntryId(ULONG cbEntryId, LPENTRYID lpEntryId)
  106. {
  107. HRESULT hr;
  108. hr = ECMsgStore::SetEntryId(cbEntryId, lpEntryId);
  109. if(hr != hrSuccess)
  110. return hr;
  111. return BuildIPMSubTree();
  112. }
  113. HRESULT ECMsgStorePublic::OpenEntry(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulFlags, ULONG *lpulObjType, LPUNKNOWN *lppUnk)
  114. {
  115. HRESULT hr = hrSuccess;
  116. unsigned int ulObjType = 0;
  117. object_ptr<ECMAPIFolder> lpMAPIFolder;
  118. BOOL fModifyObject = FALSE;
  119. enumPublicEntryID ePublicEntryID = ePE_None;
  120. ULONG ulResult = 0;
  121. object_ptr<IECPropStorage> lpPropStorage;
  122. object_ptr<WSMAPIFolderOps> lpFolderOps;
  123. memory_ptr<SPropValue> lpsPropValue, lpParentProp;
  124. memory_ptr<ENTRYID> lpEntryIDIntern;
  125. ULONG ulResults;
  126. // Check input/output variables
  127. if (lpulObjType == nullptr || lppUnk == nullptr)
  128. return MAPI_E_INVALID_PARAMETER;
  129. if(ulFlags & MAPI_MODIFY) {
  130. if (!fModify)
  131. return MAPI_E_NO_ACCESS;
  132. else
  133. fModifyObject = TRUE;
  134. }
  135. if(ulFlags & MAPI_BEST_ACCESS)
  136. fModifyObject = fModify;
  137. // Open always online the root folder
  138. if (cbEntryID == 0 || lpEntryID == nullptr)
  139. return ECMsgStore::OpenEntry(cbEntryID, lpEntryID, lpInterface, ulFlags, lpulObjType, lppUnk);
  140. hr = HrCompareEntryIdWithStoreGuid(cbEntryID, lpEntryID, &GetStoreGuid());
  141. if(hr != hrSuccess)
  142. return hr;
  143. if(ComparePublicEntryId(ePE_IPMSubtree, cbEntryID, lpEntryID, &ulResult) == hrSuccess && ulResult == TRUE)
  144. ePublicEntryID = ePE_IPMSubtree;
  145. else if(ComparePublicEntryId(ePE_Favorites, cbEntryID, lpEntryID, &ulResult) == hrSuccess && ulResult == TRUE)
  146. ePublicEntryID = ePE_Favorites;
  147. else if(ComparePublicEntryId(ePE_PublicFolders, cbEntryID, lpEntryID, &ulResult) == hrSuccess && ulResult == TRUE)
  148. ePublicEntryID = ePE_PublicFolders;
  149. else if (lpEntryID && (lpEntryID->abFlags[3] & KOPANO_FAVORITE)) {
  150. ePublicEntryID = ePE_FavoriteSubFolder;
  151. // Replace the original entryid because this one is only readable
  152. hr = MAPIAllocateBuffer(cbEntryID, &~lpEntryIDIntern);
  153. if (hr != hrSuccess)
  154. return hr;
  155. memcpy(lpEntryIDIntern, lpEntryID, cbEntryID);
  156. // Remove Flags intern
  157. lpEntryIDIntern->abFlags[3] &= ~KOPANO_FAVORITE;
  158. lpEntryID = lpEntryIDIntern;
  159. }
  160. hr = HrGetObjTypeFromEntryId(cbEntryID, (LPBYTE)lpEntryID, &ulObjType);
  161. if(hr != hrSuccess)
  162. return hr;
  163. if (ulObjType != MAPI_FOLDER && ePublicEntryID != ePE_FavoriteSubFolder)
  164. // Open online Messages.
  165. // On success, message is open, now we can exit
  166. return ECMsgStore::OpenEntry(cbEntryID, lpEntryID, lpInterface, ulFlags, lpulObjType, lppUnk);
  167. switch( ulObjType ) {
  168. case MAPI_FOLDER:
  169. if (ePublicEntryID == ePE_PublicFolders) {
  170. hr = MAPIAllocateBuffer(sizeof(SPropValue), &~lpsPropValue);
  171. if(hr != hrSuccess)
  172. return hr;
  173. // Get the online Subtree entryid
  174. hr = HrGetRealProp(PR_IPM_SUBTREE_ENTRYID, 0, lpsPropValue, lpsPropValue);
  175. if(hr != hrSuccess)
  176. return hr;
  177. cbEntryID = lpsPropValue->Value.bin.cb;
  178. lpEntryID = (LPENTRYID)lpsPropValue->Value.bin.lpb;
  179. }
  180. if (ePublicEntryID != ePE_IPMSubtree && ePublicEntryID != ePE_Favorites) {
  181. hr = lpTransport->HrOpenFolderOps(cbEntryID, lpEntryID, &~lpFolderOps);
  182. if(hr != hrSuccess)
  183. return hr;
  184. } else {
  185. lpFolderOps.reset();
  186. }
  187. hr = ECMAPIFolderPublic::Create(this, fModifyObject, lpFolderOps, ePublicEntryID, &~lpMAPIFolder);
  188. if(hr != hrSuccess)
  189. return hr;
  190. if (ePublicEntryID != ePE_IPMSubtree && ePublicEntryID != ePE_Favorites) {
  191. //FIXME: Wrong parent entryid
  192. hr = lpTransport->HrOpenPropStorage(m_cbEntryId, m_lpEntryId, cbEntryID, lpEntryID, ulFlags & SHOW_SOFT_DELETES, &~lpPropStorage);
  193. if(hr != hrSuccess)
  194. return hr;
  195. hr = lpMAPIFolder->HrSetPropStorage(lpPropStorage, TRUE);
  196. if(hr != hrSuccess)
  197. return hr;
  198. //if(ePublicEntryID == ePE_FavoriteSubFolder)
  199. //lpEntryID->abFlags[3] = KOPANO_FAVORITE;
  200. } else {
  201. lpMAPIFolder->HrLoadEmptyProps();
  202. }
  203. hr = lpMAPIFolder->SetEntryId(cbEntryID, lpEntryID);
  204. if(hr != hrSuccess)
  205. return hr;
  206. // Get the parent entryid of a folder a check if this is the online subtree entryid. When it is,
  207. // change the parent to the static parent entryid
  208. hr = MAPIAllocateBuffer(sizeof(SPropValue), &~lpsPropValue);
  209. if(hr != hrSuccess)
  210. return hr;
  211. if (HrGetOneProp((LPMAPIPROP)(&lpMAPIFolder->m_xMAPIFolder), PR_PARENT_ENTRYID, &~lpParentProp) == hrSuccess &&
  212. HrGetRealProp(PR_IPM_SUBTREE_ENTRYID, 0, lpsPropValue, lpsPropValue) == hrSuccess &&
  213. CompareEntryIDs(lpsPropValue->Value.bin.cb, (LPENTRYID)lpsPropValue->Value.bin.lpb, lpParentProp->Value.bin.cb, (LPENTRYID)lpParentProp->Value.bin.lpb, 0, &ulResults) == hrSuccess &&
  214. ulResults == TRUE)
  215. lpMAPIFolder->SetParentID(this->m_cIPMPublicFoldersID, this->m_lpIPMPublicFoldersID);
  216. AddChild(lpMAPIFolder);
  217. if(lpInterface)
  218. hr = lpMAPIFolder->QueryInterface(*lpInterface,(void **)lppUnk);
  219. else
  220. hr = lpMAPIFolder->QueryInterface(IID_IMAPIFolder, (void **)lppUnk);
  221. if(lpulObjType)
  222. *lpulObjType = MAPI_FOLDER;
  223. break;
  224. case MAPI_MESSAGE:
  225. //FIXME: change for offline support
  226. hr = ECMsgStore::OpenEntry(cbEntryID, lpEntryID, lpInterface, ulFlags, lpulObjType, lppUnk);
  227. if (hr != hrSuccess)
  228. return hr;
  229. break;
  230. default:
  231. return MAPI_E_NOT_FOUND;
  232. }
  233. return hr;
  234. }
  235. HRESULT ECMsgStorePublic::InitEntryIDs()
  236. {
  237. HRESULT hr;
  238. if (m_lpIPMSubTreeID == NULL) {
  239. hr = ::GetPublicEntryId(ePE_IPMSubtree, GetStoreGuid(), NULL, &m_cIPMSubTreeID, &m_lpIPMSubTreeID);
  240. if(hr != hrSuccess)
  241. return hr;
  242. }
  243. if (m_lpIPMPublicFoldersID == NULL) {
  244. hr = ::GetPublicEntryId(ePE_PublicFolders, GetStoreGuid(), NULL, &m_cIPMPublicFoldersID, &m_lpIPMPublicFoldersID);
  245. if(hr != hrSuccess)
  246. return hr;
  247. }
  248. if (m_lpIPMFavoritesID == NULL) {
  249. hr = ::GetPublicEntryId(ePE_Favorites, GetStoreGuid(), NULL, &m_cIPMFavoritesID, &m_lpIPMFavoritesID);
  250. if(hr != hrSuccess)
  251. return hr;
  252. }
  253. return hrSuccess;
  254. }
  255. HRESULT ECMsgStorePublic::GetPublicEntryId(enumPublicEntryID ePublicEntryID, void *lpBase, ULONG *lpcbEntryID, LPENTRYID *lppEntryID)
  256. {
  257. ULONG cbPublicID = 0;
  258. LPENTRYID lpPublicID = NULL;
  259. LPENTRYID lpEntryID = NULL;
  260. HRESULT hr = InitEntryIDs();
  261. if(hr != hrSuccess)
  262. return hr;
  263. if (lpcbEntryID == NULL || lppEntryID == NULL)
  264. return MAPI_E_INVALID_PARAMETER;
  265. switch(ePublicEntryID)
  266. {
  267. case ePE_IPMSubtree:
  268. cbPublicID = m_cIPMSubTreeID;
  269. lpPublicID = m_lpIPMSubTreeID;
  270. break;
  271. case ePE_PublicFolders:
  272. cbPublicID = m_cIPMPublicFoldersID;
  273. lpPublicID = m_lpIPMPublicFoldersID;
  274. break;
  275. case ePE_Favorites:
  276. cbPublicID = m_cIPMFavoritesID;
  277. lpPublicID = m_lpIPMFavoritesID;
  278. break;
  279. default:
  280. return MAPI_E_INVALID_PARAMETER;
  281. }
  282. if (lpBase)
  283. hr = MAPIAllocateMore(cbPublicID, lpBase, (void**)&lpEntryID);
  284. else
  285. hr = MAPIAllocateBuffer(cbPublicID, (void**)&lpEntryID);
  286. if (hr != hrSuccess)
  287. return hr;
  288. memcpy(lpEntryID, lpPublicID, cbPublicID);
  289. *lpcbEntryID = cbPublicID;
  290. *lppEntryID = lpEntryID;
  291. return hrSuccess;
  292. }
  293. HRESULT ECMsgStorePublic::ComparePublicEntryId(enumPublicEntryID ePublicEntryID, ULONG cbEntryID, LPENTRYID lpEntryID, ULONG *lpulResult)
  294. {
  295. HRESULT hr;
  296. ULONG ulResult = 0;
  297. ULONG cbPublicID = 0;
  298. LPENTRYID lpPublicID = NULL;
  299. hr = InitEntryIDs();
  300. if(hr != hrSuccess)
  301. return hr;
  302. if (lpEntryID == NULL || lpulResult == NULL)
  303. return MAPI_E_INVALID_PARAMETER;
  304. switch(ePublicEntryID)
  305. {
  306. case ePE_IPMSubtree:
  307. cbPublicID = m_cIPMSubTreeID;
  308. lpPublicID = m_lpIPMSubTreeID;
  309. break;
  310. case ePE_PublicFolders:
  311. cbPublicID = m_cIPMPublicFoldersID;
  312. lpPublicID = m_lpIPMPublicFoldersID;
  313. break;
  314. case ePE_Favorites:
  315. cbPublicID = m_cIPMFavoritesID;
  316. lpPublicID = m_lpIPMFavoritesID;
  317. break;
  318. default:
  319. return MAPI_E_INVALID_PARAMETER;
  320. }
  321. hr = GetMsgStore()->CompareEntryIDs(cbEntryID, lpEntryID, cbPublicID, lpPublicID, 0, &ulResult);
  322. if(hr != hrSuccess)
  323. return hr;
  324. *lpulResult = ulResult;
  325. return hrSuccess;
  326. }
  327. HRESULT ECMsgStorePublic::BuildIPMSubTree()
  328. {
  329. HRESULT hr = hrSuccess;
  330. ECMemTable *lpIPMSubTree = NULL;
  331. memory_ptr<SPropValue> lpProps;
  332. ULONG cProps = 0;
  333. ULONG cMaxProps = 0;
  334. ULONG ulRowId = 0;
  335. SPropValue sKeyProp;
  336. static constexpr const SizedSPropTagArray(13, sPropsHierarchyColumns) = {13, {
  337. PR_ENTRYID, PR_DISPLAY_NAME_W,
  338. PR_CONTENT_COUNT, PR_CONTENT_UNREAD,
  339. PR_STORE_ENTRYID, PR_STORE_RECORD_KEY,
  340. PR_STORE_SUPPORT_MASK, PR_INSTANCE_KEY,
  341. PR_RECORD_KEY, PR_ACCESS, PR_ACCESS_LEVEL,
  342. PR_OBJECT_TYPE, PR_FOLDER_TYPE} };
  343. if (m_lpIPMSubTree != NULL){
  344. assert(false);
  345. return hrSuccess;
  346. }
  347. hr = ECMemTable::Create(sPropsHierarchyColumns, PR_ROWID, &lpIPMSubTree);
  348. if(hr != hrSuccess)
  349. return hr;
  350. // Favorites
  351. ulRowId = 1;
  352. cMaxProps = 22;
  353. hr = MAPIAllocateBuffer(sizeof(SPropValue) * cMaxProps, &~lpProps);
  354. if(hr != hrSuccess)
  355. return hr;
  356. lpProps[cProps].ulPropTag = PR_ENTRYID;
  357. hr = GetPublicEntryId(ePE_Favorites, lpProps, &lpProps[cProps].Value.bin.cb, (LPENTRYID*)&lpProps[cProps].Value.bin.lpb);
  358. if(hr != hrSuccess)
  359. return hr;
  360. ++cProps;
  361. lpProps[cProps].ulPropTag = PR_LONGTERM_ENTRYID_FROM_TABLE;
  362. hr = GetPublicEntryId(ePE_Favorites, lpProps, &lpProps[cProps].Value.bin.cb, (LPENTRYID*)&lpProps[cProps].Value.bin.lpb);
  363. if(hr != hrSuccess)
  364. return hr;
  365. ++cProps;
  366. lpProps[cProps].ulPropTag = PR_DISPLAY_TYPE;
  367. lpProps[cProps++].Value.ul = DT_FOLDER;
  368. lpProps[cProps].ulPropTag = PR_DEPTH;
  369. lpProps[cProps++].Value.ul = 1;
  370. lpProps[cProps].ulPropTag = PR_PARENT_ENTRYID;
  371. hr = GetPublicEntryId(ePE_IPMSubtree, lpProps, &lpProps[cProps].Value.bin.cb, (LPENTRYID*)&lpProps[cProps].Value.bin.lpb);
  372. if (hr != hrSuccess)
  373. return hr;
  374. ++cProps;
  375. lpProps[cProps].ulPropTag = PR_DISPLAY_NAME_W;
  376. lpProps[cProps++].Value.lpszW = _W("Favorites"); // FIXME: Use dynamic name, read from global profile (like exchange)
  377. lpProps[cProps].ulPropTag = PR_CONTENT_COUNT;
  378. lpProps[cProps++].Value.ul = 0;
  379. lpProps[cProps].ulPropTag = PR_CONTENT_UNREAD;
  380. lpProps[cProps++].Value.ul = 0;
  381. if (ECMAPIProp::DefaultMAPIGetProp(PR_STORE_ENTRYID, this, 0, &lpProps[cProps], this, lpProps) == hrSuccess)
  382. ++cProps;
  383. if (ECMAPIProp::DefaultMAPIGetProp(PR_STORE_RECORD_KEY, this, 0, &lpProps[cProps], this, lpProps) == hrSuccess)
  384. ++cProps;
  385. if (ECMAPIProp::DefaultMAPIGetProp(PR_STORE_SUPPORT_MASK, this, 0, &lpProps[cProps], this, lpProps) == hrSuccess)
  386. ++cProps;
  387. lpProps[cProps].ulPropTag = PR_INSTANCE_KEY;
  388. lpProps[cProps].Value.bin.cb = sizeof(ULONG)*2;
  389. hr = MAPIAllocateMore(lpProps[cProps].Value.bin.cb, lpProps, (void**)&lpProps[cProps].Value.bin.lpb);
  390. if(hr != hrSuccess)
  391. return hr;
  392. memset(lpProps[cProps].Value.bin.lpb, 0, lpProps[cProps].Value.bin.cb );
  393. memcpy(lpProps[cProps].Value.bin.lpb, &ulRowId, sizeof(ULONG));
  394. ++cProps;
  395. lpProps[cProps].ulPropTag = PR_RECORD_KEY;
  396. hr = GetPublicEntryId(ePE_Favorites, lpProps, &lpProps[cProps].Value.bin.cb, (LPENTRYID*)&lpProps[cProps].Value.bin.lpb);
  397. if(hr != hrSuccess)
  398. return hr;
  399. ++cProps;
  400. lpProps[cProps].ulPropTag = PR_ACCESS;
  401. lpProps[cProps++].Value.ul = MAPI_ACCESS_READ;
  402. lpProps[cProps].ulPropTag = PR_ACCESS_LEVEL;
  403. lpProps[cProps++].Value.ul = 0;
  404. lpProps[cProps].ulPropTag = PR_RIGHTS;
  405. lpProps[cProps++].Value.ul = ecRightsAll;
  406. lpProps[cProps].ulPropTag = PR_SUBFOLDERS;
  407. lpProps[cProps++].Value.b = true;
  408. lpProps[cProps].ulPropTag = PR_OBJECT_TYPE;
  409. lpProps[cProps++].Value.ul = MAPI_FOLDER;
  410. lpProps[cProps].ulPropTag = PR_FOLDER_TYPE;
  411. lpProps[cProps++].Value.ul = FOLDER_GENERIC;
  412. lpProps[cProps].ulPropTag = PR_ROWID;
  413. lpProps[cProps++].Value.ul = ulRowId;
  414. sKeyProp.ulPropTag = PR_ROWID;
  415. sKeyProp.Value.ul = ulRowId;
  416. hr = lpIPMSubTree->HrModifyRow(ECKeyTable::TABLE_ROW_ADD, &sKeyProp, lpProps, cProps);
  417. if (hr != hrSuccess)
  418. return hr;
  419. assert(cProps <= cMaxProps);
  420. // the folder "Public Folders"
  421. ++ulRowId;
  422. cProps = 0;
  423. cMaxProps = 20;
  424. hr = MAPIAllocateBuffer(sizeof(SPropValue) * cMaxProps, &~lpProps);
  425. if(hr != hrSuccess)
  426. return hr;
  427. lpProps[cProps].ulPropTag = PR_ENTRYID;
  428. hr = ((ECMsgStorePublic*)GetMsgStore())->GetPublicEntryId(ePE_PublicFolders, lpProps, &lpProps[cProps].Value.bin.cb, (LPENTRYID*)&lpProps[cProps].Value.bin.lpb);
  429. if(hr != hrSuccess)
  430. return hr;
  431. ++cProps;
  432. lpProps[cProps].ulPropTag = PR_LONGTERM_ENTRYID_FROM_TABLE;
  433. hr = GetPublicEntryId(ePE_PublicFolders, lpProps, &lpProps[cProps].Value.bin.cb, (LPENTRYID*)&lpProps[cProps].Value.bin.lpb);
  434. if(hr != hrSuccess)
  435. return hr;
  436. ++cProps;
  437. lpProps[cProps].ulPropTag = PR_DISPLAY_TYPE;
  438. lpProps[cProps++].Value.ul = DT_FOLDER;
  439. lpProps[cProps].ulPropTag = PR_DEPTH;
  440. lpProps[cProps++].Value.ul = 1;
  441. lpProps[cProps].ulPropTag = PR_PARENT_ENTRYID;
  442. hr = GetPublicEntryId(ePE_IPMSubtree, lpProps, &lpProps[cProps].Value.bin.cb, (LPENTRYID*)&lpProps[cProps].Value.bin.lpb);
  443. if (hr != hrSuccess)
  444. return hr;
  445. ++cProps;
  446. lpProps[cProps].ulPropTag = PR_DISPLAY_NAME_W;
  447. lpProps[cProps++].Value.lpszW = _W("Public Folders"); // FIXME: Use dynamic name, read from global profile (like exchange)
  448. lpProps[cProps].ulPropTag = PR_CONTENT_COUNT;
  449. lpProps[cProps++].Value.ul = 0;
  450. lpProps[cProps].ulPropTag = PR_CONTENT_UNREAD;
  451. lpProps[cProps++].Value.ul = 0;
  452. if (ECMAPIProp::DefaultMAPIGetProp(PR_STORE_ENTRYID, this, 0, &lpProps[cProps], this, lpProps) == hrSuccess)
  453. ++cProps;
  454. if (ECMAPIProp::DefaultMAPIGetProp(PR_STORE_RECORD_KEY, this, 0, &lpProps[cProps], this, lpProps) == hrSuccess)
  455. ++cProps;
  456. if (ECMAPIProp::DefaultMAPIGetProp(PR_STORE_SUPPORT_MASK, this, 0, &lpProps[cProps], this, lpProps) == hrSuccess)
  457. ++cProps;
  458. lpProps[cProps].ulPropTag = PR_INSTANCE_KEY;
  459. lpProps[cProps].Value.bin.cb = sizeof(ULONG)*2;
  460. hr = MAPIAllocateMore(lpProps[cProps].Value.bin.cb, lpProps, (void**)&lpProps[cProps].Value.bin.lpb);
  461. if(hr != hrSuccess)
  462. return hr;
  463. memset(lpProps[cProps].Value.bin.lpb, 0, lpProps[cProps].Value.bin.cb );
  464. memcpy(lpProps[cProps].Value.bin.lpb, &ulRowId, sizeof(ULONG));
  465. ++cProps;
  466. lpProps[cProps].ulPropTag = PR_RECORD_KEY;
  467. hr = GetPublicEntryId(ePE_PublicFolders, lpProps, &lpProps[cProps].Value.bin.cb, (LPENTRYID*)&lpProps[cProps].Value.bin.lpb);
  468. if(hr != hrSuccess)
  469. return hr;
  470. ++cProps;
  471. lpProps[cProps].ulPropTag = PR_ACCESS;
  472. lpProps[cProps++].Value.ul = 2; //FIXME: use variable
  473. lpProps[cProps].ulPropTag = PR_ACCESS_LEVEL;
  474. lpProps[cProps++].Value.ul = 1;
  475. //lpProps[cProps].ulPropTag = PR_RIGHTS;
  476. //lpProps[cProps++].Value.ul = 1;
  477. lpProps[cProps].ulPropTag = PR_SUBFOLDERS;
  478. lpProps[cProps++].Value.b = true;
  479. lpProps[cProps].ulPropTag = PR_OBJECT_TYPE;
  480. lpProps[cProps++].Value.ul = MAPI_FOLDER;
  481. lpProps[cProps].ulPropTag = PR_FOLDER_TYPE;
  482. lpProps[cProps++].Value.ul = FOLDER_GENERIC;
  483. lpProps[cProps].ulPropTag = PR_ROWID;
  484. lpProps[cProps++].Value.ul = ulRowId;
  485. sKeyProp.ulPropTag = PR_ROWID;
  486. sKeyProp.Value.ul = ulRowId;
  487. hr = lpIPMSubTree->HrModifyRow(ECKeyTable::TABLE_ROW_ADD, &sKeyProp, lpProps, cProps);
  488. if (hr != hrSuccess)
  489. return hr;
  490. assert(cProps <= cMaxProps);
  491. m_lpIPMSubTree = lpIPMSubTree;
  492. return hrSuccess;
  493. }
  494. ECMemTable *ECMsgStorePublic::GetIPMSubTree()
  495. {
  496. assert(m_lpIPMSubTree != NULL);
  497. return m_lpIPMSubTree;
  498. }
  499. HRESULT ECMsgStorePublic::GetDefaultShortcutFolder(IMAPIFolder** lppFolder)
  500. {
  501. HRESULT hr = hrSuccess;
  502. ULONG ulObjType;
  503. object_ptr<IMAPIFolder> lpFolder;
  504. object_ptr<IMsgStore> lpMsgStore;
  505. memory_ptr<SPropValue> lpPropValue;
  506. ULONG cbEntryId;
  507. memory_ptr<ENTRYID> lpEntryId, lpStoreEntryID;
  508. ULONG cbStoreEntryID;
  509. string strRedirServer;
  510. object_ptr<WSTransport> lpTmpTransport;
  511. if (m_lpDefaultMsgStore == NULL)
  512. {
  513. // Get the default store for this user
  514. hr = lpTransport->HrGetStore(0, NULL, &cbStoreEntryID, &~lpStoreEntryID, NULL, NULL, &strRedirServer);
  515. if (hr == MAPI_E_UNABLE_TO_COMPLETE) {
  516. // reopen store of user which is on another server
  517. hr = lpTransport->CreateAndLogonAlternate(strRedirServer.c_str(), &~lpTmpTransport);
  518. if (hr != hrSuccess)
  519. goto exit;
  520. hr = lpTmpTransport->HrGetStore(0, NULL, &cbStoreEntryID, &~lpStoreEntryID, NULL, NULL);
  521. }
  522. if(hr != hrSuccess)
  523. goto exit;
  524. hr = WrapStoreEntryID(0, (LPTSTR)WCLIENT_DLL_NAME, cbStoreEntryID, lpStoreEntryID, &cbEntryId, &~lpEntryId);
  525. if(hr != hrSuccess)
  526. goto exit;
  527. // Open default store
  528. hr = lpSupport->OpenEntry(cbEntryId, lpEntryId, &IID_IMsgStore, MAPI_BEST_ACCESS, &ulObjType, &~lpMsgStore);
  529. if(hr != hrSuccess)
  530. goto exit;
  531. hr = lpMsgStore->QueryInterface(IID_IMsgStore, (void**)&m_lpDefaultMsgStore);
  532. if (hr != hrSuccess)
  533. goto exit;
  534. }
  535. // Get shortcut entryid
  536. hr = HrGetOneProp(m_lpDefaultMsgStore, PR_IPM_FAVORITES_ENTRYID, &~lpPropValue);
  537. if(hr != hrSuccess)
  538. goto exit;
  539. // Open Shortcut folder
  540. hr = m_lpDefaultMsgStore->OpenEntry(lpPropValue->Value.bin.cb, reinterpret_cast<ENTRYID *>(lpPropValue->Value.bin.lpb), &IID_IMAPIFolder, MAPI_BEST_ACCESS, &ulObjType, &~lpFolder);
  541. if (hr != hrSuccess)
  542. goto exit;
  543. hr = lpFolder->QueryInterface(IID_IMAPIFolder, (void**)lppFolder);
  544. if (hr != hrSuccess)
  545. goto exit;
  546. exit:
  547. if (lpTmpTransport != nullptr)
  548. lpTmpTransport->HrLogOff();
  549. return hr;
  550. }
  551. HRESULT ECMsgStorePublic::Advise(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulEventMask, LPMAPIADVISESINK lpAdviseSink, ULONG *lpulConnection)
  552. {
  553. HRESULT hr = hrSuccess;
  554. ULONG ulResult = 0;
  555. memory_ptr<ENTRYID> lpEntryIDIntern;
  556. if(ComparePublicEntryId(ePE_IPMSubtree, cbEntryID, lpEntryID, &ulResult) == hrSuccess && ulResult == TRUE) {
  557. return MAPI_E_NO_SUPPORT; // FIXME
  558. } else if(ComparePublicEntryId(ePE_Favorites, cbEntryID, lpEntryID, &ulResult) == hrSuccess && ulResult == TRUE) {
  559. return MAPI_E_NO_SUPPORT; // FIXME
  560. } else if(ComparePublicEntryId(ePE_PublicFolders, cbEntryID, lpEntryID, &ulResult) == hrSuccess && ulResult == TRUE) {
  561. return MAPI_E_NO_SUPPORT; // FIXME
  562. } else if (lpEntryID && (lpEntryID->abFlags[3] & KOPANO_FAVORITE)) {
  563. // Replace the original entryid because this one is only readable
  564. hr = MAPIAllocateBuffer(cbEntryID, &~lpEntryIDIntern);
  565. if (hr != hrSuccess)
  566. return hr;
  567. memcpy(lpEntryIDIntern, lpEntryID, cbEntryID);
  568. // Remove Flags intern
  569. lpEntryIDIntern->abFlags[3] &= ~KOPANO_FAVORITE;
  570. lpEntryID = lpEntryIDIntern;
  571. }
  572. return ECMsgStore::Advise(cbEntryID, lpEntryID, ulEventMask, lpAdviseSink, lpulConnection);
  573. }