ArchiverSession.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  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 "ArchiverSession.h"
  21. #include <kopano/ecversion.h>
  22. #include <kopano/mapi_ptr.h>
  23. #include <kopano/ECConfig.h>
  24. #include <kopano/ECLogger.h>
  25. #include <kopano/ECRestriction.h>
  26. #include <kopano/CommonUtil.h>
  27. #include <kopano/mapiext.h>
  28. #include <kopano/userutil.h>
  29. #include "ECMsgStore.h"
  30. namespace KC {
  31. typedef KCHL::memory_ptr<ECSERVERLIST> ECServerListPtr;
  32. /**
  33. * Create a ArchiverSession object based on the passed configuration and a specific logger
  34. *
  35. * @param[in] lpConfig
  36. * The configuration used for creating the session. The values extracted from the
  37. * configuration are server_path, sslkey_file and sslkey_path.
  38. * @param[in] lpLogger
  39. * The logger to which logging will occur.
  40. * @param[out] lppSession
  41. * Pointer to a Session pointer that will be assigned the address of the returned
  42. * ArchiverSession object.
  43. */
  44. HRESULT ArchiverSession::Create(ECConfig *lpConfig, ECLogger *lpLogger, ArchiverSessionPtr *lpptrSession)
  45. {
  46. HRESULT hr;
  47. ArchiverSession *lpSession = NULL;
  48. if (!lpConfig || !lpLogger)
  49. return MAPI_E_INVALID_PARAMETER;
  50. lpSession = new(std::nothrow) ArchiverSession(lpLogger);
  51. if (lpSession == nullptr)
  52. return MAPI_E_NOT_ENOUGH_MEMORY;
  53. hr = lpSession->Init(lpConfig);
  54. if (FAILED(hr)) {
  55. delete lpSession;
  56. return hr;
  57. }
  58. lpptrSession->reset(lpSession);
  59. return hr;
  60. }
  61. /**
  62. * Create a Session object based on an existing MAPISession.
  63. *
  64. * @param[in] ptrSession
  65. * MAPISessionPtr that points to the MAPISession to contruct a
  66. * Session object for.
  67. * @param[in] lpLogger
  68. * An ECLogger instance.
  69. * @param[out] lppSession
  70. * Pointer to a Session pointer that will be assigned the address of the returned
  71. * Session object.
  72. */
  73. HRESULT ArchiverSession::Create(const MAPISessionPtr &ptrSession, ECLogger *lpLogger, ArchiverSessionPtr *lpptrSession)
  74. {
  75. return ArchiverSession::Create(ptrSession, NULL, lpLogger, lpptrSession);
  76. }
  77. /**
  78. * Create a ArchiverSession object based on an existing MAPISession.
  79. *
  80. * @param[in] ptrSession
  81. * MAPISessionPtr that points to the MAPISession to contruct a
  82. * ArchiverSession object for.
  83. * @param[in] lpConfig
  84. * An ECConfig instance containing sslkey_file and sslkey_pass.
  85. * @param[in] lpLogger
  86. * An ECLogger instance.
  87. * @param[out] lppSession
  88. * Pointer to a ArchiverSession pointer that will be assigned the address of the returned
  89. * ArchiverSession object.
  90. */
  91. HRESULT ArchiverSession::Create(const MAPISessionPtr &ptrSession, ECConfig *lpConfig, ECLogger *lpLogger, ArchiverSessionPtr *lpptrSession)
  92. {
  93. HRESULT hr = hrSuccess;
  94. ArchiverSession *lpSession = NULL;
  95. KCHL::object_ptr<ECLogger> lpLocalLogger;
  96. const char *lpszSslKeyFile = NULL;
  97. const char *lpszSslKeyPass = NULL;
  98. if (lpLogger != nullptr)
  99. lpLocalLogger.reset(lpLogger);
  100. else
  101. lpLocalLogger.reset(new ECLogger_Null(), false);
  102. if (lpConfig) {
  103. lpszSslKeyFile = lpConfig->GetSetting("sslkey_file", "", NULL);
  104. lpszSslKeyPass = lpConfig->GetSetting("sslkey_pass", "", NULL);
  105. }
  106. lpSession = new ArchiverSession(lpLocalLogger);
  107. hr = lpSession->Init(ptrSession, lpszSslKeyFile, lpszSslKeyPass);
  108. if (FAILED(hr)) {
  109. delete lpSession;
  110. return hr;
  111. }
  112. lpptrSession->reset(lpSession);
  113. return hr;
  114. }
  115. ArchiverSession::~ArchiverSession()
  116. {
  117. m_lpLogger->Release();
  118. }
  119. ArchiverSession::ArchiverSession(ECLogger *lpLogger): m_lpLogger(lpLogger)
  120. {
  121. m_lpLogger->AddRef();
  122. }
  123. /**
  124. * Initialize a ArchiverSession object based on the passed configuration.
  125. *
  126. * @param[in] lpConfig
  127. * The configuration used for creating the ArchiverSession. The values extracted from the
  128. * configuration are server_path, sslkey_file and sslkey_path.
  129. */
  130. HRESULT ArchiverSession::Init(ECConfig *lpConfig)
  131. {
  132. return Init(GetServerUnixSocket(lpConfig->GetSetting("server_socket")),
  133. lpConfig->GetSetting("sslkey_file", "", NULL),
  134. lpConfig->GetSetting("sslkey_pass", "", NULL));
  135. }
  136. /**
  137. * Initialize a ArchiverSession object.
  138. *
  139. * @param[in] lpszServerPath
  140. * The path to use to connect with the server.
  141. * @param[in] lpszSslPath
  142. * The path to the certificate.
  143. * @param[in]
  144. * lpszSslPass
  145. * The password for the certificate.
  146. */
  147. HRESULT ArchiverSession::Init(const char *lpszServerPath, const char *lpszSslPath, const char *lpszSslPass)
  148. {
  149. HRESULT hr;
  150. hr = HrOpenECAdminSession(&~m_ptrSession, "kopano-archiver:system",
  151. PROJECT_SVN_REV_STR, const_cast<char *>(lpszServerPath),
  152. EC_PROFILE_FLAGS_NO_NOTIFICATIONS, const_cast<char *>(lpszSslPath),
  153. const_cast<char *>(lpszSslPass));
  154. if (hr != hrSuccess) {
  155. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Unable to open Admin ArchiverSession.");
  156. switch (hr) {
  157. case MAPI_E_NETWORK_ERROR:
  158. m_lpLogger->Log(EC_LOGLEVEL_INFO, "The server is not running, or not accessible through %s.", lpszServerPath);
  159. break;
  160. case MAPI_E_LOGON_FAILED:
  161. case MAPI_E_NO_ACCESS:
  162. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Access was denied on %s.", lpszServerPath);
  163. break;
  164. default:
  165. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Unknown cause (hr=%s).", stringify(hr,true).c_str());
  166. break;
  167. };
  168. return hr;
  169. }
  170. hr = HrOpenDefaultStore(m_ptrSession, MDB_NO_MAIL | MDB_TEMPORARY, &~m_ptrAdminStore);
  171. if (hr != hrSuccess) {
  172. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Unable to open Admin store (hr=%s).", stringify(hr,true).c_str());
  173. return hr;
  174. }
  175. if (lpszSslPath)
  176. m_strSslPath = lpszSslPath;
  177. if (lpszSslPass)
  178. m_strSslPass = lpszSslPass;
  179. return hrSuccess;
  180. }
  181. /**
  182. * Initialize a ArchiverSession object based on an existing MAPISession.
  183. *
  184. * @param[in] ptrSession
  185. * MAPISessionPtr that points to the MAPISession to contruct this
  186. * ArchiverSession object for.
  187. */
  188. HRESULT ArchiverSession::Init(const MAPISessionPtr &ptrSession, const char *lpszSslPath, const char *lpszSslPass)
  189. {
  190. HRESULT hr;
  191. m_ptrSession = ptrSession;
  192. hr = HrOpenDefaultStore(m_ptrSession, &~m_ptrAdminStore);
  193. if (hr != hrSuccess)
  194. return hr;
  195. if (lpszSslPath)
  196. m_strSslPath = lpszSslPath;
  197. if (lpszSslPass)
  198. m_strSslPass = lpszSslPass;
  199. return hrSuccess;
  200. }
  201. /**
  202. * Open a message store based on a username.
  203. *
  204. * @param[in] strUser
  205. * The username of the user for which to open the store.
  206. * @param[out] lppMsgStore
  207. * Pointer to a IMsgStore pointer that will be assigned the
  208. * address of the returned message store.
  209. */
  210. HRESULT ArchiverSession::OpenStoreByName(const tstring &strUser, LPMDB *lppMsgStore)
  211. {
  212. HRESULT hr;
  213. ExchangeManageStorePtr ptrEMS;
  214. MsgStorePtr ptrUserStore;
  215. ULONG cbEntryId = 0;
  216. EntryIdPtr ptrEntryId;
  217. hr = m_ptrAdminStore->QueryInterface(ptrEMS.iid(), &~ptrEMS);
  218. if (hr != hrSuccess) {
  219. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to get EMS interface (hr=%s).", stringify(hr, true).c_str());
  220. return hr;
  221. }
  222. hr = ptrEMS->CreateStoreEntryID(NULL, (LPTSTR)strUser.c_str(), fMapiUnicode, &cbEntryId, &~ptrEntryId);
  223. if (hr != hrSuccess) {
  224. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to create store entryid for user '" TSTRING_PRINTF "' (hr=%s).", strUser.c_str(), stringify(hr, true).c_str());
  225. return hr;
  226. }
  227. hr = m_ptrSession->OpenMsgStore(0, cbEntryId, ptrEntryId, &ptrUserStore.iid(), MDB_WRITE | fMapiDeferredErrors | MDB_NO_MAIL | MDB_TEMPORARY, &~ptrUserStore);
  228. if (hr != hrSuccess) {
  229. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to open store for user '" TSTRING_PRINTF "' (hr=%s).", strUser.c_str(), stringify(hr, true).c_str());
  230. return hr;
  231. }
  232. return ptrUserStore->QueryInterface(IID_IMsgStore,
  233. reinterpret_cast<LPVOID *>(lppMsgStore));
  234. }
  235. /**
  236. * Open a message store with best access.
  237. *
  238. * @param[in] sEntryId
  239. * The entryid of the store to open.
  240. * @param[in] ulFlags
  241. * Flags that are passed on to OpenMsgStore
  242. * @param[out] lppMsgStore
  243. * Pointer to a IMsgStore pointer that will be assigned the
  244. * address of the returned message store.
  245. */
  246. HRESULT ArchiverSession::OpenStore(const entryid_t &sEntryId, ULONG ulFlags, LPMDB *lppMsgStore)
  247. {
  248. HRESULT hr;
  249. MsgStorePtr ptrUserStore;
  250. ArchiverSessionPtr ptrSession;
  251. if (sEntryId.isWrapped()) {
  252. entryid_t sTempEntryId = sEntryId;
  253. std::string strPath;
  254. sTempEntryId.unwrap(&strPath);
  255. m_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Archive store entryid is wrapped.");
  256. hr = CreateRemote(strPath.c_str(), m_lpLogger, &ptrSession);
  257. if (hr != hrSuccess) {
  258. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to create ArchiverSession on '%s' (hr=%s)", strPath.c_str(), stringify(hr, true).c_str());
  259. return hr;
  260. }
  261. hr = ptrSession->OpenStore(sTempEntryId, ulFlags, lppMsgStore);
  262. } else {
  263. hr = m_ptrSession->OpenMsgStore(0, sEntryId.size(), sEntryId, &ptrUserStore.iid(), ulFlags, &~ptrUserStore);
  264. if (hr != hrSuccess) {
  265. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to open store. (entryid=%s, hr=%s)", sEntryId.tostring().c_str(), stringify(hr, true).c_str());
  266. return hr;
  267. }
  268. hr = ptrUserStore->QueryInterface(IID_IMsgStore, (LPVOID*)lppMsgStore);
  269. }
  270. return hr;
  271. }
  272. /**
  273. * Open a message store with best access.
  274. *
  275. * @param[in] sEntryId
  276. * The entryid of the store to open.
  277. * @param[out] lppMsgStore
  278. * Pointer to a IMsgStore pointer that will be assigned the
  279. * address of the returned message store.
  280. */
  281. HRESULT ArchiverSession::OpenStore(const entryid_t &sEntryId, LPMDB *lppMsgStore)
  282. {
  283. return OpenStore(sEntryId, MDB_WRITE|fMapiDeferredErrors|MDB_NO_MAIL|MDB_TEMPORARY, lppMsgStore);
  284. }
  285. /**
  286. * Open a message store with read-only access.
  287. *
  288. * @param[in] sEntryId
  289. * The entryid of the store to open.
  290. * @param[out] lppMsgStore
  291. * Pointer to a IMsgStore pointer that will be assigned the
  292. * address of the returned message store.
  293. */
  294. HRESULT ArchiverSession::OpenReadOnlyStore(const entryid_t &sEntryId, LPMDB *lppMsgStore)
  295. {
  296. return OpenStore(sEntryId, fMapiDeferredErrors|MDB_NO_MAIL|MDB_TEMPORARY, lppMsgStore);
  297. }
  298. /**
  299. * Resolve a user and return its username and entryid.
  300. *
  301. * @param[in] strUser
  302. * The user to resolve.
  303. * @param[out] lpsEntryId
  304. * Pointer to a entryid_t that will be populated with the entryid
  305. * of the resovled user. This argument can be set to NULL if the entryid
  306. * is not required.
  307. * @param[out] lpstrFullname
  308. * Pointer to a std::string that will be populated with the full name
  309. * of the resolved user. This argument can be set to NULL if the full name
  310. * is not required.
  311. * @param[out] lpbAclCapable
  312. * Pointer to a boolean that will be set to true if the user is ACL capable.
  313. * This argument can be set to NULL if the active/non-active
  314. * information is not required.
  315. */
  316. HRESULT ArchiverSession::GetUserInfo(const tstring &strUser, abentryid_t *lpsEntryId, tstring *lpstrFullname, bool *lpbAclCapable)
  317. {
  318. HRESULT hr;
  319. MsgStorePtr ptrStore;
  320. ECServiceAdminPtr ptrServiceAdmin;
  321. ULONG cbEntryId = 0;
  322. EntryIdPtr ptrEntryId;
  323. hr = HrOpenDefaultStore(m_ptrSession, &~ptrStore);
  324. if (hr != hrSuccess) {
  325. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to open default store (hr=%s)", stringify(hr, true).c_str());
  326. return hr;
  327. }
  328. hr = ptrStore.QueryInterface(ptrServiceAdmin);
  329. if (hr != hrSuccess) {
  330. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to obtain the serviceadmin interface (hr=%s)", stringify(hr, true).c_str());
  331. return hr;
  332. }
  333. hr = ptrServiceAdmin->ResolveUserName((LPCTSTR)strUser.c_str(), fMapiUnicode, &cbEntryId, &~ptrEntryId);
  334. if (hr != hrSuccess) {
  335. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to resolve user '" TSTRING_PRINTF "' (hr=%s)", strUser.c_str(), stringify(hr, true).c_str());
  336. return hr;
  337. }
  338. if (lpstrFullname || lpbAclCapable) {
  339. ULONG ulType = 0;
  340. MailUserPtr ptrUser;
  341. ULONG cValues = 0;
  342. SPropArrayPtr ptrUserProps;
  343. static constexpr const SizedSPropTagArray(2, sptaUserProps) =
  344. {2, {PR_DISPLAY_NAME, PR_DISPLAY_TYPE_EX}};
  345. enum {IDX_DISPLAY_NAME, IDX_DISPLAY_TYPE_EX};
  346. hr = m_ptrSession->OpenEntry(cbEntryId, ptrEntryId, &IID_IMailUser, 0, &ulType, &~ptrUser);
  347. if (hr != hrSuccess) {
  348. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to open user object for user '" TSTRING_PRINTF "' (hr=%s)", strUser.c_str(), stringify(hr, true).c_str());
  349. return hr;
  350. }
  351. hr = ptrUser->GetProps(sptaUserProps, 0, &cValues, &~ptrUserProps);
  352. if (FAILED(hr)) {
  353. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to obtain properties from user '" TSTRING_PRINTF "' (hr=0x%08x)", strUser.c_str(), hr);
  354. return hr;
  355. }
  356. if (lpstrFullname) {
  357. if (ptrUserProps[IDX_DISPLAY_NAME].ulPropTag != PR_DISPLAY_NAME) {
  358. hr = ptrUserProps[IDX_DISPLAY_NAME].Value.err;
  359. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to obtain the display name for user '" TSTRING_PRINTF "' (hr=%s)", strUser.c_str(), stringify(hr, true).c_str());
  360. return hr;
  361. }
  362. lpstrFullname->assign(ptrUserProps[IDX_DISPLAY_NAME].Value.LPSZ);
  363. }
  364. if (lpbAclCapable) {
  365. if (ptrUserProps[IDX_DISPLAY_TYPE_EX].ulPropTag != PR_DISPLAY_TYPE_EX) {
  366. hr = ptrUserProps[IDX_DISPLAY_TYPE_EX].Value.err;
  367. m_lpLogger->Log(EC_LOGLEVEL_INFO, "Failed to obtain the type for user '" TSTRING_PRINTF "' (hr=%s)", strUser.c_str(), stringify(hr, true).c_str());
  368. return hr;
  369. }
  370. *lpbAclCapable = (ptrUserProps[IDX_DISPLAY_TYPE_EX].Value.ul & DTE_FLAG_ACL_CAPABLE);
  371. }
  372. }
  373. if (lpsEntryId)
  374. lpsEntryId->assign(cbEntryId, ptrEntryId);
  375. return hr;
  376. }
  377. HRESULT ArchiverSession::GetUserInfo(const abentryid_t &sEntryId, tstring *lpstrUser, tstring *lpstrFullname)
  378. {
  379. HRESULT hr;
  380. ULONG ulType = 0;
  381. MAPIPropPtr ptrUser;
  382. ULONG cUserProps = 0;
  383. SPropArrayPtr ptrUserProps;
  384. static constexpr const SizedSPropTagArray(2, sptaUserProps) =
  385. {2, {PR_ACCOUNT, PR_DISPLAY_NAME}};
  386. enum {IDX_ACCOUNT, IDX_DISPLAY_NAME};
  387. hr = m_ptrSession->OpenEntry(sEntryId.size(), sEntryId, nullptr, MAPI_DEFERRED_ERRORS, &ulType, &~ptrUser);
  388. if (hr != hrSuccess)
  389. return hr;
  390. hr = ptrUser->GetProps(sptaUserProps, 0, &cUserProps, &~ptrUserProps);
  391. if (FAILED(hr))
  392. return hr;
  393. if (lpstrUser) {
  394. if (PROP_TYPE(ptrUserProps[IDX_ACCOUNT].ulPropTag) != PT_ERROR)
  395. lpstrUser->assign(ptrUserProps[IDX_ACCOUNT].Value.LPSZ);
  396. else
  397. lpstrUser->assign(_T("<Unknown>"));
  398. }
  399. if (lpstrFullname) {
  400. if (PROP_TYPE(ptrUserProps[IDX_DISPLAY_NAME].ulPropTag) != PT_ERROR)
  401. lpstrFullname->assign(ptrUserProps[IDX_DISPLAY_NAME].Value.LPSZ);
  402. else
  403. lpstrFullname->assign(_T("<Unknown>"));
  404. }
  405. return hrSuccess;
  406. }
  407. /**
  408. * Get the global address list.
  409. *
  410. * @param[out] lppAbContainer
  411. * Pointer to a IABContainer pointer that will be assigned the
  412. * address of the returned addressbook container.
  413. */
  414. HRESULT ArchiverSession::GetGAL(LPABCONT *lppAbContainer)
  415. {
  416. HRESULT hr;
  417. AddrBookPtr ptrAdrBook;
  418. ABContainerPtr ptrABRootContainer;
  419. ABContainerPtr ptrGAL;
  420. MAPITablePtr ptrABRCTable;
  421. SRowSetPtr ptrRows;
  422. ULONG ulType = 0;
  423. static constexpr const SizedSPropTagArray(1, sGALProps) = {1, {PR_ENTRYID}};
  424. SPropValue sGALPropVal = {0};
  425. hr = m_ptrSession->OpenAddressBook(0, &ptrAdrBook.iid(), AB_NO_DIALOG, &~ptrAdrBook);
  426. if (hr != hrSuccess)
  427. return hr;
  428. hr = ptrAdrBook->OpenEntry(0, nullptr, &ptrABRootContainer.iid(), MAPI_BEST_ACCESS, &ulType, &~ptrABRootContainer);
  429. if (hr != hrSuccess)
  430. return hr;
  431. hr = ptrABRootContainer->GetHierarchyTable(0, &~ptrABRCTable);
  432. if (hr != hrSuccess)
  433. return hr;
  434. sGALPropVal.ulPropTag = PR_AB_PROVIDER_ID;
  435. sGALPropVal.Value.bin.cb = sizeof(GUID);
  436. sGALPropVal.Value.bin.lpb = (LPBYTE)&MUIDECSAB;
  437. hr = ptrABRCTable->SetColumns(sGALProps, TBL_BATCH);
  438. if (hr != hrSuccess)
  439. return hr;
  440. hr = ECPropertyRestriction(RELOP_EQ, PR_AB_PROVIDER_ID, &sGALPropVal, ECRestriction::Cheap)
  441. .RestrictTable(ptrABRCTable, TBL_BATCH);
  442. if (hr != hrSuccess)
  443. return hr;
  444. hr = ptrABRCTable->QueryRows(1, 0, &ptrRows);
  445. if (hr != hrSuccess)
  446. return hr;
  447. if (ptrRows.size() != 1 || ptrRows[0].lpProps[0].ulPropTag != PR_ENTRYID)
  448. return MAPI_E_NOT_FOUND;
  449. hr = ptrAdrBook->OpenEntry(ptrRows[0].lpProps[0].Value.bin.cb,
  450. reinterpret_cast<ENTRYID *>(ptrRows[0].lpProps[0].Value.bin.lpb), &ptrGAL.iid(),
  451. MAPI_BEST_ACCESS, &ulType, &~ptrGAL);
  452. if (hr != hrSuccess)
  453. return hr;
  454. return ptrGAL->QueryInterface(IID_IABContainer,
  455. reinterpret_cast<void **>(lppAbContainer));
  456. }
  457. /**
  458. * Check if two MsgStorePtr point to the same store by comparing their entryids.
  459. * This function is used to make sure a store is not attached to itself as archive (hence the argument names)
  460. *
  461. * @param[in] lpUserStore
  462. * MsgStorePtr that points to the user store.
  463. * @param[in] lpArchiveStore
  464. * MsgStorePtr that points to the archive store.
  465. * @param[out] lpbResult
  466. * Pointer to a boolean that will be set to true if the two stores
  467. * reference the same store.
  468. */
  469. HRESULT ArchiverSession::CompareStoreIds(LPMDB lpUserStore, LPMDB lpArchiveStore, bool *lpbResult)
  470. {
  471. HRESULT hr;
  472. SPropValuePtr ptrUserStoreEntryId;
  473. SPropValuePtr ptrArchiveStoreEntryId;
  474. ULONG ulResult = 0;
  475. hr = HrGetOneProp(lpUserStore, PR_ENTRYID, &~ptrUserStoreEntryId);
  476. if (hr != hrSuccess)
  477. return hr;
  478. hr = HrGetOneProp(lpArchiveStore, PR_ENTRYID, &~ptrArchiveStoreEntryId);
  479. if (hr != hrSuccess)
  480. return hr;
  481. hr = m_ptrSession->CompareEntryIDs(ptrUserStoreEntryId->Value.bin.cb, (LPENTRYID)ptrUserStoreEntryId->Value.bin.lpb,
  482. ptrArchiveStoreEntryId->Value.bin.cb, (LPENTRYID)ptrArchiveStoreEntryId->Value.bin.lpb,
  483. 0, &ulResult);
  484. if (hr != hrSuccess)
  485. return hr;
  486. *lpbResult = (ulResult == TRUE);
  487. return hrSuccess;
  488. }
  489. /**
  490. * Compare two store entryids to see if they reference the same store.
  491. *
  492. * @param[in] sEntryId1
  493. * Entryid 1.
  494. * @param[in] sEntryId2
  495. * Entryid 2.
  496. * @param[out] lpbResult
  497. * Pointer to a boolean that will be set to true if the two ids
  498. * reference the same store.
  499. */
  500. HRESULT ArchiverSession::CompareStoreIds(const entryid_t &sEntryId1, const entryid_t &sEntryId2, bool *lpbResult)
  501. {
  502. HRESULT hr;
  503. ULONG ulResult = 0;
  504. hr = m_ptrSession->CompareEntryIDs(sEntryId1.size(), sEntryId1,
  505. sEntryId2.size(), sEntryId2,
  506. 0, &ulResult);
  507. if (hr != hrSuccess)
  508. return hr;
  509. *lpbResult = (ulResult == TRUE);
  510. return hrSuccess;
  511. }
  512. /**
  513. * Create a ArchiverSession on another server, with the same credentials (SSL) as the current ArchiverSession.
  514. *
  515. * @param[in] lpszServerPath The path of the server to connect with.
  516. * @param[in] lpLogger THe logger to log to.
  517. * @param[ou]t lppSession The returned ArchiverSession.
  518. *
  519. * @retval hrSuccess The new ArchiverSession was successfully created.
  520. */
  521. HRESULT ArchiverSession::CreateRemote(const char *lpszServerPath, ECLogger *lpLogger, ArchiverSessionPtr *lpptrSession)
  522. {
  523. auto lpSession = new ArchiverSession(lpLogger);
  524. HRESULT hr = lpSession->Init(lpszServerPath, m_strSslPath.c_str(), m_strSslPass.c_str());
  525. if (FAILED(hr)) {
  526. delete lpSession;
  527. return hr;
  528. }
  529. lpptrSession->reset(lpSession);
  530. return hr;
  531. }
  532. HRESULT ArchiverSession::OpenMAPIProp(ULONG cbEntryID, LPENTRYID lpEntryID, LPMAPIPROP *lppProp)
  533. {
  534. HRESULT hr;
  535. ULONG ulType = 0;
  536. MAPIPropPtr ptrMapiProp;
  537. hr = m_ptrSession->OpenEntry(cbEntryID, lpEntryID, &ptrMapiProp.iid(),
  538. MAPI_BEST_ACCESS|fMapiDeferredErrors, &ulType, &~ptrMapiProp);
  539. if (hr != hrSuccess)
  540. return hr;
  541. return ptrMapiProp->QueryInterface(IID_IMAPIProp,
  542. reinterpret_cast<LPVOID *>(lppProp));
  543. }
  544. const char *ArchiverSession::GetSSLPath() const {
  545. return m_strSslPath.c_str();
  546. }
  547. const char *ArchiverSession::GetSSLPass() const {
  548. return m_strSslPass.c_str();
  549. }
  550. HRESULT ArchiverSession::OpenOrCreateArchiveStore(const tstring& strUserName, const tstring& strServerName, LPMDB *lppArchiveStore)
  551. {
  552. HRESULT hr;
  553. ECServiceAdminPtr ptrServiceAdmin;
  554. ULONG cbStoreId;
  555. EntryIdPtr ptrStoreId;
  556. MsgStorePtr ptrArchiveStore;
  557. hr = m_ptrAdminStore.QueryInterface(ptrServiceAdmin);
  558. if (hr != hrSuccess)
  559. return hr;
  560. hr = ptrServiceAdmin->GetArchiveStoreEntryID(strUserName.c_str(), strServerName.c_str(), fMapiUnicode, &cbStoreId, &~ptrStoreId);
  561. if (hr == hrSuccess)
  562. hr = m_ptrSession->OpenMsgStore(0, cbStoreId, ptrStoreId, &ptrArchiveStore.iid(), MDB_WRITE, &~ptrArchiveStore);
  563. else if (hr == MAPI_E_NOT_FOUND)
  564. hr = CreateArchiveStore(strUserName, strServerName, &~ptrArchiveStore);
  565. if (hr != hrSuccess)
  566. return hr;
  567. return ptrArchiveStore->QueryInterface(IID_IMsgStore,
  568. reinterpret_cast<LPVOID *>(lppArchiveStore));
  569. }
  570. HRESULT ArchiverSession::GetArchiveStoreEntryId(const tstring& strUserName, const tstring& strServerName, entryid_t *lpArchiveId)
  571. {
  572. HRESULT hr;
  573. ECServiceAdminPtr ptrServiceAdmin;
  574. ULONG cbStoreId;
  575. EntryIdPtr ptrStoreId;
  576. hr = m_ptrAdminStore.QueryInterface(ptrServiceAdmin);
  577. if (hr != hrSuccess)
  578. return hr;
  579. hr = ptrServiceAdmin->GetArchiveStoreEntryID(strUserName.c_str(), strServerName.c_str(), fMapiUnicode, &cbStoreId, &~ptrStoreId);
  580. if (hr != hrSuccess)
  581. return hr;
  582. lpArchiveId->assign(cbStoreId, ptrStoreId);
  583. return hrSuccess;
  584. }
  585. HRESULT ArchiverSession::CreateArchiveStore(const tstring& strUserName, const tstring& strServerName, LPMDB *lppArchiveStore)
  586. {
  587. HRESULT hr;
  588. MsgStorePtr ptrRemoteAdminStore;
  589. ECServiceAdminPtr ptrRemoteServiceAdmin;
  590. abentryid_t userId;
  591. ULONG cbStoreId = 0;
  592. EntryIdPtr ptrStoreId;
  593. ULONG cbRootId = 0;
  594. EntryIdPtr ptrRootId;
  595. MsgStorePtr ptrArchiveStore;
  596. MAPIFolderPtr ptrRoot;
  597. ULONG ulType;
  598. MAPIFolderPtr ptrIpmSubtree;
  599. SPropValuePtr ptrIpmSubtreeId;
  600. hr = GetUserInfo(strUserName, &userId, NULL, NULL);
  601. if (hr != hrSuccess)
  602. return hr;
  603. hr = HrGetRemoteAdminStore(m_ptrSession, m_ptrAdminStore, strServerName.c_str(), fMapiUnicode, &~ptrRemoteAdminStore);
  604. if (hr != hrSuccess)
  605. return hr;
  606. hr = ptrRemoteAdminStore.QueryInterface(ptrRemoteServiceAdmin);
  607. if (hr != hrSuccess)
  608. return hr;
  609. hr = ptrRemoteServiceAdmin->CreateEmptyStore(ECSTORE_TYPE_ARCHIVE, userId.size(), userId, EC_OVERRIDE_HOMESERVER, &cbStoreId, &~ptrStoreId, &cbRootId, &~ptrRootId);
  610. if (hr != hrSuccess)
  611. return hr;
  612. // The entryids returned from CreateEmptyStore are unwrapped and unusable from external client code. So
  613. // we'll resolve the correct entryids through GetArchiveStoreEntryID.
  614. hr = ptrRemoteServiceAdmin->GetArchiveStoreEntryID(strUserName.c_str(), strServerName.c_str(), fMapiUnicode, &cbStoreId, &~ptrStoreId);
  615. if (hr != hrSuccess)
  616. return hr;
  617. hr = m_ptrSession->OpenMsgStore(0, cbStoreId, ptrStoreId, &ptrArchiveStore.iid(), MDB_WRITE, &~ptrArchiveStore);
  618. if (hr != hrSuccess)
  619. return hr;
  620. hr = ptrArchiveStore->OpenEntry(0, nullptr, &ptrRoot.iid(), MAPI_MODIFY, &ulType, &~ptrRoot);
  621. if (hr != hrSuccess)
  622. return hr;
  623. hr = ptrRoot->CreateFolder(FOLDER_GENERIC,
  624. const_cast<TCHAR *>(_T("IPM_SUBTREE")),
  625. const_cast<TCHAR *>(_T("")), &IID_IMAPIFolder, fMapiUnicode,
  626. &~ptrIpmSubtree);
  627. if (hr != hrSuccess)
  628. return hr;
  629. hr = HrGetOneProp(ptrIpmSubtree, PR_ENTRYID, &~ptrIpmSubtreeId);
  630. if (hr != hrSuccess)
  631. return hr;
  632. ptrIpmSubtreeId->ulPropTag = PR_IPM_SUBTREE_ENTRYID;
  633. hr = ptrArchiveStore->SetProps(1, ptrIpmSubtreeId, NULL);
  634. if (hr != hrSuccess)
  635. return hr;
  636. return ptrArchiveStore->QueryInterface(IID_IMsgStore,
  637. reinterpret_cast<LPVOID *>(lppArchiveStore));
  638. }
  639. } /* namespace */