Source code of Windows XP (NT5)
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.

1345 lines
36 KiB

  1. #include "private.h"
  2. #include "offline.h"
  3. #undef TF_THISMODULE
  4. #define TF_THISMODULE TF_DIALMON
  5. // prototypes
  6. DIALPROPDATA * InitDialData(void);
  7. //
  8. // uuid for our command target
  9. //
  10. const UUID CGID_ConnCmdGrp = { 0x1dc1fd0, 0xdc49, 0x11d0, {0xaf, 0x95, 0x00, 0xc0, 0x4f, 0xd9, 0x40, 0xbe} };
  11. //
  12. // Registry keys we use to get autodial information
  13. //
  14. // Key name
  15. const TCHAR c_szAutodial[] = TEXT("EnableAutodial");
  16. const TCHAR c_szProxy[] = TEXT("ProxyServer");
  17. const TCHAR c_szUnknown[] = TEXT("<unknown>");
  18. // from schedule.cpp
  19. extern TCHAR szInternetSettings[];
  20. extern TCHAR szProxyEnable[];
  21. // length of general text strings
  22. #define TEXT_LENGTH 200
  23. // our connection agent instance
  24. CConnectionAgent *pAgent = NULL;
  25. //////////////////////////////////////////////////////////////////////////
  26. //////////////////////////////////////////////////////////////////////////
  27. //
  28. // Connection Agent class factory helper
  29. //
  30. //////////////////////////////////////////////////////////////////////////
  31. //////////////////////////////////////////////////////////////////////////
  32. HRESULT CConnectionAgent_CreateInstance(LPUNKNOWN pUnkOuter, IUnknown **ppunk)
  33. {
  34. IUnknown *punk, *punkClient = NULL;
  35. HRESULT hr;
  36. CConnClient *pClient;
  37. *ppunk = NULL;
  38. // create new con client instance
  39. pClient = new CConnClient;
  40. if(NULL == pClient)
  41. return E_OUTOFMEMORY;
  42. // Look for CConnectionAgent in ROT
  43. hr = GetActiveObject(CLSID_ConnectionAgent, NULL, &punk);
  44. if (NULL == punk) {
  45. // Not there - create one
  46. ASSERT(NULL == pAgent);
  47. pAgent = new CConnectionAgent;
  48. if(NULL == pAgent) {
  49. pClient->Release();
  50. return E_OUTOFMEMORY;
  51. }
  52. // Get an IUnknown on new object
  53. hr = pAgent->QueryInterface(IID_IUnknown, (LPVOID *)&punk);
  54. if (FAILED(hr) || NULL == punk) {
  55. SAFERELEASE(pAgent);
  56. pClient->Release();
  57. return E_FAIL;
  58. }
  59. // Register new connection agent
  60. hr = RegisterActiveObject(punk, CLSID_ConnectionAgent,
  61. ACTIVEOBJECT_STRONG, &pAgent->m_dwRegisterHandle);
  62. SAFERELEASE(pAgent);
  63. if (FAILED(hr))
  64. {
  65. DBG_WARN("CConnectionAgentClassFactory RegisterActiveObject failed.");
  66. pClient->Release();
  67. punk->Release();
  68. return hr;
  69. }
  70. DBG("New connection agent object created.");
  71. }
  72. #ifdef DEBUG
  73. else
  74. {
  75. DBG("Using existing connection agent object.");
  76. }
  77. #endif
  78. // Now we have pClient and punk. Tell client who the boss is
  79. hr = pClient->SetConnAgent(punk);
  80. punk->Release();
  81. if(FAILED(hr)) {
  82. pClient->Release();
  83. return E_FAIL;
  84. }
  85. *ppunk = (IOleCommandTarget *)pClient;
  86. return hr;
  87. }
  88. //////////////////////////////////////////////////////////////////////////
  89. //////////////////////////////////////////////////////////////////////////
  90. //
  91. // Helper functions
  92. //
  93. //////////////////////////////////////////////////////////////////////////
  94. //////////////////////////////////////////////////////////////////////////
  95. //////////////////////////////////////////////////////////////////////////
  96. //////////////////////////////////////////////////////////////////////////
  97. //
  98. // Ping Class
  99. //
  100. //////////////////////////////////////////////////////////////////////////
  101. //////////////////////////////////////////////////////////////////////////
  102. //
  103. // helper stuff
  104. //
  105. #define IS_DIGIT(ch) InRange(ch, TEXT('0'), TEXT('9'))
  106. void UnloadICMP(void);
  107. long g_lPingWndReg = 0;
  108. const TCHAR c_szPingWndClass[] = TEXT("PingClass");
  109. #define WM_NAME (WM_USER)
  110. #define WM_STOP (WM_USER+1)
  111. class CPing
  112. {
  113. protected:
  114. HANDLE _hPing;
  115. HANDLE _hAsync;
  116. HWND _hwnd;
  117. UINT _uTimerID;
  118. BOOL _fResult;
  119. UINT _uTimeoutSec;
  120. BOOL EnableAutodial(BOOL fEnable);
  121. public:
  122. CPing();
  123. ~CPing();
  124. BOOL Init(UINT uTimeoutSec);
  125. BOOL PingSite(LPTSTR pszSite);
  126. static LRESULT CPing::WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
  127. };
  128. CPing::CPing()
  129. {
  130. _hPing = INVALID_HANDLE_VALUE;
  131. _hwnd = NULL;
  132. _hAsync = NULL;
  133. _uTimeoutSec = 10;
  134. }
  135. CPing::~CPing()
  136. {
  137. if(_hwnd)
  138. DestroyWindow(_hwnd);
  139. if(_hPing)
  140. IcmpCloseHandle(_hPing);
  141. UnloadICMP();
  142. }
  143. BOOL
  144. CPing::Init(UINT uTimeoutSec)
  145. {
  146. // save timeout
  147. _uTimeoutSec = uTimeoutSec;
  148. // load ICMP.DLL and get a ping handle
  149. _hPing = IcmpCreateFile();
  150. if(INVALID_HANDLE_VALUE == _hPing)
  151. return FALSE;
  152. // register window class if necessary
  153. if(!g_lPingWndReg) {
  154. g_lPingWndReg++;
  155. WNDCLASS wc;
  156. wc.style = 0;
  157. wc.lpfnWndProc = CPing::WndProc;
  158. wc.cbClsExtra = 0;
  159. wc.cbWndExtra = 0;
  160. wc.hInstance = g_hInst;
  161. wc.hIcon = NULL;
  162. wc.hCursor = NULL;
  163. wc.hbrBackground = (HBRUSH)NULL;
  164. wc.lpszMenuName = NULL;
  165. wc.lpszClassName = c_szPingWndClass;
  166. RegisterClass(&wc);
  167. }
  168. if(NULL == _hwnd)
  169. _hwnd = CreateWindow(c_szPingWndClass, NULL, WS_OVERLAPPED,
  170. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  171. NULL, NULL, g_hInst, (LPVOID)this);
  172. if(NULL == _hwnd)
  173. return FALSE;
  174. return TRUE;
  175. }
  176. LRESULT
  177. CPing::WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  178. {
  179. CPing *pping = (CPing *)GetWindowLong(hWnd, GWL_USERDATA);
  180. LPCREATESTRUCT pcs = NULL;
  181. switch(Msg) {
  182. case WM_CREATE:
  183. pcs = (LPCREATESTRUCT)lParam;
  184. SetWindowLong(hWnd, GWL_USERDATA, ((LONG) (pcs->lpCreateParams)));
  185. break;
  186. case WM_NAME:
  187. // gethostbyname completed
  188. if(0 == WSAGETASYNCERROR(lParam))
  189. pping->_fResult = TRUE;
  190. // fall through to WM_TIMER
  191. case WM_TIMER:
  192. // we ran out of time
  193. PostMessage(hWnd, WM_STOP, 0, 0);
  194. break;
  195. default:
  196. return DefWindowProc(hWnd, Msg, wParam, lParam);
  197. }
  198. return 0;
  199. }
  200. BOOL
  201. CPing::EnableAutodial(BOOL fEnable)
  202. {
  203. DWORD dwNewState = 0, dwOldState = 0, dwSize = sizeof(DWORD);
  204. BOOL fOldEnable = FALSE;
  205. if(g_fIsWinNT) {
  206. //
  207. // In NT land, 1 means disabled, 0 means enabled
  208. //
  209. // Get WinNT autodial state
  210. _RasGetAutodialParam(RASADP_LoginSessionDisable, &dwOldState, &dwSize);
  211. if(0 == dwOldState) fOldEnable = TRUE;
  212. // set new state
  213. if(FALSE == fEnable) dwNewState = 1;
  214. _RasSetAutodialParam(RASADP_LoginSessionDisable, &dwNewState, sizeof(DWORD));
  215. } else {
  216. //
  217. // In Win95 land, 1 means enabled, 0 means disabled
  218. //
  219. // Get Win95 autodial state
  220. if(!ReadRegValue(HKEY_CURRENT_USER, szInternetSettings, c_szAutodial,
  221. &dwOldState, sizeof(DWORD)))
  222. dwOldState = 0;
  223. if(dwOldState) fOldEnable = TRUE;
  224. // set new state
  225. if(fEnable) dwNewState = 1;
  226. WriteRegValue(HKEY_CURRENT_USER, szInternetSettings, c_szAutodial,
  227. &dwNewState, sizeof(DWORD), REG_BINARY);
  228. }
  229. return fOldEnable;
  230. }
  231. BOOL
  232. CPing::PingSite(LPTSTR pszHost)
  233. {
  234. IPAddr ipAddress = INADDR_NONE;
  235. DWORD dwPingSend = 0xdeadbeef, dwCount;
  236. WSADATA wsaData;
  237. BOOL fOldState;
  238. TCHAR pszWork[1024], *pEnd;
  239. BYTE pGetHostBuff[MAXGETHOSTSTRUCT];
  240. int iErr;
  241. // assume failure
  242. _fResult = FALSE;
  243. if(INVALID_HANDLE_VALUE == _hPing) {
  244. DBG("CPing::PingSite no ICMP handle");
  245. return FALSE;
  246. }
  247. // fire up winsock
  248. if(iErr = WSAStartup(0x0101, &wsaData)) {
  249. TraceMsg(TF_THISMODULE,"CPing::PingSite WSAStartup failed, iErr=%d", iErr);
  250. return FALSE;
  251. }
  252. if(IS_DIGIT(*pszHost)) {
  253. // try to convert ip address
  254. ipAddress = inet_addr(pszHost);
  255. }
  256. // turn off autodial
  257. fOldState = EnableAutodial(FALSE);
  258. if(INADDR_NONE == ipAddress) {
  259. // strip port (if any) from host name
  260. lstrcpyn(pszWork, pszHost, ARRAYSIZE(pszWork));
  261. pEnd = StrChr(pszWork, TEXT(':'));
  262. if(pEnd)
  263. *pEnd = 0;
  264. // start async gethostbyname
  265. _uTimerID = SetTimer(_hwnd, 1, _uTimeoutSec * 1000, NULL);
  266. _hAsync = WSAAsyncGetHostByName(_hwnd, WM_NAME, pszWork,
  267. (char *)pGetHostBuff, MAXGETHOSTSTRUCT);
  268. if(_hAsync) {
  269. // operation started... wait for completion or time out
  270. MSG msg;
  271. while(1) {
  272. GetMessage(&msg, _hwnd, 0, 0);
  273. if(msg.message == WM_STOP)
  274. break;
  275. TranslateMessage(&msg);
  276. DispatchMessage(&msg);
  277. } /* while */
  278. if(_fResult) {
  279. // it worked, snarf address
  280. struct hostent *phe;
  281. phe = (struct hostent *)pGetHostBuff;
  282. memcpy(&ipAddress, phe->h_addr, sizeof(IPAddr));
  283. } else {
  284. // If we timed out, clean up pending request
  285. WSACancelAsyncRequest(_hAsync);
  286. }
  287. #ifdef DEBUG
  288. } else {
  289. // operation failed to start
  290. iErr = WSAGetLastError();
  291. TraceMsg(TF_THISMODULE, "CPing::PingSite WSAAsyncGetHostByName failed, error=%d", iErr);
  292. #endif
  293. }
  294. // kill the timer
  295. if(_uTimerID) {
  296. KillTimer(_hwnd, _uTimerID);
  297. _uTimerID = 0;
  298. }
  299. }
  300. // assume the ping will fail
  301. _fResult = FALSE;
  302. if(INADDR_NONE != ipAddress) {
  303. // try to ping that address
  304. dwCount = IcmpSendEcho(
  305. _hPing,
  306. ipAddress,
  307. &dwPingSend,
  308. sizeof(DWORD),
  309. NULL,
  310. pszWork,
  311. sizeof(pszWork),
  312. _uTimeoutSec * 1000);
  313. if(dwCount) {
  314. // ping succeeded!!
  315. _fResult = TRUE;
  316. #ifdef DEBUG
  317. } else {
  318. // didn't work - spew
  319. iErr = GetLastError();
  320. TraceMsg(TF_THISMODULE, "CPing::PingSite IcmpSendEcho failed, error=%x", iErr);
  321. #endif
  322. }
  323. }
  324. // restore autodial
  325. EnableAutodial(fOldState);
  326. #ifdef DEBUG
  327. if(_fResult)
  328. TraceMsg(TF_THISMODULE, "CPing::PingSite ping <%s> success", pszHost);
  329. else
  330. TraceMsg(TF_THISMODULE, "CPing::PingSite ping <%s> FAILURE", pszHost);
  331. #endif
  332. WSACleanup();
  333. return _fResult;
  334. }
  335. //
  336. // PingProxy - exported function to decide if the proxy is available or not
  337. //
  338. BOOL PingProxy(UINT uTimeoutSec)
  339. {
  340. BOOL fRet = FALSE;
  341. TCHAR pszProxy[TEXT_LENGTH], *pszHttp, *pszSemi;
  342. DWORD dwValue;
  343. // check for proxy enabled
  344. if(ReadRegValue(HKEY_CURRENT_USER, szInternetSettings, szProxyEnable,
  345. &dwValue, sizeof(DWORD))) {
  346. if(0 == dwValue)
  347. return FALSE;
  348. }
  349. // proxy is enabled in registry. Ping it to see if it's around.
  350. if(ReadRegValue(HKEY_CURRENT_USER, szInternetSettings, c_szProxy,
  351. pszProxy, TEXT_LENGTH)) {
  352. // if there's an '=' in the proxy string, we'll look for the http= proxy
  353. if(NULL != StrChr(pszProxy, '=')) {
  354. pszHttp = StrStrI(pszProxy, TEXT("http="));
  355. if(NULL == pszHttp)
  356. // don't understand proxy string
  357. return FALSE;
  358. pszHttp += 5; // 5 chars in "http="
  359. // remove following entries - they're separated by ;
  360. pszSemi = StrChr(pszHttp, ';');
  361. if(pszSemi)
  362. *pszSemi = 0;
  363. } else {
  364. pszHttp = pszProxy;
  365. }
  366. // got a proxy, crack the host name out of it
  367. TCHAR *pszPingSite;
  368. URL_COMPONENTS comp;
  369. ZeroMemory(&comp, sizeof(comp));
  370. comp.dwStructSize = sizeof(comp);
  371. comp.dwHostNameLength = 1;
  372. if(InternetCrackUrlA(pszHttp, 0, 0, &comp) && (comp.nScheme != INTERNET_SCHEME_UNKNOWN)) {
  373. pszPingSite = comp.lpszHostName;
  374. pszPingSite[comp.dwHostNameLength] = 0;
  375. } else {
  376. pszPingSite = pszHttp;
  377. }
  378. // ping it
  379. CPing ping;
  380. if(ping.Init(uTimeoutSec))
  381. fRet = ping.PingSite(pszPingSite);
  382. }
  383. return fRet;
  384. }
  385. //////////////////////////////////////////////////////////////////////////
  386. //////////////////////////////////////////////////////////////////////////
  387. //
  388. // Connection Client object
  389. //
  390. //////////////////////////////////////////////////////////////////////////
  391. //////////////////////////////////////////////////////////////////////////
  392. //
  393. // Constructor / Destructor
  394. //
  395. CConnClient::CConnClient()
  396. {
  397. m_cRef = 1;
  398. m_poctAgent = NULL;
  399. m_pReport = NULL;
  400. m_State = CLIENT_NEW;
  401. m_bstrURL = NULL;
  402. }
  403. //////////////////////////////////////////////////////////////////////////
  404. //
  405. // IUnknown members
  406. //
  407. STDMETHODIMP CConnClient::QueryInterface(REFIID riid, void ** ppv)
  408. {
  409. *ppv=NULL;
  410. // Validate requested interface
  411. if ((IID_IUnknown == riid) ||
  412. (IID_INotificationSink == riid))
  413. {
  414. *ppv=(INotificationSink*)this;
  415. } else if(IID_IOleCommandTarget == riid) {
  416. *ppv=(IOleCommandTarget*)this;
  417. } else {
  418. return E_NOINTERFACE;
  419. }
  420. ((LPUNKNOWN)*ppv)->AddRef();
  421. return NOERROR;
  422. }
  423. STDMETHODIMP_(ULONG) CConnClient::AddRef(void)
  424. {
  425. TraceMsg(TF_THISMODULE, "CConnClient::Addref (%08x) m_cRef=%d", this, m_cRef+1);
  426. return ++m_cRef;
  427. }
  428. STDMETHODIMP_(ULONG) CConnClient::Release(void)
  429. {
  430. TraceMsg(TF_THISMODULE, "CConnClient::Release (%08x) m_cRef=%d", this, m_cRef-1);
  431. if( 0L != --m_cRef )
  432. return m_cRef;
  433. DBG("CConClient::Release Bye Bye");
  434. // Make sure we're disconnected
  435. Disconnect();
  436. m_poctAgent->Release();
  437. if(m_bstrURL)
  438. SysFreeString(m_bstrURL);
  439. delete this;
  440. return 0L;
  441. }
  442. //////////////////////////////////////////////////////////////////////////
  443. //
  444. // CConClient helper functions
  445. //
  446. HRESULT CConnClient::SetConnAgent(IUnknown *punk)
  447. {
  448. return punk->QueryInterface(IID_IOleCommandTarget, (void **)&m_poctAgent);
  449. }
  450. HRESULT CConnClient::Connect()
  451. {
  452. HRESULT hr;
  453. VARIANTARG vin, vout;
  454. m_State = CLIENT_CONNECTING;
  455. // tell agent we want to connect
  456. vin.vt = VT_UNKNOWN;
  457. vin.punkVal = (IOleCommandTarget *)this;
  458. VariantInit(&vout);
  459. hr = m_poctAgent->Exec(&CGID_ConnCmdGrp, AGENT_CONNECT, 0, &vin, &vout);
  460. if(SUCCEEDED(hr)) {
  461. ASSERT(vout.vt == VT_I4);
  462. m_iCookie = vout.lVal;
  463. }
  464. return hr;
  465. }
  466. HRESULT CConnClient::Disconnect()
  467. {
  468. HRESULT hr;
  469. VARIANTARG vin;
  470. if(CLIENT_DISCONNECTED == m_State)
  471. return S_OK;
  472. m_State = CLIENT_DISCONNECTED;
  473. // tell agent we want to disconnect
  474. vin.vt = VT_I4;
  475. vin.ulVal = m_iCookie;
  476. hr = m_poctAgent->Exec(&CGID_ConnCmdGrp, AGENT_DISCONNECT, 0, &vin, NULL);
  477. // done with report pointer
  478. SAFERELEASE(m_pReport);
  479. return hr;
  480. }
  481. //////////////////////////////////////////////////////////////////////////
  482. //////////////////////////////////////////////////////////////////////////
  483. //
  484. // INotificationSink members
  485. //
  486. STDMETHODIMP CConnClient::OnNotification(
  487. LPNOTIFICATION pNotification,
  488. LPNOTIFICATIONREPORT pNotificationReport,
  489. DWORD dwReserved
  490. )
  491. {
  492. NOTIFICATIONTYPE nt;
  493. HRESULT hr = S_OK;
  494. hr = pNotification->GetNotificationInfo(&nt, NULL,NULL,NULL,0);
  495. if(FAILED(hr)) {
  496. DBG_WARN("CConnClient::OnNotification failed to get not type!");
  497. return E_INVALIDARG;
  498. }
  499. if(IsEqualGUID(nt, NOTIFICATIONTYPE_AGENT_START)) {
  500. DBG("CConnClient::OnNotification AGENT_START");
  501. if(CLIENT_NEW == m_State) {
  502. // Must have a report pointer!
  503. if(NULL == pNotificationReport) {
  504. DBG("CConnClient::OnNotification no report on START!");
  505. return E_UNEXPECTED;
  506. }
  507. // save report pointer
  508. TraceMsg(TF_THISMODULE, "CConClient::OnNotification (%08x) addreffing report pointer", this);
  509. m_pReport = pNotificationReport;
  510. m_pReport->AddRef();
  511. // get the URL
  512. hr = ReadBSTR(pNotification, NULL, c_szPropURL, &m_bstrURL);
  513. // convert to ansi and log url connection request
  514. TCHAR pszURL[INTERNET_MAX_URL_LENGTH];
  515. MyOleStrToStrN(pszURL, INTERNET_MAX_URL_LENGTH, m_bstrURL);
  516. LogEvent("Connecting for <%s>", pszURL);
  517. // Tell agent to connect
  518. Connect();
  519. } else {
  520. DBG("CConnClient::OnNotification unexpected connect");
  521. return E_UNEXPECTED;
  522. }
  523. } else if(IsEqualGUID(nt, NOTIFICATIONTYPE_TASKS_COMPLETED)) {
  524. DBG("CConnClient::OnNotification TASKS_COMPLETED");
  525. // convert url to ansi
  526. TCHAR pszURL[INTERNET_MAX_URL_LENGTH];
  527. MyOleStrToStrN(pszURL, INTERNET_MAX_URL_LENGTH, m_bstrURL);
  528. switch(m_State) {
  529. case CLIENT_CONNECTING:
  530. m_State = CLIENT_ABORT;
  531. // log connection abort
  532. LogEvent("Aborting connection for <%s>", pszURL);
  533. break;
  534. case CLIENT_CONNECTED:
  535. // log disconnect
  536. LogEvent("Disconnecting for <%s>", pszURL);
  537. Disconnect();
  538. break;
  539. default:
  540. DBG("CConnClient::OnNotification unexpected disconnect");
  541. return E_UNEXPECTED;
  542. }
  543. } else {
  544. DBG("CConnClient::OnNotification unknown type");
  545. }
  546. return S_OK;
  547. }
  548. //////////////////////////////////////////////////////////////////////////
  549. //////////////////////////////////////////////////////////////////////////
  550. //
  551. // IOleCommandTarget members
  552. //
  553. STDMETHODIMP CConnClient::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
  554. OLECMD prgCmds[], OLECMDTEXT *pCmdText)
  555. {
  556. if (IsEqualGUID(*pguidCmdGroup, CGID_ConnCmdGrp)) {
  557. return S_OK;
  558. }
  559. return OLECMDERR_E_UNKNOWNGROUP;
  560. }
  561. STDMETHODIMP CConnClient::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
  562. DWORD nCmdexecopt, VARIANTARG *pvaIn,
  563. VARIANTARG *pvaOut)
  564. {
  565. HRESULT hr = E_NOTIMPL;
  566. if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_ConnCmdGrp))
  567. {
  568. switch(nCmdID) {
  569. case AGENT_NOTIFY:
  570. if(VT_ERROR == pvaIn->vt) {
  571. hr = DeliverProgressReport(pvaIn->scode, NULL);
  572. } else {
  573. hr = E_INVALIDARG;
  574. }
  575. break;
  576. }
  577. }
  578. return hr;
  579. }
  580. //////////////////////////////////////////////////////////////////////////
  581. //
  582. // Other methods
  583. //
  584. HRESULT CConnClient::DeliverProgressReport(SCODE scode, BSTR bstrErrorText)
  585. {
  586. HRESULT hr = S_OK;
  587. INotificationMgr *pMgr;
  588. INotification *pStatus;
  589. switch(m_State) {
  590. case CLIENT_CONNECTING:
  591. // Get Notification manager
  592. hr = CoCreateInstance(CLSID_StdNotificationMgr, NULL,
  593. CLSCTX_INPROC_SERVER, IID_INotificationMgr, (void**)&pMgr);
  594. if(FAILED(hr))
  595. return hr;
  596. // create notification to deliver
  597. hr = pMgr->CreateNotification(NOTIFICATIONTYPE_PROGRESS_REPORT,
  598. (NOTIFICATIONFLAGS)0, NULL, &pStatus, 0);
  599. pMgr->Release();
  600. if(FAILED(hr))
  601. return hr;
  602. // stick result and string in progress report
  603. // WriteOLESTR(pStatus, NULL, c_szPropStatusString, bstrErrorText);
  604. WriteSCODE(pStatus, NULL, c_szPropStatusCode, scode);
  605. // deliver notification
  606. hr = m_pReport->DeliverUpdate(pStatus, 0, 0);
  607. pStatus->Release();
  608. if(SUCCEEDED(scode)) {
  609. m_State = CLIENT_CONNECTED;
  610. } else {
  611. Disconnect();
  612. }
  613. break;
  614. case CLIENT_ABORT:
  615. Disconnect();
  616. break;
  617. }
  618. return hr;
  619. }
  620. //////////////////////////////////////////////////////////////////////////
  621. //////////////////////////////////////////////////////////////////////////
  622. //
  623. // Connection agent
  624. //
  625. //////////////////////////////////////////////////////////////////////////
  626. //////////////////////////////////////////////////////////////////////////
  627. //
  628. // Constructor and destructor
  629. //
  630. CConnectionAgent::CConnectionAgent()
  631. {
  632. m_pData = NULL;
  633. m_cRef = 1;
  634. m_dwRegisterHandle = 0;
  635. m_lConnectionCount = 0;
  636. m_dwFlags = 0;
  637. m_hdpaClient = NULL;
  638. // Get the notification manager
  639. m_pMgr = NULL;
  640. CoCreateInstance(CLSID_StdNotificationMgr, NULL,
  641. CLSCTX_INPROC_SERVER, IID_INotificationMgr, (void**)&m_pMgr);
  642. }
  643. CConnectionAgent::~CConnectionAgent()
  644. {
  645. SAFERELEASE(m_pMgr);
  646. SAFELOCALFREE(m_pData);
  647. if(IsFlagSet(m_dwFlags, CA_LOADED_RAS))
  648. UnloadRasDLL();
  649. }
  650. //
  651. // Clean - clean up strong lock and ref count
  652. //
  653. void
  654. CConnectionAgent::Clean(void)
  655. {
  656. DWORD dwHandle = m_dwRegisterHandle;
  657. int iCurReport, i;
  658. CLIENTINFO *pClient;
  659. // don't do anything if there are outstanding connections
  660. if(m_lConnectionCount)
  661. return;
  662. // clean up client dpa
  663. if(m_hdpaClient) {
  664. iCurReport = DPA_GetPtrCount(m_hdpaClient);
  665. for(i=0; i<iCurReport; i++) {
  666. pClient = (CLIENTINFO *)(DPA_GetPtr(m_hdpaClient, i));
  667. if(pClient)
  668. delete pClient;
  669. }
  670. DPA_Destroy(m_hdpaClient);
  671. m_hdpaClient = NULL;
  672. }
  673. // release our strong registration
  674. DBG("CConnectionAgent::Clean revoking connection agent object");
  675. m_dwRegisterHandle = 0;
  676. RevokeActiveObject(dwHandle, NULL);
  677. }
  678. //////////////////////////////////////////////////////////////////////////
  679. //////////////////////////////////////////////////////////////////////////
  680. //
  681. // Connect - entry point to connect
  682. //
  683. void
  684. CConnectionAgent::Connect(void)
  685. {
  686. BOOL fDone = FALSE;
  687. TCHAR pszText[TEXT_LENGTH];
  688. //
  689. // increment connection count
  690. //
  691. m_lConnectionCount ++;
  692. TraceMsg(TF_THISMODULE, "CConnectionAgent::Connect ref count now %d", m_lConnectionCount);
  693. //
  694. // Store offline state if we haven't already and go online
  695. //
  696. if(FALSE == IsFlagSet(m_dwFlags, CA_OFFLINE_STATE_READ)) {
  697. if(IsGlobalOffline())
  698. SetFlag(m_dwFlags, CA_OFFLINE);
  699. // make sure we're online
  700. SetGlobalOffline(FALSE);
  701. SetFlag(m_dwFlags, CA_OFFLINE_STATE_READ);
  702. }
  703. //
  704. // check for pending dialup connection
  705. //
  706. if(IsFlagSet(m_dwFlags, CA_CONNECTING_NOW)) {
  707. // already working on a connection
  708. DBG("CConnectionAgent::Connect already trying to connect");
  709. return;
  710. }
  711. //
  712. // check to see if we can dial to get a connection
  713. //
  714. if(FALSE == IsDialPossible()) {
  715. //
  716. // can't dial - better have a direct connection
  717. //
  718. DBG("CConnectionAgent::Connect guessing connected");
  719. if(!MLLoadString(IDS_DIAL_DIRECT, pszText, TEXT_LENGTH))
  720. lstrcpy(pszText, "direct");
  721. Notify(S_OK, pszText);
  722. return;
  723. }
  724. //
  725. // check for an existing dialup connection
  726. //
  727. if(FALSE == IsFlagSet(m_dwFlags, CA_LOADED_RAS)) {
  728. SetFlag(m_dwFlags, CA_LOADED_RAS);
  729. LoadRasDLL();
  730. }
  731. if(IsDialExisting()) {
  732. DBG("CConnectionAgent::Connect already connected");
  733. if(!MLLoadString(IDS_DIAL_ALREADY_CONNECTED, pszText, TEXT_LENGTH))
  734. lstrcpy(pszText, "success");
  735. Notify(S_OK, pszText);
  736. return;
  737. }
  738. #ifdef COOL_MODEM_ACTION
  739. // since we assume connected for direct connect, no proxy check is
  740. // necessary. If this check is put in, cool behavior results: It uses
  741. // the proxy server if it can find it, otherwise it autodials.
  742. // Autodial needs to be made consistant with this before it gets turned
  743. // on
  744. //
  745. // check for a proxy connection
  746. //
  747. if(PingProxy(5)) {
  748. // Dial is possible but proxy is available! Turn off autodial and
  749. // flag to turn it back on when we're done
  750. CPing::EnableAutodial(FALSE);
  751. SetFlag(m_dwFlags, CA_AUTODIAL_OFF);
  752. // Using proxy
  753. DBG("CConnectionAgent::Connect using proxy");
  754. if(!MLLoadString(IDS_DIAL_PROXY, pszText, TEXT_LENGTH))
  755. lstrcpy(pszText, "proxy");
  756. Notify(S_OK, pszText);
  757. return;
  758. }
  759. #endif
  760. /////////////////////////////////////////////////////////////////////
  761. /////////////////////////////////////////////////////////////////////
  762. //
  763. // Ensure we can dial without user intervention
  764. //
  765. BOOL fContinue = TRUE;
  766. if(SHRestricted2W(REST_NoUnattendedDialing, NULL, 0))
  767. // dialing restricted
  768. fContinue = FALSE;
  769. //
  770. // No existing connection but we can dial. do it now.
  771. //
  772. SetFlag(m_dwFlags, CA_CONNECTING_NOW);
  773. DWORD dwRetCode;
  774. if(fContinue)
  775. {
  776. dwRetCode = ERROR_SUCCESS;
  777. if(!InternetAutodial((INTERNET_AUTODIAL_FORCE_ONLINE |
  778. INTERNET_AUTODIAL_FORCE_UNATTENDED |
  779. INTERNET_AUTODIAL_FAILIFSECURITYCHECK), 0))
  780. {
  781. dwRetCode = GetLastError();
  782. }
  783. }
  784. if (fContinue && (ERROR_SUCCESS == dwRetCode)) {
  785. // successful connection made
  786. SetFlag(m_dwFlags, CA_DIALED);
  787. if(!MLLoadString(IDS_DIAL_SUCCESS, pszText, TEXT_LENGTH))
  788. lstrcpy(pszText, "success");
  789. Notify(S_OK, pszText);
  790. } else {
  791. //UINT uID;
  792. HRESULT hrDialResult;
  793. // unable to dial
  794. if(ERROR_INTERNET_FAILED_DUETOSECURITYCHECK == dwRetCode)
  795. {
  796. hrDialResult = E_ABORT;
  797. // uID = IDS_STRING_E_SECURITYCHECK; not needed - since MLLoadString below is commented out
  798. }
  799. else
  800. {
  801. hrDialResult = E_INVALIDARG;
  802. // uID = IDS_STRING_E_CONFIG;not needed - since MLLoadString below is commented out
  803. }
  804. // if(!MLLoadString(uID, pszText, TEXT_LENGTH)) // Don't bother : This is ignored anyway
  805. lstrcpy(pszText, "Connection Not Made");
  806. Notify(hrDialResult, pszText);
  807. }
  808. ClearFlag(m_dwFlags, CA_CONNECTING_NOW);
  809. }
  810. //
  811. // Disconnect - entry point to disconnect
  812. //
  813. void
  814. CConnectionAgent::Disconnect(void)
  815. {
  816. // If we're the last connection, hang up
  817. m_lConnectionCount --;
  818. TraceMsg(TF_THISMODULE, "CConnectionAgent::Disconnect ref count now %d", m_lConnectionCount);
  819. if(0 == m_lConnectionCount) {
  820. // If we dialed this connection, hang it up
  821. if(IsFlagSet(m_dwFlags, CA_DIALED)) {
  822. LogEvent(TEXT("EVT: Hanging up"));
  823. InternetAutodialHangup(0);
  824. }
  825. #ifdef COOL_MODEM_ACTION
  826. if(IsFlagSet(m_dwFlags, CA_AUTODIAL_OFF)) {
  827. // we turned autodial off - turn it back on
  828. CPing::EnableAutodial(TRUE);
  829. // tell wininet we've changed it
  830. InternetSetOption(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
  831. }
  832. #endif
  833. // restore original offline state
  834. SetGlobalOffline(IsFlagSet(m_dwFlags, CA_OFFLINE));
  835. // revoke our object
  836. Clean();
  837. }
  838. }
  839. //////////////////////////////////////////////////////////////////////////
  840. //////////////////////////////////////////////////////////////////////////
  841. //
  842. // IsDialPossible - search around and make sure all necessary info
  843. // is available to connect. If fQuiet is false, may bring up dialogs
  844. // to get necessary info
  845. //
  846. BOOL
  847. CConnectionAgent::IsDialPossible()
  848. {
  849. BOOL fPossible = TRUE;
  850. // Refresh data in case properties has been up and changed it
  851. if(m_pData)
  852. MemFree(m_pData);
  853. m_pData = InitDialData();
  854. if(NULL == m_pData)
  855. return FALSE;
  856. if(FALSE == m_pData->fEnabled)
  857. // not enabled
  858. fPossible = FALSE;
  859. if(!m_pData->pszConnection[0])
  860. // no connection
  861. fPossible = FALSE;
  862. return fPossible;
  863. }
  864. //
  865. // IsDialExisting - check to see if there's an existing dialup connection
  866. // that we didn't do
  867. //
  868. #define MAX_CONNECTION 8
  869. BOOL
  870. CConnectionAgent::IsDialExisting(void)
  871. {
  872. TCHAR pszConn[RAS_MaxEntryName+1];
  873. RASCONN pRasCon[MAX_CONNECTION];
  874. DWORD dwSize = MAX_CONNECTION * sizeof(RASCONN), dwConn, dwCur;
  875. HKEY hkeyRoot = HKEY_CURRENT_USER;
  876. // read internet connectoid from registry
  877. if(!ReadRegValue(hkeyRoot, c_szRASKey, c_szProfile, pszConn,
  878. RAS_MaxEntryName+1)) {
  879. DBG("CConnectionAgent::IsDialExisting unable to read internet connectoid");
  880. return FALSE;
  881. }
  882. // have Ras enumerate existing connections
  883. pRasCon[0].dwSize = sizeof(RASCONN);
  884. if(_RasEnumConnections(pRasCon, &dwSize, &dwConn)) {
  885. DBG("CConnectionAgent::IsDialExisting RasEnumConnections failed");
  886. return FALSE;
  887. }
  888. // do any of them match our internet connectoid?
  889. for(dwCur=0; dwCur<dwConn; dwCur++) {
  890. if(0 == lstrcmp(pszConn, pRasCon[dwCur].szEntryName))
  891. return TRUE;
  892. }
  893. return FALSE;
  894. }
  895. //////////////////////////////////////////////////////////////////////////
  896. //////////////////////////////////////////////////////////////////////////
  897. //
  898. // IUnknown members
  899. //
  900. STDMETHODIMP CConnectionAgent::QueryInterface(REFIID riid, void ** ppv)
  901. {
  902. *ppv=NULL;
  903. // Validate requested interface
  904. if ((IID_IUnknown == riid) ||
  905. (IID_IOleCommandTarget == riid))
  906. {
  907. *ppv=(IOleCommandTarget*)this;
  908. } else {
  909. return E_NOINTERFACE;
  910. }
  911. ((LPUNKNOWN)*ppv)->AddRef();
  912. return NOERROR;
  913. }
  914. STDMETHODIMP_(ULONG) CConnectionAgent::AddRef(void)
  915. {
  916. TraceMsg(TF_THISMODULE, "CConnectionAgent::Addref m_cRef=%d", m_cRef+1);
  917. return ++m_cRef;
  918. }
  919. STDMETHODIMP_(ULONG) CConnectionAgent::Release(void)
  920. {
  921. TraceMsg(TF_THISMODULE, "CConnectionAgent::Release m_cRef=%d", m_cRef-1);
  922. if( 0L != --m_cRef )
  923. return m_cRef;
  924. DBG("CConnectionAgent::Release Bye Bye");
  925. delete this;
  926. return 0L;
  927. }
  928. //////////////////////////////////////////////////////////////////////////
  929. //////////////////////////////////////////////////////////////////////////
  930. //
  931. // IOleCommandTarget members
  932. //
  933. STDMETHODIMP CConnectionAgent::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
  934. OLECMD prgCmds[], OLECMDTEXT *pCmdText)
  935. {
  936. if (IsEqualGUID(*pguidCmdGroup, CGID_ConnCmdGrp))
  937. {
  938. // We like connection agent commands
  939. return S_OK;
  940. }
  941. return OLECMDERR_E_UNKNOWNGROUP;
  942. }
  943. STDMETHODIMP CConnectionAgent::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
  944. DWORD nCmdexecopt, VARIANTARG *pvaIn,
  945. VARIANTARG *pvaOut)
  946. {
  947. HRESULT hr;
  948. CLIENTINFO *pInfo;
  949. int iIndex;
  950. if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_ConnCmdGrp))
  951. {
  952. switch(nCmdID) {
  953. case AGENT_CONNECT:
  954. // validate input arguments
  955. if(VT_UNKNOWN != pvaIn->vt || NULL == pvaOut)
  956. return E_INVALIDARG;
  957. // create dpa if necessary
  958. if(NULL == m_hdpaClient)
  959. m_hdpaClient = DPA_Create(0);
  960. if(NULL == m_hdpaClient)
  961. return E_OUTOFMEMORY;
  962. // create and initialize new clientinfo struct
  963. pInfo = new CLIENTINFO;
  964. if(NULL == pInfo)
  965. return E_OUTOFMEMORY;
  966. pInfo->dwFlags = 0;
  967. hr = pvaIn->punkVal->QueryInterface(IID_IOleCommandTarget, (void **)&pInfo->poctClient);
  968. if(FAILED(hr))
  969. return hr;
  970. // insert struct into dpa and return index
  971. iIndex = DPA_InsertPtr(m_hdpaClient, DPA_APPEND, pInfo);
  972. if(iIndex < 0) {
  973. delete pInfo;
  974. return E_OUTOFMEMORY;
  975. } else {
  976. pvaOut->vt = VT_I4;
  977. pvaOut->ulVal = iIndex;
  978. }
  979. // connect
  980. Connect();
  981. return S_OK;
  982. case AGENT_DISCONNECT:
  983. // validate input parameters
  984. if(VT_I4 != pvaIn->vt)
  985. return E_INVALIDARG;
  986. // mark client record as disconnected
  987. pInfo = (CLIENTINFO *)DPA_GetPtr(m_hdpaClient, pvaIn->lVal);
  988. if(pInfo) {
  989. pInfo->dwFlags |= CLIENT_DISCONNECT;
  990. SAFERELEASE(pInfo->poctClient);
  991. }
  992. // disconnect
  993. Disconnect();
  994. return S_OK;
  995. }
  996. }
  997. return E_NOTIMPL;
  998. }
  999. //////////////////////////////////////////////////////////////////////////
  1000. //////////////////////////////////////////////////////////////////////////
  1001. //
  1002. // Notify all waiting agents of success or failure of dial attempt
  1003. //
  1004. void CConnectionAgent::Notify(HRESULT hrDialResult, TCHAR *pszErrorText)
  1005. {
  1006. CLIENTINFO *pClient;
  1007. int i, iCurReport;
  1008. //WCHAR pwszStatus[TEXT_LENGTH];
  1009. VARIANTARG vin;
  1010. // We're done connecting
  1011. ClearFlag(m_dwFlags, CA_CONNECTING_NOW);
  1012. // Create the notifications to send
  1013. if(S_OK == hrDialResult) {
  1014. DBG("CConnectionAgent::Notify sending ONLINE");
  1015. LogEvent(TEXT("EVT: Successful connection"));
  1016. } else {
  1017. DBG("CConnectionAgent::Notify sending OFFLINE");
  1018. LogEvent(TEXT("EVT: Unsuccessful connection - hr=%08x"), hrDialResult);
  1019. }
  1020. // convert string to bstr
  1021. // MyStrToOleStrN(pwszStatus, TEXT_LENGTH, pszErrorText);
  1022. // build exec paramaters
  1023. vin.vt = VT_ERROR;
  1024. vin.scode = hrDialResult;
  1025. // Send it to all the clients
  1026. iCurReport = DPA_GetPtrCount(m_hdpaClient);
  1027. for(i=0; i<iCurReport; i++) {
  1028. pClient = (CLIENTINFO *)(DPA_GetPtr(m_hdpaClient, i));
  1029. if(pClient && 0 == pClient->dwFlags) {
  1030. pClient->poctClient->Exec(&CGID_ConnCmdGrp, AGENT_NOTIFY, 0,
  1031. &vin, NULL);
  1032. // This can get blown away out from under us.
  1033. if (m_hdpaClient)
  1034. {
  1035. pClient->dwFlags |= CLIENT_NOTIFIED;
  1036. SAFERELEASE(pClient->poctClient);
  1037. }
  1038. }
  1039. }
  1040. // if we're disconnected, clean ourselves up
  1041. Clean();
  1042. }
  1043. BOOL
  1044. GetLogonInfo(DIALPROPDATA *pData)
  1045. {
  1046. RASDIALPARAMS dp;
  1047. DWORD dwRes;
  1048. BOOL fPassword = FALSE;
  1049. // initially set name/password/domain to null
  1050. pData->pszUsername[0] = 0;
  1051. pData->pszPassword[0] = 0;
  1052. pData->pszDomain[0] = 0;
  1053. // if there's no connection, we're done
  1054. if(0 == pData->pszConnection[0])
  1055. return FALSE;
  1056. // Try and get name/password/domain from Ras
  1057. memset(&dp, 0, sizeof(RASDIALPARAMS));
  1058. dp.dwSize = sizeof(RASDIALPARAMS);
  1059. lstrcpyn(dp.szEntryName, pData->pszConnection, ARRAYSIZE(dp.szEntryName));
  1060. dwRes = _RasGetEntryDialParams(NULL, &dp, &fPassword);
  1061. if(fPassword && 0 == dwRes) {
  1062. // Copy ras information to pData.
  1063. lstrcpyn(pData->pszUsername, dp.szUserName, ARRAYSIZE(pData->pszUsername));
  1064. lstrcpyn(pData->pszPassword, dp.szPassword, ARRAYSIZE(pData->pszPassword));
  1065. lstrcpyn(pData->pszDomain, dp.szDomain, ARRAYSIZE(pData->pszDomain));
  1066. }
  1067. return fPassword;
  1068. }
  1069. DIALPROPDATA * InitDialData(void)
  1070. {
  1071. DIALPROPDATA * pData = (DIALPROPDATA *)MemAlloc(LPTR, sizeof(DIALPROPDATA));
  1072. HKEY hkeyRoot = HKEY_CURRENT_USER;
  1073. BOOL fGotInfo = FALSE;
  1074. DWORD dwValue;
  1075. if(NULL == pData)
  1076. return NULL;
  1077. // Fix fEnabled from registry HKCU\...\Internet Settings\EnableAutodial
  1078. ReadRegValue(hkeyRoot, szInternetSettings, c_szAutodial, &dwValue, sizeof(DWORD));
  1079. if(dwValue == 1) {
  1080. pData->fEnabled = TRUE;
  1081. }
  1082. // Fix fUnattended from registry HKCU\...\Internet Settings\EnableUnattended
  1083. ReadRegValue(hkeyRoot, szInternetSettings, c_szEnable, &dwValue, sizeof(DWORD));
  1084. if(dwValue == 1) {
  1085. pData->fUnattended = TRUE;
  1086. }
  1087. // Try to find a connection HKCU\Remote Access\Internet Profile
  1088. if(ReadRegValue(hkeyRoot, c_szRASKey, c_szProfile, pData->pszConnection,
  1089. RAS_MaxEntryName+1)) {
  1090. GetLogonInfo(pData);
  1091. }
  1092. return pData;
  1093. }