ArchiveStateUpdater.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  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 <new>
  19. #include <utility>
  20. #include <kopano/archiver-common.h>
  21. #include "ArchiveStateUpdater.h"
  22. #include "ArchiverSession.h"
  23. #include "helpers/StoreHelper.h"
  24. #include "helpers/ArchiveHelper.h"
  25. #include "ArchiveManageImpl.h"
  26. using namespace KC::helpers;
  27. namespace KC {
  28. namespace Predicates {
  29. /**
  30. * Compare two SObjectEntry instances.
  31. * This version does a binary compare of the embedded entry ids.
  32. */
  33. class SObjectEntry_equals_binary {
  34. public:
  35. SObjectEntry_equals_binary(const SObjectEntry &objEntry): m_objEntry(objEntry) {}
  36. bool operator()(const SObjectEntry &objEntry) const { return objEntry == m_objEntry; }
  37. private:
  38. const SObjectEntry &m_objEntry;
  39. };
  40. /**
  41. * Compare two SObjectEntry instances.
  42. * This method uses CompareEntryIDs to do the comparison.
  43. */
  44. class SObjectEntry_equals_compareEntryId {
  45. public:
  46. SObjectEntry_equals_compareEntryId(IMAPISession *lpSession, const SObjectEntry &objEntry): m_lpSession(lpSession), m_objEntry(objEntry) {}
  47. bool operator()(const SObjectEntry &objEntry) const {
  48. HRESULT hr = hrSuccess;
  49. ULONG ulResult = 0;
  50. hr = m_lpSession->CompareEntryIDs(m_objEntry.sStoreEntryId.size(), m_objEntry.sStoreEntryId, objEntry.sStoreEntryId.size(), objEntry.sStoreEntryId, 0, &ulResult);
  51. if (hr != hrSuccess || ulResult == 0)
  52. return false;
  53. hr = m_lpSession->CompareEntryIDs(m_objEntry.sItemEntryId.size(), m_objEntry.sItemEntryId, objEntry.sItemEntryId.size(), objEntry.sItemEntryId, 0, &ulResult);
  54. return (hr == hrSuccess && ulResult == 1);
  55. }
  56. private:
  57. IMAPISession *m_lpSession;
  58. const SObjectEntry &m_objEntry;
  59. };
  60. /**
  61. * Compare a store entryid with the store entryid from an SObjectEntry instance.
  62. * This method uses CompareEntryIDs to do the comparison.
  63. */
  64. class storeId_equals_compareEntryId {
  65. public:
  66. storeId_equals_compareEntryId(IMAPISession *lpSession, const entryid_t &storeId): m_lpSession(lpSession), m_storeId(storeId) {}
  67. bool operator()(const SObjectEntry &objEntry) const
  68. {
  69. HRESULT hr = hrSuccess;
  70. ULONG ulResult = 0;
  71. hr = m_lpSession->CompareEntryIDs(m_storeId.size(), m_storeId, objEntry.sStoreEntryId.size(), objEntry.sStoreEntryId, 0, &ulResult);
  72. return (hr == hrSuccess && ulResult == 1);
  73. }
  74. private:
  75. IMAPISession *m_lpSession;
  76. const entryid_t &m_storeId;
  77. };
  78. class MapInfo_contains_userName {
  79. public:
  80. MapInfo_contains_userName(const tstring &userName): m_userName(userName) {}
  81. bool operator()(const ArchiveStateUpdater::ArchiveInfoMap::value_type &pair) const { return m_userName.compare(pair.second.userName) == 0; }
  82. private:
  83. const tstring &m_userName;
  84. };
  85. } // namespace Predicates
  86. /**
  87. * Create an ArchiveStateUpdater instance.
  88. * @param[in] ptrSession The archiver session.
  89. * @param[in] lpLogger The logger.
  90. * @param[in] mapArchiveInfo The map containing the users that have and/or
  91. * should have an archive attached to their
  92. * primary store.
  93. * @param[out] lpptrUpdater The new ArchiveStateUpdater instance
  94. */
  95. HRESULT ArchiveStateUpdater::Create(const ArchiverSessionPtr &ptrSession, ECLogger *lpLogger, const ArchiveInfoMap &mapArchiveInfo, ArchiveStateUpdaterPtr *lpptrUpdater)
  96. {
  97. ArchiveStateUpdaterPtr ptrUpdater(
  98. new(std::nothrow) ArchiveStateUpdater(ptrSession, lpLogger,
  99. mapArchiveInfo));
  100. if (ptrUpdater == nullptr)
  101. return MAPI_E_NOT_ENOUGH_MEMORY;
  102. *lpptrUpdater = std::move(ptrUpdater);
  103. return hrSuccess;
  104. }
  105. /**
  106. * @param[in] ptrSession The archiver session.
  107. * @param[in] lpLogger The logger.
  108. * @param[in] mapArchiveInfo The map containing the users that have and/or
  109. * should have an archive attached to their
  110. * primary store.
  111. */
  112. ArchiveStateUpdater::ArchiveStateUpdater(const ArchiverSessionPtr &ptrSession, ECLogger *lpLogger, const ArchiveInfoMap &mapArchiveInfo): m_ptrSession(ptrSession), m_lpLogger(lpLogger), m_mapArchiveInfo(mapArchiveInfo)
  113. {
  114. if (m_lpLogger)
  115. m_lpLogger->AddRef();
  116. else
  117. m_lpLogger = new ECLogger_Null();
  118. }
  119. ArchiveStateUpdater::~ArchiveStateUpdater()
  120. {
  121. m_lpLogger->Release();
  122. }
  123. /**
  124. * Update all users to the required state.
  125. */
  126. HRESULT ArchiveStateUpdater::UpdateAll(unsigned int ulAttachFlags)
  127. {
  128. HRESULT hr = hrSuccess;
  129. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "ArchiveStateUpdater::UpdateAll() function entry");
  130. for (const auto &i : m_mapArchiveInfo) {
  131. HRESULT hrTmp = UpdateOne(i.first, i.second, ulAttachFlags);
  132. if (hrTmp != hrSuccess)
  133. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to auto attach store for user '" TSTRING_PRINTF "', hr=0x%08x", i.second.userName.c_str(), hrTmp);
  134. }
  135. return hr;
  136. }
  137. /**
  138. * Update a single user to the required state.
  139. * @param[in] userName The username of the user to update.
  140. */
  141. HRESULT ArchiveStateUpdater::Update(const tstring &userName, unsigned int ulAttachFlags)
  142. {
  143. HRESULT hr;
  144. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "ArchiveStateUpdater::Update(): function entry");
  145. // First see if the username can be found in the map.
  146. auto i = std::find_if(m_mapArchiveInfo.cbegin(),
  147. m_mapArchiveInfo.cend(),
  148. Predicates::MapInfo_contains_userName(userName));
  149. if (i == m_mapArchiveInfo.end()) {
  150. // Resolve the username and search by entryid.
  151. abentryid_t userId;
  152. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Unable to find entry for user '" TSTRING_PRINTF "', trying to resolve.", userName.c_str());
  153. hr = m_ptrSession->GetUserInfo(userName, &userId, NULL, NULL);
  154. if (hr != hrSuccess)
  155. return hr;
  156. i = m_mapArchiveInfo.find(userId);
  157. if (i == m_mapArchiveInfo.end()) {
  158. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Unable to find entry for userid %s.", userId.tostring().c_str());
  159. return MAPI_E_NOT_FOUND;
  160. }
  161. }
  162. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "ArchiveStateUpdater::Update(): about to call UpdateOne()");
  163. hr = UpdateOne(i->first, i->second, ulAttachFlags);
  164. if (hr != hrSuccess)
  165. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to auto attach store for user '" TSTRING_PRINTF "', hr=0x%08x", userName.c_str(), hr);
  166. return hr;
  167. }
  168. /**
  169. * Update one single user.
  170. * @param[in] userId The entryid of the user to update.
  171. * @param[in[ info The ArchiveInfo object containing the current and
  172. * required state.
  173. */
  174. HRESULT ArchiveStateUpdater::UpdateOne(const abentryid_t &userId, const ArchiveInfo& info, unsigned int ulAttachFlags)
  175. {
  176. HRESULT hr = hrSuccess;
  177. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "ArchiveStateUpdater::UpdateOne() function entry");
  178. if (info.userName.empty()) {
  179. // Found a store that has archives attached but no archive- servers or couplings
  180. // are defined in the GAB.
  181. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "ArchiveStateUpdater::UpdateOne() about to call RemoveImplicit()");
  182. hr = RemoveImplicit(info.storeId, tstring(), userId, info.lstArchives);
  183. }
  184. else if (info.storeId.empty()) {
  185. // Found a user in the GAB that has at least one archive- server or coupling
  186. // defined but has no archives attached.
  187. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "ArchiveStateUpdater::UpdateOne() about to call AddCouplingBased()");
  188. hr = AddCouplingBased(info.userName, info.lstCouplings, ulAttachFlags);
  189. if (hr == hrSuccess)
  190. {
  191. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "ArchiveStateUpdater::UpdateOne() about to call AddServerBased()");
  192. hr = AddServerBased(info.userName, userId, info.lstServers, ulAttachFlags);
  193. }
  194. }
  195. else {
  196. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "ArchiveStateUpdater::UpdateOne() about to call VerifyAndUpdate()");
  197. hr = VerifyAndUpdate(userId, info, ulAttachFlags);
  198. }
  199. return hr;
  200. }
  201. /**
  202. * Remove/detach all implicit attached archives
  203. * @param[in] storeId The entryid of the primary store to process.
  204. * @param[in] userName The name of the user owning the store to process. This
  205. * is an alternative way of finding the store if
  206. * storeId is unwrapped.
  207. * @param[in] userId The entryid of the user owning the store to process.
  208. * This is an alternative way of finding the store if
  209. * storeId is unwrapped and userName is unknown.
  210. * @param[in] lstArchives The list of archives to remove the implicit attached
  211. * archives from.
  212. */
  213. HRESULT ArchiveStateUpdater::RemoveImplicit(const entryid_t &storeId, const tstring &userName, const abentryid_t &userId, const ObjectEntryList &lstArchives)
  214. {
  215. HRESULT hr;
  216. MsgStorePtr ptrUserStore;
  217. StoreHelperPtr ptrUserStoreHelper;
  218. ObjectEntryList lstCurrentArchives;
  219. ULONG ulDetachCount = 0;
  220. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Removing implicitly attached archives.");
  221. hr = m_ptrSession->OpenStore(storeId, &~ptrUserStore);
  222. if (hr == MAPI_E_INVALID_ENTRYID) {
  223. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Got invalid entryid, attempting to resolve...");
  224. // The storeId was obtained from the MailboxTable that currently does not return
  225. if (!userName.empty()) {
  226. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Resolving user '" TSTRING_PRINTF "'", userName.c_str());
  227. hr = m_ptrSession->OpenStoreByName(userName, &~ptrUserStore);
  228. if (hr != hrSuccess) {
  229. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to resolve store for user '" TSTRING_PRINTF "'", userName.c_str());
  230. return hr;
  231. }
  232. } else if (userId.size() != 0) {
  233. tstring strUserName;
  234. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Resolving user id %s", userId.tostring().c_str());
  235. hr = m_ptrSession->GetUserInfo(userId, &strUserName, NULL);
  236. if (hr != hrSuccess) {
  237. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to get info for user id %s", userId.tostring().c_str());
  238. return hr;
  239. }
  240. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Resolving user '" TSTRING_PRINTF "'", userName.c_str());
  241. hr = m_ptrSession->OpenStoreByName(strUserName, &~ptrUserStore);
  242. if (hr != hrSuccess) {
  243. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to resolve store for user '" TSTRING_PRINTF "'", userName.c_str());
  244. return hr;
  245. }
  246. }
  247. }
  248. if (hr != hrSuccess)
  249. return hr;
  250. hr = StoreHelper::Create(ptrUserStore, &ptrUserStoreHelper);
  251. if (hr != hrSuccess)
  252. return hr;
  253. hr = ptrUserStoreHelper->GetArchiveList(&lstCurrentArchives);
  254. if (hr != hrSuccess)
  255. return hr;
  256. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Processing %zu archives for implicitly attached archives", lstArchives.size());
  257. for (const auto &i : lstArchives) {
  258. MsgStorePtr ptrArchStore;
  259. ULONG ulType;
  260. MAPIFolderPtr ptrArchFolder;
  261. ArchiveHelperPtr ptrArchiveHelper;
  262. AttachType attachType;
  263. hr = m_ptrSession->OpenStore(i.sStoreEntryId, &~ptrArchStore);
  264. if (hr == MAPI_E_NOT_FOUND) {
  265. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Archive store returned not found, detaching it.");
  266. lstCurrentArchives.remove_if(Predicates::SObjectEntry_equals_binary(i));
  267. continue;
  268. }
  269. if (hr != hrSuccess) {
  270. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to open archive store. hr=0x%08x", hr);
  271. return hr;
  272. }
  273. hr = ptrArchStore->OpenEntry(i.sItemEntryId.size(), i.sItemEntryId, &ptrArchFolder.iid(), 0, &ulType, &~ptrArchFolder);
  274. if (hr != hrSuccess) {
  275. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to open archive root. hr=0x%08x", hr);
  276. if (hr == MAPI_E_NOT_FOUND) {
  277. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Possibly invalid entry, skipping...");
  278. continue;
  279. }
  280. return hr;
  281. }
  282. hr = ArchiveHelper::Create(ptrArchStore, ptrArchFolder, NULL, &ptrArchiveHelper);
  283. if (hr != hrSuccess)
  284. return hr;
  285. hr = ptrArchiveHelper->GetArchiveType(NULL, &attachType);
  286. if (hr != hrSuccess) {
  287. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to get attachType. hr=0x%08x", hr);
  288. return hr;
  289. }
  290. if (attachType == ImplicitAttach) {
  291. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Archive was implicitly attached, detaching.");
  292. lstCurrentArchives.remove_if(Predicates::SObjectEntry_equals_binary(i));
  293. ++ulDetachCount;
  294. } else
  295. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Archive was explicitly attached");
  296. }
  297. if (ulDetachCount > 0) {
  298. hr = ptrUserStoreHelper->SetArchiveList(lstCurrentArchives, true);
  299. if (hr != hrSuccess) {
  300. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to set archive list, hr=0x%08x", hr);
  301. return hr;
  302. }
  303. if (!userName.empty())
  304. m_lpLogger->Log(EC_LOGLEVEL_FATAL, "Auto detached %u archive(s) from '" TSTRING_PRINTF "'.", ulDetachCount, userName.c_str());
  305. else {
  306. tstring strUserName;
  307. if (m_ptrSession->GetUserInfo(userId, &strUserName, NULL) == hrSuccess)
  308. m_lpLogger->Log(EC_LOGLEVEL_FATAL, "Auto detached %u archive(s) from '" TSTRING_PRINTF "'.", ulDetachCount, strUserName.c_str());
  309. else
  310. m_lpLogger->Log(EC_LOGLEVEL_FATAL, "Auto detached %u archive(s).", ulDetachCount);
  311. }
  312. hr = ptrUserStoreHelper->UpdateSearchFolders();
  313. if (hr != hrSuccess)
  314. return hr;
  315. }
  316. return hrSuccess;
  317. }
  318. /**
  319. * Split a coupling in a store name and a folder name.
  320. * A coupling is defined as <storename>:<foldername>
  321. * @param[in] strCoupling The coupling to parse
  322. * @param[out] lpstrArchive The archive store name
  323. * @param[out] lpstrFolder The archive folder name
  324. */
  325. HRESULT ArchiveStateUpdater::ParseCoupling(const tstring &strCoupling, tstring *lpstrArchive, tstring *lpstrFolder)
  326. {
  327. tstring strArchive = strCoupling;
  328. tstring strFolder;
  329. tstring::size_type idxColon;
  330. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Coupling: '" TSTRING_PRINTF "'", strArchive.c_str());
  331. idxColon = strArchive.find(':');
  332. if (idxColon == std::string::npos) {
  333. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "No ':' separator found in coupling");
  334. return MAPI_E_INVALID_PARAMETER;
  335. }
  336. strFolder.assign(strArchive.substr(idxColon + 1));
  337. strArchive.resize(idxColon);
  338. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Coupling: archive='" TSTRING_PRINTF "', folder='" TSTRING_PRINTF "'", strArchive.c_str(), strFolder.c_str());
  339. if (strArchive.empty() || strFolder.empty()) {
  340. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Invalid coupling: archive='" TSTRING_PRINTF "', folder='" TSTRING_PRINTF "'", strArchive.c_str(), strFolder.c_str());
  341. return MAPI_E_INVALID_PARAMETER;
  342. }
  343. lpstrArchive->swap(strArchive);
  344. lpstrFolder->swap(strFolder);
  345. return hrSuccess;
  346. }
  347. /**
  348. * Add/attach coupling based archives.
  349. * @param[in] userName The username of the primary store to attach the
  350. * archives to.
  351. * @param[in] lstCouplings The list of couplings to attach to the store.
  352. */
  353. HRESULT ArchiveStateUpdater::AddCouplingBased(const tstring &userName, const std::list<tstring> &lstCouplings, unsigned int ulAttachFlags)
  354. {
  355. HRESULT hr;
  356. ArchiveManagePtr ptrManage;
  357. ArchiveManageImpl* lpManage = NULL;
  358. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Attaching coupling based archives.");
  359. if (lstCouplings.empty()) {
  360. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Empty coupling list");
  361. return hrSuccess;
  362. }
  363. hr = ArchiveManageImpl::Create(m_ptrSession, NULL, userName.c_str(), m_lpLogger, &ptrManage);
  364. if (hr != hrSuccess)
  365. return hr;
  366. lpManage = dynamic_cast<ArchiveManageImpl*>(ptrManage.get());
  367. assert(lpManage != NULL);
  368. if (lpManage == NULL) {
  369. m_lpLogger->Log(EC_LOGLEVEL_FATAL, "Unable to dynamic cast to ArchiveManageImpl pointer.");
  370. return MAPI_E_CALL_FAILED;
  371. }
  372. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Attaching %lu couplings", lstCouplings.size());
  373. for (const auto &i : lstCouplings) {
  374. tstring strArchive;
  375. tstring strFolder;
  376. hr = ParseCoupling(i, &strArchive, &strFolder);
  377. if (hr != hrSuccess)
  378. return hr;
  379. hr = lpManage->AttachTo(NULL, strArchive.c_str(), strFolder.c_str(), ulAttachFlags, ImplicitAttach);
  380. if (hr != hrSuccess) {
  381. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to attach to store '" TSTRING_PRINTF "' in folder '" TSTRING_PRINTF "', hr=0x%08x", strArchive.c_str(), strFolder.c_str(), hr);
  382. return hr;
  383. }
  384. }
  385. return hrSuccess;
  386. }
  387. /**
  388. * Add/attach server based archives.
  389. * @param[in] userName The username of the primary store to attach the
  390. * archives to.
  391. * @param[in] userId The entryid of the user whose primary store to
  392. * attach to.
  393. * @param[in] lstServers The list of servers on which an archive for userName
  394. * should be created or opened and attached to the
  395. * primary store.
  396. */
  397. HRESULT ArchiveStateUpdater::AddServerBased(const tstring &userName, const abentryid_t &userId, const std::list<tstring> &lstServers, unsigned int ulAttachFlags)
  398. {
  399. HRESULT hr;
  400. ArchiveManagePtr ptrManage;
  401. ArchiveManageImpl* lpManage = NULL;
  402. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Attaching servername based archives.");
  403. if (lstServers.empty()) {
  404. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Empty servername list");
  405. return hrSuccess;
  406. }
  407. hr = ArchiveManageImpl::Create(m_ptrSession, NULL, userName.c_str(), m_lpLogger, &ptrManage);
  408. if (hr != hrSuccess)
  409. return hr;
  410. lpManage = dynamic_cast<ArchiveManageImpl*>(ptrManage.get());
  411. assert(lpManage != NULL);
  412. if (lpManage == NULL) {
  413. m_lpLogger->Log(EC_LOGLEVEL_FATAL, "Unable to dynamic cast to ArchiveManageImpl pointer.");
  414. return MAPI_E_CALL_FAILED;
  415. }
  416. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Attaching %zu servers", lstServers.size());
  417. for (const auto &i : lstServers) {
  418. MsgStorePtr ptrArchive;
  419. hr = m_ptrSession->OpenOrCreateArchiveStore(userName, i, &~ptrArchive);
  420. if (hr != hrSuccess) {
  421. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to open or create the archive for user '" TSTRING_PRINTF "' on server '" TSTRING_PRINTF "', hr=0x%08x", userName.c_str(), i.c_str(), hr);
  422. return hr;
  423. }
  424. hr = lpManage->AttachTo(ptrArchive, L"", NULL, userId, ulAttachFlags, ImplicitAttach);
  425. if (hr != hrSuccess) {
  426. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to attach to archive store for user '" TSTRING_PRINTF "' on server '" TSTRING_PRINTF "', hr=0x%08x", userName.c_str(), i.c_str(), hr);
  427. return hr;
  428. }
  429. }
  430. return hrSuccess;
  431. }
  432. /**
  433. * Verify the current state and update it to match the required state.
  434. * @param[in] userId The entryid of the user whose primary store to
  435. * process.
  436. * @param[in] info ArchiveInfo instance containing the current and
  437. * requried state.
  438. */
  439. HRESULT ArchiveStateUpdater::VerifyAndUpdate(const abentryid_t &userId, const ArchiveInfo& info, unsigned int ulAttachFlags)
  440. {
  441. HRESULT hr;
  442. std::list<tstring> lstServers;
  443. std::list<tstring> lstCouplings;
  444. ObjectEntryList lstArchives = info.lstArchives;
  445. // Handle the automated couplings
  446. for (const auto &i : info.lstCouplings) {
  447. tstring strArchive;
  448. tstring strFolder;
  449. SObjectEntry objEntry;
  450. hr = ParseCoupling(i, &strArchive, &strFolder);
  451. if (hr != hrSuccess)
  452. return hr;
  453. hr = FindArchiveEntry(strArchive, strFolder, &objEntry);
  454. if (hr == MAPI_E_NOT_FOUND) {
  455. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "store '" TSTRING_PRINTF "', folder '" TSTRING_PRINTF "' does not exist. Adding to coupling list", strArchive.c_str(), strFolder.c_str());
  456. lstCouplings.push_back(i);
  457. continue;
  458. }
  459. if (hr != hrSuccess) {
  460. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to get archive entry for store '" TSTRING_PRINTF "', folder '" TSTRING_PRINTF "', hr=0x%08x", strArchive.c_str(), strFolder.c_str(), hr);
  461. return hr;
  462. }
  463. // see if entry is in list of attached archives.
  464. auto iObjEntry = std::find_if(lstArchives.begin(), lstArchives.end(), Predicates::SObjectEntry_equals_compareEntryId(m_ptrSession->GetMAPISession(), objEntry));
  465. if (iObjEntry == lstArchives.end()) {
  466. // Found a coupling that's not yet attached. Add it to the to-attach-list.
  467. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "store '" TSTRING_PRINTF "', folder '" TSTRING_PRINTF "' not yet attached. Adding to coupling list", strArchive.c_str(), strFolder.c_str());
  468. lstCouplings.push_back(i);
  469. } else {
  470. // Found a coupling that's already attached. Remove it from lstArchives, which is later processed to remove all
  471. // implicitly attached archives from it.
  472. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "store '" TSTRING_PRINTF "', folder '" TSTRING_PRINTF "' already attached. Removing from post process list", strArchive.c_str(), strFolder.c_str());
  473. lstArchives.erase(iObjEntry);
  474. }
  475. }
  476. // Handle the automated archive stores
  477. for (const auto &i : info.lstServers) {
  478. entryid_t archiveId;
  479. hr = m_ptrSession->GetArchiveStoreEntryId(info.userName, i, &archiveId);
  480. if (hr == MAPI_E_NOT_FOUND) {
  481. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "archive store for '" TSTRING_PRINTF "' on server '" TSTRING_PRINTF "' does not exist. Adding to server list", info.userName.c_str(), i.c_str());
  482. lstServers.push_back(i);
  483. continue;
  484. }
  485. if (hr != hrSuccess) {
  486. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to get archive store id for '" TSTRING_PRINTF "' on server '" TSTRING_PRINTF "', hr=0x%08x", info.userName.c_str(), i.c_str(), hr);
  487. return hr;
  488. }
  489. // see if entry is in list of attached archives (store entryid only)
  490. auto iObjEntry = std::find_if(lstArchives.begin(), lstArchives.end(), Predicates::storeId_equals_compareEntryId(m_ptrSession->GetMAPISession(), archiveId));
  491. if (iObjEntry == lstArchives.end()) {
  492. // Found a server/archive that's not yet attached. Add it to the to-attach-list.
  493. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "archive store for '" TSTRING_PRINTF "' on server '" TSTRING_PRINTF "' not yet attached. Adding to server list", info.userName.c_str(), i.c_str());
  494. lstServers.push_back(i);
  495. } else {
  496. // Found a server/archive that's already attached. Remove it from lstArchives, which is later processed to remove all
  497. // implicitly attached archives from it.
  498. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "archive store for '" TSTRING_PRINTF "' on server '" TSTRING_PRINTF "' already attached. Removing from post process list", info.userName.c_str(), i.c_str());
  499. lstArchives.erase(iObjEntry);
  500. }
  501. }
  502. hr = RemoveImplicit(info.storeId, info.userName, abentryid_t(), lstArchives);
  503. if (hr != hrSuccess)
  504. return hr;
  505. hr = AddCouplingBased(info.userName, lstCouplings, ulAttachFlags);
  506. if (hr != hrSuccess)
  507. return hr;
  508. hr = AddServerBased(info.userName, userId, lstServers, ulAttachFlags);
  509. if (hr != hrSuccess)
  510. return hr;
  511. return hrSuccess;
  512. }
  513. /**
  514. * Find the SObjectEntry for the archive specified by store- and foldername.
  515. * @param[in] strArchive The store name of the archive.
  516. * @param[in] strFolder The folder name of the archive.
  517. * @param[out] lpObjEntry The returned SObjectEntry.
  518. * @retval MAPI_E_NOT_FOUND The requested archive does not exist.
  519. */
  520. HRESULT ArchiveStateUpdater::FindArchiveEntry(const tstring &strArchive, const tstring &strFolder, SObjectEntry *lpObjEntry)
  521. {
  522. HRESULT hr;
  523. MsgStorePtr ptrArchiveStore;
  524. ArchiveHelperPtr ptrArchiveHelper;
  525. hr = m_ptrSession->OpenStoreByName(strArchive, &~ptrArchiveStore);
  526. if (hr != hrSuccess) {
  527. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to open store for user '" TSTRING_PRINTF "', hr=0x%08x", strArchive.c_str(), hr);
  528. return hr;
  529. }
  530. hr = ArchiveHelper::Create(ptrArchiveStore, strFolder, NULL, &ptrArchiveHelper);
  531. if (hr != hrSuccess)
  532. return hr;
  533. hr = ptrArchiveHelper->GetArchiveEntry(false, lpObjEntry);
  534. if (hr != hrSuccess) {
  535. if (hr != MAPI_E_NOT_FOUND)
  536. m_lpLogger->Log(EC_LOGLEVEL_ERROR, "Failed to get archive entry for folder '" TSTRING_PRINTF "', hr=0x%08x", strFolder.c_str(), hr);
  537. return hr;
  538. }
  539. return hrSuccess;
  540. }
  541. } /* namespace */