Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1106 lines
32 KiB

  1. // --------------------------------------------------------------------------------
  2. // Ixpbase.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "dllmain.h"
  8. #include "ixpbase.h"
  9. #include "imnact.h"
  10. #include "ixputil.h"
  11. #include "sicily.h"
  12. #include "resource.h"
  13. #include "demand.h"
  14. #include "shlwapi.h"
  15. // --------------------------------------------------------------------------------
  16. // CIxpBase::CIxpBase
  17. // --------------------------------------------------------------------------------
  18. CIxpBase::CIxpBase(IXPTYPE ixptype) : m_ixptype(ixptype)
  19. {
  20. m_fBusy = FALSE;
  21. m_status = IXP_DISCONNECTED;
  22. m_cRef = 1;
  23. m_pszResponse = NULL;
  24. m_uiResponse = 0;
  25. m_hrResponse = S_OK;
  26. m_pLogFile = NULL;
  27. m_pSocket = NULL;
  28. m_pCallback = NULL;
  29. ZeroMemory(&m_rServer, sizeof(m_rServer));
  30. m_fConnectAuth = FALSE;
  31. m_fConnectTLS = FALSE;
  32. m_fCommandLogging = FALSE;
  33. m_fAuthenticated = FALSE;
  34. InitializeCriticalSection(&m_cs);
  35. }
  36. // --------------------------------------------------------------------------------
  37. // CIxpBase::~CIxpBase
  38. // --------------------------------------------------------------------------------
  39. CIxpBase::~CIxpBase(void)
  40. {
  41. Reset();
  42. DeleteCriticalSection(&m_cs);
  43. }
  44. // --------------------------------------------------------------------------------
  45. // CIxpBase::Reset
  46. // --------------------------------------------------------------------------------
  47. void CIxpBase::Reset(void)
  48. {
  49. EnterCriticalSection(&m_cs);
  50. m_fBusy = FALSE;
  51. m_status = IXP_DISCONNECTED;
  52. SafeMemFree(m_pszResponse);
  53. m_uiResponse = 0;
  54. m_hrResponse = S_OK;
  55. SafeRelease(m_pLogFile);
  56. if (NULL != m_pSocket)
  57. {
  58. m_pSocket->Close();
  59. SafeRelease(m_pSocket);
  60. }
  61. SafeRelease(m_pCallback);
  62. ZeroMemory(&m_rServer, sizeof(m_rServer));
  63. m_fConnectAuth = FALSE;
  64. m_fConnectTLS = FALSE;
  65. m_fCommandLogging = FALSE;
  66. m_fAuthenticated = FALSE;
  67. LeaveCriticalSection(&m_cs);
  68. }
  69. // --------------------------------------------------------------------------------
  70. // CIxpBase::IsState
  71. // --------------------------------------------------------------------------------
  72. STDMETHODIMP CIxpBase::IsState(IXPISSTATE isstate)
  73. {
  74. // Locals
  75. HRESULT hr=S_FALSE;
  76. // Thread Safety
  77. EnterCriticalSection(&m_cs);
  78. #if 0
  79. // Initialized
  80. if (NULL == m_pSocket || NULL == m_pCallback)
  81. {
  82. hr = TrapError(IXP_E_NOT_INIT);
  83. goto exit;
  84. }
  85. #endif
  86. // Handle IsType
  87. switch(isstate)
  88. {
  89. // Are we connected
  90. case IXP_IS_CONNECTED:
  91. hr = (IXP_DISCONNECTED == m_status) ? S_FALSE : S_OK;
  92. break;
  93. // Are we busy
  94. case IXP_IS_BUSY:
  95. hr = (TRUE == m_fBusy) ? S_OK : S_FALSE;
  96. break;
  97. // Are we busy
  98. case IXP_IS_READY:
  99. hr = (FALSE == m_fBusy) ? S_OK : S_FALSE;
  100. break;
  101. // Have we been authenticated yet
  102. case IXP_IS_AUTHENTICATED:
  103. hr = (TRUE == m_fAuthenticated) ? S_OK : S_FALSE;
  104. break;
  105. // Unhandled ixpistype
  106. default:
  107. IxpAssert(FALSE);
  108. break;
  109. }
  110. // Thread Safety
  111. LeaveCriticalSection(&m_cs);
  112. // Done
  113. return hr;
  114. }
  115. // --------------------------------------------------------------------------------
  116. // CIxpBase::OnPrompt
  117. // --------------------------------------------------------------------------------
  118. int CIxpBase::OnPrompt(HRESULT hrError, LPCTSTR pszText, LPCTSTR pszCaption, UINT uType)
  119. {
  120. // $$BUGBUG$$ Need to return an error
  121. if (NULL == m_pCallback)
  122. return TrapError(IXP_E_NOT_INIT);
  123. // Call the callback
  124. return m_pCallback->OnPrompt(hrError, pszText, pszCaption, uType, this);
  125. }
  126. // --------------------------------------------------------------------------------
  127. // CIxpBase::OnError
  128. // --------------------------------------------------------------------------------
  129. void CIxpBase::OnError(HRESULT hrResult, LPSTR pszProblem)
  130. {
  131. // Locals
  132. IXPRESULT rIxpResult;
  133. // No Callback
  134. if (NULL == m_pCallback)
  135. return;
  136. // Zero It
  137. ZeroMemory(&rIxpResult, sizeof(IXPRESULT));
  138. // Save current state
  139. rIxpResult.hrResult = hrResult;
  140. rIxpResult.pszResponse = PszDupA(m_pszResponse);
  141. rIxpResult.uiServerError = m_uiResponse;
  142. rIxpResult.hrServerError = m_hrResponse;
  143. rIxpResult.dwSocketError = m_pSocket->GetLastError();
  144. rIxpResult.pszProblem = PszDupA(pszProblem);
  145. if (m_pLogFile && pszProblem)
  146. {
  147. // Locals
  148. char szErrorTxt[1024];
  149. // Build the Error
  150. wnsprintf(szErrorTxt, ARRAYSIZE(szErrorTxt), "ERROR: \"%.900s\", hr=%lu", pszProblem, hrResult);
  151. // Write the error
  152. m_pLogFile->WriteLog(LOGFILE_DB, szErrorTxt);
  153. }
  154. // Tell the watchdog to take a nap
  155. m_pSocket->StopWatchDog();
  156. // Give to callback
  157. m_pCallback->OnError(m_status, &rIxpResult, this);
  158. // Start the watchdog and wait for normal socket activity
  159. m_pSocket->StartWatchDog();
  160. // Free stuff
  161. SafeMemFree(rIxpResult.pszResponse);
  162. SafeMemFree(rIxpResult.pszProblem);
  163. }
  164. // --------------------------------------------------------------------------------
  165. // CIxpBase::OnStatus
  166. // --------------------------------------------------------------------------------
  167. void CIxpBase::OnStatus(IXPSTATUS ixpstatus)
  168. {
  169. // Save new Status
  170. m_status = ixpstatus;
  171. if (IXP_AUTHORIZED == ixpstatus)
  172. m_fAuthenticated = TRUE;
  173. else if (IXP_DISCONNECTED == ixpstatus || IXP_DISCONNECTING == ixpstatus)
  174. m_fAuthenticated = FALSE;
  175. // Give Status to callback
  176. if (m_pCallback)
  177. m_pCallback->OnStatus(ixpstatus, this);
  178. // If we're informing caller that we're authorized, head immediately to IXP_CONNECTED
  179. // UNLESS m_status is changed: this indicates state change (eg, disconnect) during callback
  180. if (IXP_AUTHORIZED == ixpstatus && IXP_AUTHORIZED == m_status)
  181. {
  182. m_status = IXP_CONNECTED;
  183. if (m_pCallback)
  184. m_pCallback->OnStatus(IXP_CONNECTED, this);
  185. }
  186. }
  187. // --------------------------------------------------------------------------------
  188. // CIxpBase::HrEnterBusy
  189. // --------------------------------------------------------------------------------
  190. HRESULT CIxpBase::HrEnterBusy(void)
  191. {
  192. // Locals
  193. HRESULT hr=S_OK;
  194. // Thread Safety
  195. EnterCriticalSection(&m_cs);
  196. // Initialized
  197. if (NULL == m_pSocket || NULL == m_pCallback)
  198. {
  199. hr = TrapError(IXP_E_NOT_INIT);
  200. goto exit;
  201. }
  202. // Not Ready
  203. if (TRUE == m_fBusy)
  204. {
  205. hr = TrapError(IXP_E_BUSY);
  206. goto exit;
  207. }
  208. // Start WatchDog
  209. m_pSocket->StartWatchDog();
  210. // Busy
  211. m_fBusy = TRUE;
  212. exit:
  213. // Thread Safety
  214. LeaveCriticalSection(&m_cs);
  215. // Done
  216. return hr;
  217. }
  218. // --------------------------------------------------------------------------------
  219. // CIxpBase::LeaveBusy
  220. // --------------------------------------------------------------------------------
  221. void CIxpBase::LeaveBusy(void)
  222. {
  223. // Thread Safety
  224. EnterCriticalSection(&m_cs);
  225. // Start WatchDog
  226. if (NULL != m_pSocket)
  227. {
  228. m_pSocket->StopWatchDog();
  229. }
  230. // Busy
  231. m_fBusy = FALSE;
  232. // Thread Safety
  233. LeaveCriticalSection(&m_cs);
  234. }
  235. // --------------------------------------------------------------------------------
  236. // CIxpBase::HandsOffCallback
  237. // --------------------------------------------------------------------------------
  238. STDMETHODIMP CIxpBase::HandsOffCallback(void)
  239. {
  240. // Locals
  241. HRESULT hr=S_OK;
  242. // Thread Safety
  243. EnterCriticalSection(&m_cs);
  244. // No current callback
  245. if (NULL == m_pCallback)
  246. {
  247. hr = TrapError(S_FALSE);
  248. goto exit;
  249. }
  250. // Release it
  251. SafeRelease(m_pCallback);
  252. exit:
  253. // Thread Safety
  254. LeaveCriticalSection(&m_cs);
  255. // Done
  256. return hr;
  257. }
  258. // --------------------------------------------------------------------------------
  259. // CIxpBase::OnInitNew
  260. // --------------------------------------------------------------------------------
  261. HRESULT CIxpBase::OnInitNew(LPSTR pszProtocol, LPSTR pszLogFilePath, DWORD dwShareMode,
  262. ITransportCallback *pCallback)
  263. {
  264. // Locals
  265. HRESULT hr=S_OK;
  266. // check params
  267. if (NULL == pCallback || NULL == pszProtocol)
  268. return TrapError(E_INVALIDARG);
  269. // Thread Safety
  270. EnterCriticalSection(&m_cs);
  271. // Not connected
  272. if (IXP_DISCONNECTED != m_status)
  273. {
  274. hr = TrapError(IXP_E_ALREADY_CONNECTED);
  275. goto exit;
  276. }
  277. // release current objects
  278. Reset();
  279. ResetBase();
  280. // open log file
  281. if (pszLogFilePath)
  282. {
  283. // create the log file
  284. CreateLogFile(g_hInst, pszLogFilePath, pszProtocol, DONT_TRUNCATE, &m_pLogFile, dwShareMode);
  285. }
  286. // Create the socket
  287. m_pSocket = new CAsyncConn(m_pLogFile, (IAsyncConnCB *)this, (IAsyncConnPrompt *)this);
  288. if (NULL == m_pSocket)
  289. {
  290. hr = TrapError(E_OUTOFMEMORY);
  291. goto exit;
  292. }
  293. // Add Ref callback
  294. m_pCallback = pCallback;
  295. m_pCallback->AddRef();
  296. exit:
  297. // Thread Safety
  298. LeaveCriticalSection(&m_cs);
  299. // Done
  300. return hr;
  301. }
  302. // --------------------------------------------------------------------------------
  303. // CIxpBase::GetServerInfo
  304. // --------------------------------------------------------------------------------
  305. STDMETHODIMP CIxpBase::GetServerInfo(LPINETSERVER pInetServer)
  306. {
  307. // check params
  308. if (NULL == pInetServer)
  309. return TrapError(E_INVALIDARG);
  310. // Thread Safety
  311. EnterCriticalSection(&m_cs);
  312. // Copy Server information
  313. CopyMemory(pInetServer, &m_rServer, sizeof(INETSERVER));
  314. // Thread Safety
  315. LeaveCriticalSection(&m_cs);
  316. // Done
  317. return S_OK;
  318. }
  319. // --------------------------------------------------------------------------------
  320. // CIxpBase::Disconnect
  321. // --------------------------------------------------------------------------------
  322. STDMETHODIMP CIxpBase::Disconnect(void)
  323. {
  324. // Locals
  325. HRESULT hr=S_OK;
  326. // Thread Safety
  327. EnterCriticalSection(&m_cs);
  328. // No socket...
  329. if (NULL == m_pSocket)
  330. {
  331. hr = TrapError(IXP_E_NOT_INIT);
  332. goto exit;
  333. }
  334. // Not connected
  335. if (IXP_DISCONNECTED == m_status)
  336. {
  337. hr = TrapError(IXP_E_NOT_CONNECTED);
  338. goto exit;
  339. }
  340. // Disconnecting
  341. OnStatus(IXP_DISCONNECTING);
  342. // State
  343. DoQuit();
  344. exit:
  345. // Thread Safety
  346. LeaveCriticalSection(&m_cs);
  347. // Done
  348. return hr;
  349. }
  350. // --------------------------------------------------------------------------------
  351. // CIxpBase::DropConnection
  352. // --------------------------------------------------------------------------------
  353. STDMETHODIMP CIxpBase::DropConnection(void)
  354. {
  355. // Locals
  356. HRESULT hr=S_OK;
  357. // Thread Safety
  358. EnterCriticalSection(&m_cs);
  359. // No socket...
  360. if (NULL == m_pSocket)
  361. {
  362. hr = TrapError(IXP_E_NOT_INIT);
  363. goto exit;
  364. }
  365. // Already IXP_DISCONNECTED
  366. if (IXP_DISCONNECTED != m_status)
  367. {
  368. // State
  369. OnStatus(IXP_DISCONNECTING);
  370. // Done
  371. CHECKHR(hr = m_pSocket->Close());
  372. }
  373. exit:
  374. // Thread Safety
  375. LeaveCriticalSection(&m_cs);
  376. // Done
  377. return hr;
  378. }
  379. // --------------------------------------------------------------------------------
  380. // CIxpBase::InetServerFromAccount
  381. // --------------------------------------------------------------------------------
  382. STDMETHODIMP CIxpBase::InetServerFromAccount(IImnAccount *pAccount, LPINETSERVER pInetServer)
  383. {
  384. // Locals
  385. HRESULT hr=S_OK;
  386. DWORD fAlwaysPromptPassword=FALSE;
  387. // check params
  388. if (NULL == pAccount || NULL == pInetServer)
  389. return TrapError(E_INVALIDARG);
  390. // ZeroInit
  391. ZeroMemory(pInetServer, sizeof(INETSERVER));
  392. // Get the account name
  393. hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, pInetServer->szAccount, ARRAYSIZE(pInetServer->szAccount));
  394. if (FAILED(hr))
  395. {
  396. hr = TrapError(IXP_E_INVALID_ACCOUNT);
  397. goto exit;
  398. }
  399. // Get the RAS connectoid
  400. if (FAILED(pAccount->GetPropSz(AP_RAS_CONNECTOID, pInetServer->szConnectoid, ARRAYSIZE(pInetServer->szConnectoid))))
  401. *pInetServer->szConnectoid = '\0';
  402. // Connection Type
  403. Assert(sizeof(pInetServer->rasconntype) == sizeof(DWORD));
  404. if (FAILED(pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, (DWORD *)&pInetServer->rasconntype)))
  405. pInetServer->rasconntype = RAS_CONNECT_LAN;
  406. // Connection Flags
  407. // IXP_SMTP
  408. if (IXP_SMTP == m_ixptype)
  409. {
  410. // Locals
  411. SMTPAUTHTYPE authtype;
  412. // Get Server Name
  413. hr = pAccount->GetPropSz(AP_SMTP_SERVER, pInetServer->szServerName, sizeof(pInetServer->szServerName));
  414. if (FAILED(hr))
  415. {
  416. hr = TrapError(IXP_E_INVALID_ACCOUNT);
  417. goto exit;
  418. }
  419. // SSL
  420. Assert(sizeof(pInetServer->fSSL) == sizeof(DWORD));
  421. pAccount->GetPropDw(AP_SMTP_SSL, (DWORD *)&pInetServer->fSSL);
  422. // Sicily
  423. Assert(sizeof(authtype) == sizeof(DWORD));
  424. if (FAILED(pAccount->GetPropDw(AP_SMTP_USE_SICILY, (DWORD *)&authtype)))
  425. authtype = SMTP_AUTH_NONE;
  426. if (SMTP_AUTH_NONE != authtype)
  427. {
  428. pInetServer->dwFlags |= ISF_QUERYAUTHSUPPORT;
  429. }
  430. // SMTP_AUTH_USE_POP3ORIMAP_SETTINGS
  431. if (SMTP_AUTH_USE_POP3ORIMAP_SETTINGS == authtype)
  432. {
  433. // Locals
  434. DWORD dwServers;
  435. DWORD dw;
  436. BOOL fIMAP;
  437. // Get Server Types
  438. if (FAILED(pAccount->GetServerTypes(&dwServers)))
  439. {
  440. hr = TrapError(IXP_E_INVALID_ACCOUNT);
  441. goto exit;
  442. }
  443. // fIMAP
  444. fIMAP = (ISFLAGSET(dwServers, SRV_IMAP)) ? TRUE : FALSE;
  445. // Using DPA
  446. if (SUCCEEDED(pAccount->GetPropDw(fIMAP ? AP_IMAP_USE_SICILY : AP_POP3_USE_SICILY, &dw)) && dw)
  447. pInetServer->fTrySicily = TRUE;
  448. // Get default username and password
  449. pAccount->GetPropSz(fIMAP ? AP_IMAP_USERNAME : AP_POP3_USERNAME, pInetServer->szUserName, sizeof(pInetServer->szUserName));
  450. if (FAILED(pAccount->GetPropDw(fIMAP ? AP_IMAP_PROMPT_PASSWORD : AP_POP3_PROMPT_PASSWORD, &fAlwaysPromptPassword)) ||
  451. FALSE == fAlwaysPromptPassword)
  452. {
  453. pAccount->GetPropSz(fIMAP ? AP_IMAP_PASSWORD : AP_POP3_PASSWORD, pInetServer->szPassword, sizeof(pInetServer->szPassword));
  454. }
  455. if (!pInetServer->fTrySicily && fAlwaysPromptPassword)
  456. pInetServer->dwFlags|=ISF_ALWAYSPROMPTFORPASSWORD;
  457. }
  458. // SMTP_AUTH_USE_SMTP_SETTINGS
  459. else if (SMTP_AUTH_USE_SMTP_SETTINGS == authtype)
  460. {
  461. pInetServer->fTrySicily = TRUE;
  462. pAccount->GetPropSz(AP_SMTP_USERNAME, pInetServer->szUserName, sizeof(pInetServer->szUserName));
  463. if (FAILED(pAccount->GetPropDw(AP_SMTP_PROMPT_PASSWORD, &fAlwaysPromptPassword)) ||
  464. FALSE == fAlwaysPromptPassword)
  465. {
  466. pAccount->GetPropSz(AP_SMTP_PASSWORD, pInetServer->szPassword, sizeof(pInetServer->szPassword));
  467. }
  468. if (fAlwaysPromptPassword)
  469. pInetServer->dwFlags|=ISF_ALWAYSPROMPTFORPASSWORD;
  470. }
  471. // Handle Authenticatin type
  472. else if (SMTP_AUTH_SICILY == authtype)
  473. pInetServer->fTrySicily = TRUE;
  474. // Port
  475. if (FAILED(pAccount->GetPropDw(AP_SMTP_PORT, &pInetServer->dwPort)))
  476. pInetServer->dwPort = DEFAULT_SMTP_PORT;
  477. // Timeout
  478. pAccount->GetPropDw(AP_SMTP_TIMEOUT, &pInetServer->dwTimeout);
  479. if (0 == pInetServer->dwTimeout)
  480. pInetServer->dwTimeout = 30;
  481. // Use STARTTLS?
  482. if ((FALSE != pInetServer->fSSL) && (DEFAULT_SMTP_PORT == pInetServer->dwPort))
  483. pInetServer->dwFlags|=ISF_SSLONSAMEPORT;
  484. }
  485. // IXP_POP3
  486. else if (IXP_POP3 == m_ixptype)
  487. {
  488. // Get Server Name
  489. hr = pAccount->GetPropSz(AP_POP3_SERVER, pInetServer->szServerName, sizeof(pInetServer->szServerName));
  490. if (FAILED(hr))
  491. {
  492. hr = TrapError(IXP_E_INVALID_ACCOUNT);
  493. goto exit;
  494. }
  495. // Password
  496. if (FAILED(pAccount->GetPropDw(AP_POP3_PROMPT_PASSWORD, &fAlwaysPromptPassword)) ||
  497. FALSE == fAlwaysPromptPassword)
  498. pAccount->GetPropSz(AP_POP3_PASSWORD, pInetServer->szPassword, sizeof(pInetServer->szPassword));
  499. // SSL
  500. Assert(sizeof(pInetServer->fSSL) == sizeof(DWORD));
  501. pAccount->GetPropDw(AP_POP3_SSL, (DWORD *)&pInetServer->fSSL);
  502. // Sicily
  503. Assert(sizeof(pInetServer->fTrySicily) == sizeof(DWORD));
  504. pAccount->GetPropDw(AP_POP3_USE_SICILY, (DWORD *)&pInetServer->fTrySicily);
  505. if (!pInetServer->fTrySicily && fAlwaysPromptPassword)
  506. pInetServer->dwFlags|=ISF_ALWAYSPROMPTFORPASSWORD;
  507. // Port
  508. if (FAILED(pAccount->GetPropDw(AP_POP3_PORT, &pInetServer->dwPort)))
  509. pInetServer->dwPort = 110;
  510. // User Name
  511. pAccount->GetPropSz(AP_POP3_USERNAME, pInetServer->szUserName, sizeof(pInetServer->szUserName));
  512. // Timeout
  513. pAccount->GetPropDw(AP_POP3_TIMEOUT, &pInetServer->dwTimeout);
  514. }
  515. // IXP_IMAP
  516. else if (IXP_IMAP == m_ixptype)
  517. {
  518. // User name, password and server
  519. hr = pAccount->GetPropSz(AP_IMAP_USERNAME, pInetServer->szUserName,
  520. ARRAYSIZE(pInetServer->szUserName));
  521. if (FAILED(hr))
  522. pInetServer->szUserName[0] = '\0'; // If this is incorrect, we will re-prompt user
  523. hr = pAccount->GetPropDw(AP_IMAP_PROMPT_PASSWORD, &fAlwaysPromptPassword);
  524. if (FAILED(hr) || FALSE == fAlwaysPromptPassword)
  525. {
  526. hr = pAccount->GetPropSz(AP_IMAP_PASSWORD, pInetServer->szPassword,
  527. ARRAYSIZE(pInetServer->szPassword));
  528. if (FAILED(hr))
  529. pInetServer->szPassword[0] = '\0'; // If this is incorrect, we will re-prompt user
  530. }
  531. if (FAILED(hr = pAccount->GetPropSz(AP_IMAP_SERVER, pInetServer->szServerName,
  532. ARRAYSIZE(pInetServer->szServerName))))
  533. goto exit; // We NEED to have a server name, so fail this function
  534. Assert(*pInetServer->szServerName);
  535. // Da port
  536. if (FAILED(hr = pAccount->GetPropDw(AP_IMAP_PORT, &pInetServer->dwPort)))
  537. pInetServer->dwPort = 143; // Default port number
  538. // Convert DWORD to boolean
  539. Assert(sizeof(pInetServer->fSSL) == sizeof(DWORD));
  540. hr = pAccount->GetPropDw(AP_IMAP_SSL, (DWORD *)&pInetServer->fSSL);
  541. if (FAILED(hr))
  542. pInetServer->fSSL = FALSE; // Default this value
  543. Assert(sizeof(pInetServer->fTrySicily) == sizeof(DWORD));
  544. hr = pAccount->GetPropDw(AP_IMAP_USE_SICILY, (DWORD *)&pInetServer->fTrySicily);
  545. if (FAILED(hr))
  546. pInetServer->fTrySicily = FALSE; // Default this value
  547. if (!pInetServer->fTrySicily && fAlwaysPromptPassword)
  548. pInetServer->dwFlags|=ISF_ALWAYSPROMPTFORPASSWORD;
  549. // Get the timeout
  550. hr = pAccount->GetPropDw(AP_IMAP_TIMEOUT, &pInetServer->dwTimeout);
  551. if (FAILED(hr))
  552. pInetServer->dwTimeout = 30; // Default this value
  553. // If we've reached this point, we may have a failed HRESULT, but since we
  554. // must have defaulted the value, we should return success.
  555. hr = S_OK;
  556. }
  557. // IXP_NNTP
  558. else if (IXP_NNTP == m_ixptype)
  559. {
  560. // Get the server name
  561. hr = pAccount->GetPropSz(AP_NNTP_SERVER, pInetServer->szServerName, sizeof(pInetServer->szServerName));
  562. if (FAILED(hr))
  563. {
  564. hr = TrapError(IXP_E_INVALID_ACCOUNT);
  565. goto exit;
  566. }
  567. // Password
  568. if (FAILED(pAccount->GetPropDw(AP_NNTP_PROMPT_PASSWORD, &fAlwaysPromptPassword)) ||
  569. FALSE == fAlwaysPromptPassword)
  570. pAccount->GetPropSz(AP_NNTP_PASSWORD, pInetServer->szPassword, sizeof(pInetServer->szPassword));
  571. // SSL
  572. Assert(sizeof(pInetServer->fSSL) == sizeof(DWORD));
  573. pAccount->GetPropDw(AP_NNTP_SSL, (DWORD *)&pInetServer->fSSL);
  574. // Sicily
  575. Assert(sizeof(pInetServer->fTrySicily) == sizeof(DWORD));
  576. pAccount->GetPropDw(AP_NNTP_USE_SICILY, (DWORD *)&pInetServer->fTrySicily);
  577. if (!pInetServer->fTrySicily && fAlwaysPromptPassword)
  578. pInetServer->dwFlags|=ISF_ALWAYSPROMPTFORPASSWORD;
  579. // Port
  580. if (FAILED(pAccount->GetPropDw(AP_NNTP_PORT, &pInetServer->dwPort)))
  581. pInetServer->dwPort = 119;
  582. // User Name
  583. pAccount->GetPropSz(AP_NNTP_USERNAME, pInetServer->szUserName, sizeof(pInetServer->szUserName));
  584. // Timeout
  585. pAccount->GetPropDw(AP_NNTP_TIMEOUT, &pInetServer->dwTimeout);
  586. }
  587. // Fix timeout
  588. if (pInetServer->dwTimeout < 30)
  589. pInetServer->dwTimeout = 30;
  590. exit:
  591. // Done
  592. return hr;
  593. }
  594. // --------------------------------------------------------------------------------
  595. // CIxpBase::Connect
  596. // --------------------------------------------------------------------------------
  597. STDMETHODIMP CIxpBase::Connect(LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging)
  598. {
  599. // Locals
  600. HRESULT hr=S_OK;
  601. BOOL fSecureSocket = FALSE;
  602. BOOL fConnectTLS = FALSE;
  603. // check params
  604. if (NULL == pInetServer || FIsEmptyA(pInetServer->szServerName) || pInetServer->dwPort == 0)
  605. return TrapError(E_INVALIDARG);
  606. // Thread Safety
  607. EnterCriticalSection(&m_cs);
  608. // not init
  609. if (NULL == m_pSocket || NULL == m_pCallback)
  610. {
  611. hr = TrapError(IXP_E_NOT_INIT);
  612. goto exit;
  613. }
  614. // busy
  615. if (IXP_DISCONNECTED != m_status)
  616. {
  617. hr = TrapError(IXP_E_ALREADY_CONNECTED);
  618. goto exit;
  619. }
  620. // Initialize Winsock
  621. CHECKHR(hr = HrInitializeWinsock());
  622. // invalid sicily params
  623. if (pInetServer->fTrySicily && !FIsSicilyInstalled())
  624. {
  625. hr = TrapError(IXP_E_LOAD_SICILY_FAILED);
  626. goto exit;
  627. }
  628. // Copy Server information
  629. CopyMemory(&m_rServer, pInetServer, sizeof(INETSERVER));
  630. // Reset current
  631. ResetBase();
  632. // Do we really want to connect to SMTP securely
  633. if (FALSE != m_rServer.fSSL)
  634. {
  635. // Do we want to connect to SMTP via a secure socket?
  636. fSecureSocket = (0 == (m_rServer.dwFlags & ISF_SSLONSAMEPORT));
  637. // Do we want to use STARTTLS to get the secure connection?
  638. fConnectTLS = (0 != (m_rServer.dwFlags & ISF_SSLONSAMEPORT));
  639. Assert(fSecureSocket != fConnectTLS);
  640. }
  641. // Get connection info needed to init async socket
  642. hr = m_pSocket->HrInit(m_rServer.szServerName, m_rServer.dwPort, fSecureSocket, m_rServer.dwTimeout);
  643. if (FAILED(hr))
  644. {
  645. hr = TrapError(IXP_E_SOCKET_INIT_ERROR);
  646. goto exit;
  647. }
  648. // Finding Host Progress
  649. OnStatus(IXP_FINDINGHOST);
  650. // Connect to server
  651. hr = m_pSocket->Connect();
  652. if (FAILED(hr))
  653. {
  654. hr = TrapError(IXP_E_SOCKET_CONNECT_ERROR);
  655. goto exit;
  656. }
  657. // Were busy
  658. m_fBusy = TRUE;
  659. // Start WatchDog
  660. m_pSocket->StartWatchDog();
  661. // Authenticate
  662. m_fConnectAuth = fAuthenticate;
  663. m_fConnectTLS = fConnectTLS;
  664. m_fCommandLogging = fCommandLogging;
  665. exit:
  666. // Thread Safety
  667. LeaveCriticalSection(&m_cs);
  668. // Done
  669. return hr;
  670. }
  671. // --------------------------------------------------------------------------------
  672. // CIxpBase::GetIXPType
  673. // --------------------------------------------------------------------------------
  674. STDMETHODIMP_(IXPTYPE) CIxpBase::GetIXPType(void)
  675. {
  676. return m_ixptype;
  677. }
  678. // --------------------------------------------------------------------------------
  679. // CIxpBase::OnConnected
  680. // --------------------------------------------------------------------------------
  681. void CIxpBase::OnConnected(void)
  682. {
  683. OnStatus(IXP_CONNECTED);
  684. }
  685. // --------------------------------------------------------------------------------
  686. // CIxpBase::OnDisconnected
  687. // --------------------------------------------------------------------------------
  688. void CIxpBase::OnDisconnected(void)
  689. {
  690. LeaveBusy();
  691. OnStatus(IXP_DISCONNECTED);
  692. }
  693. // --------------------------------------------------------------------------------
  694. // CIxpBase::OnNotify
  695. // --------------------------------------------------------------------------------
  696. void CIxpBase::OnNotify(ASYNCSTATE asOld, ASYNCSTATE asNew, ASYNCEVENT ae)
  697. {
  698. // Enter Critical Section
  699. EnterCriticalSection(&m_cs);
  700. switch(ae)
  701. {
  702. // --------------------------------------------------------------------------------
  703. case AE_LOOKUPDONE:
  704. if (AS_DISCONNECTED == asNew)
  705. {
  706. char szFmt[CCHMAX_STRINGRES];
  707. char szFailureText[CCHMAX_STRINGRES];
  708. LoadString(g_hLocRes, idsHostNotFoundFmt, szFmt, ARRAYSIZE(szFmt));
  709. wnsprintf(szFailureText, ARRAYSIZE(szFailureText), szFmt, m_rServer.szServerName);
  710. OnError(IXP_E_CANT_FIND_HOST, szFailureText);
  711. OnDisconnected();
  712. }
  713. else
  714. OnStatus(IXP_CONNECTING);
  715. break;
  716. // --------------------------------------------------------------------------------
  717. case AE_CONNECTDONE:
  718. if (AS_DISCONNECTED == asNew)
  719. {
  720. char szFailureText[CCHMAX_STRINGRES];
  721. LoadString(g_hLocRes, idsFailedToConnect, szFailureText,
  722. ARRAYSIZE(szFailureText));
  723. OnError(IXP_E_FAILED_TO_CONNECT, szFailureText);
  724. OnDisconnected();
  725. }
  726. else if (AS_HANDSHAKING == asNew)
  727. {
  728. OnStatus(IXP_SECURING);
  729. }
  730. else
  731. OnConnected();
  732. break;
  733. // --------------------------------------------------------------------------------
  734. case AE_TIMEOUT:
  735. // Tell the watch dog to take nap
  736. m_pSocket->StopWatchDog();
  737. // Provide the client with a change to continue, or abort
  738. if (m_pCallback && m_pCallback->OnTimeout(&m_rServer.dwTimeout, this) == S_OK)
  739. {
  740. // Start the watchdog and wait for normal socket activity
  741. m_pSocket->StartWatchDog();
  742. }
  743. // Otherwise, if we are connected
  744. else
  745. {
  746. // Drop the connection now
  747. DropConnection();
  748. }
  749. break;
  750. // --------------------------------------------------------------------------------
  751. case AE_CLOSE:
  752. if (AS_RECONNECTING != asNew && IXP_AUTHRETRY != m_status)
  753. {
  754. if (IXP_DISCONNECTING != m_status && IXP_DISCONNECTED != m_status)
  755. {
  756. char szFailureText[CCHMAX_STRINGRES];
  757. if (AS_HANDSHAKING == asOld)
  758. {
  759. LoadString(g_hLocRes, idsFailedToConnectSecurely, szFailureText,
  760. ARRAYSIZE(szFailureText));
  761. OnError(IXP_E_SECURE_CONNECT_FAILED, szFailureText);
  762. }
  763. else
  764. {
  765. LoadString(g_hLocRes, idsUnexpectedTermination, szFailureText,
  766. ARRAYSIZE(szFailureText));
  767. OnError(IXP_E_CONNECTION_DROPPED, szFailureText);
  768. }
  769. }
  770. OnDisconnected();
  771. }
  772. break;
  773. }
  774. // Leave Critical Section
  775. LeaveCriticalSection(&m_cs);
  776. }
  777. // ------------------------------------------------------------------------------------
  778. // CIxpBase::HrReadLine
  779. // ------------------------------------------------------------------------------------
  780. HRESULT CIxpBase::HrReadLine(LPSTR *ppszLine, INT *pcbLine, BOOL *pfComplete)
  781. {
  782. // Locals
  783. HRESULT hr = E_INVALIDARG;
  784. // check params
  785. IxpAssert(ppszLine && pcbLine && pfComplete);
  786. if (!ppszLine || !pcbLine || !pfComplete)
  787. goto exit;
  788. // Init
  789. *ppszLine = NULL;
  790. *pcbLine = 0;
  791. // Read the line
  792. hr = m_pSocket->ReadLine(ppszLine, pcbLine);
  793. // Incomplete line - wait for next AE_RECV
  794. if (IXP_E_INCOMPLETE == hr)
  795. {
  796. hr = S_OK;
  797. *pfComplete = FALSE;
  798. goto exit;
  799. }
  800. // Otherwise, if failure...
  801. else if (FAILED(hr))
  802. {
  803. hr = TrapError(IXP_E_SOCKET_READ_ERROR);
  804. goto exit;
  805. }
  806. // Complete
  807. *pfComplete = TRUE;
  808. // Log it
  809. if (m_pLogFile)
  810. m_pLogFile->WriteLog(LOGFILE_RX, (*ppszLine));
  811. // StripCRLF
  812. StripCRLF((*ppszLine), (ULONG *)pcbLine);
  813. exit:
  814. // Done
  815. return hr;
  816. }
  817. // ------------------------------------------------------------------------------------
  818. // CIxpBase::HrSendLine
  819. // ------------------------------------------------------------------------------------
  820. HRESULT CIxpBase::HrSendLine(LPSTR pszLine)
  821. {
  822. // Locals
  823. HRESULT hr=S_OK;
  824. int iSent;
  825. // Check Params
  826. Assert(m_pSocket && pszLine && pszLine[lstrlen(pszLine)-1] == '\n');
  827. // Reset Last Response
  828. SafeMemFree(m_pszResponse);
  829. m_hrResponse = S_OK;
  830. m_uiResponse = 0;
  831. // Add Detail
  832. if (m_fCommandLogging && m_pCallback)
  833. m_pCallback->OnCommand(CMD_SEND, pszLine, S_OK, this);
  834. // Log it
  835. if (m_pLogFile)
  836. m_pLogFile->WriteLog(LOGFILE_TX, pszLine);
  837. // Send it
  838. hr = m_pSocket->SendBytes(pszLine, lstrlen(pszLine), &iSent);
  839. if (FAILED(hr) && hr != IXP_E_WOULD_BLOCK)
  840. {
  841. hr = TrapError(IXP_E_SOCKET_WRITE_ERROR);
  842. goto exit;
  843. }
  844. // Success
  845. hr = S_OK;
  846. exit:
  847. // Done
  848. return hr;
  849. }
  850. // ------------------------------------------------------------------------------------
  851. // CIxpBase::HrSendCommand
  852. // ------------------------------------------------------------------------------------
  853. HRESULT CIxpBase::HrSendCommand(LPSTR pszCommand, LPSTR pszParameters, BOOL fDoBusy)
  854. {
  855. // Locals
  856. HRESULT hr=S_OK;
  857. LPSTR pszLine=NULL;
  858. // check params
  859. if (NULL == pszCommand)
  860. return TrapError(E_INVALIDARG);
  861. // Thread Safety
  862. EnterCriticalSection(&m_cs);
  863. // Busy...
  864. if (fDoBusy)
  865. {
  866. CHECKHR(hr = HrEnterBusy());
  867. }
  868. // Allocate if parameters
  869. if (pszParameters)
  870. {
  871. // Allocate Command Line
  872. DWORD cchSize = (lstrlen(pszCommand) + lstrlen(pszParameters) + 5);
  873. pszLine = PszAlloc(cchSize);
  874. if (NULL == pszLine)
  875. {
  876. hr = TrapError(E_OUTOFMEMORY);
  877. goto exit;
  878. }
  879. // Make Line
  880. wnsprintf(pszLine, cchSize, "%s %s\r\n", pszCommand, pszParameters);
  881. // Send
  882. CHECKHR(hr = HrSendLine(pszLine));
  883. }
  884. // Ohterwise, just send the command
  885. else
  886. {
  887. Assert(pszCommand[lstrlen(pszCommand)-1] == '\n');
  888. CHECKHR(hr = HrSendLine(pszCommand));
  889. }
  890. exit:
  891. // Failure
  892. if (fDoBusy && FAILED(hr))
  893. LeaveBusy();
  894. // Cleanup
  895. SafeMemFree(pszLine);
  896. // Thread Safety
  897. LeaveCriticalSection(&m_cs);
  898. // Done
  899. return hr;
  900. }
  901. // --------------------------------------------------------------------------------
  902. // CIxpBase::GetStatus
  903. // --------------------------------------------------------------------------------
  904. STDMETHODIMP CIxpBase::GetStatus(IXPSTATUS *pCurrentStatus)
  905. {
  906. if (NULL == pCurrentStatus)
  907. return E_INVALIDARG;
  908. *pCurrentStatus = m_status;
  909. return S_OK;
  910. } // GetStatus