123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- #include <new>
- #include <kopano/platform.h>
- #include "ECArchiveAwareMsgStore.h"
- #include "ECArchiveAwareAttach.h"
- #include <kopano/ECGuid.h>
- #include <edkguid.h>
- #include <kopano/mapi_ptr.h>
- #include <kopano/memory.hpp>
- #include "IECPropStorage.h"
- #include "Mem.h"
- #include <kopano/mapiext.h>
- #include <kopano/mapiguidext.h>
- #include "ECArchiveAwareMessage.h"
- #include <kopano/ECGetText.h>
- #include <kopano/stringutil.h>
- #include <sstream>
- #include <kopano/ECDebug.h>
- #include <kopano/charset/convert.h>
- #define dispidStoreEntryIds "store-entryids"
- #define dispidItemEntryIds "item-entryids"
- #define dispidStubbed "stubbed"
- #define dispidDirty "dirty"
- #define dispidOrigSourceKey "original-sourcekey"
- class PropFinder {
- public:
- PropFinder(ULONG ulPropTag): m_ulPropTag(ulPropTag) {}
- bool operator()(const ECProperty &prop) const { return prop.GetPropTag() == m_ulPropTag; }
- private:
- ULONG m_ulPropTag;
- };
- HRESULT ECArchiveAwareMessageFactory::Create(ECMsgStore *lpMsgStore, BOOL fNew, BOOL fModify, ULONG ulFlags, BOOL bEmbedded, ECMAPIProp* lpRoot, ECMessage **lppMessage) const
- {
- auto lpArchiveAwareStore = dynamic_cast<ECArchiveAwareMsgStore *>(lpMsgStore);
-
-
- if (fNew || bEmbedded || lpArchiveAwareStore == NULL)
- return ECMessage::Create(lpMsgStore, fNew, fModify, ulFlags, bEmbedded, lpRoot, lppMessage);
- return ECArchiveAwareMessage::Create(lpArchiveAwareStore, FALSE, fModify, ulFlags, lppMessage);
- }
- ECArchiveAwareMessage::ECArchiveAwareMessage(ECArchiveAwareMsgStore *lpMsgStore, BOOL fNew, BOOL fModify, ULONG ulFlags)
- : ECMessage(lpMsgStore, fNew, fModify, ulFlags, FALSE, NULL)
- , m_bLoading(false)
- , m_bNamedPropsMapped(false), __propmap(5)
- , m_mode(MODE_UNARCHIVED)
- , m_bChanged(false)
- {
-
- this->HrAddPropHandlers(PR_MESSAGE_SIZE, ECMessage::GetPropHandler, SetPropHandler, (void*)this, FALSE, FALSE);
- }
- HRESULT ECArchiveAwareMessage::Create(ECArchiveAwareMsgStore *lpMsgStore, BOOL fNew, BOOL fModify, ULONG ulFlags, ECMessage **lppMessage)
- {
- return alloc_wrap<ECArchiveAwareMessage>(lpMsgStore, fNew, fModify,
- ulFlags).as(IID_ECMessage, lppMessage);
- }
- HRESULT ECArchiveAwareMessage::HrLoadProps()
- {
- HRESULT hr = hrSuccess;
- BOOL fModifyCopy;
- ECMsgStore *lpMsgStore;
- m_bLoading = true;
- hr = ECMessage::HrLoadProps();
- if (hr != hrSuccess)
- goto exit;
-
- if (m_mode != MODE_STUBBED) {
- m_bLoading = false;
- return hr;
- }
- fModifyCopy = this->fModify;
- lpMsgStore = GetMsgStore();
-
- static constexpr const SizedSPropTagArray(4, sptaDeleteProps) =
- {4, {PR_RTF_COMPRESSED, PR_BODY, PR_HTML, PR_ICON_INDEX}};
- static constexpr const SizedSPropTagArray(6, sptaRestoreProps) =
- {6, {PR_RTF_COMPRESSED, PR_BODY, PR_HTML, PR_ICON_INDEX,
- PR_MESSAGE_CLASS, PR_MESSAGE_SIZE}};
- if (!m_ptrArchiveMsg) {
- auto lpStore = dynamic_cast<ECArchiveAwareMsgStore *>(lpMsgStore);
- if (lpStore == NULL) {
-
-
- hr = MAPI_E_NOT_FOUND;
- goto exit;
- }
- hr = lpStore->OpenItemFromArchive(m_ptrStoreEntryIDs, m_ptrItemEntryIDs, &~m_ptrArchiveMsg);
- if (hr != hrSuccess) {
- hr = CreateInfoMessage(sptaDeleteProps, CreateErrorBodyUtf8(hr));
- goto exit;
- }
- }
-
-
-
-
-
-
-
- this->fModify = TRUE;
- hr = DeleteProps(sptaDeleteProps, NULL);
- if (hr != hrSuccess) {
- this->fModify = fModifyCopy;
- goto exit;
- }
- hr = Util::DoCopyProps(&IID_IMAPIProp, &m_ptrArchiveMsg->m_xMAPIProp,
- sptaRestoreProps, 0, NULL, &IID_IMAPIProp,
- &this->m_xMAPIProp, 0, NULL);
- if (hr != hrSuccess) {
- this->fModify = fModifyCopy;
- goto exit;
- }
-
-
- hr = Util::HrDeleteAttachments(&m_xMessage);
- if (hr != hrSuccess) {
- this->fModify = fModifyCopy;
- goto exit;
- }
- hr = Util::CopyAttachments(&m_ptrArchiveMsg->m_xMessage, &m_xMessage, NULL);
- this->fModify = fModifyCopy;
- exit:
- m_bLoading = false;
- return hr;
- }
- HRESULT ECArchiveAwareMessage::HrSetRealProp(const SPropValue *lpsPropValue)
- {
- HRESULT hr;
- SPropValue copy;
- if (lpsPropValue != nullptr)
- copy = *lpsPropValue;
-
- if (m_bLoading && lpsPropValue != nullptr &&
- PROP_TYPE(lpsPropValue->ulPropTag) != PT_ERROR &&
- PROP_ID(lpsPropValue->ulPropTag) >= 0x8500) {
-
-
-
-
- if (!m_bNamedPropsMapped) {
- hr = MapNamedProps();
- if (hr != hrSuccess)
- return hr;
- }
-
- if (lpsPropValue->ulPropTag == PROP_ARCHIVE_STORE_ENTRYIDS) {
- if (m_mode == MODE_UNARCHIVED)
- m_mode = MODE_ARCHIVED;
-
- hr = MAPIAllocateBuffer(sizeof(SPropValue), &~m_ptrStoreEntryIDs);
- if (hr == hrSuccess)
- hr = Util::HrCopyProperty(m_ptrStoreEntryIDs, lpsPropValue, m_ptrStoreEntryIDs);
- if (hr != hrSuccess)
- return hr;
- }
- else if (lpsPropValue->ulPropTag == PROP_ARCHIVE_ITEM_ENTRYIDS) {
- if (m_mode == MODE_UNARCHIVED)
- m_mode = MODE_ARCHIVED;
-
- hr = MAPIAllocateBuffer(sizeof(SPropValue), &~m_ptrItemEntryIDs);
- if (hr == hrSuccess)
- hr = Util::HrCopyProperty(m_ptrItemEntryIDs, lpsPropValue, m_ptrItemEntryIDs);
- if (hr != hrSuccess)
- return hr;
- }
- else if (lpsPropValue->ulPropTag == PROP_STUBBED) {
- if (lpsPropValue->Value.b == TRUE)
- m_mode = MODE_STUBBED;
-
-
-
- copy.Value.b = FALSE;
- }
- else if (lpsPropValue->ulPropTag == PROP_DIRTY) {
- if (lpsPropValue->Value.b != FALSE)
- m_mode = MODE_DIRTY;
- }
- }
- hr = ECMessage::HrSetRealProp(lpsPropValue != nullptr ? © : nullptr);
- if (hr == hrSuccess && !m_bLoading)
-
- m_bChanged = true;
- return hr;
- }
- HRESULT ECArchiveAwareMessage::HrDeleteRealProp(ULONG ulPropTag, BOOL fOverwriteRO)
- {
- HRESULT hr = hrSuccess;
- hr = ECMessage::HrDeleteRealProp(ulPropTag, fOverwriteRO);
- if (hr == hrSuccess && !m_bLoading)
- m_bChanged = true;
- return hr;
- }
- HRESULT ECArchiveAwareMessage::OpenProperty(ULONG ulPropTag, LPCIID lpiid, ULONG ulInterfaceOptions, ULONG ulFlags, LPUNKNOWN *lppUnk)
- {
- HRESULT hr = hrSuccess;
- hr = ECMessage::OpenProperty(ulPropTag, lpiid, ulInterfaceOptions, ulFlags, lppUnk);
- if (!m_bLoading && hr == hrSuccess && ((ulFlags & MAPI_MODIFY) || (fModify && (ulFlags & MAPI_BEST_ACCESS))))
-
-
-
- m_bChanged = true;
- return hr;
- }
- HRESULT ECArchiveAwareMessage::OpenAttach(ULONG ulAttachmentNum, LPCIID lpInterface, ULONG ulFlags, LPATTACH *lppAttach)
- {
- HRESULT hr = hrSuccess;
- hr = ECMessage::OpenAttach(ulAttachmentNum, lpInterface, ulFlags, lppAttach);
-
-
-
-
- if (hr == hrSuccess && ((ulFlags & MAPI_MODIFY) || fModify))
-
-
-
- m_bChanged = true;
- return hr;
- }
- HRESULT ECArchiveAwareMessage::CreateAttach(LPCIID lpInterface, ULONG ulFlags, ULONG *lpulAttachmentNum, LPATTACH *lppAttach)
- {
- HRESULT hr = hrSuccess;
-
- if (m_bLoading)
- hr = ECMessage::CreateAttach(lpInterface, ulFlags, ECArchiveAwareAttachFactory(), lpulAttachmentNum, lppAttach);
- else {
- hr = ECMessage::CreateAttach(lpInterface, ulFlags, ECAttachFactory(), lpulAttachmentNum, lppAttach);
- if (hr == hrSuccess)
- m_bChanged = true;
- }
- return hr;
- }
- HRESULT ECArchiveAwareMessage::DeleteAttach(ULONG ulAttachmentNum, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)
- {
- HRESULT hr = hrSuccess;
- hr = ECMessage::DeleteAttach(ulAttachmentNum, ulUIParam, lpProgress, ulFlags);
- if (hr == hrSuccess && !m_bLoading)
- m_bChanged = true;
- return hr;
- }
- HRESULT ECArchiveAwareMessage::ModifyRecipients(ULONG ulFlags,
- const ADRLIST *lpMods)
- {
- HRESULT hr = hrSuccess;
- hr = ECMessage::ModifyRecipients(ulFlags, lpMods);
- if (hr == hrSuccess)
- m_bChanged = true;
- return hr;
- }
- HRESULT ECArchiveAwareMessage::SaveChanges(ULONG ulFlags)
- {
- HRESULT hr;
- SizedSPropTagArray(1, sptaStubbedProp) = {1, {PROP_STUBBED}};
- if (!fModify)
- return MAPI_E_NO_ACCESS;
-
-
- if (!m_bChanged)
- return hrSuccess;
-
- if (m_bNamedPropsMapped) {
- hr = DeleteProps(sptaStubbedProp, NULL);
- if (hr != hrSuccess)
- return hr;
- }
- if (m_mode == MODE_STUBBED || m_mode == MODE_ARCHIVED) {
- SPropValue propDirty;
- propDirty.ulPropTag = PROP_DIRTY;
- propDirty.Value.b = TRUE;
- hr = SetProps(1, &propDirty, NULL);
- if (hr != hrSuccess)
- return hr;
- m_mode = MODE_DIRTY;
- }
- return ECMessage::SaveChanges(ulFlags);
- }
- HRESULT ECArchiveAwareMessage::SetPropHandler(ULONG ulPropTag,
- void *, const SPropValue *lpsPropValue, void *lpParam)
- {
- auto lpMessage = static_cast<ECArchiveAwareMessage *>(lpParam);
- HRESULT hr = hrSuccess;
- switch(ulPropTag) {
- case PR_MESSAGE_SIZE:
- if (lpMessage->m_bLoading)
- hr = lpMessage->ECMessage::HrSetRealProp(lpsPropValue);
- else
- hr = MAPI_E_COMPUTED;
- break;
- default:
- hr = MAPI_E_NOT_FOUND;
- break;
- }
- return hr;
- }
- HRESULT ECArchiveAwareMessage::MapNamedProps()
- {
- HRESULT hr = hrSuccess;
- PROPMAP_INIT_NAMED_ID(ARCHIVE_STORE_ENTRYIDS, PT_MV_BINARY, PSETID_Archive, dispidStoreEntryIds);
- PROPMAP_INIT_NAMED_ID(ARCHIVE_ITEM_ENTRYIDS, PT_MV_BINARY, PSETID_Archive, dispidItemEntryIds);
- PROPMAP_INIT_NAMED_ID(STUBBED, PT_BOOLEAN, PSETID_Archive, dispidStubbed);
- PROPMAP_INIT_NAMED_ID(DIRTY, PT_BOOLEAN, PSETID_Archive, dispidDirty);
- PROPMAP_INIT_NAMED_ID(ORIGINAL_SOURCE_KEY, PT_BINARY, PSETID_Archive, dispidOrigSourceKey);
- PROPMAP_INIT(&this->m_xMAPIProp);
- m_bNamedPropsMapped = true;
- exitpm:
- return hr;
- }
- HRESULT ECArchiveAwareMessage::CreateInfoMessage(const SPropTagArray *lpptaDeleteProps,
- const std::string &strBodyHtml)
- {
- HRESULT hr = hrSuccess;
- SPropValue sPropVal;
- StreamPtr ptrHtmlStream;
- ULARGE_INTEGER liZero = {{0, 0}};
- this->fModify = TRUE;
- hr = DeleteProps(lpptaDeleteProps, NULL);
- if (hr != hrSuccess)
- goto exit;
- sPropVal.ulPropTag = PR_INTERNET_CPID;
- sPropVal.Value.l = 65001;
- hr = HrSetOneProp(&this->m_xMAPIProp, &sPropVal);
- if (hr != hrSuccess)
- goto exit;
- hr = OpenProperty(PR_HTML, &ptrHtmlStream.iid(), 0, MAPI_CREATE | MAPI_MODIFY, &~ptrHtmlStream);
- if (hr != hrSuccess)
- goto exit;
- hr = ptrHtmlStream->SetSize(liZero);
- if (hr != hrSuccess)
- goto exit;
- hr = ptrHtmlStream->Write(strBodyHtml.c_str(), strBodyHtml.size(), NULL);
- if (hr != hrSuccess)
- goto exit;
- hr = ptrHtmlStream->Commit(0);
- exit:
- this->fModify = FALSE;
- return hr;
- }
- std::string ECArchiveAwareMessage::CreateErrorBodyUtf8(HRESULT hResult) {
- std::basic_ostringstream<TCHAR> ossHtmlBody;
- ossHtmlBody << _T("<HTML><HEAD><STYLE type=\"text/css\">")
- _T("BODY {font-family: \"sans-serif\";margin-left: 1em;}")
- _T("P {margin: .1em 0;}")
- _T("P.spacing {margin: .8em 0;}")
- _T("H1 {margin: .3em 0;}")
- _T("SPAN#errcode {display: inline;font-weight: bold;}")
- _T("SPAN#errmsg {display: inline;font-style: italic;}")
- _T("DIV.indented {margin-left: 4em;}")
- _T("</STYLE></HEAD><BODY><H1>")
- << _("Kopano Archiver")
- << _T("</H1><P>")
- << _("An error has occurred while fetching the message from the archive.")
- << _T(" ")
- << _("Please contact your system administrator.")
- << _T("</P><P class=\"spacing\"></P>")
- _T("<P>")
- << _("Error code:")
- << _T("<SPAN id=\"errcode\">")
- << tstringify(hResult, true)
- << _T("</SPAN> (<SPAN id=\"errmsg\">")
- << convert_to<tstring>(GetMAPIErrorDescription(hResult))
- << _T("</SPAN>)</P>");
- if (hResult == MAPI_E_NO_SUPPORT) {
- ossHtmlBody << _T("<P class=\"spacing\"></P><P>")
- << _("It seems no valid archiver license is installed.")
- << _T("</P>");
- } else if (hResult == MAPI_E_NOT_FOUND) {
- ossHtmlBody << _T("<P class=\"spacing\"></P><P>")
- << _("The archive could not be found.")
- << _T("</P>");
- } else if (hResult == MAPI_E_NO_ACCESS) {
- ossHtmlBody << _T("<P class=\"spacing\"></P><P>")
- << _("You don't have sufficient access to the archive.")
- << _T("</P>");
- } else {
- KCHL::memory_ptr<TCHAR> lpszDescription;
- HRESULT hr = Util::HrMAPIErrorToText(hResult, &~lpszDescription);
- if (hr == hrSuccess)
- ossHtmlBody << _T("<P>")
- << _("Error description:")
- << _T("<DIV class=\"indented\">")
- << lpszDescription
- << _T("</DIV></P>");
- }
- ossHtmlBody << _T("</BODY></HTML>");
- tstring strHtmlBody = ossHtmlBody.str();
- return convert_to<std::string>("UTF-8", strHtmlBody, rawsize(strHtmlBody), CHARSET_TCHAR);
- }
- std::string ECArchiveAwareMessage::CreateOfflineWarnBodyUtf8()
- {
- std::basic_ostringstream<TCHAR> ossHtmlBody;
- ossHtmlBody << _T("<HTML><HEAD><STYLE type=\"text/css\">")
- _T("BODY {font-family: \"sans-serif\";margin-left: 1em;}")
- _T("P {margin: .1em 0;}")
- _T("P.spacing {margin: .8em 0;}")
- _T("H1 {margin: .3em 0;}")
- _T("SPAN#errcode {display: inline;font-weight: bold;}")
- _T("SPAN#errmsg {display: inline;font-style: italic;}")
- _T("DIV.indented {margin-left: 4em;}")
- _T("</STYLE></HEAD><BODY><H1>")
- << _("Kopano Archiver")
- << _T("</H1><P>")
- << _("Archives can not be destubbed when working offline.")
- << _T("</P></BODY></HTML>");
- tstring strHtmlBody = ossHtmlBody.str();
- return convert_to<std::string>("UTF-8", strHtmlBody, rawsize(strHtmlBody), CHARSET_TCHAR);
- }
|