123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638 |
- /*
- * Copyright 2005 - 2016 Zarafa and its licensors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <kopano/platform.h>
- #include <chrono>
- #include <condition_variable>
- #include <new>
- #include <kopano/lockhelper.hpp>
- #include <kopano/memory.hpp>
- #include <mapi.h>
- #include <mapispi.h>
- #include <mapiutil.h>
- #include <kopano/mapiguidext.h>
- #include <kopano/ECGuid.h>
- #include <kopano/ECInterfaceDefs.h>
- #include <kopano/mapiext.h>
- #include <edkmdb.h>
- #include <edkguid.h>
- #include "kcore.hpp"
- #include "ECXPLogon.h"
- #include "ECXPProvider.h"
- #include "WSTransport.h"
- #include "Mem.h"
- #include "ClientUtil.h"
- #include <kopano/CommonUtil.h>
- #include "ECMsgStore.h"
- #include "ECMessage.h"
- #include <kopano/kcodes.h>
- #include <kopano/ECDebug.h>
- #include <kopano/ECRestriction.h>
- #include <kopano/mapi_ptr.h>
- using namespace KCHL;
- static HRESULT HrGetECMsgStore(IMAPIProp *lpProp, ECMsgStore **lppECMsgStore)
- {
- HRESULT hr;
- LPSPropValue lpPropVal = NULL;
- ECMAPIProp *lpECMAPIProp = NULL;
- hr = HrGetOneProp(lpProp, PR_EC_OBJECT, &lpPropVal);
- if(hr != hrSuccess)
- return hr;
- lpECMAPIProp = (ECMAPIProp *)lpPropVal->Value.lpszA;
- *lppECMsgStore = lpECMAPIProp->GetMsgStore();
- (*lppECMsgStore)->AddRef();
- return hrSuccess;
- }
- ECXPLogon::ECXPLogon(const std::string &strProfileName, BOOL bOffline,
- ECXPProvider *lpXPProvider, LPMAPISUP lpMAPISup) :
- ECUnknown("IXPLogon"), m_lpMAPISup(lpMAPISup),
- m_lpXPProvider(lpXPProvider), m_bOffline(bOffline)
- {
- m_lpMAPISup->AddRef();
- }
- ECXPLogon::~ECXPLogon()
- {
- if(m_lppszAdrTypeArray)
- ECFreeBuffer(m_lppszAdrTypeArray);
- if(m_lpMAPISup)
- m_lpMAPISup->Release();
- }
- HRESULT ECXPLogon::Create(const std::string &strProfileName, BOOL bOffline, ECXPProvider *lpXPProvider, LPMAPISUP lpMAPISup, ECXPLogon **lppECXPLogon)
- {
- HRESULT hr = hrSuccess;
- auto lpXPLogon = new(std::nothrow) ECXPLogon(strProfileName, bOffline, lpXPProvider, lpMAPISup);
- if (lpXPLogon == nullptr)
- return MAPI_E_NOT_ENOUGH_MEMORY;
- hr = lpXPLogon->QueryInterface(IID_ECXPLogon, (void **)lppECXPLogon);
- if(hr != hrSuccess)
- delete lpXPLogon;
- return hr;
- }
- HRESULT ECXPLogon::QueryInterface(REFIID refiid, void **lppInterface)
- {
- REGISTER_INTERFACE2(ECXPLogon, this);
- REGISTER_INTERFACE2(IXPLogon, &this->m_xXPLogon);
- return MAPI_E_INTERFACE_NOT_SUPPORTED;
- }
- HRESULT ECXPLogon::AddressTypes(ULONG * lpulFlags, ULONG * lpcAdrType, LPTSTR ** lpppszAdrTypeArray, ULONG * lpcMAPIUID, LPMAPIUID ** lpppUIDArray)
- {
- HRESULT hr;
- if(m_lppszAdrTypeArray == NULL) {
- hr = ECAllocateBuffer(sizeof(TCHAR *) * 3, (LPVOID *)&m_lppszAdrTypeArray);
- if(hr != hrSuccess)
- return hr;
- hr = ECAllocateMore((_tcslen(TRANSPORT_ADDRESS_TYPE_SMTP)+1) * sizeof(TCHAR), m_lppszAdrTypeArray, (LPVOID *)&m_lppszAdrTypeArray[0]);
- if(hr != hrSuccess)
- return hr;
- _tcscpy(m_lppszAdrTypeArray[0], TRANSPORT_ADDRESS_TYPE_SMTP);
- hr = ECAllocateMore((_tcslen(TRANSPORT_ADDRESS_TYPE_ZARAFA)+1) * sizeof(TCHAR), m_lppszAdrTypeArray, (LPVOID *)&m_lppszAdrTypeArray[1]);
- if(hr != hrSuccess)
- return hr;
- _tcscpy(m_lppszAdrTypeArray[1], TRANSPORT_ADDRESS_TYPE_ZARAFA);
- hr = ECAllocateMore((_tcslen(TRANSPORT_ADDRESS_TYPE_FAX)+1) * sizeof(TCHAR), m_lppszAdrTypeArray, (LPVOID *)&m_lppszAdrTypeArray[2]);
- if(hr != hrSuccess)
- return hr;
- _tcscpy(m_lppszAdrTypeArray[2], TRANSPORT_ADDRESS_TYPE_FAX);
- }
- *lpulFlags = fMapiUnicode;
- *lpcMAPIUID = 0;
- *lpppUIDArray = NULL; // We could specify the Kopano addressbook's UID here to stop the MAPI spooler doing expansions on them (IE EntryID -> Email address)
- *lpcAdrType = 3;
- *lpppszAdrTypeArray = m_lppszAdrTypeArray;
- return hrSuccess;
- }
- HRESULT ECXPLogon::RegisterOptions(ULONG * lpulFlags, ULONG * lpcOptions, LPOPTIONDATA * lppOptions)
- {
- *lpulFlags = 0;//fMapiUnicode ?
- *lpcOptions = 0;
- *lppOptions = NULL;
- return hrSuccess;
- }
- HRESULT ECXPLogon::TransportNotify(ULONG * lpulFlags, LPVOID * lppvData)
- {
- if(*lpulFlags & NOTIFY_ABORT_DEFERRED)
- //FIXME: m_ulTransportStatus
- // doe iets met lppvData
- // Remove item, out the spooler list (outgoing queue ???)
- /* nothing */;
- if (*lpulFlags & NOTIFY_BEGIN_INBOUND)
- m_ulTransportStatus |= STATUS_INBOUND_ENABLED;
- if (*lpulFlags & NOTIFY_BEGIN_INBOUND_FLUSH)
- m_ulTransportStatus |= STATUS_INBOUND_FLUSH;
- if (*lpulFlags & NOTIFY_BEGIN_OUTBOUND)
- m_ulTransportStatus |= STATUS_OUTBOUND_ENABLED;
- if (*lpulFlags & NOTIFY_BEGIN_OUTBOUND_FLUSH)
- m_ulTransportStatus |= STATUS_OUTBOUND_FLUSH;
- if (*lpulFlags & NOTIFY_CANCEL_MESSAGE) {
- scoped_lock lock(m_hExitMutex);
- m_bCancel = true;
- m_hExitSignal.notify_one();
- }
- if (*lpulFlags & NOTIFY_END_INBOUND)
- m_ulTransportStatus &= ~STATUS_INBOUND_ENABLED;
- if (*lpulFlags & NOTIFY_END_INBOUND_FLUSH)
- m_ulTransportStatus &= ~STATUS_INBOUND_FLUSH;
- if (*lpulFlags & NOTIFY_END_OUTBOUND)
- m_ulTransportStatus &= ~STATUS_OUTBOUND_ENABLED;
- if (*lpulFlags & NOTIFY_END_OUTBOUND_FLUSH)
- m_ulTransportStatus &= ~STATUS_OUTBOUND_FLUSH;
- return HrUpdateTransportStatus();
- }
- HRESULT ECXPLogon::Idle(ULONG ulFlags)
- {
- // The MAPI spooler periodically calls the IXPLogon::Idle method during times when the system is idle
- // We do nothing ..
- return hrSuccess;
- }
- HRESULT ECXPLogon::TransportLogoff(ULONG ulFlags)
- {
- return hrSuccess;
- }
- /**
- * Clear not deleted submit message
- *
- * The messages older than 10 days will be deleted. This function delete
- * only the first 50 messages. Normally it should be zero!
- *
- * @param[in] lpFolder Folder with submitted messages
- *
- * @return MAPI error code
- */
- HRESULT ECXPLogon::ClearOldSubmittedMessages(LPMAPIFOLDER lpFolder)
- {
- HRESULT hr = hrSuccess;
- static constexpr const SizedSPropTagArray(1, sptDelete) = {1, {PR_ENTRYID}};
- MAPITablePtr ptrContentsTable;
- memory_ptr<ENTRYLIST> lpDeleteItemEntryList;
- SPropValue sPropDelAfterSubmit = {0};
- SPropValue sPropxDaysBefore = {0};
- SRowSetPtr ptrRows;
- time_t tNow = 0;
- hr = lpFolder->GetContentsTable(0, &~ptrContentsTable);
- if (hr != hrSuccess)
- return hr;
- hr = ptrContentsTable->SetColumns(sptDelete, MAPI_DEFERRED_ERRORS);
- if(hr != hrSuccess)
- return hr;
- // build restriction where we search for messages which must deleted after the submit
- sPropDelAfterSubmit.ulPropTag = PR_DELETE_AFTER_SUBMIT;
- sPropDelAfterSubmit.Value.b = TRUE;
- sPropxDaysBefore.ulPropTag = PR_CREATION_TIME;
- time(&tNow);
- UnixTimeToFileTime(tNow - (10 * 24 * 60 * 60), &sPropxDaysBefore.Value.ft);
- hr = ECAndRestriction(
- ECAndRestriction(
- ECExistRestriction(PR_DELETE_AFTER_SUBMIT) +
- ECPropertyRestriction(RELOP_EQ, PR_DELETE_AFTER_SUBMIT, &sPropDelAfterSubmit, ECRestriction::Cheap)
- ) +
- ECPropertyRestriction(RELOP_LE, PR_CREATION_TIME, &sPropxDaysBefore, ECRestriction::Cheap)
- ).RestrictTable(ptrContentsTable, MAPI_DEFERRED_ERRORS);
- if (hr != hrSuccess)
- return hr;
- hr = MAPIAllocateBuffer(sizeof(ENTRYLIST), &~lpDeleteItemEntryList);
- if (hr != hrSuccess)
- return hr;
- hr = MAPIAllocateMore(50 * sizeof(SBinary), lpDeleteItemEntryList, (void**)&lpDeleteItemEntryList->lpbin);
- if (hr != hrSuccess)
- return hr;
- lpDeleteItemEntryList->cValues = 0;
- // Get only the first 50 items
- hr = ptrContentsTable->QueryRows(50, 0, &ptrRows);
- if (hr != hrSuccess)
- return hr;
- for (unsigned int i = 0; i < ptrRows.size(); ++i)
- if(ptrRows[i].lpProps[0].ulPropTag == PR_ENTRYID)
- lpDeleteItemEntryList->lpbin[lpDeleteItemEntryList->cValues++] = ptrRows[i].lpProps[0].Value.bin;
- if(lpDeleteItemEntryList->cValues > 0)
- hr = lpFolder->DeleteMessages(lpDeleteItemEntryList, 0, NULL, 0); //Delete message on the server
- return hr;
- }
- HRESULT ECXPLogon::SubmitMessage(ULONG ulFlags, LPMESSAGE lpMessage, ULONG * lpulMsgRef, ULONG * lpulReturnParm)
- {
- HRESULT hr = hrSuccess;
- object_ptr<IMAPITable> lpRecipTable;
- rowset_ptr lpRecipRows;
- ULONG ulRow = 0;
- ULONG ulRowCount = 0;
- memory_ptr<SPropValue> lpEntryID, lpECObject;
- object_ptr<IMsgStore> lpOnlineStore;
- object_ptr<ECMsgStore> lpOnlineECMsgStore, lpECMsgStore;
- ULONG ulObjType;
- object_ptr<IMAPIFolder> lpSubmitFolder;
- object_ptr<IMessage> lpSubmitMessage;
- SPropValue sDeleteAfterSubmitProp;
- ULONG ulOnlineAdviseConnection = 0;
- ENTRYLIST sDelete;
- object_ptr<IMsgStore> lpMsgStore;
- ULONG ulType = 0;
- static constexpr const SizedSPropTagArray(6, sptExcludeProps) =
- {6, {PR_SENTMAIL_ENTRYID, PR_SOURCE_KEY, PR_CHANGE_KEY,
- PR_PREDECESSOR_CHANGE_LIST, PR_ENTRYID, PR_SUBMIT_FLAGS}};
- // Un-cancel
- ulock_normal l_exit(m_hExitMutex);
- m_bCancel = false;
- l_exit.unlock();
- // Save some outgoing properties for the server
- hr = SetOutgoingProps(lpMessage);
- if (hr != erSuccess)
- return hr;
- hr = lpMessage->SaveChanges(KEEP_OPEN_READWRITE);
- if (hr != erSuccess)
- return hr;
- // Get the recipient table from the message
- hr = lpMessage->GetRecipientTable(fMapiUnicode, &~lpRecipTable);
- if (hr != hrSuccess)
- return hr;
- // The spooler marks all the message recipients this transport has to
- // handle with PR_RESPONSIBILITY set to FALSE
- SPropValue spvRecipUnsent;
- spvRecipUnsent.ulPropTag = PR_RESPONSIBILITY;
- spvRecipUnsent.Value.b = FALSE;
- SRestriction srRecipientUnhandled;
- srRecipientUnhandled.rt = RES_PROPERTY;
- srRecipientUnhandled.res.resProperty.relop = RELOP_EQ;
- srRecipientUnhandled.res.resProperty.ulPropTag = PR_RESPONSIBILITY;
- srRecipientUnhandled.res.resProperty.lpProp = &spvRecipUnsent;
- hr = lpRecipTable->Restrict(&srRecipientUnhandled, 0);
- if (hr != hrSuccess)
- return hr;
- hr = lpRecipTable->GetRowCount(0, &ulRowCount);
- if (hr != hrSuccess)
- return hr;
- if (ulRowCount == 0)
- return MAPI_E_NOT_ME;
- if (HrGetECMsgStore(lpMessage, &~lpECMsgStore) != hrSuccess) {
- hr = m_lpMAPISup->OpenEntry(this->m_lpXPProvider->m_lpIdentityProps[XPID_STORE_EID].Value.bin.cb, reinterpret_cast<ENTRYID *>(this->m_lpXPProvider->m_lpIdentityProps[XPID_STORE_EID].Value.bin.lpb), nullptr, MAPI_MODIFY, &ulType, &~lpMsgStore);
- if (hr != hrSuccess)
- return hr;
- hr = HrGetOneProp(lpMsgStore, PR_EC_OBJECT, &~lpECObject);
- if (hr != hrSuccess)
- return hr;
- lpECMsgStore.reset(reinterpret_cast<ECMsgStore *>(lpECObject->Value.lpszA));
- }
- hr = lpECMsgStore->QueryInterface(IID_ECMsgStoreOnline, &~lpOnlineStore);
- if (hr != hrSuccess)
- return hr;
- hr = HrGetECMsgStore(lpOnlineStore, &~lpOnlineECMsgStore);
- if (hr != hrSuccess)
- return hr;
- hr = lpOnlineStore->OpenEntry(0, nullptr, &IID_IMAPIFolder, MAPI_MODIFY, &ulObjType, &~lpSubmitFolder);
- if (hr != hrSuccess)
- return hr;
- hr = ClearOldSubmittedMessages(lpSubmitFolder);
- if (FAILED(hr))
- return hr;
- hr = lpSubmitFolder->CreateMessage(&IID_IMessage, 0, &~lpSubmitMessage);
- if (hr != hrSuccess)
- return hr;
- hr = lpMessage->CopyTo(0, NULL, sptExcludeProps, 0, NULL,
- &IID_IMessage, lpSubmitMessage, 0, NULL);
- if (hr != hrSuccess)
- return hr;
-
- sDeleteAfterSubmitProp.ulPropTag = PR_DELETE_AFTER_SUBMIT;
- sDeleteAfterSubmitProp.Value.b = true;
- hr = HrSetOneProp(lpSubmitMessage, &sDeleteAfterSubmitProp);
- if (hr != hrSuccess)
- return hr;
- hr = lpSubmitMessage->SaveChanges(KEEP_OPEN_READWRITE);
- if (hr != hrSuccess)
- return hr;
- hr = HrGetOneProp(lpSubmitMessage, PR_ENTRYID, &~lpEntryID);
- if (hr != hrSuccess)
- return hr;
- sDelete.cValues = 1;
- sDelete.lpbin = &lpEntryID->Value.bin;
- // Add the message to the master outgoing queue on the server
- l_exit.lock();
- hr = lpOnlineStore->Advise(lpEntryID->Value.bin.cb, (LPENTRYID)lpEntryID->Value.bin.lpb, fnevObjectDeleted, &this->m_xMAPIAdviseSink, &ulOnlineAdviseConnection);
- if (hr != hrSuccess) {
- lpSubmitFolder->DeleteMessages(&sDelete, 0, NULL, 0); //Delete message on the server
- l_exit.unlock();
- return hr;
- }
- hr = lpOnlineECMsgStore->lpTransport->HrSubmitMessage(lpEntryID->Value.bin.cb, (LPENTRYID)lpEntryID->Value.bin.lpb, EC_SUBMIT_MASTER | EC_SUBMIT_DOSENTMAIL);
- if (hr != hrSuccess) {
- lpSubmitFolder->DeleteMessages(&sDelete, 0, NULL, 0); //Delete message on the server
- l_exit.unlock();
- return hr;
- }
- if (m_hExitSignal.wait_for(l_exit, std::chrono::minutes(5)) == std::cv_status::timeout)
- m_bCancel = true;
- lpOnlineStore->Unadvise(ulOnlineAdviseConnection);
- if(m_bCancel){
- l_exit.unlock();
- lpOnlineECMsgStore->lpTransport->HrFinishedMessage(lpEntryID->Value.bin.cb, (LPENTRYID)lpEntryID->Value.bin.lpb, EC_SUBMIT_MASTER);
-
- sDelete.cValues = 1;
- sDelete.lpbin = &lpEntryID->Value.bin;
- lpSubmitFolder->DeleteMessages(&sDelete, 0, NULL, 0);
- // Message still in queue (other error occurred or still in queue)
- if(lpulReturnParm)
- *lpulReturnParm = 60;
- return MAPI_E_CANCEL;
- }
- l_exit.unlock();
- if(lpulMsgRef)
- *lpulMsgRef = rand_mt();
- // Update the recipient table because we sent the message OK
- hr = HrQueryAllRows(lpRecipTable, nullptr, nullptr, nullptr, 0, &~lpRecipRows);
- if (hr != erSuccess)
- return hr;
- for (ulRow = 0; ulRow < lpRecipRows->cRows; ++ulRow) {
- auto lpsPropValue = PCpropFindProp(lpRecipRows->aRow[ulRow].lpProps, lpRecipRows->aRow[ulRow].cValues, PR_ADDRTYPE);
- auto lpsResponsibility = PpropFindProp(lpRecipRows->aRow[ulRow].lpProps, lpRecipRows->aRow[ulRow].cValues, PR_RESPONSIBILITY);
- if(lpsPropValue == NULL || lpsResponsibility == NULL)
- continue;
- // Accept all SMTP-type addresses and set PR_RESPONSIBILITY set to TRUE
- if (_tcsicmp(lpsPropValue->Value.LPSZ, TRANSPORT_ADDRESS_TYPE_SMTP) == 0 ||
- _tcsicmp(lpsPropValue->Value.LPSZ, TRANSPORT_ADDRESS_TYPE_ZARAFA) == 0 ||
- _tcsicmp(lpsPropValue->Value.LPSZ, TRANSPORT_ADDRESS_TYPE_FAX) == 0)
- lpsResponsibility->Value.b = TRUE;
- }
- // Note that these modifications are *not* saved. This is correct, because they are
- // only important for other transports running on the same lpMessage.
- return lpMessage->ModifyRecipients(MODRECIP_MODIFY,
- reinterpret_cast<ADRLIST *>(lpRecipRows.get()));
- }
- #define OUT_MSG_PROPS 2
- static constexpr const SizedSPropTagArray(OUT_MSG_PROPS, sptOutMsgProps) =
- {
- OUT_MSG_PROPS,
- {
- PR_SENDER_ENTRYID,
- PR_SENT_REPRESENTING_NAME
- }
- };
- HRESULT ECXPLogon::SetOutgoingProps (LPMESSAGE lpMessage)
- {
- ecmem_ptr<SPropValue> lpspvSender;
- ULONG ulValues;
- HRESULT hr = erSuccess;
- #define NUM_OUTGOING_PROPS 12
- SPropValue spvProps[NUM_OUTGOING_PROPS] = {{0}};
- ULONG i = 0;
- FILETIME ft;
- hr = lpMessage->GetProps(sptOutMsgProps, 0, &ulValues, &~lpspvSender);
- if (FAILED(hr))
- lpspvSender = NULL; // So that we may recover and continue using default values
- assert(ulValues == 2);
- // If no sender has been stamped on the message use the identity of the transport
- if (!lpspvSender || PR_SENDER_ENTRYID != lpspvSender[0].ulPropTag)
- {
- spvProps[i].ulPropTag = PR_SENDER_NAME;
- spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_NAME].Value.lpszA;
- spvProps[i].ulPropTag = PR_SENDER_EMAIL_ADDRESS;
- spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_ADDRESS].Value.lpszA;
- spvProps[i].ulPropTag = PR_SENDER_ADDRTYPE;
- spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_ADDRTYPE].Value.lpszA;
- spvProps[i].ulPropTag = PR_SENDER_ENTRYID;
- spvProps[i++].Value.bin = m_lpXPProvider->m_lpIdentityProps[XPID_EID].Value.bin;
- spvProps[i].ulPropTag = PR_SENDER_SEARCH_KEY;
- spvProps[i++].Value.bin = m_lpXPProvider->m_lpIdentityProps[XPID_SEARCH_KEY].Value.bin;
-
- }
- // The MS Exchange mail viewer requires these properties
- if (!lpspvSender || PR_SENT_REPRESENTING_NAME != lpspvSender[1].ulPropTag)
- {
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_NAME;
- spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_NAME].Value.lpszA;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_SEARCH_KEY;
- spvProps[i++].Value.bin = m_lpXPProvider->m_lpIdentityProps[XPID_SEARCH_KEY].Value.bin;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ENTRYID;
- spvProps[i++].Value.bin = m_lpXPProvider->m_lpIdentityProps[XPID_EID].Value.bin;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ADDRTYPE;
- spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_ADDRTYPE].Value.lpszA;
- spvProps[i].ulPropTag = PR_SENT_REPRESENTING_EMAIL_ADDRESS;
- spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_ADDRESS].Value.lpszA;
-
- }
-
- GetSystemTimeAsFileTime(&ft);
- // Set the time when this transport actually transmitted the message
- spvProps[i].ulPropTag = PR_MESSAGE_DELIVERY_TIME;
- spvProps[i++].Value.ft = ft;
- spvProps[i].ulPropTag = PR_PROVIDER_SUBMIT_TIME;
- spvProps[i++].Value.ft = ft;
- assert (i <= NUM_OUTGOING_PROPS);
- hr = lpMessage->SetProps (i, spvProps, NULL);
- return hr;
- }
- HRESULT ECXPLogon::EndMessage(ULONG ulMsgRef, ULONG * lpulFlags)
- {
- return hrSuccess;
- }
- HRESULT ECXPLogon::Poll(ULONG * lpulIncoming)
- {
- *lpulIncoming = 0;
- //lpulIncoming [out] Value indicating the existence of inbound messages.
- //A nonzero value indicates that there are inbound messages.
- return hrSuccess;
- }
- HRESULT ECXPLogon::StartMessage(ULONG ulFlags, LPMESSAGE lpMessage, ULONG * lpulMsgRef)
- {
- *lpulMsgRef = 0;
- return hrSuccess;
- }
- HRESULT ECXPLogon::OpenStatusEntry(LPCIID lpInterface, ULONG ulFlags, ULONG * lpulObjType, LPMAPISTATUS * lppEntry)
- {
- return MAPI_E_CALL_FAILED;
- }
- HRESULT ECXPLogon::ValidateState(ULONG ulUIParam, ULONG ulFlags)
- {
- return hrSuccess;
- }
- HRESULT ECXPLogon::FlushQueues(ULONG ulUIParam, ULONG cbTargetTransport, LPENTRYID lpTargetTransport, ULONG ulFlags)
- {
- //The outbound message queue or queues should be flushed.
- if (ulFlags & FLUSH_UPLOAD)
- m_ulTransportStatus |= STATUS_OUTBOUND_FLUSH;
- //The inbound message queue or queues should be flushed.
- if (ulFlags & FLUSH_DOWNLOAD)
- m_ulTransportStatus |= STATUS_INBOUND_FLUSH;
- return HrUpdateTransportStatus();
- }
- ULONG ECXPLogon::OnNotify(ULONG cNotif, LPNOTIFICATION lpNotifs){
- for (unsigned int i = 0; i < cNotif; ++i)
- if(lpNotifs[i].ulEventType == fnevObjectDeleted) {
- scoped_lock lock(m_hExitMutex);
- m_hExitSignal.notify_one();
- }
- return S_OK;
- }
- static const TCHAR *GetStatusString(ULONG ulFlags)
- {
- const TCHAR *lpszStatus = NULL;
- if (ulFlags & STATUS_INBOUND_ACTIVE)
- lpszStatus = _T("Uploading messages...");
- else if (ulFlags & STATUS_OUTBOUND_ACTIVE)
- lpszStatus = _T("Downloading messages...");
- else if (ulFlags & STATUS_INBOUND_FLUSH)
- lpszStatus = _T("Inbound Flushing...");
- else if (ulFlags & STATUS_OUTBOUND_FLUSH)
- lpszStatus = _T("Outbound Flushing...");
- else if ((ulFlags & STATUS_AVAILABLE) &&
- ((ulFlags & STATUS_INBOUND_ENABLED) ||
- (ulFlags & STATUS_OUTBOUND_ENABLED)))
- lpszStatus = _T("On-Line");
- else if (ulFlags & STATUS_AVAILABLE)
- lpszStatus = _T("Available");
- else
- lpszStatus = _T("Off-Line");
- return lpszStatus;
- }
- HRESULT ECXPLogon::HrUpdateTransportStatus()
- {
- HRESULT hResult;
- ULONG cProps = 2;
- SPropValue rgProps[2];
- const TCHAR *lpszStatus = NULL;
-
- // Store the new Transport Provider Status Code.
- rgProps[0].ulPropTag = PR_STATUS_CODE;
- // Set the STATUS_OFFLINE flag if the store is offline. This causes the following:
- // Outlook 2000: Disables 'send all data at outlook exit'
- // Outlook XP:
- //
- // Outlook 2007: No effect
- rgProps[0].Value.ul = m_ulTransportStatus | (m_bOffline ? STATUS_OFFLINE : 0);
- // Set the Status String according to ulStatus
- lpszStatus = GetStatusString(m_ulTransportStatus);
- if (!lpszStatus)
- {
- rgProps[1].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_STATUS_STRING));
- rgProps[1].Value.err = MAPI_E_NOT_FOUND;
- }
- else
- {
- rgProps[1].ulPropTag = PR_STATUS_STRING;
- rgProps[1].Value.lpszA = (LPSTR)lpszStatus; // @todo: Check if this 'hack' actually works for wide character strings.
- }
-
- // OK. Notify the Spooler. It will tell MAPI.
- hResult = m_lpMAPISup->ModifyStatusRow(cProps, rgProps, STATUSROW_UPDATE);
- return hResult;
- }
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, QueryInterface, (REFIID, refiid), (void **, lppInterface))
- DEF_ULONGMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, AddRef, (void))
- DEF_ULONGMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, Release, (void))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, AddressTypes, (ULONG *, lpulFlags), (ULONG *, lpcAdrType), (LPTSTR **, lpppszAdrTypeArray), (ULONG *, lpcMAPIUID), (LPMAPIUID **, lpppUIDArray))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, RegisterOptions, (ULONG *, lpulFlags), (ULONG *, lpcOptions), (LPOPTIONDATA *, lppOptions))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, TransportNotify, (ULONG *, lpulFlags), (LPVOID *, lppvData))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, Idle, (ULONG, ulFlags))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, TransportLogoff, (ULONG, ulFlags))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, SubmitMessage, (ULONG, ulFlags), (LPMESSAGE, lpMessage), (ULONG *, lpulMsgRef), (ULONG *, lpulReturnParm))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, EndMessage, (ULONG, ulMsgRef), (ULONG *, lpulFlags))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, Poll, (ULONG *, lpulIncoming))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, StartMessage, (ULONG, ulFlags), (LPMESSAGE, lpMessage), (ULONG *, lpulMsgRef))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, OpenStatusEntry, (LPCIID, lpInterface), (ULONG, ulFlags), (ULONG *, lpulObjType), (LPMAPISTATUS *, lppEntry))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, ValidateState, (ULONG, ulUIParam), (ULONG, ulFlags))
- DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, FlushQueues, (ULONG, ulUIParam), (ULONG, cbTargetTransport), (LPENTRYID, lpTargetTransport), (ULONG, ulFlags))
- DEF_ULONGMETHOD1(TRACE_MAPI, ECXPLogon, MAPIAdviseSink, OnNotify, (ULONG, cNotif), (LPNOTIFICATION, lpNotifs))
- DEF_HRMETHOD_NOSUPPORT(TRACE_MAPI, ECXPLogon, MAPIAdviseSink, QueryInterface, (REFIID, refiid), (void **, lppInterface))
- ULONG __stdcall ECXPLogon::xMAPIAdviseSink::AddRef(){
- return 1;
- }
- ULONG __stdcall ECXPLogon::xMAPIAdviseSink::Release(){
- return 1;
- }
|