transaction.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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 <utility>
  19. #include <kopano/Util.h>
  20. #include "transaction.h"
  21. #include "ArchiverSession.h"
  22. namespace KC { namespace operations {
  23. Transaction::Transaction(const SObjectEntry &objectEntry): m_objectEntry(objectEntry)
  24. { }
  25. HRESULT Transaction::SaveChanges(ArchiverSessionPtr ptrSession, RollbackPtr *lpptrRollback)
  26. {
  27. HRESULT hr = hrSuccess;
  28. RollbackPtr ptrRollback(new Rollback());
  29. bool bPSAFailure = false;
  30. if (lpptrRollback == NULL) {
  31. hr = MAPI_E_INVALID_PARAMETER;
  32. goto exit;
  33. }
  34. for (const auto &msg : m_lstSave) {
  35. if (msg.bDeleteOnFailure) {
  36. hr = ptrRollback->Delete(ptrSession, msg.ptrMessage);
  37. if (hr == hrSuccess)
  38. goto exit;
  39. }
  40. hr = msg.ptrMessage->SaveChanges(0);
  41. if (hr != hrSuccess)
  42. goto exit;
  43. if (msg.ptrPSAction != NULL && msg.ptrPSAction->Execute() != hrSuccess)
  44. bPSAFailure = true;
  45. }
  46. *lpptrRollback = ptrRollback;
  47. exit:
  48. if (hr != hrSuccess)
  49. ptrRollback->Execute(ptrSession);
  50. if (hr == hrSuccess && bPSAFailure)
  51. hr = MAPI_W_ERRORS_RETURNED;
  52. return hr;
  53. }
  54. HRESULT Transaction::PurgeDeletes(ArchiverSessionPtr ptrSession, TransactionPtr ptrDeferredTransaction)
  55. {
  56. HRESULT hr = hrSuccess;
  57. MessagePtr ptrMessage;
  58. IMAPISession *lpSession = ptrSession->GetMAPISession();
  59. for (const auto &obj : m_lstDelete) {
  60. HRESULT hrTmp;
  61. if (obj.bDeferredDelete && ptrDeferredTransaction != NULL)
  62. hrTmp = ptrDeferredTransaction->Delete(obj.objectEntry);
  63. else {
  64. ULONG ulType;
  65. hrTmp = lpSession->OpenEntry(obj.objectEntry.sItemEntryId.size(), obj.objectEntry.sItemEntryId, &ptrMessage.iid(), 0, &ulType, &~ptrMessage);
  66. if (hrTmp == MAPI_E_NOT_FOUND) {
  67. MsgStorePtr ptrStore;
  68. // Try to open the message on the store
  69. hrTmp = ptrSession->OpenStore(obj.objectEntry.sStoreEntryId, &~ptrStore);
  70. if (hrTmp == hrSuccess)
  71. hrTmp = ptrStore->OpenEntry(obj.objectEntry.sItemEntryId.size(), obj.objectEntry.sItemEntryId, &ptrMessage.iid(), 0, &ulType, &~ptrMessage);
  72. }
  73. if (hrTmp == hrSuccess)
  74. hrTmp = Util::HrDeleteMessage(lpSession, ptrMessage);
  75. }
  76. if (hrTmp != hrSuccess)
  77. hr = MAPI_W_ERRORS_RETURNED;
  78. }
  79. return hr;
  80. }
  81. HRESULT Transaction::Save(IMessage *lpMessage, bool bDeleteOnFailure, const PostSaveActionPtr &ptrPSAction)
  82. {
  83. SaveEntry se;
  84. lpMessage->AddRef();
  85. se.bDeleteOnFailure = bDeleteOnFailure;
  86. se.ptrMessage.reset(lpMessage, false);
  87. se.ptrPSAction = ptrPSAction;
  88. m_lstSave.push_back(std::move(se));
  89. return hrSuccess;
  90. }
  91. HRESULT Transaction::Delete(const SObjectEntry &objectEntry, bool bDeferredDelete)
  92. {
  93. DelEntry de;
  94. de.objectEntry = objectEntry;
  95. de.bDeferredDelete = bDeferredDelete;
  96. m_lstDelete.push_back(std::move(de));
  97. return hrSuccess;
  98. }
  99. HRESULT Rollback::Delete(ArchiverSessionPtr ptrSession, IMessage *lpMessage)
  100. {
  101. HRESULT hr;
  102. SPropArrayPtr ptrMsgProps;
  103. ULONG cMsgProps;
  104. ULONG ulType;
  105. DelEntry entry;
  106. static constexpr const SizedSPropTagArray(2, sptaMsgProps) =
  107. {2, {PR_ENTRYID, PR_PARENT_ENTRYID}};
  108. enum {IDX_ENTRYID, IDX_PARENT_ENTRYID};
  109. if (lpMessage == NULL)
  110. return MAPI_E_INVALID_PARAMETER;
  111. hr = lpMessage->GetProps(sptaMsgProps, 0, &cMsgProps, &~ptrMsgProps);
  112. if (hr != hrSuccess)
  113. return hr;
  114. hr = ptrSession->GetMAPISession()->OpenEntry(ptrMsgProps[IDX_PARENT_ENTRYID].Value.bin.cb, reinterpret_cast<ENTRYID *>(ptrMsgProps[IDX_PARENT_ENTRYID].Value.bin.lpb), &entry.ptrFolder.iid(), MAPI_MODIFY, &ulType, &~entry.ptrFolder);
  115. if (hr != hrSuccess)
  116. return hr;
  117. entry.eidMessage.assign(ptrMsgProps[IDX_ENTRYID].Value.bin);
  118. m_lstDelete.push_back(entry);
  119. return hrSuccess;
  120. }
  121. HRESULT Rollback::Execute(ArchiverSessionPtr ptrSession)
  122. {
  123. HRESULT hr = hrSuccess;
  124. SBinary entryID = {0, NULL};
  125. ENTRYLIST entryList = {1, &entryID};
  126. for (const auto &obj : m_lstDelete) {
  127. entryID.cb = obj.eidMessage.size();
  128. entryID.lpb = obj.eidMessage;
  129. if (obj.ptrFolder->DeleteMessages(&entryList, 0, NULL, 0) != hrSuccess)
  130. hr = MAPI_W_ERRORS_RETURNED;
  131. }
  132. return hr;
  133. }
  134. }} /* namespace */