ECMAPIFolderPublic.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  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 "ECMAPIFolderPublic.h"
  21. #include "Mem.h"
  22. #include <kopano/ECGuid.h>
  23. #include <edkguid.h>
  24. #include <kopano/CommonUtil.h>
  25. #include <kopano/Util.h>
  26. #include "ClientUtil.h"
  27. #include "pcutil.hpp"
  28. #include <kopano/ECDebug.h>
  29. #include <edkmdb.h>
  30. #include <kopano/mapiext.h>
  31. #include <kopano/stringutil.h>
  32. #include "ECMsgStorePublic.h"
  33. #include "ECMemTablePublic.h"
  34. #include "favoritesutil.h"
  35. #include <kopano/charset/convstring.h>
  36. #include <kopano/ECGetText.h>
  37. #include <mapiutil.h>
  38. using namespace KCHL;
  39. ECMAPIFolderPublic::ECMAPIFolderPublic(ECMsgStore *lpMsgStore, BOOL fModify, WSMAPIFolderOps *lpFolderOps, enumPublicEntryID ePublicEntryID) :
  40. ECMAPIFolder(lpMsgStore, fModify, lpFolderOps, "IMAPIFolderPublic")
  41. {
  42. HrAddPropHandlers(PR_ACCESS, GetPropHandler, DefaultSetPropComputed, (void *)this);
  43. HrAddPropHandlers(PR_ACCESS_LEVEL, GetPropHandler, DefaultSetPropComputed, (void *)this);
  44. HrAddPropHandlers(PR_RIGHTS, GetPropHandler, DefaultSetPropComputed, (void *)this);
  45. HrAddPropHandlers(PR_ENTRYID, GetPropHandler, DefaultSetPropComputed, (void *)this);
  46. // FIXME: special for publicfolders, save in global profile
  47. HrAddPropHandlers(PR_DISPLAY_NAME, GetPropHandler, SetPropHandler, (void *)this);
  48. HrAddPropHandlers(PR_COMMENT, GetPropHandler, SetPropHandler, (void *)this);
  49. HrAddPropHandlers(PR_RECORD_KEY, GetPropHandler, DefaultSetPropComputed, (void*) this);
  50. HrAddPropHandlers(PR_PARENT_ENTRYID,GetPropHandler, DefaultSetPropComputed, (void*) this);
  51. HrAddPropHandlers(PR_FOLDER_TYPE, GetPropHandler, DefaultSetPropSetReal, (void*) this);
  52. HrAddPropHandlers(PR_FOLDER_CHILD_COUNT, GetPropHandler, DefaultSetPropComputed, (void *)this);
  53. HrAddPropHandlers(PR_SUBFOLDERS, GetPropHandler, DefaultSetPropComputed, (void *)this);
  54. HrAddPropHandlers(PR_ORIGINAL_ENTRYID, GetPropHandler, DefaultSetPropComputed, (void *)this, FALSE, TRUE);
  55. m_ePublicEntryID = ePublicEntryID;
  56. }
  57. HRESULT ECMAPIFolderPublic::QueryInterface(REFIID refiid, void **lppInterface)
  58. {
  59. REGISTER_INTERFACE2(ECMAPIFolderPublic, this);
  60. return ECMAPIFolder::QueryInterface(refiid, lppInterface);
  61. }
  62. HRESULT ECMAPIFolderPublic::Create(ECMsgStore *lpMsgStore, BOOL fModify, WSMAPIFolderOps *lpFolderOps, enumPublicEntryID ePublicEntryID, ECMAPIFolder **lppECMAPIFolder)
  63. {
  64. HRESULT hr = hrSuccess;
  65. auto lpMAPIFolder = new(std::nothrow) ECMAPIFolderPublic(lpMsgStore, fModify, lpFolderOps, ePublicEntryID);
  66. if (lpMAPIFolder == nullptr)
  67. return MAPI_E_NOT_ENOUGH_MEMORY;
  68. hr = lpMAPIFolder->QueryInterface(IID_ECMAPIFolder, (void **)lppECMAPIFolder);
  69. if(hr != hrSuccess)
  70. delete lpMAPIFolder;
  71. return hr;
  72. }
  73. HRESULT ECMAPIFolderPublic::GetPropHandler(ULONG ulPropTag, void* lpProvider, ULONG ulFlags, LPSPropValue lpsPropValue, void *lpParam, void *lpBase)
  74. {
  75. HRESULT hr = hrSuccess;
  76. LPCTSTR lpszName = NULL;
  77. auto lpFolder = static_cast<ECMAPIFolderPublic *>(lpParam);
  78. switch(PROP_ID(ulPropTag)) {
  79. case PROP_ID(PR_FOLDER_TYPE):
  80. if (lpFolder->m_ePublicEntryID == ePE_PublicFolders || lpFolder->m_ePublicEntryID == ePE_IPMSubtree || lpFolder->m_ePublicEntryID == ePE_Favorites) {
  81. lpsPropValue->ulPropTag = PR_FOLDER_TYPE;
  82. lpsPropValue->Value.l = FOLDER_GENERIC;
  83. } else {
  84. hr = lpFolder->HrGetRealProp(PR_FOLDER_TYPE, ulFlags, lpBase, lpsPropValue);
  85. }
  86. break;
  87. case PROP_ID(PR_ACCESS):
  88. // FIXME: use MAPI_ACCESS_MODIFY for favorites, public, favo sub folders to change the displayname and comment
  89. if (lpFolder->m_ePublicEntryID == ePE_IPMSubtree) {
  90. lpsPropValue->ulPropTag = PR_ACCESS;
  91. lpsPropValue->Value.l = MAPI_ACCESS_READ;
  92. }else if (lpFolder->m_ePublicEntryID == ePE_Favorites) {
  93. lpsPropValue->ulPropTag = PR_ACCESS;
  94. lpsPropValue->Value.l = MAPI_ACCESS_READ;
  95. } else {
  96. hr = lpFolder->HrGetRealProp(PR_ACCESS, ulFlags, lpBase, lpsPropValue);
  97. if (hr == hrSuccess && lpFolder->m_ePublicEntryID == ePE_FavoriteSubFolder)
  98. lpsPropValue->Value.l |= MAPI_ACCESS_READ | MAPI_ACCESS_DELETE;
  99. else if(hr == hrSuccess && lpFolder->m_ePublicEntryID == ePE_PublicFolders)
  100. lpsPropValue->Value.l &= ~(MAPI_ACCESS_CREATE_CONTENTS | MAPI_ACCESS_CREATE_ASSOCIATED);
  101. }
  102. break;
  103. case PROP_ID(PR_ACCESS_LEVEL):
  104. if (lpFolder->m_ePublicEntryID == ePE_IPMSubtree || lpFolder->m_ePublicEntryID == ePE_FavoriteSubFolder) {
  105. lpsPropValue->ulPropTag = PR_ACCESS_LEVEL;
  106. lpsPropValue->Value.l = MAPI_MODIFY;
  107. } else if(lpFolder->m_ePublicEntryID == ePE_Favorites) {
  108. lpsPropValue->ulPropTag = PR_ACCESS_LEVEL;
  109. lpsPropValue->Value.l = 0;
  110. } else {
  111. hr = lpFolder->HrGetRealProp(PR_ACCESS_LEVEL, ulFlags, lpBase, lpsPropValue);
  112. }
  113. break;
  114. case PROP_ID(PR_RIGHTS):
  115. if (lpFolder->m_ePublicEntryID == ePE_IPMSubtree) {
  116. lpsPropValue->ulPropTag = PR_RIGHTS;
  117. lpsPropValue->Value.l = ecRightsFolderVisible | ecRightsReadAny;
  118. } else if (lpFolder->m_ePublicEntryID == ePE_Favorites) {
  119. lpsPropValue->ulPropTag = PR_RIGHTS;
  120. lpsPropValue->Value.l = ecRightsAll;
  121. } else if (lpFolder->m_ePublicEntryID == ePE_PublicFolders) {
  122. lpsPropValue->ulPropTag = PR_RIGHTS;
  123. lpsPropValue->Value.l = ecRightsAll &~ecRightsCreate;
  124. } else {
  125. hr = lpFolder->HrGetRealProp(PR_RIGHTS, ulFlags, lpBase, lpsPropValue);
  126. }
  127. break;
  128. case PROP_ID(PR_ENTRYID):
  129. if (lpFolder->m_ePublicEntryID == ePE_PublicFolders) {
  130. lpsPropValue->ulPropTag = PR_ENTRYID;
  131. hr = ::GetPublicEntryId(ePE_PublicFolders, ((ECMsgStorePublic*)lpFolder->GetMsgStore())->GetStoreGuid(), lpBase, &lpsPropValue->Value.bin.cb, (LPENTRYID*)&lpsPropValue->Value.bin.lpb);
  132. } else {
  133. hr = ECGenericProp::DefaultGetProp(PR_ENTRYID, lpProvider, ulFlags, lpsPropValue, lpParam, lpBase);
  134. if(hr == hrSuccess && lpFolder->m_ePublicEntryID == ePE_FavoriteSubFolder)
  135. ((LPENTRYID)lpsPropValue->Value.bin.lpb)->abFlags[3] = KOPANO_FAVORITE;
  136. }
  137. break;
  138. case PROP_ID(PR_DISPLAY_NAME):
  139. // FIXME: Should be from the global profile and/or gettext (PR_FAVORITES_DEFAULT_NAME)
  140. if (lpFolder->m_ePublicEntryID == ePE_PublicFolders)
  141. lpszName = _("Public Folders");
  142. else if (lpFolder->m_ePublicEntryID == ePE_Favorites)
  143. lpszName = _("Favorites");
  144. else if (lpFolder->m_ePublicEntryID == ePE_IPMSubtree)
  145. lpszName = _T("IPM_SUBTREE");
  146. if (lpszName)
  147. {
  148. if (PROP_TYPE(ulPropTag) == PT_UNICODE) {
  149. const std::wstring strTmp = convert_to<std::wstring>(lpszName);
  150. hr = MAPIAllocateMore((strTmp.size() + 1) * sizeof(WCHAR), lpBase, (void**)&lpsPropValue->Value.lpszW);
  151. if (hr != hrSuccess)
  152. return hr;
  153. wcscpy(lpsPropValue->Value.lpszW, strTmp.c_str());
  154. lpsPropValue->ulPropTag = PR_DISPLAY_NAME_W;
  155. } else {
  156. const std::string strTmp = convert_to<std::string>(lpszName);
  157. hr = MAPIAllocateMore(strTmp.size() + 1, lpBase, (void**)&lpsPropValue->Value.lpszA);
  158. if (hr != hrSuccess)
  159. return hr;
  160. strcpy(lpsPropValue->Value.lpszA, strTmp.c_str());
  161. lpsPropValue->ulPropTag = PR_DISPLAY_NAME_A;
  162. }
  163. } else {
  164. hr = lpFolder->HrGetRealProp(ulPropTag, ulFlags, lpBase, lpsPropValue);
  165. }
  166. break;
  167. case PROP_ID(PR_COMMENT):
  168. // FIXME: load the message class from shortcut (favorite) folder, see setprops
  169. hr = lpFolder->HrGetRealProp(ulPropTag, ulFlags, lpBase, lpsPropValue);
  170. break;
  171. case PROP_ID(PR_RECORD_KEY):
  172. // Use entryid as record key because it should be global unique in outlook.
  173. hr = ECMAPIFolderPublic::GetPropHandler(PR_ENTRYID, lpProvider, ulFlags, lpsPropValue, lpParam, lpBase);
  174. if (hr == hrSuccess) {
  175. if(lpFolder->m_ePublicEntryID == ePE_FavoriteSubFolder)
  176. ((LPENTRYID)lpsPropValue->Value.bin.lpb)->abFlags[3] = KOPANO_FAVORITE;
  177. lpsPropValue->ulPropTag = PR_RECORD_KEY;
  178. }
  179. break;
  180. case PROP_ID(PR_PARENT_ENTRYID):
  181. if (lpFolder->m_ePublicEntryID == ePE_IPMSubtree || lpFolder->m_ePublicEntryID == ePE_PublicFolders || lpFolder->m_ePublicEntryID == ePE_Favorites) {
  182. lpsPropValue->ulPropTag = PR_PARENT_ENTRYID;
  183. hr = ::GetPublicEntryId(ePE_IPMSubtree, ((ECMsgStorePublic*)lpFolder->GetMsgStore())->GetStoreGuid(), lpBase, &lpsPropValue->Value.bin.cb, (LPENTRYID*)&lpsPropValue->Value.bin.lpb);
  184. } else {
  185. hr = ECMAPIFolder::DefaultMAPIGetProp(PR_PARENT_ENTRYID, lpProvider, ulFlags, lpsPropValue, lpParam, lpBase);
  186. }
  187. break;
  188. case PROP_ID(PR_FOLDER_CHILD_COUNT):
  189. if (lpFolder->m_ePublicEntryID == ePE_IPMSubtree) {
  190. lpsPropValue->ulPropTag = PR_FOLDER_CHILD_COUNT;
  191. lpsPropValue->Value.ul = 2;
  192. } else {
  193. hr = ECMAPIFolder::GetPropHandler(PR_FOLDER_CHILD_COUNT, lpProvider, ulFlags, lpsPropValue, lpParam, lpBase);
  194. }
  195. break;
  196. case PROP_ID(PR_SUBFOLDERS):
  197. if (lpFolder->m_ePublicEntryID == ePE_IPMSubtree) {
  198. lpsPropValue->ulPropTag = PR_SUBFOLDERS;
  199. lpsPropValue->Value.b = TRUE;
  200. } else {
  201. hr = ECMAPIFolder::GetPropHandler(PR_SUBFOLDERS, lpProvider, ulFlags, lpsPropValue, lpParam, lpBase);
  202. }
  203. break;
  204. case PROP_ID(PR_DISPLAY_TYPE):
  205. if (lpFolder->m_ePublicEntryID == ePE_FavoriteSubFolder) {
  206. lpsPropValue->ulPropTag = PR_DISPLAY_TYPE;
  207. lpsPropValue->Value.ul = DT_FOLDER_LINK;
  208. }else {
  209. hr = lpFolder->HrGetRealProp(PR_DISPLAY_TYPE, ulFlags, lpBase, lpsPropValue);
  210. }
  211. break;
  212. case PROP_ID(PR_ORIGINAL_ENTRYID):
  213. // entryid on the server (only used for "Public Folders" folder)
  214. if (lpFolder->m_lpEntryId) {
  215. if ((hr = MAPIAllocateMore(lpFolder->m_cbEntryId, lpBase, (LPVOID*)&lpsPropValue->Value.bin.lpb)) != hrSuccess)
  216. return hr;
  217. memcpy(lpsPropValue->Value.bin.lpb, lpFolder->m_lpEntryId, lpFolder->m_cbEntryId);
  218. lpsPropValue->Value.bin.cb = lpFolder->m_cbEntryId;
  219. hr = hrSuccess;
  220. } else {
  221. hr = MAPI_E_NOT_FOUND;
  222. }
  223. break;
  224. default:
  225. hr = MAPI_E_NOT_FOUND;
  226. break;
  227. }
  228. return hr;
  229. }
  230. HRESULT ECMAPIFolderPublic::SetPropHandler(ULONG ulPropTag, void *lpProvider,
  231. const SPropValue *lpsPropValue, void *lpParam)
  232. {
  233. HRESULT hr = hrSuccess;
  234. auto lpFolder = static_cast<ECMAPIFolderPublic *>(lpParam);
  235. switch(PROP_ID(ulPropTag)) {
  236. case PROP_ID(PR_DISPLAY_NAME):
  237. if (lpFolder->m_ePublicEntryID == ePE_PublicFolders)
  238. hr = MAPI_E_COMPUTED;
  239. // FIXME: save in profile, #define PR_PROFILE_ALLPUB_DISPLAY_NAME PROP_TAG(PT_STRING8, pidProfileMin+0x16)
  240. else if (lpFolder->m_ePublicEntryID == ePE_Favorites)
  241. hr = MAPI_E_COMPUTED;
  242. // FIXME: save in profile, #define PR_PROFILE_FAVFLD_DISPLAY_NAME PROP_TAG(PT_STRING8, pidProfileMin+0x0F)
  243. else if (lpFolder->m_ePublicEntryID == ePE_FavoriteSubFolder)
  244. hr = MAPI_E_COMPUTED;
  245. // FIXME: Save the property to private shortcut folder message
  246. else
  247. hr = lpFolder->HrSetRealProp(lpsPropValue);
  248. break;
  249. case PROP_ID(PR_COMMENT):
  250. if (lpFolder->m_ePublicEntryID == ePE_PublicFolders)
  251. hr = MAPI_E_COMPUTED;
  252. // FIXME: save in profile, #define PR_PROFILE_FAVFLD_COMMENT PROP_TAG(PT_STRING8, pidProfileMin+0x15)
  253. else if (lpFolder->m_ePublicEntryID == ePE_Favorites)
  254. hr = MAPI_E_COMPUTED;
  255. // FIXME: save in profile, #define PR_PROFILE_FAVFLD_COMMENT PROP_TAG(PT_STRING8, pidProfileMin+0x15)
  256. else
  257. hr = lpFolder->HrSetRealProp(lpsPropValue);
  258. break;
  259. default:
  260. hr = MAPI_E_NOT_FOUND;
  261. break;
  262. }
  263. return hr;
  264. }
  265. HRESULT ECMAPIFolderPublic::GetContentsTable(ULONG ulFlags, LPMAPITABLE *lppTable)
  266. {
  267. HRESULT hr = hrSuccess;
  268. object_ptr<ECMemTable> lpMemTable;
  269. object_ptr<ECMemTableView> lpView;
  270. memory_ptr<SPropTagArray> lpPropTagArray;
  271. static constexpr const SizedSPropTagArray(11, sPropsContentColumns) =
  272. {11, {PR_ENTRYID, PR_DISPLAY_NAME, PR_MESSAGE_FLAGS, PR_SUBJECT,
  273. PR_STORE_ENTRYID, PR_STORE_RECORD_KEY, PR_STORE_SUPPORT_MASK,
  274. PR_INSTANCE_KEY, PR_RECORD_KEY, PR_ACCESS, PR_ACCESS_LEVEL}};
  275. if (m_ePublicEntryID != ePE_IPMSubtree && m_ePublicEntryID != ePE_Favorites)
  276. return ECMAPIFolder::GetContentsTable(ulFlags, lppTable);
  277. if (ulFlags & SHOW_SOFT_DELETES)
  278. return MAPI_E_NO_SUPPORT;
  279. hr = Util::HrCopyUnicodePropTagArray(ulFlags,
  280. sPropsContentColumns, &~lpPropTagArray);
  281. if (hr != hrSuccess)
  282. return hr;
  283. hr = ECMemTable::Create(lpPropTagArray, PR_ROWID, &~lpMemTable);
  284. if (hr != hrSuccess)
  285. return hr;
  286. hr = lpMemTable->HrGetView(createLocaleFromName(""), ulFlags & MAPI_UNICODE, &~lpView);
  287. if (hr != hrSuccess)
  288. return hr;
  289. return lpView->QueryInterface(IID_IMAPITable, reinterpret_cast<void **>(lppTable));
  290. }
  291. HRESULT ECMAPIFolderPublic::GetHierarchyTable(ULONG ulFlags, LPMAPITABLE *lppTable)
  292. {
  293. HRESULT hr = hrSuccess;
  294. object_ptr<ECMemTableView> lpView;
  295. object_ptr<ECMemTablePublic> lpMemTable;
  296. if( m_ePublicEntryID == ePE_IPMSubtree)
  297. {
  298. // FIXME: if exchange support CONVENIENT_DEPTH than we must implement this
  299. if (ulFlags & (SHOW_SOFT_DELETES | CONVENIENT_DEPTH))
  300. return MAPI_E_NO_SUPPORT;
  301. hr = ((ECMsgStorePublic *)GetMsgStore())->GetIPMSubTree()->HrGetView(createLocaleFromName(""), ulFlags, &~lpView);
  302. if(hr != hrSuccess)
  303. return hr;
  304. return lpView->QueryInterface(IID_IMAPITable, (void **)lppTable);
  305. } else if( m_ePublicEntryID == ePE_Favorites || m_ePublicEntryID == ePE_FavoriteSubFolder) {
  306. // FIXME: if exchange support CONVENIENT_DEPTH than we must implement this
  307. if (ulFlags & (SHOW_SOFT_DELETES | CONVENIENT_DEPTH))
  308. return MAPI_E_NO_SUPPORT;
  309. hr = ECMemTablePublic::Create(this, &~lpMemTable);
  310. if(hr != hrSuccess)
  311. return hr;
  312. hr = lpMemTable->Init(ulFlags&MAPI_UNICODE);
  313. if(hr != hrSuccess)
  314. return hr;
  315. hr = lpMemTable->HrGetView(createLocaleFromName(""), ulFlags & MAPI_UNICODE, &~lpView);
  316. if(hr != hrSuccess)
  317. return hr;
  318. return lpView->QueryInterface(IID_IMAPITable, reinterpret_cast<void **>(lppTable));
  319. } else {
  320. return ECMAPIFolder::GetHierarchyTable(ulFlags, lppTable);
  321. }
  322. }
  323. HRESULT ECMAPIFolderPublic::SaveChanges(ULONG ulFlags)
  324. {
  325. HRESULT hr = hrSuccess;
  326. // Nothing to do
  327. return hr;
  328. }
  329. HRESULT ECMAPIFolderPublic::SetProps(ULONG cValues,
  330. const SPropValue *lpPropArray, SPropProblemArray **lppProblems)
  331. {
  332. HRESULT hr;
  333. hr = ECMAPIContainer::SetProps(cValues, lpPropArray, lppProblems);
  334. if (hr != hrSuccess)
  335. return hr;
  336. if (lpStorage)
  337. {
  338. hr = ECMAPIContainer::SaveChanges(KEEP_OPEN_READWRITE);
  339. if (hr != hrSuccess)
  340. return hr;
  341. }
  342. return hrSuccess;
  343. }
  344. HRESULT ECMAPIFolderPublic::DeleteProps(const SPropTagArray *lpPropTagArray,
  345. SPropProblemArray **lppProblems)
  346. {
  347. HRESULT hr;
  348. hr = ECMAPIContainer::DeleteProps(lpPropTagArray, lppProblems);
  349. if (hr != hrSuccess)
  350. return hr;
  351. if (lpStorage == nullptr)
  352. return hrSuccess;
  353. return ECMAPIContainer::SaveChanges(KEEP_OPEN_READWRITE);
  354. }
  355. HRESULT ECMAPIFolderPublic::OpenEntry(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulFlags, ULONG *lpulObjType, LPUNKNOWN *lppUnk)
  356. {
  357. HRESULT hr;
  358. unsigned int ulObjType = 0;
  359. if (cbEntryID > 0)
  360. {
  361. hr = HrGetObjTypeFromEntryId(cbEntryID, (LPBYTE)lpEntryID, &ulObjType);
  362. if(hr != hrSuccess)
  363. return hr;
  364. if (ulObjType == MAPI_FOLDER && m_ePublicEntryID == ePE_FavoriteSubFolder)
  365. lpEntryID->abFlags[3] = KOPANO_FAVORITE;
  366. }
  367. return ECMAPIFolder::OpenEntry(cbEntryID, lpEntryID, lpInterface, ulFlags, lpulObjType, lppUnk);
  368. }
  369. HRESULT ECMAPIFolderPublic::SetEntryId(ULONG cbEntryId, LPENTRYID lpEntryId)
  370. {
  371. if (m_ePublicEntryID == ePE_Favorites || m_ePublicEntryID == ePE_IPMSubtree)
  372. return ECGenericProp::SetEntryId(cbEntryId, lpEntryId);
  373. // With notification handler
  374. return ECMAPIFolder::SetEntryId(cbEntryId, lpEntryId);
  375. }
  376. // @note if you change this function please look also at ECMAPIFolder::CopyFolder
  377. HRESULT ECMAPIFolderPublic::CopyFolder(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, LPVOID lpDestFolder, LPTSTR lpszNewFolderName, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)
  378. {
  379. HRESULT hr = hrSuccess;
  380. ULONG ulResult = 0;
  381. object_ptr<IMAPIFolder> lpMapiFolder;
  382. ecmem_ptr<SPropValue> lpPropArray;
  383. GUID guidDest;
  384. GUID guidFrom;
  385. //Get the interface of destinationfolder
  386. if(lpInterface == NULL || *lpInterface == IID_IMAPIFolder)
  387. hr = ((IMAPIFolder*)lpDestFolder)->QueryInterface(IID_IMAPIFolder, &~lpMapiFolder);
  388. else if(*lpInterface == IID_IMAPIContainer)
  389. hr = ((IMAPIContainer*)lpDestFolder)->QueryInterface(IID_IMAPIFolder, &~lpMapiFolder);
  390. else if(*lpInterface == IID_IUnknown)
  391. hr = ((IUnknown*)lpDestFolder)->QueryInterface(IID_IMAPIFolder, &~lpMapiFolder);
  392. else if(*lpInterface == IID_IMAPIProp)
  393. hr = ((IMAPIProp*)lpDestFolder)->QueryInterface(IID_IMAPIFolder, &~lpMapiFolder);
  394. else
  395. hr = MAPI_E_INTERFACE_NOT_SUPPORTED;
  396. if(hr != hrSuccess)
  397. return hr;
  398. // Get the destination entry ID
  399. hr = HrGetOneProp(lpMapiFolder, PR_ENTRYID, &~lpPropArray);
  400. if(hr != hrSuccess)
  401. return hr;
  402. // Check if it's the same store of kopano so we can copy/move fast
  403. if( IsKopanoEntryId(cbEntryID, (LPBYTE)lpEntryID) &&
  404. IsKopanoEntryId(lpPropArray[0].Value.bin.cb, lpPropArray[0].Value.bin.lpb) &&
  405. HrGetStoreGuidFromEntryId(cbEntryID, (LPBYTE)lpEntryID, &guidFrom) == hrSuccess &&
  406. HrGetStoreGuidFromEntryId(lpPropArray[0].Value.bin.cb, lpPropArray[0].Value.bin.lpb, &guidDest) == hrSuccess &&
  407. memcmp(&guidFrom, &guidDest, sizeof(GUID)) == 0 &&
  408. lpFolderOps != NULL)
  409. {
  410. // if the entryid a a publicfolders entryid just change the entryid to a server entryid
  411. if(((ECMsgStorePublic*)GetMsgStore())->ComparePublicEntryId(ePE_PublicFolders, lpPropArray[0].Value.bin.cb, (LPENTRYID)lpPropArray[0].Value.bin.lpb, &ulResult) == hrSuccess && ulResult == TRUE)
  412. {
  413. hr = HrGetOneProp(lpMapiFolder, PR_ORIGINAL_ENTRYID, &~lpPropArray);
  414. if(hr != hrSuccess)
  415. return hr;
  416. }
  417. //FIXME: Progressbar
  418. hr = this->lpFolderOps->HrCopyFolder(cbEntryID, lpEntryID, lpPropArray[0].Value.bin.cb, (LPENTRYID)lpPropArray[0].Value.bin.lpb, convstring(lpszNewFolderName, ulFlags), ulFlags, 0);
  419. }else
  420. {
  421. // Support object handled de copy/move
  422. hr = this->GetMsgStore()->lpSupport->CopyFolder(&IID_IMAPIFolder, &this->m_xMAPIFolder, cbEntryID, lpEntryID, lpInterface, lpDestFolder, lpszNewFolderName, ulUIParam, lpProgress, ulFlags);
  423. }
  424. return hr;
  425. }
  426. HRESULT ECMAPIFolderPublic::DeleteFolder(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)
  427. {
  428. HRESULT hr = hrSuccess;
  429. ULONG ulObjType = 0;
  430. memory_ptr<SPropValue> lpProp;
  431. if (ValidateZEntryId(cbEntryID, reinterpret_cast<BYTE *>(lpEntryID), MAPI_FOLDER) == false)
  432. return MAPI_E_INVALID_ENTRYID;
  433. if (cbEntryID <= 4 || !(lpEntryID->abFlags[3] & KOPANO_FAVORITE))
  434. return ECMAPIFolder::DeleteFolder(cbEntryID, lpEntryID,
  435. ulUIParam, lpProgress, ulFlags);
  436. // remove the shortcut from the shortcut folder
  437. object_ptr<IMAPIFolder> lpFolder, lpShortcutFolder;
  438. hr = OpenEntry(cbEntryID, lpEntryID, nullptr, 0, &ulObjType, &~lpFolder);
  439. if (hr != hrSuccess)
  440. return hr;
  441. hr = HrGetOneProp(lpFolder, PR_SOURCE_KEY, &~lpProp);
  442. if (hr != hrSuccess)
  443. return hr;
  444. hr = ((ECMsgStorePublic *)GetMsgStore())->GetDefaultShortcutFolder(&~lpShortcutFolder);
  445. if (hr != hrSuccess)
  446. return hr;
  447. return DelFavoriteFolder(lpShortcutFolder, lpProp);
  448. }
  449. HRESULT ECMAPIFolderPublic::CopyMessages(LPENTRYLIST lpMsgList, LPCIID lpInterface, LPVOID lpDestFolder, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)
  450. {
  451. HRESULT hr = hrSuccess;
  452. ULONG ulResult = 0;
  453. object_ptr<IMAPIFolder> lpMapiFolder;
  454. memory_ptr<SPropValue> lpPropArray;
  455. if(lpMsgList == NULL || lpMsgList->cValues == 0)
  456. return hr;
  457. if (lpMsgList->lpbin == nullptr)
  458. return MAPI_E_INVALID_PARAMETER;
  459. //Get the interface of destinationfolder
  460. if(lpInterface == NULL || *lpInterface == IID_IMAPIFolder)
  461. hr = ((IMAPIFolder*)lpDestFolder)->QueryInterface(IID_IMAPIFolder, &~lpMapiFolder);
  462. else if(*lpInterface == IID_IMAPIContainer)
  463. hr = ((IMAPIContainer*)lpDestFolder)->QueryInterface(IID_IMAPIFolder, &~lpMapiFolder);
  464. else if(*lpInterface == IID_IUnknown)
  465. hr = ((IUnknown*)lpDestFolder)->QueryInterface(IID_IMAPIFolder, &~lpMapiFolder);
  466. else if(*lpInterface == IID_IMAPIProp)
  467. hr = ((IMAPIProp*)lpDestFolder)->QueryInterface(IID_IMAPIFolder, &~lpMapiFolder);
  468. else
  469. hr = MAPI_E_INTERFACE_NOT_SUPPORTED;
  470. if(hr != hrSuccess)
  471. return hr;
  472. // Get the destination entry ID
  473. hr = HrGetOneProp(lpMapiFolder, PR_ENTRYID, &~lpPropArray);
  474. if(hr != hrSuccess)
  475. return hr;
  476. // if the destination is the publicfolders entryid, just block
  477. if(((ECMsgStorePublic*)GetMsgStore())->ComparePublicEntryId(ePE_PublicFolders, lpPropArray[0].Value.bin.cb, (LPENTRYID)lpPropArray[0].Value.bin.lpb, &ulResult) == hrSuccess && ulResult == TRUE)
  478. return MAPI_E_NO_ACCESS;
  479. return ECMAPIFolder::CopyMessages(lpMsgList, lpInterface, lpDestFolder, ulUIParam, lpProgress, ulFlags);
  480. }
  481. HRESULT ECMAPIFolderPublic::CreateMessage(LPCIID lpInterface, ULONG ulFlags, LPMESSAGE *lppMessage)
  482. {
  483. if (m_ePublicEntryID == ePE_PublicFolders)
  484. return MAPI_E_NO_ACCESS;
  485. return ECMAPIFolder::CreateMessage(lpInterface, ulFlags, lppMessage);
  486. }