ECArchiveAwareMsgStore.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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 "ECArchiveAwareMsgStore.h"
  21. #include "ECArchiveAwareMessage.h"
  22. #include <kopano/ECGuid.h>
  23. #include <kopano/mapi_ptr.h>
  24. using namespace KCHL;
  25. ECArchiveAwareMsgStore::ECArchiveAwareMsgStore(char *lpszProfname, LPMAPISUP lpSupport, WSTransport *lpTransport, BOOL fModify, ULONG ulProfileFlags, BOOL fIsSpooler, BOOL fIsDefaultStore, BOOL bOfflineStore)
  26. : ECMsgStore(lpszProfname, lpSupport, lpTransport, fModify, ulProfileFlags, fIsSpooler, fIsDefaultStore, bOfflineStore)
  27. { }
  28. HRESULT ECArchiveAwareMsgStore::Create(char *lpszProfname, LPMAPISUP lpSupport, WSTransport *lpTransport, BOOL fModify, ULONG ulProfileFlags, BOOL fIsSpooler, BOOL fIsDefaultStore, BOOL bOfflineStore, ECMsgStore **lppECMsgStore)
  29. {
  30. return alloc_wrap<ECArchiveAwareMsgStore>(lpszProfname, lpSupport,
  31. lpTransport, fModify, ulProfileFlags, fIsSpooler, fIsDefaultStore,
  32. bOfflineStore).as(IID_ECMsgStore, lppECMsgStore);
  33. }
  34. HRESULT ECArchiveAwareMsgStore::OpenEntry(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulFlags, ULONG *lpulObjType, LPUNKNOWN *lppUnk)
  35. {
  36. // By default we'll try to open an archive aware message when a message is opened. The exception
  37. // is when the client is not licensed to do so or when it's explicitly disabled by passing
  38. // IID_IECMessageRaw as the lpInterface parameter. This is for instance needed for the archiver
  39. // itself becaus it needs to operate on the non-stubbed (or raw) message.
  40. // In this override, we only check for the presence of IID_IECMessageRaw. If that's found, we'll
  41. // pass an ECMessageFactory instance to our parents OpenEntry.
  42. // Otherwise we'll pass an ECArchiveAwareMessageFactory instance, which will check the license
  43. // create the appropriate message type. If the object turns out to be a message that is.
  44. const bool bRawMessage = (lpInterface && memcmp(lpInterface, &IID_IECMessageRaw, sizeof(IID)) == 0);
  45. HRESULT hr = hrSuccess;
  46. if (bRawMessage)
  47. hr = ECMsgStore::OpenEntry(cbEntryID, lpEntryID, &IID_IMessage, ulFlags, ECMessageFactory(), lpulObjType, lppUnk);
  48. else
  49. hr = ECMsgStore::OpenEntry(cbEntryID, lpEntryID, lpInterface, ulFlags, ECArchiveAwareMessageFactory(), lpulObjType, lppUnk);
  50. return hr;
  51. }
  52. HRESULT ECArchiveAwareMsgStore::OpenItemFromArchive(LPSPropValue lpPropStoreEIDs, LPSPropValue lpPropItemEIDs, ECMessage **lppMessage)
  53. {
  54. HRESULT hr;
  55. BinaryList lstStoreEIDs;
  56. BinaryList lstItemEIDs;
  57. BinaryListIterator iterStoreEID;
  58. BinaryListIterator iterIterEID;
  59. object_ptr<ECMessage, IID_ECMessage> ptrArchiveMessage;
  60. if (lpPropStoreEIDs == NULL ||
  61. lpPropItemEIDs == NULL ||
  62. lppMessage == NULL ||
  63. PROP_TYPE(lpPropStoreEIDs->ulPropTag) != PT_MV_BINARY ||
  64. PROP_TYPE(lpPropItemEIDs->ulPropTag) != PT_MV_BINARY ||
  65. lpPropStoreEIDs->Value.MVbin.cValues != lpPropItemEIDs->Value.MVbin.cValues)
  66. return MAPI_E_INVALID_PARAMETER;
  67. // First get a list of items that could be retrieved from cached archive stores.
  68. hr = CreateCacheBasedReorderedList(lpPropStoreEIDs->Value.MVbin, lpPropItemEIDs->Value.MVbin, &lstStoreEIDs, &lstItemEIDs);
  69. if (hr != hrSuccess)
  70. return hr;
  71. iterStoreEID = lstStoreEIDs.begin();
  72. iterIterEID = lstItemEIDs.begin();
  73. for (; iterStoreEID != lstStoreEIDs.end(); ++iterStoreEID, ++iterIterEID) {
  74. ECMsgStorePtr ptrArchiveStore;
  75. ULONG ulType = 0;
  76. hr = GetArchiveStore(*iterStoreEID, &~ptrArchiveStore);
  77. if (hr == MAPI_E_NO_SUPPORT)
  78. return hr; // No need to try any other archives.
  79. if (hr != hrSuccess)
  80. continue;
  81. hr = ptrArchiveStore->OpenEntry((*iterIterEID)->cb, reinterpret_cast<ENTRYID *>((*iterIterEID)->lpb), &IID_ECMessage, 0, &ulType, &~ptrArchiveMessage);
  82. if (hr != hrSuccess)
  83. continue;
  84. break;
  85. }
  86. if (iterStoreEID == lstStoreEIDs.end())
  87. return MAPI_E_NOT_FOUND;
  88. if (ptrArchiveMessage)
  89. hr = ptrArchiveMessage->QueryInterface(IID_ECMessage, (LPVOID*)lppMessage);
  90. return hr;
  91. }
  92. HRESULT ECArchiveAwareMsgStore::CreateCacheBasedReorderedList(SBinaryArray sbaStoreEIDs, SBinaryArray sbaItemEIDs, BinaryList *lplstStoreEIDs, BinaryList *lplstItemEIDs)
  93. {
  94. BinaryList lstStoreEIDs;
  95. BinaryList lstItemEIDs;
  96. BinaryList lstUncachedStoreEIDs;
  97. BinaryList lstUncachedItemEIDs;
  98. for (ULONG i = 0; i < sbaStoreEIDs.cValues; ++i) {
  99. const std::vector<BYTE> eid(sbaStoreEIDs.lpbin[i].lpb, sbaStoreEIDs.lpbin[i].lpb + sbaStoreEIDs.lpbin[i].cb);
  100. if (m_mapStores.find(eid) != m_mapStores.end()) {
  101. lstStoreEIDs.push_back(sbaStoreEIDs.lpbin + i);
  102. lstItemEIDs.push_back(sbaItemEIDs.lpbin + i);
  103. } else {
  104. lstUncachedStoreEIDs.push_back(sbaStoreEIDs.lpbin + i);
  105. lstUncachedItemEIDs.push_back(sbaItemEIDs.lpbin + i);
  106. }
  107. }
  108. lstStoreEIDs.splice(lstStoreEIDs.end(), lstUncachedStoreEIDs);
  109. lstItemEIDs.splice(lstItemEIDs.end(), lstUncachedItemEIDs);
  110. lplstStoreEIDs->swap(lstStoreEIDs);
  111. lplstItemEIDs->swap(lstItemEIDs);
  112. return hrSuccess;
  113. }
  114. HRESULT ECArchiveAwareMsgStore::GetArchiveStore(LPSBinary lpStoreEID, ECMsgStore **lppArchiveStore)
  115. {
  116. HRESULT hr;
  117. const std::vector<BYTE> eid(lpStoreEID->lpb, lpStoreEID->lpb + lpStoreEID->cb);
  118. MsgStoreMap::const_iterator iterStore = m_mapStores.find(eid);
  119. if (iterStore != m_mapStores.cend())
  120. return iterStore->second->QueryInterface(IID_ECMsgStore, (LPVOID*)lppArchiveStore);
  121. // @todo: Consolidate this with ECMSProvider::LogonByEntryID
  122. UnknownPtr ptrUnknown;
  123. ECMsgStorePtr ptrOnlineStore;
  124. ULONG cbEntryID = 0;
  125. EntryIdPtr ptrEntryID;
  126. std::string ServerURL;
  127. bool bIsPseudoUrl = false;
  128. std::string strServer;
  129. bool bIsPeer = false;
  130. object_ptr<WSTransport> ptrTransport;
  131. ECMsgStorePtr ptrArchiveStore;
  132. object_ptr<IECPropStorage, IID_IECPropStorage> ptrPropStorage;
  133. hr = QueryInterface(IID_ECMsgStoreOnline, &~ptrUnknown);
  134. if (hr != hrSuccess)
  135. return hr;
  136. hr = ptrUnknown->QueryInterface(IID_ECMsgStore, &~ptrOnlineStore);
  137. if (hr != hrSuccess)
  138. return hr;
  139. hr = UnWrapStoreEntryID(lpStoreEID->cb, (LPENTRYID)lpStoreEID->lpb, &cbEntryID, &~ptrEntryID);
  140. if (hr != hrSuccess)
  141. return hr;
  142. hr = HrGetServerURLFromStoreEntryId(cbEntryID, ptrEntryID, ServerURL, &bIsPseudoUrl);
  143. if (hr != hrSuccess)
  144. return hr;
  145. if (bIsPseudoUrl) {
  146. hr = HrResolvePseudoUrl(ptrOnlineStore->lpTransport, ServerURL.c_str(), strServer, &bIsPeer);
  147. if (hr != hrSuccess)
  148. return hr;
  149. if (!bIsPeer)
  150. ServerURL = strServer;
  151. else {
  152. // We can't just use the transport from ptrOnlineStore as that will be
  153. // logged off when ptrOnlineStore gets destroyed (at the end of this finction).
  154. hr = ptrOnlineStore->lpTransport->CloneAndRelogon(&~ptrTransport);
  155. if (hr != hrSuccess)
  156. return hr;
  157. }
  158. }
  159. if (!ptrTransport) {
  160. // We get here if lpszServer wasn't a pseudo URL or if it was and it resolved
  161. // to another server than the one we're connected with.
  162. hr = ptrOnlineStore->lpTransport->CreateAndLogonAlternate(ServerURL.c_str(), &~ptrTransport);
  163. if (hr != hrSuccess)
  164. return hr;
  165. }
  166. hr = ECMsgStore::Create(const_cast<char *>(GetProfileName()), this->lpSupport, ptrTransport, FALSE, 0, FALSE, FALSE, FALSE, &~ptrArchiveStore);
  167. if (hr != hrSuccess)
  168. return hr;
  169. // Get a propstorage for the message store
  170. hr = ptrTransport->HrOpenPropStorage(0, nullptr, cbEntryID, ptrEntryID, 0, &~ptrPropStorage);
  171. if (hr != hrSuccess)
  172. return hr;
  173. // Set up the message store to use this storage
  174. hr = ptrArchiveStore->HrSetPropStorage(ptrPropStorage, FALSE);
  175. if (hr != hrSuccess)
  176. return hr;
  177. // Setup callback for session change
  178. hr = ptrTransport->AddSessionReloadCallback(ptrArchiveStore, ECMsgStore::Reload, NULL);
  179. if (hr != hrSuccess)
  180. return hr;
  181. hr = ptrArchiveStore->SetEntryId(cbEntryID, ptrEntryID);
  182. if (hr != hrSuccess)
  183. return hr;
  184. hr = ptrArchiveStore->QueryInterface(IID_ECMsgStore, (LPVOID*)lppArchiveStore);
  185. if (hr != hrSuccess)
  186. return hr;
  187. m_mapStores.insert(MsgStoreMap::value_type(eid, ptrArchiveStore));
  188. return hrSuccess;
  189. }