ECXPLogon.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  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. #include <kopano/platform.h>
  17. #include <chrono>
  18. #include <condition_variable>
  19. #include <new>
  20. #include <kopano/lockhelper.hpp>
  21. #include <kopano/memory.hpp>
  22. #include <mapi.h>
  23. #include <mapispi.h>
  24. #include <mapiutil.h>
  25. #include <kopano/mapiguidext.h>
  26. #include <kopano/ECGuid.h>
  27. #include <kopano/ECInterfaceDefs.h>
  28. #include <kopano/mapiext.h>
  29. #include <edkmdb.h>
  30. #include <edkguid.h>
  31. #include "kcore.hpp"
  32. #include "ECXPLogon.h"
  33. #include "ECXPProvider.h"
  34. #include "WSTransport.h"
  35. #include "Mem.h"
  36. #include "ClientUtil.h"
  37. #include <kopano/CommonUtil.h>
  38. #include "ECMsgStore.h"
  39. #include "ECMessage.h"
  40. #include <kopano/kcodes.h>
  41. #include <kopano/ECDebug.h>
  42. #include <kopano/ECRestriction.h>
  43. #include <kopano/mapi_ptr.h>
  44. using namespace KCHL;
  45. static HRESULT HrGetECMsgStore(IMAPIProp *lpProp, ECMsgStore **lppECMsgStore)
  46. {
  47. HRESULT hr;
  48. LPSPropValue lpPropVal = NULL;
  49. ECMAPIProp *lpECMAPIProp = NULL;
  50. hr = HrGetOneProp(lpProp, PR_EC_OBJECT, &lpPropVal);
  51. if(hr != hrSuccess)
  52. return hr;
  53. lpECMAPIProp = (ECMAPIProp *)lpPropVal->Value.lpszA;
  54. *lppECMsgStore = lpECMAPIProp->GetMsgStore();
  55. (*lppECMsgStore)->AddRef();
  56. return hrSuccess;
  57. }
  58. ECXPLogon::ECXPLogon(const std::string &strProfileName, BOOL bOffline,
  59. ECXPProvider *lpXPProvider, LPMAPISUP lpMAPISup) :
  60. ECUnknown("IXPLogon"), m_lpMAPISup(lpMAPISup),
  61. m_lpXPProvider(lpXPProvider), m_bOffline(bOffline)
  62. {
  63. m_lpMAPISup->AddRef();
  64. }
  65. ECXPLogon::~ECXPLogon()
  66. {
  67. if(m_lppszAdrTypeArray)
  68. ECFreeBuffer(m_lppszAdrTypeArray);
  69. if(m_lpMAPISup)
  70. m_lpMAPISup->Release();
  71. }
  72. HRESULT ECXPLogon::Create(const std::string &strProfileName, BOOL bOffline, ECXPProvider *lpXPProvider, LPMAPISUP lpMAPISup, ECXPLogon **lppECXPLogon)
  73. {
  74. HRESULT hr = hrSuccess;
  75. auto lpXPLogon = new(std::nothrow) ECXPLogon(strProfileName, bOffline, lpXPProvider, lpMAPISup);
  76. if (lpXPLogon == nullptr)
  77. return MAPI_E_NOT_ENOUGH_MEMORY;
  78. hr = lpXPLogon->QueryInterface(IID_ECXPLogon, (void **)lppECXPLogon);
  79. if(hr != hrSuccess)
  80. delete lpXPLogon;
  81. return hr;
  82. }
  83. HRESULT ECXPLogon::QueryInterface(REFIID refiid, void **lppInterface)
  84. {
  85. REGISTER_INTERFACE2(ECXPLogon, this);
  86. REGISTER_INTERFACE2(IXPLogon, &this->m_xXPLogon);
  87. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  88. }
  89. HRESULT ECXPLogon::AddressTypes(ULONG * lpulFlags, ULONG * lpcAdrType, LPTSTR ** lpppszAdrTypeArray, ULONG * lpcMAPIUID, LPMAPIUID ** lpppUIDArray)
  90. {
  91. HRESULT hr;
  92. if(m_lppszAdrTypeArray == NULL) {
  93. hr = ECAllocateBuffer(sizeof(TCHAR *) * 3, (LPVOID *)&m_lppszAdrTypeArray);
  94. if(hr != hrSuccess)
  95. return hr;
  96. hr = ECAllocateMore((_tcslen(TRANSPORT_ADDRESS_TYPE_SMTP)+1) * sizeof(TCHAR), m_lppszAdrTypeArray, (LPVOID *)&m_lppszAdrTypeArray[0]);
  97. if(hr != hrSuccess)
  98. return hr;
  99. _tcscpy(m_lppszAdrTypeArray[0], TRANSPORT_ADDRESS_TYPE_SMTP);
  100. hr = ECAllocateMore((_tcslen(TRANSPORT_ADDRESS_TYPE_ZARAFA)+1) * sizeof(TCHAR), m_lppszAdrTypeArray, (LPVOID *)&m_lppszAdrTypeArray[1]);
  101. if(hr != hrSuccess)
  102. return hr;
  103. _tcscpy(m_lppszAdrTypeArray[1], TRANSPORT_ADDRESS_TYPE_ZARAFA);
  104. hr = ECAllocateMore((_tcslen(TRANSPORT_ADDRESS_TYPE_FAX)+1) * sizeof(TCHAR), m_lppszAdrTypeArray, (LPVOID *)&m_lppszAdrTypeArray[2]);
  105. if(hr != hrSuccess)
  106. return hr;
  107. _tcscpy(m_lppszAdrTypeArray[2], TRANSPORT_ADDRESS_TYPE_FAX);
  108. }
  109. *lpulFlags = fMapiUnicode;
  110. *lpcMAPIUID = 0;
  111. *lpppUIDArray = NULL; // We could specify the Kopano addressbook's UID here to stop the MAPI spooler doing expansions on them (IE EntryID -> Email address)
  112. *lpcAdrType = 3;
  113. *lpppszAdrTypeArray = m_lppszAdrTypeArray;
  114. return hrSuccess;
  115. }
  116. HRESULT ECXPLogon::RegisterOptions(ULONG * lpulFlags, ULONG * lpcOptions, LPOPTIONDATA * lppOptions)
  117. {
  118. *lpulFlags = 0;//fMapiUnicode ?
  119. *lpcOptions = 0;
  120. *lppOptions = NULL;
  121. return hrSuccess;
  122. }
  123. HRESULT ECXPLogon::TransportNotify(ULONG * lpulFlags, LPVOID * lppvData)
  124. {
  125. if(*lpulFlags & NOTIFY_ABORT_DEFERRED)
  126. //FIXME: m_ulTransportStatus
  127. // doe iets met lppvData
  128. // Remove item, out the spooler list (outgoing queue ???)
  129. /* nothing */;
  130. if (*lpulFlags & NOTIFY_BEGIN_INBOUND)
  131. m_ulTransportStatus |= STATUS_INBOUND_ENABLED;
  132. if (*lpulFlags & NOTIFY_BEGIN_INBOUND_FLUSH)
  133. m_ulTransportStatus |= STATUS_INBOUND_FLUSH;
  134. if (*lpulFlags & NOTIFY_BEGIN_OUTBOUND)
  135. m_ulTransportStatus |= STATUS_OUTBOUND_ENABLED;
  136. if (*lpulFlags & NOTIFY_BEGIN_OUTBOUND_FLUSH)
  137. m_ulTransportStatus |= STATUS_OUTBOUND_FLUSH;
  138. if (*lpulFlags & NOTIFY_CANCEL_MESSAGE) {
  139. scoped_lock lock(m_hExitMutex);
  140. m_bCancel = true;
  141. m_hExitSignal.notify_one();
  142. }
  143. if (*lpulFlags & NOTIFY_END_INBOUND)
  144. m_ulTransportStatus &= ~STATUS_INBOUND_ENABLED;
  145. if (*lpulFlags & NOTIFY_END_INBOUND_FLUSH)
  146. m_ulTransportStatus &= ~STATUS_INBOUND_FLUSH;
  147. if (*lpulFlags & NOTIFY_END_OUTBOUND)
  148. m_ulTransportStatus &= ~STATUS_OUTBOUND_ENABLED;
  149. if (*lpulFlags & NOTIFY_END_OUTBOUND_FLUSH)
  150. m_ulTransportStatus &= ~STATUS_OUTBOUND_FLUSH;
  151. return HrUpdateTransportStatus();
  152. }
  153. HRESULT ECXPLogon::Idle(ULONG ulFlags)
  154. {
  155. // The MAPI spooler periodically calls the IXPLogon::Idle method during times when the system is idle
  156. // We do nothing ..
  157. return hrSuccess;
  158. }
  159. HRESULT ECXPLogon::TransportLogoff(ULONG ulFlags)
  160. {
  161. return hrSuccess;
  162. }
  163. /**
  164. * Clear not deleted submit message
  165. *
  166. * The messages older than 10 days will be deleted. This function delete
  167. * only the first 50 messages. Normally it should be zero!
  168. *
  169. * @param[in] lpFolder Folder with submitted messages
  170. *
  171. * @return MAPI error code
  172. */
  173. HRESULT ECXPLogon::ClearOldSubmittedMessages(LPMAPIFOLDER lpFolder)
  174. {
  175. HRESULT hr = hrSuccess;
  176. static constexpr const SizedSPropTagArray(1, sptDelete) = {1, {PR_ENTRYID}};
  177. MAPITablePtr ptrContentsTable;
  178. memory_ptr<ENTRYLIST> lpDeleteItemEntryList;
  179. SPropValue sPropDelAfterSubmit = {0};
  180. SPropValue sPropxDaysBefore = {0};
  181. SRowSetPtr ptrRows;
  182. time_t tNow = 0;
  183. hr = lpFolder->GetContentsTable(0, &~ptrContentsTable);
  184. if (hr != hrSuccess)
  185. return hr;
  186. hr = ptrContentsTable->SetColumns(sptDelete, MAPI_DEFERRED_ERRORS);
  187. if(hr != hrSuccess)
  188. return hr;
  189. // build restriction where we search for messages which must deleted after the submit
  190. sPropDelAfterSubmit.ulPropTag = PR_DELETE_AFTER_SUBMIT;
  191. sPropDelAfterSubmit.Value.b = TRUE;
  192. sPropxDaysBefore.ulPropTag = PR_CREATION_TIME;
  193. time(&tNow);
  194. UnixTimeToFileTime(tNow - (10 * 24 * 60 * 60), &sPropxDaysBefore.Value.ft);
  195. hr = ECAndRestriction(
  196. ECAndRestriction(
  197. ECExistRestriction(PR_DELETE_AFTER_SUBMIT) +
  198. ECPropertyRestriction(RELOP_EQ, PR_DELETE_AFTER_SUBMIT, &sPropDelAfterSubmit, ECRestriction::Cheap)
  199. ) +
  200. ECPropertyRestriction(RELOP_LE, PR_CREATION_TIME, &sPropxDaysBefore, ECRestriction::Cheap)
  201. ).RestrictTable(ptrContentsTable, MAPI_DEFERRED_ERRORS);
  202. if (hr != hrSuccess)
  203. return hr;
  204. hr = MAPIAllocateBuffer(sizeof(ENTRYLIST), &~lpDeleteItemEntryList);
  205. if (hr != hrSuccess)
  206. return hr;
  207. hr = MAPIAllocateMore(50 * sizeof(SBinary), lpDeleteItemEntryList, (void**)&lpDeleteItemEntryList->lpbin);
  208. if (hr != hrSuccess)
  209. return hr;
  210. lpDeleteItemEntryList->cValues = 0;
  211. // Get only the first 50 items
  212. hr = ptrContentsTable->QueryRows(50, 0, &ptrRows);
  213. if (hr != hrSuccess)
  214. return hr;
  215. for (unsigned int i = 0; i < ptrRows.size(); ++i)
  216. if(ptrRows[i].lpProps[0].ulPropTag == PR_ENTRYID)
  217. lpDeleteItemEntryList->lpbin[lpDeleteItemEntryList->cValues++] = ptrRows[i].lpProps[0].Value.bin;
  218. if(lpDeleteItemEntryList->cValues > 0)
  219. hr = lpFolder->DeleteMessages(lpDeleteItemEntryList, 0, NULL, 0); //Delete message on the server
  220. return hr;
  221. }
  222. HRESULT ECXPLogon::SubmitMessage(ULONG ulFlags, LPMESSAGE lpMessage, ULONG * lpulMsgRef, ULONG * lpulReturnParm)
  223. {
  224. HRESULT hr = hrSuccess;
  225. object_ptr<IMAPITable> lpRecipTable;
  226. rowset_ptr lpRecipRows;
  227. ULONG ulRow = 0;
  228. ULONG ulRowCount = 0;
  229. memory_ptr<SPropValue> lpEntryID, lpECObject;
  230. object_ptr<IMsgStore> lpOnlineStore;
  231. object_ptr<ECMsgStore> lpOnlineECMsgStore, lpECMsgStore;
  232. ULONG ulObjType;
  233. object_ptr<IMAPIFolder> lpSubmitFolder;
  234. object_ptr<IMessage> lpSubmitMessage;
  235. SPropValue sDeleteAfterSubmitProp;
  236. ULONG ulOnlineAdviseConnection = 0;
  237. ENTRYLIST sDelete;
  238. object_ptr<IMsgStore> lpMsgStore;
  239. ULONG ulType = 0;
  240. static constexpr const SizedSPropTagArray(6, sptExcludeProps) =
  241. {6, {PR_SENTMAIL_ENTRYID, PR_SOURCE_KEY, PR_CHANGE_KEY,
  242. PR_PREDECESSOR_CHANGE_LIST, PR_ENTRYID, PR_SUBMIT_FLAGS}};
  243. // Un-cancel
  244. ulock_normal l_exit(m_hExitMutex);
  245. m_bCancel = false;
  246. l_exit.unlock();
  247. // Save some outgoing properties for the server
  248. hr = SetOutgoingProps(lpMessage);
  249. if (hr != erSuccess)
  250. return hr;
  251. hr = lpMessage->SaveChanges(KEEP_OPEN_READWRITE);
  252. if (hr != erSuccess)
  253. return hr;
  254. // Get the recipient table from the message
  255. hr = lpMessage->GetRecipientTable(fMapiUnicode, &~lpRecipTable);
  256. if (hr != hrSuccess)
  257. return hr;
  258. // The spooler marks all the message recipients this transport has to
  259. // handle with PR_RESPONSIBILITY set to FALSE
  260. SPropValue spvRecipUnsent;
  261. spvRecipUnsent.ulPropTag = PR_RESPONSIBILITY;
  262. spvRecipUnsent.Value.b = FALSE;
  263. SRestriction srRecipientUnhandled;
  264. srRecipientUnhandled.rt = RES_PROPERTY;
  265. srRecipientUnhandled.res.resProperty.relop = RELOP_EQ;
  266. srRecipientUnhandled.res.resProperty.ulPropTag = PR_RESPONSIBILITY;
  267. srRecipientUnhandled.res.resProperty.lpProp = &spvRecipUnsent;
  268. hr = lpRecipTable->Restrict(&srRecipientUnhandled, 0);
  269. if (hr != hrSuccess)
  270. return hr;
  271. hr = lpRecipTable->GetRowCount(0, &ulRowCount);
  272. if (hr != hrSuccess)
  273. return hr;
  274. if (ulRowCount == 0)
  275. return MAPI_E_NOT_ME;
  276. if (HrGetECMsgStore(lpMessage, &~lpECMsgStore) != hrSuccess) {
  277. 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);
  278. if (hr != hrSuccess)
  279. return hr;
  280. hr = HrGetOneProp(lpMsgStore, PR_EC_OBJECT, &~lpECObject);
  281. if (hr != hrSuccess)
  282. return hr;
  283. lpECMsgStore.reset(reinterpret_cast<ECMsgStore *>(lpECObject->Value.lpszA));
  284. }
  285. hr = lpECMsgStore->QueryInterface(IID_ECMsgStoreOnline, &~lpOnlineStore);
  286. if (hr != hrSuccess)
  287. return hr;
  288. hr = HrGetECMsgStore(lpOnlineStore, &~lpOnlineECMsgStore);
  289. if (hr != hrSuccess)
  290. return hr;
  291. hr = lpOnlineStore->OpenEntry(0, nullptr, &IID_IMAPIFolder, MAPI_MODIFY, &ulObjType, &~lpSubmitFolder);
  292. if (hr != hrSuccess)
  293. return hr;
  294. hr = ClearOldSubmittedMessages(lpSubmitFolder);
  295. if (FAILED(hr))
  296. return hr;
  297. hr = lpSubmitFolder->CreateMessage(&IID_IMessage, 0, &~lpSubmitMessage);
  298. if (hr != hrSuccess)
  299. return hr;
  300. hr = lpMessage->CopyTo(0, NULL, sptExcludeProps, 0, NULL,
  301. &IID_IMessage, lpSubmitMessage, 0, NULL);
  302. if (hr != hrSuccess)
  303. return hr;
  304. sDeleteAfterSubmitProp.ulPropTag = PR_DELETE_AFTER_SUBMIT;
  305. sDeleteAfterSubmitProp.Value.b = true;
  306. hr = HrSetOneProp(lpSubmitMessage, &sDeleteAfterSubmitProp);
  307. if (hr != hrSuccess)
  308. return hr;
  309. hr = lpSubmitMessage->SaveChanges(KEEP_OPEN_READWRITE);
  310. if (hr != hrSuccess)
  311. return hr;
  312. hr = HrGetOneProp(lpSubmitMessage, PR_ENTRYID, &~lpEntryID);
  313. if (hr != hrSuccess)
  314. return hr;
  315. sDelete.cValues = 1;
  316. sDelete.lpbin = &lpEntryID->Value.bin;
  317. // Add the message to the master outgoing queue on the server
  318. l_exit.lock();
  319. hr = lpOnlineStore->Advise(lpEntryID->Value.bin.cb, (LPENTRYID)lpEntryID->Value.bin.lpb, fnevObjectDeleted, &this->m_xMAPIAdviseSink, &ulOnlineAdviseConnection);
  320. if (hr != hrSuccess) {
  321. lpSubmitFolder->DeleteMessages(&sDelete, 0, NULL, 0); //Delete message on the server
  322. l_exit.unlock();
  323. return hr;
  324. }
  325. hr = lpOnlineECMsgStore->lpTransport->HrSubmitMessage(lpEntryID->Value.bin.cb, (LPENTRYID)lpEntryID->Value.bin.lpb, EC_SUBMIT_MASTER | EC_SUBMIT_DOSENTMAIL);
  326. if (hr != hrSuccess) {
  327. lpSubmitFolder->DeleteMessages(&sDelete, 0, NULL, 0); //Delete message on the server
  328. l_exit.unlock();
  329. return hr;
  330. }
  331. if (m_hExitSignal.wait_for(l_exit, std::chrono::minutes(5)) == std::cv_status::timeout)
  332. m_bCancel = true;
  333. lpOnlineStore->Unadvise(ulOnlineAdviseConnection);
  334. if(m_bCancel){
  335. l_exit.unlock();
  336. lpOnlineECMsgStore->lpTransport->HrFinishedMessage(lpEntryID->Value.bin.cb, (LPENTRYID)lpEntryID->Value.bin.lpb, EC_SUBMIT_MASTER);
  337. sDelete.cValues = 1;
  338. sDelete.lpbin = &lpEntryID->Value.bin;
  339. lpSubmitFolder->DeleteMessages(&sDelete, 0, NULL, 0);
  340. // Message still in queue (other error occurred or still in queue)
  341. if(lpulReturnParm)
  342. *lpulReturnParm = 60;
  343. return MAPI_E_CANCEL;
  344. }
  345. l_exit.unlock();
  346. if(lpulMsgRef)
  347. *lpulMsgRef = rand_mt();
  348. // Update the recipient table because we sent the message OK
  349. hr = HrQueryAllRows(lpRecipTable, nullptr, nullptr, nullptr, 0, &~lpRecipRows);
  350. if (hr != erSuccess)
  351. return hr;
  352. for (ulRow = 0; ulRow < lpRecipRows->cRows; ++ulRow) {
  353. auto lpsPropValue = PCpropFindProp(lpRecipRows->aRow[ulRow].lpProps, lpRecipRows->aRow[ulRow].cValues, PR_ADDRTYPE);
  354. auto lpsResponsibility = PpropFindProp(lpRecipRows->aRow[ulRow].lpProps, lpRecipRows->aRow[ulRow].cValues, PR_RESPONSIBILITY);
  355. if(lpsPropValue == NULL || lpsResponsibility == NULL)
  356. continue;
  357. // Accept all SMTP-type addresses and set PR_RESPONSIBILITY set to TRUE
  358. if (_tcsicmp(lpsPropValue->Value.LPSZ, TRANSPORT_ADDRESS_TYPE_SMTP) == 0 ||
  359. _tcsicmp(lpsPropValue->Value.LPSZ, TRANSPORT_ADDRESS_TYPE_ZARAFA) == 0 ||
  360. _tcsicmp(lpsPropValue->Value.LPSZ, TRANSPORT_ADDRESS_TYPE_FAX) == 0)
  361. lpsResponsibility->Value.b = TRUE;
  362. }
  363. // Note that these modifications are *not* saved. This is correct, because they are
  364. // only important for other transports running on the same lpMessage.
  365. return lpMessage->ModifyRecipients(MODRECIP_MODIFY,
  366. reinterpret_cast<ADRLIST *>(lpRecipRows.get()));
  367. }
  368. #define OUT_MSG_PROPS 2
  369. static constexpr const SizedSPropTagArray(OUT_MSG_PROPS, sptOutMsgProps) =
  370. {
  371. OUT_MSG_PROPS,
  372. {
  373. PR_SENDER_ENTRYID,
  374. PR_SENT_REPRESENTING_NAME
  375. }
  376. };
  377. HRESULT ECXPLogon::SetOutgoingProps (LPMESSAGE lpMessage)
  378. {
  379. ecmem_ptr<SPropValue> lpspvSender;
  380. ULONG ulValues;
  381. HRESULT hr = erSuccess;
  382. #define NUM_OUTGOING_PROPS 12
  383. SPropValue spvProps[NUM_OUTGOING_PROPS] = {{0}};
  384. ULONG i = 0;
  385. FILETIME ft;
  386. hr = lpMessage->GetProps(sptOutMsgProps, 0, &ulValues, &~lpspvSender);
  387. if (FAILED(hr))
  388. lpspvSender = NULL; // So that we may recover and continue using default values
  389. assert(ulValues == 2);
  390. // If no sender has been stamped on the message use the identity of the transport
  391. if (!lpspvSender || PR_SENDER_ENTRYID != lpspvSender[0].ulPropTag)
  392. {
  393. spvProps[i].ulPropTag = PR_SENDER_NAME;
  394. spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_NAME].Value.lpszA;
  395. spvProps[i].ulPropTag = PR_SENDER_EMAIL_ADDRESS;
  396. spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_ADDRESS].Value.lpszA;
  397. spvProps[i].ulPropTag = PR_SENDER_ADDRTYPE;
  398. spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_ADDRTYPE].Value.lpszA;
  399. spvProps[i].ulPropTag = PR_SENDER_ENTRYID;
  400. spvProps[i++].Value.bin = m_lpXPProvider->m_lpIdentityProps[XPID_EID].Value.bin;
  401. spvProps[i].ulPropTag = PR_SENDER_SEARCH_KEY;
  402. spvProps[i++].Value.bin = m_lpXPProvider->m_lpIdentityProps[XPID_SEARCH_KEY].Value.bin;
  403. }
  404. // The MS Exchange mail viewer requires these properties
  405. if (!lpspvSender || PR_SENT_REPRESENTING_NAME != lpspvSender[1].ulPropTag)
  406. {
  407. spvProps[i].ulPropTag = PR_SENT_REPRESENTING_NAME;
  408. spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_NAME].Value.lpszA;
  409. spvProps[i].ulPropTag = PR_SENT_REPRESENTING_SEARCH_KEY;
  410. spvProps[i++].Value.bin = m_lpXPProvider->m_lpIdentityProps[XPID_SEARCH_KEY].Value.bin;
  411. spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ENTRYID;
  412. spvProps[i++].Value.bin = m_lpXPProvider->m_lpIdentityProps[XPID_EID].Value.bin;
  413. spvProps[i].ulPropTag = PR_SENT_REPRESENTING_ADDRTYPE;
  414. spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_ADDRTYPE].Value.lpszA;
  415. spvProps[i].ulPropTag = PR_SENT_REPRESENTING_EMAIL_ADDRESS;
  416. spvProps[i++].Value.lpszA = m_lpXPProvider->m_lpIdentityProps[XPID_ADDRESS].Value.lpszA;
  417. }
  418. GetSystemTimeAsFileTime(&ft);
  419. // Set the time when this transport actually transmitted the message
  420. spvProps[i].ulPropTag = PR_MESSAGE_DELIVERY_TIME;
  421. spvProps[i++].Value.ft = ft;
  422. spvProps[i].ulPropTag = PR_PROVIDER_SUBMIT_TIME;
  423. spvProps[i++].Value.ft = ft;
  424. assert (i <= NUM_OUTGOING_PROPS);
  425. hr = lpMessage->SetProps (i, spvProps, NULL);
  426. return hr;
  427. }
  428. HRESULT ECXPLogon::EndMessage(ULONG ulMsgRef, ULONG * lpulFlags)
  429. {
  430. return hrSuccess;
  431. }
  432. HRESULT ECXPLogon::Poll(ULONG * lpulIncoming)
  433. {
  434. *lpulIncoming = 0;
  435. //lpulIncoming [out] Value indicating the existence of inbound messages.
  436. //A nonzero value indicates that there are inbound messages.
  437. return hrSuccess;
  438. }
  439. HRESULT ECXPLogon::StartMessage(ULONG ulFlags, LPMESSAGE lpMessage, ULONG * lpulMsgRef)
  440. {
  441. *lpulMsgRef = 0;
  442. return hrSuccess;
  443. }
  444. HRESULT ECXPLogon::OpenStatusEntry(LPCIID lpInterface, ULONG ulFlags, ULONG * lpulObjType, LPMAPISTATUS * lppEntry)
  445. {
  446. return MAPI_E_CALL_FAILED;
  447. }
  448. HRESULT ECXPLogon::ValidateState(ULONG ulUIParam, ULONG ulFlags)
  449. {
  450. return hrSuccess;
  451. }
  452. HRESULT ECXPLogon::FlushQueues(ULONG ulUIParam, ULONG cbTargetTransport, LPENTRYID lpTargetTransport, ULONG ulFlags)
  453. {
  454. //The outbound message queue or queues should be flushed.
  455. if (ulFlags & FLUSH_UPLOAD)
  456. m_ulTransportStatus |= STATUS_OUTBOUND_FLUSH;
  457. //The inbound message queue or queues should be flushed.
  458. if (ulFlags & FLUSH_DOWNLOAD)
  459. m_ulTransportStatus |= STATUS_INBOUND_FLUSH;
  460. return HrUpdateTransportStatus();
  461. }
  462. ULONG ECXPLogon::OnNotify(ULONG cNotif, LPNOTIFICATION lpNotifs){
  463. for (unsigned int i = 0; i < cNotif; ++i)
  464. if(lpNotifs[i].ulEventType == fnevObjectDeleted) {
  465. scoped_lock lock(m_hExitMutex);
  466. m_hExitSignal.notify_one();
  467. }
  468. return S_OK;
  469. }
  470. static const TCHAR *GetStatusString(ULONG ulFlags)
  471. {
  472. const TCHAR *lpszStatus = NULL;
  473. if (ulFlags & STATUS_INBOUND_ACTIVE)
  474. lpszStatus = _T("Uploading messages...");
  475. else if (ulFlags & STATUS_OUTBOUND_ACTIVE)
  476. lpszStatus = _T("Downloading messages...");
  477. else if (ulFlags & STATUS_INBOUND_FLUSH)
  478. lpszStatus = _T("Inbound Flushing...");
  479. else if (ulFlags & STATUS_OUTBOUND_FLUSH)
  480. lpszStatus = _T("Outbound Flushing...");
  481. else if ((ulFlags & STATUS_AVAILABLE) &&
  482. ((ulFlags & STATUS_INBOUND_ENABLED) ||
  483. (ulFlags & STATUS_OUTBOUND_ENABLED)))
  484. lpszStatus = _T("On-Line");
  485. else if (ulFlags & STATUS_AVAILABLE)
  486. lpszStatus = _T("Available");
  487. else
  488. lpszStatus = _T("Off-Line");
  489. return lpszStatus;
  490. }
  491. HRESULT ECXPLogon::HrUpdateTransportStatus()
  492. {
  493. HRESULT hResult;
  494. ULONG cProps = 2;
  495. SPropValue rgProps[2];
  496. const TCHAR *lpszStatus = NULL;
  497. // Store the new Transport Provider Status Code.
  498. rgProps[0].ulPropTag = PR_STATUS_CODE;
  499. // Set the STATUS_OFFLINE flag if the store is offline. This causes the following:
  500. // Outlook 2000: Disables 'send all data at outlook exit'
  501. // Outlook XP:
  502. //
  503. // Outlook 2007: No effect
  504. rgProps[0].Value.ul = m_ulTransportStatus | (m_bOffline ? STATUS_OFFLINE : 0);
  505. // Set the Status String according to ulStatus
  506. lpszStatus = GetStatusString(m_ulTransportStatus);
  507. if (!lpszStatus)
  508. {
  509. rgProps[1].ulPropTag = PROP_TAG(PT_ERROR, PROP_ID(PR_STATUS_STRING));
  510. rgProps[1].Value.err = MAPI_E_NOT_FOUND;
  511. }
  512. else
  513. {
  514. rgProps[1].ulPropTag = PR_STATUS_STRING;
  515. rgProps[1].Value.lpszA = (LPSTR)lpszStatus; // @todo: Check if this 'hack' actually works for wide character strings.
  516. }
  517. // OK. Notify the Spooler. It will tell MAPI.
  518. hResult = m_lpMAPISup->ModifyStatusRow(cProps, rgProps, STATUSROW_UPDATE);
  519. return hResult;
  520. }
  521. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  522. DEF_ULONGMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, AddRef, (void))
  523. DEF_ULONGMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, Release, (void))
  524. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, AddressTypes, (ULONG *, lpulFlags), (ULONG *, lpcAdrType), (LPTSTR **, lpppszAdrTypeArray), (ULONG *, lpcMAPIUID), (LPMAPIUID **, lpppUIDArray))
  525. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, RegisterOptions, (ULONG *, lpulFlags), (ULONG *, lpcOptions), (LPOPTIONDATA *, lppOptions))
  526. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, TransportNotify, (ULONG *, lpulFlags), (LPVOID *, lppvData))
  527. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, Idle, (ULONG, ulFlags))
  528. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, TransportLogoff, (ULONG, ulFlags))
  529. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, SubmitMessage, (ULONG, ulFlags), (LPMESSAGE, lpMessage), (ULONG *, lpulMsgRef), (ULONG *, lpulReturnParm))
  530. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, EndMessage, (ULONG, ulMsgRef), (ULONG *, lpulFlags))
  531. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, Poll, (ULONG *, lpulIncoming))
  532. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, StartMessage, (ULONG, ulFlags), (LPMESSAGE, lpMessage), (ULONG *, lpulMsgRef))
  533. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, OpenStatusEntry, (LPCIID, lpInterface), (ULONG, ulFlags), (ULONG *, lpulObjType), (LPMAPISTATUS *, lppEntry))
  534. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, ValidateState, (ULONG, ulUIParam), (ULONG, ulFlags))
  535. DEF_HRMETHOD1(TRACE_MAPI, ECXPLogon, XPLogon, FlushQueues, (ULONG, ulUIParam), (ULONG, cbTargetTransport), (LPENTRYID, lpTargetTransport), (ULONG, ulFlags))
  536. DEF_ULONGMETHOD1(TRACE_MAPI, ECXPLogon, MAPIAdviseSink, OnNotify, (ULONG, cNotif), (LPNOTIFICATION, lpNotifs))
  537. DEF_HRMETHOD_NOSUPPORT(TRACE_MAPI, ECXPLogon, MAPIAdviseSink, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  538. ULONG __stdcall ECXPLogon::xMAPIAdviseSink::AddRef(){
  539. return 1;
  540. }
  541. ULONG __stdcall ECXPLogon::xMAPIAdviseSink::Release(){
  542. return 1;
  543. }