windows-nt/Source/XPSP1/NT/shell/ext/webcheck/dialer.cpp
2020-09-26 16:20:57 +08:00

1346 lines
36 KiB
C++

#include "private.h"
#include "offline.h"
#undef TF_THISMODULE
#define TF_THISMODULE TF_DIALMON
// prototypes
DIALPROPDATA * InitDialData(void);
//
// uuid for our command target
//
const UUID CGID_ConnCmdGrp = { 0x1dc1fd0, 0xdc49, 0x11d0, {0xaf, 0x95, 0x00, 0xc0, 0x4f, 0xd9, 0x40, 0xbe} };
//
// Registry keys we use to get autodial information
//
// Key name
const TCHAR c_szAutodial[] = TEXT("EnableAutodial");
const TCHAR c_szProxy[] = TEXT("ProxyServer");
const TCHAR c_szUnknown[] = TEXT("<unknown>");
// from schedule.cpp
extern TCHAR szInternetSettings[];
extern TCHAR szProxyEnable[];
// length of general text strings
#define TEXT_LENGTH 200
// our connection agent instance
CConnectionAgent *pAgent = NULL;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// Connection Agent class factory helper
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
HRESULT CConnectionAgent_CreateInstance(LPUNKNOWN pUnkOuter, IUnknown **ppunk)
{
IUnknown *punk, *punkClient = NULL;
HRESULT hr;
CConnClient *pClient;
*ppunk = NULL;
// create new con client instance
pClient = new CConnClient;
if(NULL == pClient)
return E_OUTOFMEMORY;
// Look for CConnectionAgent in ROT
hr = GetActiveObject(CLSID_ConnectionAgent, NULL, &punk);
if (NULL == punk) {
// Not there - create one
ASSERT(NULL == pAgent);
pAgent = new CConnectionAgent;
if(NULL == pAgent) {
pClient->Release();
return E_OUTOFMEMORY;
}
// Get an IUnknown on new object
hr = pAgent->QueryInterface(IID_IUnknown, (LPVOID *)&punk);
if (FAILED(hr) || NULL == punk) {
SAFERELEASE(pAgent);
pClient->Release();
return E_FAIL;
}
// Register new connection agent
hr = RegisterActiveObject(punk, CLSID_ConnectionAgent,
ACTIVEOBJECT_STRONG, &pAgent->m_dwRegisterHandle);
SAFERELEASE(pAgent);
if (FAILED(hr))
{
DBG_WARN("CConnectionAgentClassFactory RegisterActiveObject failed.");
pClient->Release();
punk->Release();
return hr;
}
DBG("New connection agent object created.");
}
#ifdef DEBUG
else
{
DBG("Using existing connection agent object.");
}
#endif
// Now we have pClient and punk. Tell client who the boss is
hr = pClient->SetConnAgent(punk);
punk->Release();
if(FAILED(hr)) {
pClient->Release();
return E_FAIL;
}
*ppunk = (IOleCommandTarget *)pClient;
return hr;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// Helper functions
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// Ping Class
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// helper stuff
//
#define IS_DIGIT(ch) InRange(ch, TEXT('0'), TEXT('9'))
void UnloadICMP(void);
long g_lPingWndReg = 0;
const TCHAR c_szPingWndClass[] = TEXT("PingClass");
#define WM_NAME (WM_USER)
#define WM_STOP (WM_USER+1)
class CPing
{
protected:
HANDLE _hPing;
HANDLE _hAsync;
HWND _hwnd;
UINT _uTimerID;
BOOL _fResult;
UINT _uTimeoutSec;
BOOL EnableAutodial(BOOL fEnable);
public:
CPing();
~CPing();
BOOL Init(UINT uTimeoutSec);
BOOL PingSite(LPTSTR pszSite);
static LRESULT CPing::WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
};
CPing::CPing()
{
_hPing = INVALID_HANDLE_VALUE;
_hwnd = NULL;
_hAsync = NULL;
_uTimeoutSec = 10;
}
CPing::~CPing()
{
if(_hwnd)
DestroyWindow(_hwnd);
if(_hPing)
IcmpCloseHandle(_hPing);
UnloadICMP();
}
BOOL
CPing::Init(UINT uTimeoutSec)
{
// save timeout
_uTimeoutSec = uTimeoutSec;
// load ICMP.DLL and get a ping handle
_hPing = IcmpCreateFile();
if(INVALID_HANDLE_VALUE == _hPing)
return FALSE;
// register window class if necessary
if(!g_lPingWndReg) {
g_lPingWndReg++;
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = CPing::WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = c_szPingWndClass;
RegisterClass(&wc);
}
if(NULL == _hwnd)
_hwnd = CreateWindow(c_szPingWndClass, NULL, WS_OVERLAPPED,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, g_hInst, (LPVOID)this);
if(NULL == _hwnd)
return FALSE;
return TRUE;
}
LRESULT
CPing::WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
CPing *pping = (CPing *)GetWindowLong(hWnd, GWL_USERDATA);
LPCREATESTRUCT pcs = NULL;
switch(Msg) {
case WM_CREATE:
pcs = (LPCREATESTRUCT)lParam;
SetWindowLong(hWnd, GWL_USERDATA, ((LONG) (pcs->lpCreateParams)));
break;
case WM_NAME:
// gethostbyname completed
if(0 == WSAGETASYNCERROR(lParam))
pping->_fResult = TRUE;
// fall through to WM_TIMER
case WM_TIMER:
// we ran out of time
PostMessage(hWnd, WM_STOP, 0, 0);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}
BOOL
CPing::EnableAutodial(BOOL fEnable)
{
DWORD dwNewState = 0, dwOldState = 0, dwSize = sizeof(DWORD);
BOOL fOldEnable = FALSE;
if(g_fIsWinNT) {
//
// In NT land, 1 means disabled, 0 means enabled
//
// Get WinNT autodial state
_RasGetAutodialParam(RASADP_LoginSessionDisable, &dwOldState, &dwSize);
if(0 == dwOldState) fOldEnable = TRUE;
// set new state
if(FALSE == fEnable) dwNewState = 1;
_RasSetAutodialParam(RASADP_LoginSessionDisable, &dwNewState, sizeof(DWORD));
} else {
//
// In Win95 land, 1 means enabled, 0 means disabled
//
// Get Win95 autodial state
if(!ReadRegValue(HKEY_CURRENT_USER, szInternetSettings, c_szAutodial,
&dwOldState, sizeof(DWORD)))
dwOldState = 0;
if(dwOldState) fOldEnable = TRUE;
// set new state
if(fEnable) dwNewState = 1;
WriteRegValue(HKEY_CURRENT_USER, szInternetSettings, c_szAutodial,
&dwNewState, sizeof(DWORD), REG_BINARY);
}
return fOldEnable;
}
BOOL
CPing::PingSite(LPTSTR pszHost)
{
IPAddr ipAddress = INADDR_NONE;
DWORD dwPingSend = 0xdeadbeef, dwCount;
WSADATA wsaData;
BOOL fOldState;
TCHAR pszWork[1024], *pEnd;
BYTE pGetHostBuff[MAXGETHOSTSTRUCT];
int iErr;
// assume failure
_fResult = FALSE;
if(INVALID_HANDLE_VALUE == _hPing) {
DBG("CPing::PingSite no ICMP handle");
return FALSE;
}
// fire up winsock
if(iErr = WSAStartup(0x0101, &wsaData)) {
TraceMsg(TF_THISMODULE,"CPing::PingSite WSAStartup failed, iErr=%d", iErr);
return FALSE;
}
if(IS_DIGIT(*pszHost)) {
// try to convert ip address
ipAddress = inet_addr(pszHost);
}
// turn off autodial
fOldState = EnableAutodial(FALSE);
if(INADDR_NONE == ipAddress) {
// strip port (if any) from host name
lstrcpyn(pszWork, pszHost, ARRAYSIZE(pszWork));
pEnd = StrChr(pszWork, TEXT(':'));
if(pEnd)
*pEnd = 0;
// start async gethostbyname
_uTimerID = SetTimer(_hwnd, 1, _uTimeoutSec * 1000, NULL);
_hAsync = WSAAsyncGetHostByName(_hwnd, WM_NAME, pszWork,
(char *)pGetHostBuff, MAXGETHOSTSTRUCT);
if(_hAsync) {
// operation started... wait for completion or time out
MSG msg;
while(1) {
GetMessage(&msg, _hwnd, 0, 0);
if(msg.message == WM_STOP)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
} /* while */
if(_fResult) {
// it worked, snarf address
struct hostent *phe;
phe = (struct hostent *)pGetHostBuff;
memcpy(&ipAddress, phe->h_addr, sizeof(IPAddr));
} else {
// If we timed out, clean up pending request
WSACancelAsyncRequest(_hAsync);
}
#ifdef DEBUG
} else {
// operation failed to start
iErr = WSAGetLastError();
TraceMsg(TF_THISMODULE, "CPing::PingSite WSAAsyncGetHostByName failed, error=%d", iErr);
#endif
}
// kill the timer
if(_uTimerID) {
KillTimer(_hwnd, _uTimerID);
_uTimerID = 0;
}
}
// assume the ping will fail
_fResult = FALSE;
if(INADDR_NONE != ipAddress) {
// try to ping that address
dwCount = IcmpSendEcho(
_hPing,
ipAddress,
&dwPingSend,
sizeof(DWORD),
NULL,
pszWork,
sizeof(pszWork),
_uTimeoutSec * 1000);
if(dwCount) {
// ping succeeded!!
_fResult = TRUE;
#ifdef DEBUG
} else {
// didn't work - spew
iErr = GetLastError();
TraceMsg(TF_THISMODULE, "CPing::PingSite IcmpSendEcho failed, error=%x", iErr);
#endif
}
}
// restore autodial
EnableAutodial(fOldState);
#ifdef DEBUG
if(_fResult)
TraceMsg(TF_THISMODULE, "CPing::PingSite ping <%s> success", pszHost);
else
TraceMsg(TF_THISMODULE, "CPing::PingSite ping <%s> FAILURE", pszHost);
#endif
WSACleanup();
return _fResult;
}
//
// PingProxy - exported function to decide if the proxy is available or not
//
BOOL PingProxy(UINT uTimeoutSec)
{
BOOL fRet = FALSE;
TCHAR pszProxy[TEXT_LENGTH], *pszHttp, *pszSemi;
DWORD dwValue;
// check for proxy enabled
if(ReadRegValue(HKEY_CURRENT_USER, szInternetSettings, szProxyEnable,
&dwValue, sizeof(DWORD))) {
if(0 == dwValue)
return FALSE;
}
// proxy is enabled in registry. Ping it to see if it's around.
if(ReadRegValue(HKEY_CURRENT_USER, szInternetSettings, c_szProxy,
pszProxy, TEXT_LENGTH)) {
// if there's an '=' in the proxy string, we'll look for the http= proxy
if(NULL != StrChr(pszProxy, '=')) {
pszHttp = StrStrI(pszProxy, TEXT("http="));
if(NULL == pszHttp)
// don't understand proxy string
return FALSE;
pszHttp += 5; // 5 chars in "http="
// remove following entries - they're separated by ;
pszSemi = StrChr(pszHttp, ';');
if(pszSemi)
*pszSemi = 0;
} else {
pszHttp = pszProxy;
}
// got a proxy, crack the host name out of it
TCHAR *pszPingSite;
URL_COMPONENTS comp;
ZeroMemory(&comp, sizeof(comp));
comp.dwStructSize = sizeof(comp);
comp.dwHostNameLength = 1;
if(InternetCrackUrlA(pszHttp, 0, 0, &comp) && (comp.nScheme != INTERNET_SCHEME_UNKNOWN)) {
pszPingSite = comp.lpszHostName;
pszPingSite[comp.dwHostNameLength] = 0;
} else {
pszPingSite = pszHttp;
}
// ping it
CPing ping;
if(ping.Init(uTimeoutSec))
fRet = ping.PingSite(pszPingSite);
}
return fRet;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// Connection Client object
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// Constructor / Destructor
//
CConnClient::CConnClient()
{
m_cRef = 1;
m_poctAgent = NULL;
m_pReport = NULL;
m_State = CLIENT_NEW;
m_bstrURL = NULL;
}
//////////////////////////////////////////////////////////////////////////
//
// IUnknown members
//
STDMETHODIMP CConnClient::QueryInterface(REFIID riid, void ** ppv)
{
*ppv=NULL;
// Validate requested interface
if ((IID_IUnknown == riid) ||
(IID_INotificationSink == riid))
{
*ppv=(INotificationSink*)this;
} else if(IID_IOleCommandTarget == riid) {
*ppv=(IOleCommandTarget*)this;
} else {
return E_NOINTERFACE;
}
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
STDMETHODIMP_(ULONG) CConnClient::AddRef(void)
{
TraceMsg(TF_THISMODULE, "CConnClient::Addref (%08x) m_cRef=%d", this, m_cRef+1);
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CConnClient::Release(void)
{
TraceMsg(TF_THISMODULE, "CConnClient::Release (%08x) m_cRef=%d", this, m_cRef-1);
if( 0L != --m_cRef )
return m_cRef;
DBG("CConClient::Release Bye Bye");
// Make sure we're disconnected
Disconnect();
m_poctAgent->Release();
if(m_bstrURL)
SysFreeString(m_bstrURL);
delete this;
return 0L;
}
//////////////////////////////////////////////////////////////////////////
//
// CConClient helper functions
//
HRESULT CConnClient::SetConnAgent(IUnknown *punk)
{
return punk->QueryInterface(IID_IOleCommandTarget, (void **)&m_poctAgent);
}
HRESULT CConnClient::Connect()
{
HRESULT hr;
VARIANTARG vin, vout;
m_State = CLIENT_CONNECTING;
// tell agent we want to connect
vin.vt = VT_UNKNOWN;
vin.punkVal = (IOleCommandTarget *)this;
VariantInit(&vout);
hr = m_poctAgent->Exec(&CGID_ConnCmdGrp, AGENT_CONNECT, 0, &vin, &vout);
if(SUCCEEDED(hr)) {
ASSERT(vout.vt == VT_I4);
m_iCookie = vout.lVal;
}
return hr;
}
HRESULT CConnClient::Disconnect()
{
HRESULT hr;
VARIANTARG vin;
if(CLIENT_DISCONNECTED == m_State)
return S_OK;
m_State = CLIENT_DISCONNECTED;
// tell agent we want to disconnect
vin.vt = VT_I4;
vin.ulVal = m_iCookie;
hr = m_poctAgent->Exec(&CGID_ConnCmdGrp, AGENT_DISCONNECT, 0, &vin, NULL);
// done with report pointer
SAFERELEASE(m_pReport);
return hr;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// INotificationSink members
//
STDMETHODIMP CConnClient::OnNotification(
LPNOTIFICATION pNotification,
LPNOTIFICATIONREPORT pNotificationReport,
DWORD dwReserved
)
{
NOTIFICATIONTYPE nt;
HRESULT hr = S_OK;
hr = pNotification->GetNotificationInfo(&nt, NULL,NULL,NULL,0);
if(FAILED(hr)) {
DBG_WARN("CConnClient::OnNotification failed to get not type!");
return E_INVALIDARG;
}
if(IsEqualGUID(nt, NOTIFICATIONTYPE_AGENT_START)) {
DBG("CConnClient::OnNotification AGENT_START");
if(CLIENT_NEW == m_State) {
// Must have a report pointer!
if(NULL == pNotificationReport) {
DBG("CConnClient::OnNotification no report on START!");
return E_UNEXPECTED;
}
// save report pointer
TraceMsg(TF_THISMODULE, "CConClient::OnNotification (%08x) addreffing report pointer", this);
m_pReport = pNotificationReport;
m_pReport->AddRef();
// get the URL
hr = ReadBSTR(pNotification, NULL, c_szPropURL, &m_bstrURL);
// convert to ansi and log url connection request
TCHAR pszURL[INTERNET_MAX_URL_LENGTH];
MyOleStrToStrN(pszURL, INTERNET_MAX_URL_LENGTH, m_bstrURL);
LogEvent("Connecting for <%s>", pszURL);
// Tell agent to connect
Connect();
} else {
DBG("CConnClient::OnNotification unexpected connect");
return E_UNEXPECTED;
}
} else if(IsEqualGUID(nt, NOTIFICATIONTYPE_TASKS_COMPLETED)) {
DBG("CConnClient::OnNotification TASKS_COMPLETED");
// convert url to ansi
TCHAR pszURL[INTERNET_MAX_URL_LENGTH];
MyOleStrToStrN(pszURL, INTERNET_MAX_URL_LENGTH, m_bstrURL);
switch(m_State) {
case CLIENT_CONNECTING:
m_State = CLIENT_ABORT;
// log connection abort
LogEvent("Aborting connection for <%s>", pszURL);
break;
case CLIENT_CONNECTED:
// log disconnect
LogEvent("Disconnecting for <%s>", pszURL);
Disconnect();
break;
default:
DBG("CConnClient::OnNotification unexpected disconnect");
return E_UNEXPECTED;
}
} else {
DBG("CConnClient::OnNotification unknown type");
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// IOleCommandTarget members
//
STDMETHODIMP CConnClient::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
OLECMD prgCmds[], OLECMDTEXT *pCmdText)
{
if (IsEqualGUID(*pguidCmdGroup, CGID_ConnCmdGrp)) {
return S_OK;
}
return OLECMDERR_E_UNKNOWNGROUP;
}
STDMETHODIMP CConnClient::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
DWORD nCmdexecopt, VARIANTARG *pvaIn,
VARIANTARG *pvaOut)
{
HRESULT hr = E_NOTIMPL;
if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_ConnCmdGrp))
{
switch(nCmdID) {
case AGENT_NOTIFY:
if(VT_ERROR == pvaIn->vt) {
hr = DeliverProgressReport(pvaIn->scode, NULL);
} else {
hr = E_INVALIDARG;
}
break;
}
}
return hr;
}
//////////////////////////////////////////////////////////////////////////
//
// Other methods
//
HRESULT CConnClient::DeliverProgressReport(SCODE scode, BSTR bstrErrorText)
{
HRESULT hr = S_OK;
INotificationMgr *pMgr;
INotification *pStatus;
switch(m_State) {
case CLIENT_CONNECTING:
// Get Notification manager
hr = CoCreateInstance(CLSID_StdNotificationMgr, NULL,
CLSCTX_INPROC_SERVER, IID_INotificationMgr, (void**)&pMgr);
if(FAILED(hr))
return hr;
// create notification to deliver
hr = pMgr->CreateNotification(NOTIFICATIONTYPE_PROGRESS_REPORT,
(NOTIFICATIONFLAGS)0, NULL, &pStatus, 0);
pMgr->Release();
if(FAILED(hr))
return hr;
// stick result and string in progress report
// WriteOLESTR(pStatus, NULL, c_szPropStatusString, bstrErrorText);
WriteSCODE(pStatus, NULL, c_szPropStatusCode, scode);
// deliver notification
hr = m_pReport->DeliverUpdate(pStatus, 0, 0);
pStatus->Release();
if(SUCCEEDED(scode)) {
m_State = CLIENT_CONNECTED;
} else {
Disconnect();
}
break;
case CLIENT_ABORT:
Disconnect();
break;
}
return hr;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// Connection agent
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// Constructor and destructor
//
CConnectionAgent::CConnectionAgent()
{
m_pData = NULL;
m_cRef = 1;
m_dwRegisterHandle = 0;
m_lConnectionCount = 0;
m_dwFlags = 0;
m_hdpaClient = NULL;
// Get the notification manager
m_pMgr = NULL;
CoCreateInstance(CLSID_StdNotificationMgr, NULL,
CLSCTX_INPROC_SERVER, IID_INotificationMgr, (void**)&m_pMgr);
}
CConnectionAgent::~CConnectionAgent()
{
SAFERELEASE(m_pMgr);
SAFELOCALFREE(m_pData);
if(IsFlagSet(m_dwFlags, CA_LOADED_RAS))
UnloadRasDLL();
}
//
// Clean - clean up strong lock and ref count
//
void
CConnectionAgent::Clean(void)
{
DWORD dwHandle = m_dwRegisterHandle;
int iCurReport, i;
CLIENTINFO *pClient;
// don't do anything if there are outstanding connections
if(m_lConnectionCount)
return;
// clean up client dpa
if(m_hdpaClient) {
iCurReport = DPA_GetPtrCount(m_hdpaClient);
for(i=0; i<iCurReport; i++) {
pClient = (CLIENTINFO *)(DPA_GetPtr(m_hdpaClient, i));
if(pClient)
delete pClient;
}
DPA_Destroy(m_hdpaClient);
m_hdpaClient = NULL;
}
// release our strong registration
DBG("CConnectionAgent::Clean revoking connection agent object");
m_dwRegisterHandle = 0;
RevokeActiveObject(dwHandle, NULL);
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// Connect - entry point to connect
//
void
CConnectionAgent::Connect(void)
{
BOOL fDone = FALSE;
TCHAR pszText[TEXT_LENGTH];
//
// increment connection count
//
m_lConnectionCount ++;
TraceMsg(TF_THISMODULE, "CConnectionAgent::Connect ref count now %d", m_lConnectionCount);
//
// Store offline state if we haven't already and go online
//
if(FALSE == IsFlagSet(m_dwFlags, CA_OFFLINE_STATE_READ)) {
if(IsGlobalOffline())
SetFlag(m_dwFlags, CA_OFFLINE);
// make sure we're online
SetGlobalOffline(FALSE);
SetFlag(m_dwFlags, CA_OFFLINE_STATE_READ);
}
//
// check for pending dialup connection
//
if(IsFlagSet(m_dwFlags, CA_CONNECTING_NOW)) {
// already working on a connection
DBG("CConnectionAgent::Connect already trying to connect");
return;
}
//
// check to see if we can dial to get a connection
//
if(FALSE == IsDialPossible()) {
//
// can't dial - better have a direct connection
//
DBG("CConnectionAgent::Connect guessing connected");
if(!MLLoadString(IDS_DIAL_DIRECT, pszText, TEXT_LENGTH))
lstrcpy(pszText, "direct");
Notify(S_OK, pszText);
return;
}
//
// check for an existing dialup connection
//
if(FALSE == IsFlagSet(m_dwFlags, CA_LOADED_RAS)) {
SetFlag(m_dwFlags, CA_LOADED_RAS);
LoadRasDLL();
}
if(IsDialExisting()) {
DBG("CConnectionAgent::Connect already connected");
if(!MLLoadString(IDS_DIAL_ALREADY_CONNECTED, pszText, TEXT_LENGTH))
lstrcpy(pszText, "success");
Notify(S_OK, pszText);
return;
}
#ifdef COOL_MODEM_ACTION
// since we assume connected for direct connect, no proxy check is
// necessary. If this check is put in, cool behavior results: It uses
// the proxy server if it can find it, otherwise it autodials.
// Autodial needs to be made consistant with this before it gets turned
// on
//
// check for a proxy connection
//
if(PingProxy(5)) {
// Dial is possible but proxy is available! Turn off autodial and
// flag to turn it back on when we're done
CPing::EnableAutodial(FALSE);
SetFlag(m_dwFlags, CA_AUTODIAL_OFF);
// Using proxy
DBG("CConnectionAgent::Connect using proxy");
if(!MLLoadString(IDS_DIAL_PROXY, pszText, TEXT_LENGTH))
lstrcpy(pszText, "proxy");
Notify(S_OK, pszText);
return;
}
#endif
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
//
// Ensure we can dial without user intervention
//
BOOL fContinue = TRUE;
if(SHRestricted2W(REST_NoUnattendedDialing, NULL, 0))
// dialing restricted
fContinue = FALSE;
//
// No existing connection but we can dial. do it now.
//
SetFlag(m_dwFlags, CA_CONNECTING_NOW);
DWORD dwRetCode;
if(fContinue)
{
dwRetCode = ERROR_SUCCESS;
if(!InternetAutodial((INTERNET_AUTODIAL_FORCE_ONLINE |
INTERNET_AUTODIAL_FORCE_UNATTENDED |
INTERNET_AUTODIAL_FAILIFSECURITYCHECK), 0))
{
dwRetCode = GetLastError();
}
}
if (fContinue && (ERROR_SUCCESS == dwRetCode)) {
// successful connection made
SetFlag(m_dwFlags, CA_DIALED);
if(!MLLoadString(IDS_DIAL_SUCCESS, pszText, TEXT_LENGTH))
lstrcpy(pszText, "success");
Notify(S_OK, pszText);
} else {
//UINT uID;
HRESULT hrDialResult;
// unable to dial
if(ERROR_INTERNET_FAILED_DUETOSECURITYCHECK == dwRetCode)
{
hrDialResult = E_ABORT;
// uID = IDS_STRING_E_SECURITYCHECK; not needed - since MLLoadString below is commented out
}
else
{
hrDialResult = E_INVALIDARG;
// uID = IDS_STRING_E_CONFIG;not needed - since MLLoadString below is commented out
}
// if(!MLLoadString(uID, pszText, TEXT_LENGTH)) // Don't bother : This is ignored anyway
lstrcpy(pszText, "Connection Not Made");
Notify(hrDialResult, pszText);
}
ClearFlag(m_dwFlags, CA_CONNECTING_NOW);
}
//
// Disconnect - entry point to disconnect
//
void
CConnectionAgent::Disconnect(void)
{
// If we're the last connection, hang up
m_lConnectionCount --;
TraceMsg(TF_THISMODULE, "CConnectionAgent::Disconnect ref count now %d", m_lConnectionCount);
if(0 == m_lConnectionCount) {
// If we dialed this connection, hang it up
if(IsFlagSet(m_dwFlags, CA_DIALED)) {
LogEvent(TEXT("EVT: Hanging up"));
InternetAutodialHangup(0);
}
#ifdef COOL_MODEM_ACTION
if(IsFlagSet(m_dwFlags, CA_AUTODIAL_OFF)) {
// we turned autodial off - turn it back on
CPing::EnableAutodial(TRUE);
// tell wininet we've changed it
InternetSetOption(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
}
#endif
// restore original offline state
SetGlobalOffline(IsFlagSet(m_dwFlags, CA_OFFLINE));
// revoke our object
Clean();
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// IsDialPossible - search around and make sure all necessary info
// is available to connect. If fQuiet is false, may bring up dialogs
// to get necessary info
//
BOOL
CConnectionAgent::IsDialPossible()
{
BOOL fPossible = TRUE;
// Refresh data in case properties has been up and changed it
if(m_pData)
MemFree(m_pData);
m_pData = InitDialData();
if(NULL == m_pData)
return FALSE;
if(FALSE == m_pData->fEnabled)
// not enabled
fPossible = FALSE;
if(!m_pData->pszConnection[0])
// no connection
fPossible = FALSE;
return fPossible;
}
//
// IsDialExisting - check to see if there's an existing dialup connection
// that we didn't do
//
#define MAX_CONNECTION 8
BOOL
CConnectionAgent::IsDialExisting(void)
{
TCHAR pszConn[RAS_MaxEntryName+1];
RASCONN pRasCon[MAX_CONNECTION];
DWORD dwSize = MAX_CONNECTION * sizeof(RASCONN), dwConn, dwCur;
HKEY hkeyRoot = HKEY_CURRENT_USER;
// read internet connectoid from registry
if(!ReadRegValue(hkeyRoot, c_szRASKey, c_szProfile, pszConn,
RAS_MaxEntryName+1)) {
DBG("CConnectionAgent::IsDialExisting unable to read internet connectoid");
return FALSE;
}
// have Ras enumerate existing connections
pRasCon[0].dwSize = sizeof(RASCONN);
if(_RasEnumConnections(pRasCon, &dwSize, &dwConn)) {
DBG("CConnectionAgent::IsDialExisting RasEnumConnections failed");
return FALSE;
}
// do any of them match our internet connectoid?
for(dwCur=0; dwCur<dwConn; dwCur++) {
if(0 == lstrcmp(pszConn, pRasCon[dwCur].szEntryName))
return TRUE;
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// IUnknown members
//
STDMETHODIMP CConnectionAgent::QueryInterface(REFIID riid, void ** ppv)
{
*ppv=NULL;
// Validate requested interface
if ((IID_IUnknown == riid) ||
(IID_IOleCommandTarget == riid))
{
*ppv=(IOleCommandTarget*)this;
} else {
return E_NOINTERFACE;
}
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
STDMETHODIMP_(ULONG) CConnectionAgent::AddRef(void)
{
TraceMsg(TF_THISMODULE, "CConnectionAgent::Addref m_cRef=%d", m_cRef+1);
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CConnectionAgent::Release(void)
{
TraceMsg(TF_THISMODULE, "CConnectionAgent::Release m_cRef=%d", m_cRef-1);
if( 0L != --m_cRef )
return m_cRef;
DBG("CConnectionAgent::Release Bye Bye");
delete this;
return 0L;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// IOleCommandTarget members
//
STDMETHODIMP CConnectionAgent::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
OLECMD prgCmds[], OLECMDTEXT *pCmdText)
{
if (IsEqualGUID(*pguidCmdGroup, CGID_ConnCmdGrp))
{
// We like connection agent commands
return S_OK;
}
return OLECMDERR_E_UNKNOWNGROUP;
}
STDMETHODIMP CConnectionAgent::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
DWORD nCmdexecopt, VARIANTARG *pvaIn,
VARIANTARG *pvaOut)
{
HRESULT hr;
CLIENTINFO *pInfo;
int iIndex;
if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_ConnCmdGrp))
{
switch(nCmdID) {
case AGENT_CONNECT:
// validate input arguments
if(VT_UNKNOWN != pvaIn->vt || NULL == pvaOut)
return E_INVALIDARG;
// create dpa if necessary
if(NULL == m_hdpaClient)
m_hdpaClient = DPA_Create(0);
if(NULL == m_hdpaClient)
return E_OUTOFMEMORY;
// create and initialize new clientinfo struct
pInfo = new CLIENTINFO;
if(NULL == pInfo)
return E_OUTOFMEMORY;
pInfo->dwFlags = 0;
hr = pvaIn->punkVal->QueryInterface(IID_IOleCommandTarget, (void **)&pInfo->poctClient);
if(FAILED(hr))
return hr;
// insert struct into dpa and return index
iIndex = DPA_InsertPtr(m_hdpaClient, DPA_APPEND, pInfo);
if(iIndex < 0) {
delete pInfo;
return E_OUTOFMEMORY;
} else {
pvaOut->vt = VT_I4;
pvaOut->ulVal = iIndex;
}
// connect
Connect();
return S_OK;
case AGENT_DISCONNECT:
// validate input parameters
if(VT_I4 != pvaIn->vt)
return E_INVALIDARG;
// mark client record as disconnected
pInfo = (CLIENTINFO *)DPA_GetPtr(m_hdpaClient, pvaIn->lVal);
if(pInfo) {
pInfo->dwFlags |= CLIENT_DISCONNECT;
SAFERELEASE(pInfo->poctClient);
}
// disconnect
Disconnect();
return S_OK;
}
}
return E_NOTIMPL;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//
// Notify all waiting agents of success or failure of dial attempt
//
void CConnectionAgent::Notify(HRESULT hrDialResult, TCHAR *pszErrorText)
{
CLIENTINFO *pClient;
int i, iCurReport;
//WCHAR pwszStatus[TEXT_LENGTH];
VARIANTARG vin;
// We're done connecting
ClearFlag(m_dwFlags, CA_CONNECTING_NOW);
// Create the notifications to send
if(S_OK == hrDialResult) {
DBG("CConnectionAgent::Notify sending ONLINE");
LogEvent(TEXT("EVT: Successful connection"));
} else {
DBG("CConnectionAgent::Notify sending OFFLINE");
LogEvent(TEXT("EVT: Unsuccessful connection - hr=%08x"), hrDialResult);
}
// convert string to bstr
// MyStrToOleStrN(pwszStatus, TEXT_LENGTH, pszErrorText);
// build exec paramaters
vin.vt = VT_ERROR;
vin.scode = hrDialResult;
// Send it to all the clients
iCurReport = DPA_GetPtrCount(m_hdpaClient);
for(i=0; i<iCurReport; i++) {
pClient = (CLIENTINFO *)(DPA_GetPtr(m_hdpaClient, i));
if(pClient && 0 == pClient->dwFlags) {
pClient->poctClient->Exec(&CGID_ConnCmdGrp, AGENT_NOTIFY, 0,
&vin, NULL);
// This can get blown away out from under us.
if (m_hdpaClient)
{
pClient->dwFlags |= CLIENT_NOTIFIED;
SAFERELEASE(pClient->poctClient);
}
}
}
// if we're disconnected, clean ourselves up
Clean();
}
BOOL
GetLogonInfo(DIALPROPDATA *pData)
{
RASDIALPARAMS dp;
DWORD dwRes;
BOOL fPassword = FALSE;
// initially set name/password/domain to null
pData->pszUsername[0] = 0;
pData->pszPassword[0] = 0;
pData->pszDomain[0] = 0;
// if there's no connection, we're done
if(0 == pData->pszConnection[0])
return FALSE;
// Try and get name/password/domain from Ras
memset(&dp, 0, sizeof(RASDIALPARAMS));
dp.dwSize = sizeof(RASDIALPARAMS);
lstrcpyn(dp.szEntryName, pData->pszConnection, ARRAYSIZE(dp.szEntryName));
dwRes = _RasGetEntryDialParams(NULL, &dp, &fPassword);
if(fPassword && 0 == dwRes) {
// Copy ras information to pData.
lstrcpyn(pData->pszUsername, dp.szUserName, ARRAYSIZE(pData->pszUsername));
lstrcpyn(pData->pszPassword, dp.szPassword, ARRAYSIZE(pData->pszPassword));
lstrcpyn(pData->pszDomain, dp.szDomain, ARRAYSIZE(pData->pszDomain));
}
return fPassword;
}
DIALPROPDATA * InitDialData(void)
{
DIALPROPDATA * pData = (DIALPROPDATA *)MemAlloc(LPTR, sizeof(DIALPROPDATA));
HKEY hkeyRoot = HKEY_CURRENT_USER;
BOOL fGotInfo = FALSE;
DWORD dwValue;
if(NULL == pData)
return NULL;
// Fix fEnabled from registry HKCU\...\Internet Settings\EnableAutodial
ReadRegValue(hkeyRoot, szInternetSettings, c_szAutodial, &dwValue, sizeof(DWORD));
if(dwValue == 1) {
pData->fEnabled = TRUE;
}
// Fix fUnattended from registry HKCU\...\Internet Settings\EnableUnattended
ReadRegValue(hkeyRoot, szInternetSettings, c_szEnable, &dwValue, sizeof(DWORD));
if(dwValue == 1) {
pData->fUnattended = TRUE;
}
// Try to find a connection HKCU\Remote Access\Internet Profile
if(ReadRegValue(hkeyRoot, c_szRASKey, c_szProfile, pData->pszConnection,
RAS_MaxEntryName+1)) {
GetLogonInfo(pData);
}
return pData;
}