ECMSProviderSwitch.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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/ECGetText.h>
  20. #include <kopano/ECInterfaceDefs.h>
  21. #include <kopano/memory.hpp>
  22. #include <mapi.h>
  23. #include <mapiutil.h>
  24. #include <mapispi.h>
  25. #include "ECMSProviderSwitch.h"
  26. #include "ECMSProvider.h"
  27. #include <kopano/ECGuid.h>
  28. #include <kopano/Trace.h>
  29. #include <kopano/ECDebug.h>
  30. #include <edkguid.h>
  31. #include "EntryPoint.h"
  32. #include "DLLGlobal.h"
  33. #include <edkmdb.h>
  34. #include <kopano/mapiext.h>
  35. #include "ClientUtil.h"
  36. #include "ECMsgStore.h"
  37. #include <kopano/stringutil.h>
  38. #include <csignal>
  39. #include "ProviderUtil.h"
  40. #include <kopano/charset/convstring.h>
  41. #ifdef swprintf
  42. #undef swprintf
  43. #endif
  44. using namespace KCHL;
  45. ECMSProviderSwitch::ECMSProviderSwitch(ULONG ulFlags) : ECUnknown("ECMSProviderSwitch")
  46. {
  47. m_ulFlags = ulFlags;
  48. }
  49. HRESULT ECMSProviderSwitch::Create(ULONG ulFlags, ECMSProviderSwitch **lppMSProvider)
  50. {
  51. auto lpMSProvider = new(std::nothrow) ECMSProviderSwitch(ulFlags);
  52. if (lpMSProvider == nullptr)
  53. return MAPI_E_NOT_ENOUGH_MEMORY;
  54. auto ret = lpMSProvider->QueryInterface(IID_ECUnknown/*IID_ECMSProviderSwitch*/,
  55. reinterpret_cast<void **>(lppMSProvider));
  56. if (ret != hrSuccess)
  57. delete lpMSProvider;
  58. return ret;
  59. }
  60. HRESULT ECMSProviderSwitch::QueryInterface(REFIID refiid, void **lppInterface)
  61. {
  62. /*refiid == IID_ECMSProviderSwitch */
  63. REGISTER_INTERFACE2(ECUnknown, this);
  64. REGISTER_INTERFACE2(IMSProvider, &this->m_xMSProvider);
  65. REGISTER_INTERFACE2(IUnknown, &this->m_xMSProvider);
  66. REGISTER_INTERFACE3(ISelectUnicode, IUnknown, &this->m_xUnknown);
  67. return MAPI_E_INTERFACE_NOT_SUPPORTED;
  68. }
  69. ULONG ECMSProviderSwitch::Release()
  70. {
  71. return ECUnknown::Release();
  72. }
  73. HRESULT ECMSProviderSwitch::Shutdown(ULONG * lpulFlags)
  74. {
  75. HRESULT hr = hrSuccess;
  76. //FIXME
  77. return hr;
  78. }
  79. HRESULT ECMSProviderSwitch::Logon(LPMAPISUP lpMAPISup, ULONG ulUIParam, LPTSTR lpszProfileName, ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulFlags, LPCIID lpInterface, ULONG *lpcbSpoolSecurity, LPBYTE *lppbSpoolSecurity, LPMAPIERROR *lppMAPIError, LPMSLOGON *lppMSLogon, LPMDB *lppMDB)
  80. {
  81. HRESULT hr = hrSuccess;
  82. object_ptr<ECMsgStore> lpecMDB;
  83. sGlobalProfileProps sProfileProps;
  84. object_ptr<IProfSect> lpProfSect;
  85. memory_ptr<SPropValue> lpsPropArray, lpProp, lpIdentityProps;
  86. ULONG cValues = 0;
  87. char* lpDisplayName = NULL;
  88. bool bIsDefaultStore = false;
  89. object_ptr<IMsgStore> lpMDB;
  90. object_ptr<IMSLogon> lpMSLogon;
  91. PROVIDER_INFO sProviderInfo;
  92. ULONG ulConnectType = CT_UNSPECIFIED;
  93. object_ptr<IMSProvider> lpOnline;
  94. convert_context converter;
  95. memory_ptr<ENTRYID> lpStoreID;
  96. ULONG cbStoreID = 0;
  97. convstring tstrProfileName(lpszProfileName, ulFlags);
  98. // Get the username and password from the profile settings
  99. hr = ClientUtil::GetGlobalProfileProperties(lpMAPISup, &sProfileProps);
  100. if (hr != hrSuccess)
  101. goto exit;
  102. // Open profile settings
  103. hr = lpMAPISup->OpenProfileSection(nullptr, MAPI_MODIFY, &~lpProfSect);
  104. if (hr != hrSuccess)
  105. goto exit;
  106. if (lpEntryID == NULL) {
  107. // Try to initialize the provider
  108. if (InitializeProvider(NULL, lpProfSect, sProfileProps, &cbStoreID, &~lpStoreID) != hrSuccess) {
  109. hr = MAPI_E_UNCONFIGURED;
  110. goto exit;
  111. }
  112. lpEntryID = lpStoreID;
  113. cbEntryID = cbStoreID;
  114. }
  115. static constexpr const SizedSPropTagArray(1, proptag) = {1, {PR_MDB_PROVIDER}};
  116. hr = lpProfSect->GetProps(proptag, 0, &cValues, &~lpsPropArray);
  117. if (hr == hrSuccess && lpsPropArray[0].ulPropTag == PR_MDB_PROVIDER &&
  118. (CompareMDBProvider(lpsPropArray[0].Value.bin.lpb, &KOPANO_SERVICE_GUID) ||
  119. CompareMDBProvider(lpsPropArray[0].Value.bin.lpb, &MSEMS_SERVICE_GUID)))
  120. bIsDefaultStore = true;
  121. hr = hrSuccess;
  122. hr = GetProviders(&g_mapProviders, lpMAPISup, tstrProfileName.c_str(), ulFlags, &sProviderInfo);
  123. if (hr != hrSuccess)
  124. goto exit;
  125. hr = sProviderInfo.lpMSProviderOnline->QueryInterface(IID_IMSProvider, &~lpOnline);
  126. if (hr != hrSuccess)
  127. goto exit;
  128. // Default error
  129. hr = MAPI_E_LOGON_FAILED; //or MAPI_E_FAILONEPROVIDER
  130. // Connect online if any of the following is true:
  131. // - Online store was specifically requested (MDB_ONLINE)
  132. // - Profile is not offline capable
  133. // - Store being opened is not the user's default store
  134. if ((ulFlags & MDB_ONLINE) ||
  135. !(sProviderInfo.ulProfileFlags & EC_PROFILE_FLAGS_OFFLINE) ||
  136. bIsDefaultStore == false) {
  137. bool fDone = false;
  138. while(!fDone) {
  139. hr = lpOnline->Logon(lpMAPISup, ulUIParam, lpszProfileName, cbEntryID, lpEntryID, ulFlags, lpInterface, nullptr, nullptr, nullptr, &~lpMSLogon, &~lpMDB);
  140. ulConnectType = CT_ONLINE;
  141. fDone = true;
  142. }
  143. }
  144. // Set the provider in the right connection type
  145. if (bIsDefaultStore &&
  146. SetProviderMode(lpMAPISup, &g_mapProviders, tstrProfileName.c_str(), ulConnectType) != hrSuccess) {
  147. hr = MAPI_E_INVALID_PARAMETER;
  148. goto exit;
  149. }
  150. if(hr != hrSuccess) {
  151. if(ulFlags & MDB_NO_DIALOG) {
  152. hr = MAPI_E_FAILONEPROVIDER;
  153. goto exit;
  154. } else if(hr == MAPI_E_NETWORK_ERROR) {
  155. hr = MAPI_E_FAILONEPROVIDER; //for disable public folders, so you can work offline
  156. goto exit;
  157. } else if (hr == MAPI_E_LOGON_FAILED) {
  158. hr = MAPI_E_UNCONFIGURED; // Linux error ??//
  159. //hr = MAPI_E_LOGON_FAILED;
  160. goto exit;
  161. }else{
  162. hr = MAPI_E_LOGON_FAILED;
  163. goto exit;
  164. }
  165. }
  166. hr = lpMDB->QueryInterface(IID_ECMsgStore, &~lpecMDB);
  167. if (hr != hrSuccess)
  168. goto exit;
  169. // Register ourselves with mapisupport
  170. hr = lpMAPISup->SetProviderUID((MAPIUID *)&lpecMDB->GetStoreGuid(), 0);
  171. if (hr != hrSuccess)
  172. goto exit;
  173. // Set profile identity
  174. hr = ClientUtil::HrSetIdentity(lpecMDB->lpTransport, lpMAPISup, &~lpIdentityProps);
  175. if (hr != hrSuccess)
  176. goto exit;
  177. // Get store name
  178. // The server will return MAPI_E_UNCONFIGURED when an attempt is made to open a store
  179. // that does not exist on that server. However the store is only opened the first time
  180. // when it's actually needed.
  181. // Since this is the first call that actually needs information from the store, we need
  182. // to be prepared to handle the MAPI_E_UNCONFIGURED error as we want to propagate this
  183. // up to the caller so this 'error' can be resolved by reconfiguring the profile.
  184. hr = HrGetOneProp(lpMDB, PR_DISPLAY_NAME_A, &~lpProp);
  185. if (hr == MAPI_E_UNCONFIGURED)
  186. goto exit;
  187. if (hr != hrSuccess || lpProp->ulPropTag != PR_DISPLAY_NAME_A) {
  188. lpDisplayName = _A("Unknown");
  189. hr = hrSuccess;
  190. } else {
  191. lpDisplayName = lpProp->Value.lpszA;
  192. }
  193. if (CompareMDBProvider(&lpecMDB->m_guidMDB_Provider, &KOPANO_SERVICE_GUID) ||
  194. CompareMDBProvider(&lpecMDB->m_guidMDB_Provider, &KOPANO_STORE_DELEGATE_GUID))
  195. {
  196. hr = ClientUtil::HrInitializeStatusRow(lpDisplayName, MAPI_STORE_PROVIDER, lpMAPISup, lpIdentityProps, 0);
  197. if (hr != hrSuccess)
  198. goto exit;
  199. }
  200. if (lppMSLogon) {
  201. hr = lpMSLogon->QueryInterface(IID_IMSLogon, (void **)lppMSLogon);
  202. if (hr != hrSuccess)
  203. goto exit;
  204. }
  205. if (lppMDB) {
  206. hr = lpMDB->QueryInterface(IID_IMsgStore, (void **)lppMDB);
  207. if (hr != hrSuccess)
  208. goto exit;
  209. }
  210. // Store username and password so SpoolerLogon can log on to the profile
  211. if(lppbSpoolSecurity)
  212. {
  213. ULONG cbSpoolSecurity = sizeof(wchar_t) * (sProfileProps.strUserName.length() + sProfileProps.strPassword.length() + 1 + 1);
  214. hr = MAPIAllocateBuffer(cbSpoolSecurity, (void **)lppbSpoolSecurity);
  215. if(hr != hrSuccess)
  216. goto exit;
  217. swprintf((wchar_t*)*lppbSpoolSecurity, cbSpoolSecurity, L"%s%c%s", sProfileProps.strUserName.c_str(), 0, sProfileProps.strPassword.c_str());
  218. *lpcbSpoolSecurity = cbSpoolSecurity;
  219. }
  220. exit:
  221. if (lppMAPIError)
  222. *lppMAPIError = NULL;
  223. return hr;
  224. }
  225. HRESULT ECMSProviderSwitch::SpoolerLogon(LPMAPISUP lpMAPISup, ULONG ulUIParam, LPTSTR lpszProfileName, ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulFlags, LPCIID lpInterface, ULONG cbSpoolSecurity, LPBYTE lpbSpoolSecurity, LPMAPIERROR *lppMAPIError, LPMSLOGON *lppMSLogon, LPMDB *lppMDB)
  226. {
  227. HRESULT hr = hrSuccess;
  228. IMSProvider *lpProvider = NULL; // Do not release
  229. PROVIDER_INFO sProviderInfo;
  230. object_ptr<IMsgStore> lpMDB;
  231. object_ptr<IMSLogon> lpMSLogon;
  232. object_ptr<ECMsgStore> lpecMDB;
  233. if (lpEntryID == NULL) {
  234. hr = MAPI_E_UNCONFIGURED;
  235. goto exit;
  236. }
  237. if (cbSpoolSecurity == 0 || lpbSpoolSecurity == NULL) {
  238. hr = MAPI_E_NO_ACCESS;
  239. goto exit;
  240. }
  241. hr = GetProviders(&g_mapProviders, lpMAPISup, convstring(lpszProfileName, ulFlags).c_str(), ulFlags, &sProviderInfo);
  242. if (hr != hrSuccess)
  243. goto exit;
  244. lpProvider = sProviderInfo.lpMSProviderOnline;
  245. hr = lpProvider->SpoolerLogon(lpMAPISup, ulUIParam, lpszProfileName,
  246. cbEntryID, lpEntryID, ulFlags, lpInterface, cbSpoolSecurity,
  247. lpbSpoolSecurity, nullptr, &~lpMSLogon, &~lpMDB);
  248. if (hr != hrSuccess)
  249. goto exit;
  250. hr = lpMDB->QueryInterface(IID_ECMsgStore, &~lpecMDB);
  251. if (hr != hrSuccess)
  252. goto exit;
  253. // Register ourselves with mapisupport
  254. hr = lpMAPISup->SetProviderUID((MAPIUID *)&lpecMDB->GetStoreGuid(), 0);
  255. if (hr != hrSuccess)
  256. goto exit;
  257. if (lppMSLogon) {
  258. hr = lpMSLogon->QueryInterface(IID_IMSLogon, (void **)lppMSLogon);
  259. if (hr != hrSuccess)
  260. goto exit;
  261. }
  262. if (lppMDB) {
  263. hr = lpMDB->QueryInterface(IID_IMsgStore, (void **)lppMDB);
  264. if (hr != hrSuccess)
  265. goto exit;
  266. }
  267. exit:
  268. if (lppMAPIError)
  269. *lppMAPIError = NULL;
  270. return hr;
  271. }
  272. HRESULT ECMSProviderSwitch::CompareStoreIDs(ULONG cbEntryID1, LPENTRYID lpEntryID1, ULONG cbEntryID2, LPENTRYID lpEntryID2, ULONG ulFlags, ULONG *lpulResult)
  273. {
  274. return ::CompareStoreIDs(cbEntryID1, lpEntryID1, cbEntryID2, lpEntryID2, ulFlags, lpulResult);
  275. }
  276. DEF_ULONGMETHOD1(TRACE_MAPI, ECMSProviderSwitch, MSProvider, AddRef, (void))
  277. DEF_ULONGMETHOD1(TRACE_MAPI, ECMSProviderSwitch, MSProvider, Release, (void))
  278. DEF_HRMETHOD1(TRACE_MAPI, ECMSProviderSwitch, MSProvider, QueryInterface, (REFIID, refiid), (void **, lppInterface))
  279. DEF_HRMETHOD1(TRACE_MAPI, ECMSProviderSwitch, MSProvider, Shutdown, (ULONG *, lpulFlags))
  280. HRESULT ECMSProviderSwitch::xMSProvider::Logon(LPMAPISUP lpMAPISup, ULONG ulUIParam, LPTSTR lpszProfileName, ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulFlags, LPCIID lpInterface, ULONG *lpcbSpoolSecurity, LPBYTE *lppbSpoolSecurity, LPMAPIERROR *lppMAPIError, LPMSLOGON *lppMSLogon, LPMDB *lppMDB)
  281. {
  282. TRACE_MAPI(TRACE_ENTRY, "ECMSProviderSwitch::Logon", "flags=%x, cbEntryID=%d", ulFlags, cbEntryID);
  283. METHOD_PROLOGUE_(ECMSProviderSwitch, MSProvider);
  284. HRESULT hr = pThis->Logon(lpMAPISup, ulUIParam, lpszProfileName, cbEntryID, lpEntryID,ulFlags, lpInterface, lpcbSpoolSecurity, lppbSpoolSecurity, lppMAPIError, lppMSLogon, lppMDB);
  285. TRACE_MAPI(TRACE_RETURN, "ECMSProviderSwitch::Logon", "%s", GetMAPIErrorDescription(hr).c_str());
  286. return hr;
  287. }
  288. HRESULT ECMSProviderSwitch::xMSProvider::SpoolerLogon(LPMAPISUP lpMAPISup, ULONG ulUIParam, LPTSTR lpszProfileName, ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulFlags, LPCIID lpInterface, ULONG lpcbSpoolSecurity, LPBYTE lppbSpoolSecurity, LPMAPIERROR *lppMAPIError, LPMSLOGON *lppMSLogon, LPMDB *lppMDB)
  289. {
  290. TRACE_MAPI(TRACE_ENTRY, "ECMSProviderSwitch::SpoolerLogon", "flags=%x", ulFlags);
  291. METHOD_PROLOGUE_(ECMSProviderSwitch, MSProvider);
  292. HRESULT hr = pThis->SpoolerLogon(lpMAPISup, ulUIParam, lpszProfileName, cbEntryID, lpEntryID,ulFlags, lpInterface, lpcbSpoolSecurity, lppbSpoolSecurity, lppMAPIError, lppMSLogon, lppMDB);
  293. TRACE_MAPI(TRACE_RETURN, "ECMSProviderSwitch::SpoolerLogon", "%s", GetMAPIErrorDescription(hr).c_str());
  294. return hr;
  295. }
  296. DEF_HRMETHOD1(TRACE_MAPI, ECMSProviderSwitch, MSProvider, CompareStoreIDs, (ULONG, cbEntryID1), (LPENTRYID, lpEntryID1), (ULONG, cbEntryID2), (LPENTRYID, lpEntryID2), (ULONG, ulFlags), (ULONG *, lpulResult))