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.
 
 
 
 
 
 

4083 lines
127 KiB

/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1993-1996 Microsoft Corporation. All Rights Reserved.
//
// MODULE: conman.cpp
//
// PURPOSE: Defines the CConnectionManager object for Athena.
//
#include "pch.hxx"
#include "conman.h"
#include "error.h"
#include "strconst.h"
#include "rasdlgsp.h"
#include "resource.h"
#include "xpcomm.h"
#include "goptions.h"
#include "thormsgs.h"
#include "wininet.h"
#include "shlwapip.h"
#include "demand.h"
#include "dllmain.h"
#include "browser.h"
#include <urlmon.h>
#include "menures.h"
#include "workoff.h"
#include <sync.h>
ASSERTDATA
#define DEF_HANGUP_WAIT 10 // Seconds
static const TCHAR s_szRasDlgDll[] = "RASDLG.DLL";
#ifdef UNICODE
static const TCHAR s_szRasDialDlg[] = "RasDialDlgW";
static const TCHAR s_szRasEntryDlg[] = "RasEntryDlgW";
#else
static const TCHAR s_szRasDialDlg[] = "RasDialDlgA";
static const TCHAR s_szRasEntryDlg[] = "RasEntryDlgA";
#endif
BOOL FIsPlatformWinNT();
//
// FUNCTION: CConnectionManager::CConnectionManager()
//
// PURPOSE: Constructor
//
CConnectionManager::CConnectionManager()
{
m_cRef = 1;
// Synchronization Objects
InitializeCriticalSection(&m_cs);
m_hMutexDial = INVALID_HANDLE_VALUE;
m_pAcctMan = 0;
m_fSavePassword = 0;
m_fRASLoadFailed = 0;
m_fOffline = 0;
m_dwConnId = 0;
ZeroMemory(&m_rConnInfo, sizeof(CONNINFO));
m_rConnInfo.state = CIS_REFRESH;
*m_szConnectName = 0;
ZeroMemory(&m_rdp, sizeof(RASDIALPARAMS));
m_hInstRas = NULL;
m_hInstRasDlg = NULL;
m_pNotifyList = NULL;
m_pConnListHead = NULL;
m_hInstSensDll = NULL;
m_fMobilityPackFailed = FALSE;
m_pIsDestinationReachable = NULL;
m_pIsNetworkAlive = NULL;
m_fTryAgain = FALSE;
m_fDialerUI = FALSE;
}
//
// FUNCTION: CConnectionManager::~CConnectionManager()
//
// PURPOSE: Destructor
//
CConnectionManager::~CConnectionManager()
{
SafeRelease(m_pAcctMan);
FreeNotifyList();
EnterCriticalSection(&m_cs);
if (m_hInstRas)
FreeLibrary(m_hInstRas);
if (m_hInstRasDlg)
FreeLibrary(m_hInstRasDlg);
if (m_hInstSensDll)
FreeLibrary(m_hInstSensDll);
CloseHandle(m_hMutexDial);
LeaveCriticalSection(&m_cs);
DeleteCriticalSection(&m_cs);
EmptyConnList();
}
//
// FUNCTION: CConnectionManager::HrInit()
//
// PURPOSE: Initalizes the connection manager by attempting to load RAS
// and storing a pointer to the Account Manager object that is
// passed in.
//
// PARAMETERS:
// <in> pAcctMan - Pointer to the account manager object that we will
// use to retrieve account information and register for
// account changes.
//
// RETURN VALUE:
// S_OK Everything is hunky-dorie
// HR_E_ALREADYEXISTS We already exist, can't do it twice.
// HR_S_RASNOTLOADED The system doesn't have RAS installed.
//
HRESULT CConnectionManager::HrInit(IImnAccountManager *pAcctMan)
{
HRESULT hr = S_OK;
// Make a copy of the account manager pointer
if (NULL == pAcctMan)
{
AssertSz(pAcctMan, _T("CConnectionManager::HrInit() - Requires an IAccountManager pointer."));
return (E_INVALIDARG);
}
m_pAcctMan = pAcctMan;
m_pAcctMan->AddRef();
// Register a window class for our advise handling
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = NotifyWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInst;
wc.hIcon = 0;
wc.hCursor = 0;
wc.hbrBackground = 0;
wc.lpszMenuName = 0;
wc.lpszClassName = NOTIFY_HWND;
RegisterClass(&wc);
m_hMutexDial = CreateMutex(NULL, FALSE, NULL);
if (NULL == m_hMutexDial)
return (E_FAIL);
return (S_OK);
}
HRESULT STDMETHODCALLTYPE CConnectionManager::QueryInterface(REFIID riid, LPVOID *ppvObject)
{
if (!ppvObject)
return E_INVALIDARG;
if (IsEqualIID(riid, IID_IUnknown))
*ppvObject = (LPVOID) (IUnknown*) this;
else if (IsEqualIID(riid, IID_IImnAdviseAccount))
*ppvObject = (LPVOID) (IImnAdviseAccount*) this;
else
*ppvObject = NULL;
if (*ppvObject)
{
AddRef();
return (S_OK);
}
else
return (E_NOINTERFACE);
}
ULONG STDMETHODCALLTYPE CConnectionManager::AddRef(void)
{
return (++m_cRef);
}
ULONG STDMETHODCALLTYPE CConnectionManager::Release(void)
{
ULONG cRef = --m_cRef;
if (m_cRef == 0)
{
delete this;
return (0);
}
return (cRef);
}
HRESULT STDMETHODCALLTYPE CConnectionManager::AdviseAccount(DWORD dwAdviseType,
ACTX *pactx)
{
IImnAccount *pAccount;
DWORD dwConnection;
// SendAdvise(CONNNOTIFY_RASACCOUNTSCHANGED, 0);
switch (dwAdviseType)
{
case AN_ACCOUNT_DELETED:
{
if (SUCCEEDED(m_pAcctMan->FindAccount(AP_ACCOUNT_ID, pactx->pszAccountID, &pAccount)))
{
if (SUCCEEDED(pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConnection)))
{
if (dwConnection == CONNECTION_TYPE_RAS)
{
TCHAR szConnection[CCHMAX_CONNECTOID];
*szConnection = '\0';
if (SUCCEEDED(pAccount->GetPropSz(AP_RAS_CONNECTOID, szConnection,
ARRAYSIZE(szConnection))) && *szConnection)
{
RemoveFromConnList(szConnection);
}
}
}
}
break;
}
}
return (S_OK);
}
void CConnectionManager::EmptyConnList()
{
ConnListNode *pCur;
//Delete all the nodes
while (m_pConnListHead != NULL)
{
pCur = m_pConnListHead;
m_pConnListHead = m_pConnListHead->pNext;
delete pCur;
}
m_pConnListHead = NULL;
}
void CConnectionManager::RemoveFromConnList(LPTSTR pszRasConn)
{
ConnListNode *prev = NULL,
*Cur = m_pConnListHead;
LPTSTR pRasConn;
while (Cur != NULL)
{
if (0 == lstrcmpi(pszRasConn, Cur->pszRasConn))
{
if (prev == NULL)
{
m_pConnListHead = Cur->pNext;
}
else
{
prev->pNext = Cur->pNext;
}
delete Cur;
}
else
{
prev = Cur;
Cur = Cur->pNext;
}
}
}
HRESULT CConnectionManager::AddToConnList(LPTSTR pszRasConn)
{
//We don't have to make sure that this is not already in the list because once
//it is in the list, that means its already connected and so we don't land up in this
//situation after that
ConnListNode *pnext;
HRESULT hres;
IImnAccount *pAccount;
pnext = m_pConnListHead;
m_pConnListHead = new ConnListNode;
if (m_pConnListHead != NULL)
{
m_pConnListHead->pNext = pnext;
StrCpyN(m_pConnListHead->pszRasConn, pszRasConn, ARRAYSIZE(m_pConnListHead->pszRasConn));
hres = S_OK;
}
else
hres = E_FAIL;
return hres;
}
HRESULT CConnectionManager::SearchConnList(LPTSTR pszRasConn)
{
ConnListNode *pCur = m_pConnListHead;
while (pCur != NULL)
{
if (0 == lstrcmpi(pszRasConn, pCur->pszRasConn))
return S_OK;
pCur = pCur->pNext;
}
return E_FAIL;
}
//
// FUNCTION: CConnectionManager::CanConnect()
//
// PURPOSE: Determines if the caller can connect to the given account
// using the existing connection.
//
// PARAMETERS:
// <in> pAccount - Pointer to the account object the caller wants to
// connect to.
//
// RETURN VALUE:
// S_OK - The caller can connect using the existing connection
// S_FALSE - There is no existing connection, so there is no reason the
// caller can't connect.
// E_FAIL - The existing connection is different from the account's
// connection. The user must hang up and dial again to connect
//
HRESULT CConnectionManager::CanConnect(IImnAccount *pAccount)
{
HRESULT hr;
DWORD dwConnection;
IImnAccount *pDefault = 0;
LPRASCONN pConnections = NULL;
ULONG cConnections = 0;
BOOL fFound = 0;
// Check to see if we're working offline
if (IsGlobalOffline())
return (HR_E_OFFLINE);
// If the connection the user is looking for is not RAS, then we just
// return success.
if (FAILED(hr = pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConnection)))
{
// If we didn't get the connection information, then we look for the
// connection from the default server of this type
if (FAILED(hr = GetDefaultConnection(pAccount, &pDefault)))
{
// Bug #36071 - If we haven't set up any accounts of this type yet,
// we'd fail. As a result, if you fire a URL to a server
// we'd never try to connect and download. I'm going
// to change this to succeed and we'll see what type
// of bugs that creates.
return (S_OK);
}
// We're going to use the default from now on
pAccount = pDefault;
if (FAILED(hr = pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConnection)))
{
// Bug #36071 - If we haven't set up any accounts of this type yet,
// we'd fail. As a result, if you fire a URL to a server
// we'd never try to connect and download. I'm going
// to change this to succeed and we'll see what type
// of bugs that creates.
return (S_OK);
}
}
hr = OEIsDestinationReachable(pAccount, dwConnection);
//I don't think we should be doing this here. Review again
/*
if ((hr == S_OK) && (dwConnection == CONNECTION_TYPE_RAS || dwConnection == CONNECTION_TYPE_INETSETTINGS))
{
m_rConnInfo.fConnected = TRUE;
}
*/
//exit:
SafeRelease(pDefault);
return (hr);
}
//
// FUNCTION: CConnectionManager::CanConnect()
//
// PURPOSE: Determines if the caller can connect to the given account
// using the existing connection.
//
// PARAMETERS:
// <in> pszAccount - Pointer to the name of the account the caller wants
// to connect to.
//
// RETURN VALUE:
// S_OK - The caller can connect using the existing connection
// S_FALSE - There is no existing connection, so there is no reason the
// caller can't connect.
// E_FAIL - The existing connection is different from the account's
// connection. The user must hang up and dial again to connect
// E_INVALIDARG - The account doesn't exist
//
HRESULT CConnectionManager::CanConnect(LPTSTR pszAccount)
{
IImnAccount *pAccount = NULL;
HRESULT hr;
// Check to see if we're working offline
if (IsGlobalOffline())
return (HR_E_OFFLINE);
// Look up the account name in the account manager to get the account
// object.
Assert(m_pAcctMan);
if (lstrcmpi(pszAccount, STR_LOCALSTORE) == 0)
return(S_OK);
if (SUCCEEDED(m_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAccount, &pAccount)))
{
// Call through to the polymorphic version of us
hr = CanConnect(pAccount);
pAccount->Release();
}
else
{
// Bug #36071 - If we haven't set up any accounts of this type yet,
// we'd fail. As a result, if you fire a URL to a server
// we'd never try to connect and download. I'm going
// to change this to succeed and we'll see what type
// of bugs that creates.
hr = S_OK;
}
return (hr);
}
BOOL CConnectionManager::IsAccountDisabled(LPTSTR pszAccount)
{
IImnAccount *pAccount = NULL;
DWORD dw;
// Look up the account name in the account manager to get the account
// object.
Assert(m_pAcctMan);
if (lstrcmpi(pszAccount, STR_LOCALSTORE) == 0)
return(FALSE);
if (SUCCEEDED(m_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAccount, &pAccount)))
{
if (SUCCEEDED(pAccount->GetPropDw(AP_HTTPMAIL_DOMAIN_MSN, &dw)) && dw)
{
if(HideHotmail())
return(TRUE);
}
return(FALSE);
}
return(TRUE);
}
//
// FUNCTION: CConnectionManager::Connect()
//
// PURPOSE: Attempts to establish a connection for the account specified.
//
// PARAMETERS:
// <in> pAccount - Pointer to the account object to connect to.
// <in> hwnd - Handle of the window to show UI over. Only needed if
// fShowUI is TRUE.
// <in> fShowUI - TRUE if the functions are allowed to display UI.
//
// RETURN VALUE:
// S_OK - We're connected
// E_UNEXPECTED - There wasn't enough information in pAccount to figure
// figure out which connection to use.
//
HRESULT CConnectionManager::Connect(IImnAccount *pAccount, HWND hwnd, BOOL fShowUI)
{
HRESULT hr = S_OK;
DWORD dwConnection;
IImnAccount *pDefault = 0;
if (!m_fDialerUI)
{
m_fDialerUI = TRUE;
// Check to see if we're working offline
if (IsGlobalOffline())
{
if (fShowUI)
{
if (IDNO == AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrWorkingOffline),
0, MB_YESNO | MB_ICONEXCLAMATION ))
{
m_fDialerUI = FALSE;
return (HR_E_OFFLINE);
}
else
g_pConMan->SetGlobalOffline(FALSE);
}
else
{
m_fDialerUI = FALSE;
return (HR_E_OFFLINE);
}
}
m_fDialerUI = FALSE;
}
if (CanConnect(pAccount) == S_OK)
{
return S_OK;
}
// If the connection the user is looking for is not RAS, then we just
// return success.
if (FAILED(hr = pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConnection)))
{
// If we didn't get the connection information, then we look for the
// connection from the default server of this type
if (FAILED(hr = GetDefaultConnection(pAccount, &pDefault)))
{
// Bug #36071 - If we haven't set up any accounts of this type yet,
// we'd fail. As a result, if you fire a URL to a server
// we'd never try to connect and download. I'm going
// to change this to succeed and we'll see what type
// of bugs that creates.
return (S_OK);
}
// We're going to use the default from now on
pAccount = pDefault;
if (FAILED(hr = pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConnection)))
{
// Bug #36071 - If we haven't set up any accounts of this type yet,
// we'd fail. As a result, if you fire a URL to a server
// we'd never try to connect and download. I'm going
// to change this to succeed and we'll see what type
// of bugs that creates.
hr = S_OK;
goto exit;
}
}
if (dwConnection == CONNECTION_TYPE_INETSETTINGS)
{
hr = ConnectUsingIESettings(hwnd, fShowUI);
goto exit;
}
if (dwConnection == CONNECTION_TYPE_LAN)
{
//CanConnect already told us that Lan is not present
hr = E_FAIL;
goto exit;
}
if (dwConnection != CONNECTION_TYPE_RAS)
{
hr = S_OK;
goto exit;
}
// Get the name of the connection while we're at it.
TCHAR szConnection[CCHMAX_CONNECTOID];
if (FAILED(hr = pAccount->GetPropSz(AP_RAS_CONNECTOID, szConnection,
ARRAYSIZE(szConnection))))
{
AssertSz(FALSE, _T("CConnectionManager::Connect() - No connection name."));
hr = E_UNEXPECTED;
goto exit;
}
hr = ConnectActual(szConnection, hwnd, fShowUI);
exit:
SafeRelease(pDefault);
return (hr);
}
//
// FUNCTION: CConnectionManager::Connect()
//
// PURPOSE: Attempts to establish a connection for the account specified.
//
// PARAMETERS:
// <in> pszAccount - Name of the account to connect to.
// <in> hwnd - Handle of the window to show UI over. Only needed if
// fShowUI is TRUE.
// <in> fShowUI - TRUE if the functions are allowed to display UI.
//
// RETURN VALUE:
// <???>
//
HRESULT CConnectionManager::Connect(LPTSTR pszAccount, HWND hwnd, BOOL fShowUI)
{
IImnAccount *pAccount = NULL;
HRESULT hr;
// Check to see if we're working offline
if (!m_fDialerUI)
{
m_fDialerUI = TRUE;
// Check to see if we're working offline
if (IsGlobalOffline())
{
if (fShowUI)
{
if (IDNO == AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrWorkingOffline),
0, MB_YESNO | MB_ICONEXCLAMATION ))
{
m_fDialerUI = FALSE;
return (HR_E_OFFLINE);
}
else
g_pConMan->SetGlobalOffline(FALSE);
}
else
{
m_fDialerUI = FALSE;
return (HR_E_OFFLINE);
}
}
m_fDialerUI = FALSE;
}
// Look up the account name in the account manager to get the account
// object.
Assert(m_pAcctMan);
// if (SUCCEEDED(m_pAcctMan->FindAccount(AP_ACCOUNT_NAME, pszAccount, &pAccount)))
if (SUCCEEDED(m_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAccount, &pAccount)))
{
// Call through to the polymorphic version of us
hr = Connect(pAccount, hwnd, fShowUI);
pAccount->Release();
}
else
{
// Bug #36071 - If we haven't set up any accounts of this type yet,
// we'd fail. As a result, if you fire a URL to a server
// we'd never try to connect and download. I'm going
// to change this to succeed and we'll see what type
// of bugs that creates.
hr = S_OK;
}
return (hr);
}
//
// FUNCTION: CConnectionManager::Connect()
//
// PURPOSE: Attempts to establish a connection for the account specified.
//
// PARAMETERS:
// <in> hMenu - Handle of the menu that was used to select the account
// to connect to.
// <in> cmd - Cmd ID from the menu that says which account to use.
// <in> hwnd - Handle to display UI over.
//
// RETURN VALUE:
// <???>
//
HRESULT CConnectionManager::Connect(HMENU hMenu, DWORD cmd, HWND hwnd)
{
MENUITEMINFO mii;
Assert(hMenu && cmd);
Assert(cmd >= (DWORD) ID_CONNECT_FIRST && cmd < ((DWORD) ID_CONNECT_FIRST + GetMenuItemCount(hMenu)));
// Get the account pointer from the menu item
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_DATA;
mii.dwItemData = 0;
if (GetMenuItemInfo(hMenu, cmd, FALSE, &mii))
{
Assert(mii.dwItemData);
if (mii.dwItemData)
{
return (Connect((IImnAccount *) mii.dwItemData, hwnd, TRUE));
}
}
return (E_UNEXPECTED);
}
HRESULT CConnectionManager::ConnectDefault(HWND hwnd, BOOL fShowUI)
{
IImnEnumAccounts *pEnum = NULL;
IImnAccount *pAcct = NULL;
DWORD dwConn = 0;
TCHAR szAcct[CCHMAX_ACCOUNT_NAME];
TCHAR szConn[CCHMAX_CONNECTOID];
HRESULT hr = E_UNEXPECTED;
// Get the enumerator from the account manager
if (SUCCEEDED(m_pAcctMan->Enumerate(SRV_ALL, &pEnum)))
{
pEnum->Reset();
// Walk through all the accounts
while (SUCCEEDED(pEnum->GetNext(&pAcct)))
{
// Get the connection type for this account
if (SUCCEEDED(pAcct->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConn)))
{
// If the account is a RAS account, ask for the connectoid name
// and the account name.
if (dwConn == CONNECTION_TYPE_RAS || dwConn == CONNECTION_TYPE_INETSETTINGS)
{
break;
}
}
SafeRelease(pAcct);
}
SafeRelease(pEnum);
}
if (pAcct)
{
hr = Connect(pAcct, hwnd, fShowUI);
SafeRelease(pAcct);
}
return (hr);
}
//
// FUNCTION: CConnectionManager::Disconnect()
//
// PURPOSE: Brings down the current RAS connection.
//
// PARAMETERS:
// <in> hwnd - Handle of the window to display UI over.
// <in> fShowUI - Allows to caller to determine if UI will be displayed
// while disconnecting.
// <in> fForce - Forces the connection down even if we didn't create it.
// <in> fShutdown - TRUE if we're dropping because we're shutting down.
//
// RETURN VALUE:
// S_OK - Everything worked.
// E_FAIL - We didn't create it
//
HRESULT CConnectionManager::Disconnect(HWND hwnd, BOOL fShowUI, BOOL fForce,
BOOL fShutdown)
{
HRESULT hr;
TCHAR szRes[CCHMAX_STRINGRES];
TCHAR szBuf[CCHMAX_STRINGRES];
int idAnswer = IDYES;
// RefreshConnInfo
hr = RefreshConnInfo(FALSE);
if (FAILED(hr))
return hr;
// See if we even have a RAS connection active
if (!m_rConnInfo.hRasConn)
return (S_OK);
/*
if (!(*m_rConnInfo.szCurrentConnectionName))
return S_OK;
*/
// The autodialer has it's own shutdown prompt.
if (fShutdown && m_rConnInfo.fAutoDial)
return (S_OK);
if (fShutdown && !m_rConnInfo.fIStartedRas)
return (S_OK);
if (fShutdown)
{
AthLoadString(idsRasPromptDisconnect, szRes, ARRAYSIZE(szRes));
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, m_rConnInfo.szCurrentConnectionName);
idAnswer = AthMessageBox(hwnd, MAKEINTRESOURCE(idsAthena), szBuf,
0, MB_YESNO | MB_ICONEXCLAMATION );
}
// Hang up
if (idAnswer == IDYES)
{
SendAdvise(CONNNOTIFY_DISCONNECTING, NULL);
if (S_FALSE == DoAutoDial(hwnd, m_rConnInfo.szCurrentConnectionName, FALSE))
{
InternetHangUpAndWait(m_dwConnId, DEF_HANGUP_WAIT);
/*
RasHangupAndWait(m_rConnInfo.hRasConn, DEF_HANGUP_WAIT);
*/
}
EnterCriticalSection(&m_cs);
ZeroMemory(&m_rConnInfo, sizeof(CONNINFO));
m_rConnInfo.state = CIS_CLEAN;
m_dwConnId = 0;
LeaveCriticalSection(&m_cs);
EmptyConnList();
SendAdvise(CONNNOTIFY_DISCONNECTED, NULL);
return (S_OK);
}
return (E_FAIL);
}
//
// FUNCTION: CConnectionManager::IsConnected()
//
// PURPOSE: Allows the client to query whether or not there is an active
// RAS connection that we established.
//
// RETURN VALUE:
// TRUE - We're connected, FALSE - we're not.
//
BOOL CConnectionManager::IsConnected(void)
{
BOOL f=FALSE;
EnterCriticalSection(&m_cs);
RefreshConnInfo();
if (m_rConnInfo.hRasConn)
{
f = (NULL == m_rConnInfo.hRasConn) ? FALSE : TRUE;
}
LeaveCriticalSection(&m_cs);
return f;
}
//
// FUNCTION: CConnectionManager::Advise()
//
// PURPOSE: Allows the user to register to be notified whenever connection
// status changes.
//
// PARAMETERS:
// <in> pNotify - Pointer to the IConnectionNotify interface the client
// would like called when events happen.
//
// RETURN VALUE:
// S_OK - Added ok.
// E_OUTOFMEMORY - Couldn't realloc the array
//
HRESULT CConnectionManager::Advise(IConnectionNotify *pNotify)
{
HRESULT hr = S_OK;
if (!pNotify)
return (E_INVALIDARG);
EnterCriticalSection(&m_cs);
// Check to see if we already have a notify window for this thread
NOTIFYHWND *pTemp = m_pNotifyList;
DWORD dwThread = GetCurrentThreadId();
while (pTemp)
{
if (pTemp->dwThreadId == dwThread)
break;
pTemp = pTemp->pNext;
}
// If we didn't find a notify window for this thread, create one
if (NULL == pTemp)
{
HWND hwndTemp = CreateWindow(NOTIFY_HWND, NULL, WS_OVERLAPPED, 10, 10, 10, 10,
NULL, (HMENU) 0, g_hInst, (LPVOID) this);
if (!hwndTemp)
{
hr = E_OUTOFMEMORY;
goto exit;
}
if (!MemAlloc((LPVOID*) &pTemp, sizeof(NOTIFYHWND)))
{
RemoveProp(hwndTemp, NOTIFY_HWND);
DestroyWindow(hwndTemp);
hr = E_OUTOFMEMORY;
goto exit;
}
pTemp->dwThreadId = dwThread;
pTemp->hwnd = hwndTemp;
pTemp->pNext = m_pNotifyList;
m_pNotifyList = pTemp;
}
// Allocate a NOTIFYLIST node for this caller
NOTIFYLIST *pListTemp;
if (!MemAlloc((LPVOID*) &pListTemp, sizeof(NOTIFYLIST)))
{
hr = E_OUTOFMEMORY;
goto exit;
}
pListTemp->pNotify = pNotify;
// Get the current list for this thread and insert this node at the
// beginning
pListTemp->pNext = (NOTIFYLIST *) GetWindowLongPtr(pTemp->hwnd, GWLP_USERDATA);
// Set this new list to the window
SetWindowLongPtr(pTemp->hwnd, GWLP_USERDATA, (LONG_PTR)pListTemp);
exit:
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CConnectionManager::Unadvise()
//
// PURPOSE: Allows a client that has previously registered for notifications
// to unregister itself.
//
// PARAMETERS:
// <in> pNotify - Pointer to the interface that is being called upon
// notifications.
//
// RETURN VALUE:
// E_INVALIDARG - pNotify was not found in the list
// S_OK - Everything's OK
//
HRESULT CConnectionManager::Unadvise(IConnectionNotify *pNotify)
{
DWORD index = 0;
HRESULT hr = S_OK;
EnterCriticalSection(&m_cs);
// Loop through the notify windows we own
NOTIFYHWND *pTemp = m_pNotifyList;
NOTIFYHWND *pHwndPrev = NULL;
while (pTemp)
{
// Get the list of notify callbacks for this window
NOTIFYLIST *pList = (NOTIFYLIST *)GetWindowLongPtr(pTemp->hwnd, GWLP_USERDATA);
if (pList)
{
// Loop through the callbacks looking for this one
NOTIFYLIST *pListT = pList;
NOTIFYLIST *pPrev;
// Check to see if it's the first one
if (pListT->pNotify == pNotify)
{
pList = pListT->pNext;
if (pList)
{
SetWindowLongPtr(pTemp->hwnd, GWLP_USERDATA, (LONG_PTR)pList);
}
else
{
Assert(GetCurrentThreadId() == GetWindowThreadProcessId(pTemp->hwnd, NULL));
RemoveProp(pTemp->hwnd, NOTIFY_HWND);
DestroyWindow(pTemp->hwnd);
if (pHwndPrev)
pHwndPrev->pNext = pTemp->pNext;
else
m_pNotifyList = pTemp->pNext;
MemFree(pTemp);
}
SafeMemFree(pListT);
hr = S_OK;
goto exit;
}
else
{
pPrev = pList;
pListT = pList->pNext;
while (pListT)
{
if (pListT->pNotify == pNotify)
{
pPrev->pNext = pListT->pNext;
SafeMemFree(pListT);
hr = S_OK;
goto exit;
}
pListT = pListT->pNext;
pPrev = pPrev->pNext;
}
}
}
pHwndPrev = pTemp;
pTemp = pTemp->pNext;
}
exit:
LeaveCriticalSection(&m_cs);
return (hr);
}
//
// FUNCTION: CConnectionManager::RasAccountsExist()
//
// PURPOSE: Allows the client to ask whether or not we have any accounts
// configured that require a RAS connection.
//
// RETURN VALUE:
// S_OK - Accounts exist that require RAS
// S_FALSE - No accounts exist that require RAS
//
HRESULT CConnectionManager::RasAccountsExist(void)
{
IImnEnumAccounts *pEnum = NULL;
IImnAccount *pAcct = NULL;
DWORD dwConn;
BOOL fFound = FALSE;
// If no RAS, no accounts
#ifdef SLOWDOWN_STARTUP_TIME
if (FAILED(VerifyRasLoaded()))
return (S_FALSE);
#endif
// We need to walk through the accounts in the Account Manager to see if
// any of them have a connect type of RAS. As soon as we find one, we can
// return success.
Assert(m_pAcctMan);
if (SUCCEEDED(m_pAcctMan->Enumerate(SRV_ALL, &pEnum)))
{
pEnum->Reset();
while (!fFound && SUCCEEDED(pEnum->GetNext(&pAcct)))
{
if (SUCCEEDED(pAcct->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConn)))
{
if (dwConn == CONNECTION_TYPE_RAS)
{
fFound = TRUE;
}
}
SafeRelease(pAcct);
}
SafeRelease(pEnum);
}
return (fFound ? S_OK : S_FALSE);
}
//
// FUNCTION: CConnectionManager::GetConnectMenu()
//
// PURPOSE: Returns a menu that has all the accounts that require RAS
// connections listed. A pointer to the IImnAccount for each
// account is stored in the menu item's dwItemData parameter.
// As a result, the client MUST call FreeConnectMenu() when then
// menu is no longer being used.
//
// PARAMETERS:
// <out> phMenu - Returns the menu handle
//
// RETURN VALUE:
// S_OK - phMenu contains the menu
// E_FAIL - Something unfortunate happend.
//
HRESULT CConnectionManager::GetConnectMenu(HMENU *phMenu)
{
HMENU hMenu = NULL;
IImnEnumAccounts *pEnum = NULL;
IImnAccount *pAcct = NULL;
DWORD dwConn = 0;
TCHAR szAcct[CCHMAX_ACCOUNT_NAME];
TCHAR szConn[CCHMAX_CONNECTOID];
TCHAR szConnQuoted[CCHMAX_CONNECTOID + 2], szBuf[CCHMAX_CONNECTOID + 2];
TCHAR szMenu[CCHMAX_ACCOUNT_NAME + CCHMAX_CONNECTOID];
MENUITEMINFO mii;
DWORD cAcct = 0;
// Create a menu and add all the RAS based accounts to it
Assert(m_pAcctMan);
hMenu = CreatePopupMenu();
// Get the enumerator from the account manager
if (SUCCEEDED(m_pAcctMan->Enumerate(SRV_ALL, &pEnum)))
{
pEnum->Reset();
// Walk through all the accounts
while (SUCCEEDED(pEnum->GetNext(&pAcct)))
{
// Get the connection type for this account
if (SUCCEEDED(pAcct->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConn)))
{
// If the account is a RAS account, ask for the connectoid name
// and the account name.
if (dwConn == CONNECTION_TYPE_RAS)
{
pAcct->GetPropSz(AP_RAS_CONNECTOID, szConn, ARRAYSIZE(szConn));
pAcct->GetPropSz(AP_ACCOUNT_NAME, szAcct, ARRAYSIZE(szAcct));
wnsprintf(szMenu, ARRAYSIZE(szMenu), _T("%s (%s)"), PszEscapeMenuStringA(szAcct, szBuf, sizeof(szBuf) / sizeof(TCHAR)), PszEscapeMenuStringA(szConn, szConnQuoted, sizeof(szConnQuoted) / sizeof(TCHAR)));
// Insert the menu item into the menu
ZeroMemory(&mii, sizeof(MENUITEMINFO));
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_TYPE;
mii.fType = MFT_STRING | MFT_RADIOCHECK;
mii.fState = MFS_ENABLED;
mii.wID = ID_CONNECT_FIRST + cAcct;
mii.dwItemData = (DWORD_PTR) pAcct;
mii.dwTypeData = szMenu;
pAcct->AddRef();
SideAssert(InsertMenuItem(hMenu, cAcct, TRUE, &mii));
cAcct++;
}
}
SafeRelease(pAcct);
}
SafeRelease(pEnum);
}
if (hMenu)
if(GetMenuItemCount(hMenu))
{
*phMenu = hMenu;
return (S_OK);
}
else
{
DestroyMenu(hMenu);
return (E_FAIL);
}
else
return (E_FAIL);
}
//
// FUNCTION: CConnectionManager::FreeConnectMenu()
//
// PURPOSE: Frees the item data stored with the menu returned from
// GetConnectMenu().
//
// PARAMETERS:
// <in> hMenu - Handle of the menu to free.
//
void CConnectionManager::FreeConnectMenu(HMENU hMenu)
{
// Walk through the items on this menu and free the pointers stored in
// the item data.
MENUITEMINFO mii;
int cItems = 0;
Assert(hMenu);
cItems = GetMenuItemCount(hMenu);
for (int i = 0; i < cItems; i++)
{
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_DATA;
mii.dwItemData = 0;
if (GetMenuItemInfo(hMenu, i, TRUE, &mii))
{
Assert(mii.dwItemData);
if (mii.dwItemData)
((IImnAccount *) mii.dwItemData)->Release();
}
}
DestroyMenu(hMenu);
}
//
// FUNCTION: CConnectionManager::OnActivate()
//
// PURPOSE: Called whenever the browser receives a WM_ACTIVATE message.
// In response, we check the current state of our RAS connection
// to see if we are still connected / disconnected.
void CConnectionManager::OnActivate(BOOL fActive)
{
BOOL fOfflineChanged = FALSE;
BOOL fOffline = FALSE;
if (fActive)
{
EnterCriticalSection(&m_cs);
m_rConnInfo.state = CIS_REFRESH;
// Check to see if we've gone offline
if (m_fOffline != IsGlobalOffline())
{
fOffline = m_fOffline = (!m_fOffline);
fOfflineChanged = TRUE;
}
LeaveCriticalSection(&m_cs);
// Do this outside of the critsec
if (fOfflineChanged)
SendAdvise(CONNNOTIFY_WORKOFFLINE, (LPVOID) IntToPtr(fOffline));
}
}
//
// FUNCTION: CConnectionManager::FillRasCombo()
//
// PURPOSE: This function enumerates the accounts in the account manager
// and builds a list of the RAS connections those accounts use.
// The function then inserts those connections in to the provided
// combobox.
//
// PARAMETERS:
// <in> hwndCombo - Handle of the combobox to fill
// <in> fIncludeNone - Inserts a string at the top "Don't dial a connection"
//
// RETURN VALUE:
// BOOL
//
BOOL CConnectionManager::FillRasCombo(HWND hwndCombo, BOOL fIncludeNone)
{
IImnEnumAccounts *pEnum = NULL;
IImnAccount *pAcct = NULL;
DWORD dwConn = 0;
LPTSTR *rgszConn = NULL;
TCHAR szConn[CCHMAX_CONNECTOID];
ULONG cAcct = 0;
ULONG cConn = 0;
BOOL fSucceeded = FALSE;
ULONG ul;
LPRASENTRYNAME pEntry=NULL;
DWORD dwSize,
cEntries,
dwError;
HRESULT hr = S_OK;
int i;
EnterCriticalSection(&m_cs);
#ifdef NEVER
// Find out how many accounts exist
m_pAcctMan->GetAccountCount(ACCT_NEWS, &cAcct);
m_pAcctMan->GetAccountCount(ACCT_MAIL, &ul);
cAcct += ul;
m_pAcctMan->GetAccountCount(ACCT_DIR_SERV, &ul);
cAcct += ul;
if (cAcct == 0)
{
fSucceeded = TRUE;
goto exit;
}
// Allocate an array to hold the connection list
if (!MemAlloc((LPVOID*) &rgszConn, cAcct * sizeof(LPTSTR)))
goto exit;
ZeroMemory(rgszConn, cAcct * sizeof(LPTSTR));
// Get the enumerator from the account manager
if (SUCCEEDED(m_pAcctMan->Enumerate(SRV_ALL, &pEnum)))
{
pEnum->Reset();
// Walk through all the accounts
while (SUCCEEDED(pEnum->GetNext(&pAcct)))
{
// Get the connection type for this account
if (SUCCEEDED(pAcct->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConn)))
{
// If the account is a RAS account, ask for the connectoid name
// and the account name.
if (dwConn == CONNECTION_TYPE_RAS)
{
pAcct->GetPropSz(AP_RAS_CONNECTOID, szConn, ARRAYSIZE(szConn));
// Check to see if this connection has already been inserted into
// our list
for (ULONG k = 0; k < cConn; k++)
{
if (0 == lstrcmpi(szConn, rgszConn[k]))
break;
}
// If we didn't find it, we insert it
if (k >= cConn)
{
rgszConn[cConn] = StringDup(szConn);
cConn++;
}
}
}
SafeRelease(pAcct);
}
SafeRelease(pEnum);
}
// Sort the list
int i, j, min;
LPTSTR pszT;
for (i = 0; i < (int) cConn; i++)
{
min = i;
for (j = i + 1; j < (int) cConn; j++)
if (0 > lstrcmpi(rgszConn[j], rgszConn[min]))
min = j;
pszT = rgszConn[min];
rgszConn[min] = rgszConn[i];
rgszConn[i] = pszT;
}
// Insert the items into the combo box
if (fIncludeNone)
{
AthLoadString(idsConnNoDial, szConn, ARRAYSIZE(szConn));
ComboBox_AddString(hwndCombo, szConn);
}
for (i = 0; i < (int) cConn; i++)
ComboBox_AddString(hwndCombo, rgszConn[i]);
#endif NEVER
// Make sure the RAS DLL is loaded before we try this
CHECKHR(hr = VerifyRasLoaded());
// Allocate RASENTRYNAME
dwSize = sizeof(RASENTRYNAME);
CHECKHR(hr = HrAlloc((LPVOID*)&pEntry, dwSize));
// Ver stamp the entry
pEntry->dwSize = sizeof(RASENTRYNAME);
cEntries = 0;
dwError = RasEnumEntries(NULL, NULL, pEntry, &dwSize, &cEntries);
if (dwError == ERROR_BUFFER_TOO_SMALL)
{
SafeMemFree(pEntry);
CHECKHR(hr = HrAlloc((LPVOID *)&pEntry, dwSize));
pEntry->dwSize = sizeof(RASENTRYNAME);
cEntries = 0;
dwError = RasEnumEntries(NULL, NULL, pEntry, &dwSize, &cEntries);
}
// Error ?
if (dwError)
{
hr = TrapError(IXP_E_RAS_ERROR);
goto exit;
}
// Insert the items into the combo box
if (fIncludeNone)
{
AthLoadString(idsConnNoDial, szConn, ARRAYSIZE(szConn));
ComboBox_AddString(hwndCombo, szConn);
}
for (i = 0; i < (int) cEntries; i++)
ComboBox_AddString(hwndCombo, pEntry[i].szEntryName);
fSucceeded = TRUE;
exit:
if (rgszConn)
{
for (i = 0; i < (int) cConn; i++)
SafeMemFree(rgszConn[i]);
MemFree(rgszConn);
}
SafeMemFree(pEntry);
LeaveCriticalSection(&m_cs);
return (fSucceeded);
}
//
// FUNCTION: CConnectionManager::DoStartupDial()
//
// PURPOSE: This function checks to see what the user's startup options
// are with respect to RAS and performs the actions required
// (dial, dialog, nada)
// PARAMETERS:
// <in> hwndParent - Handle to parent a dialog to
//
void CConnectionManager::DoStartupDial(HWND hwndParent)
{
DWORD dwStart;
DWORD dw;
DWORD dwReturn;
TCHAR szConn[CCHMAX_CONNECTOID];
LPRASCONN pConnections = NULL;
ULONG cConnections = 0;
DWORD dwDialFlags = 0;
DWORD dwLanFlags = 0;
// The first thing to do is figure out what the user's startup option if
dw = DwGetOption(OPT_DIALUP_START);
// If the user want's to do nothing, we're done
if (dw == START_NO_CONNECT)
return;
//ConnectUsingIESettings(hwndParent, TRUE);
if (!m_fDialerUI)
{
m_fDialerUI = TRUE;
// Check to see if we're working offline
if (IsGlobalOffline())
{
if (IDYES == AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrWorkingOffline),
0, MB_YESNO | MB_ICONEXCLAMATION ))
{
g_pConMan->SetGlobalOffline(FALSE);
}
else
{
goto DialerExit;
}
}
//We do not dial if there is an active connection already existing. Even if it is not the connection
//InternetDial would have dialed, if we had called. Heres why:
//1)We don't want to look into the registry to get the default connectoid.
//Thats why we call InternetDial with NULL and it dials the def connectoid if there is one set
//Otherwise it dials the first connectoid in the list.
//Since InternetDial figures out which connectoid to dial, we don't want to do all the work of figuring
//out if we are already connected to the connectoid we are going to dial.
//So we just do not dial even if there is one active connection.
if (SUCCEEDED(EnumerateConnections(&pConnections, &cConnections)))
{
if (cConnections > 0)
goto DialerExit;
}
dwDialFlags = INTERNET_AUTODIAL_FORCE_ONLINE;
if (VerifyMobilityPackLoaded() == S_OK)
{
if (!IsNetworkAlive(&dwLanFlags) || (!(dwLanFlags & NETWORK_ALIVE_LAN)))
dwDialFlags |= INTERNET_DIAL_SHOW_OFFLINE;
}
// Only one caller can be dialing the phone at a time.
if (WAIT_TIMEOUT == WaitForSingleObject(m_hMutexDial, 0))
{
goto DialerExit;
}
dwReturn = InternetDialA(hwndParent, NULL, dwDialFlags, &m_dwConnId, 0);
if (dwReturn == 0)
{
m_rConnInfo.fConnected = TRUE;
m_rConnInfo.fIStartedRas = TRUE;
m_rConnInfo.fAutoDial = FALSE;
m_rConnInfo.hRasConn = (HRASCONN)m_dwConnId;
SendAdvise(CONNNOTIFY_CONNECTED, NULL);
}
else
{
if (dwReturn == ERROR_USER_DISCONNECTION)
{
SendAdvise(CONNNOTIFY_USER_CANCELLED, NULL);
if (!!(dwDialFlags & INTERNET_DIAL_SHOW_OFFLINE))
SetGlobalOffline(TRUE);
}
else
{
DebugTrace("Error dialing: %d\n", GetLastError());
DebugTrace("InternetDial returned: %d\n", dwReturn);
}
}
DialerExit:
m_fDialerUI = FALSE;
SafeMemFree(pConnections);
}
ReleaseMutex(m_hMutexDial);
}
HRESULT CConnectionManager::GetDefConnectoid(LPTSTR szConn, DWORD dwSize)
{
HRESULT hr = E_FAIL;
DWORD dwType;
DWORD dwerr;
*szConn = '\0';
if ((dwerr = SHGetValue(HKEY_CURRENT_USER, c_szDefConnPath, c_szRegDefaultConnection, &dwType, szConn, &dwSize))
== ERROR_SUCCESS)
{
hr = S_OK;
}
return hr;
}
//
// FUNCTION: CConnectionManager::VerifyRasLoaded()
//
// PURPOSE: Checks to see if this object has already loaded the RAS DLL.
// If not, then the DLL is loaded and the function pointers are
// fixed up.
//
// RETURN VALUE:
// S_OK - Loaded and ready, sir.
// hrRasInitFailure - Failed to load.
//
HRESULT CConnectionManager::VerifyRasLoaded(void)
{
// Locals
UINT uOldErrorMode;
// Protected
EnterCriticalSection(&m_cs);
// Check to see if we've tried this before
if (m_fRASLoadFailed)
goto failure;
// Bug #20573 - Let's do a little voodoo here. On NT, it appears that they
// have a key in the registry to show which protocols are
// supported by RAS service. AKA - if this key doesn't exist,
// then RAS isn't installed. This may enable us to avoid some
// special bugs when RAS get's uninstalled on NT.
if (g_OSInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
HKEY hKey;
const TCHAR c_szRegKeyRAS[] = _T("SOFTWARE\\Microsoft\\RAS");
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyRAS, 0, KEY_READ, &hKey))
{
goto failure;
}
RegCloseKey(hKey);
}
// If dll is loaded, lets verify all of my function pointers
if (!m_hInstRas)
{
// Try loading Ras.
uOldErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);
m_hInstRas = LoadLibrary(szRasDll);
SetErrorMode(uOldErrorMode);
// Failure ?
if (!m_hInstRas)
goto failure;
// Did we load it
m_pRasDial = (RASDIALPROC)GetProcAddress(m_hInstRas, szRasDial);
m_pRasEnumConnections = (RASENUMCONNECTIONSPROC)GetProcAddress(m_hInstRas, szRasEnumConnections);
m_pRasEnumEntries = (RASENUMENTRIESPROC)GetProcAddress(m_hInstRas, szRasEnumEntries);
m_pRasGetConnectStatus = (RASGETCONNECTSTATUSPROC)GetProcAddress(m_hInstRas, szRasGetConnectStatus);
m_pRasGetErrorString = (RASGETERRORSTRINGPROC)GetProcAddress(m_hInstRas, szRasGetErrorString);
m_pRasHangup = (RASHANGUPPROC)GetProcAddress(m_hInstRas, szRasHangup);
m_pRasSetEntryDialParams = (RASSETENTRYDIALPARAMSPROC)GetProcAddress(m_hInstRas, szRasSetEntryDialParams);
m_pRasGetEntryDialParams = (RASGETENTRYDIALPARAMSPROC)GetProcAddress(m_hInstRas, szRasGetEntryDialParams);
m_pRasEditPhonebookEntry = (RASEDITPHONEBOOKENTRYPROC)GetProcAddress(m_hInstRas, szRasEditPhonebookEntry);
m_pRasGetEntryProperties = (RASGETENTRYPROPERTIES) GetProcAddress(m_hInstRas, szRasGetEntryProperties);
}
if (!m_hInstRasDlg && FIsPlatformWinNT())
{
// Try loading Ras.
uOldErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);
m_hInstRasDlg = LoadLibrary(s_szRasDlgDll);
SetErrorMode(uOldErrorMode);
// Failure ?
if (!m_hInstRasDlg)
goto failure;
m_pRasDialDlg = (RASDIALDLGPROC)GetProcAddress(m_hInstRasDlg, s_szRasDialDlg);
m_pRasEntryDlg = (RASENTRYDLGPROC)GetProcAddress(m_hInstRasDlg, s_szRasEntryDlg);
if (!m_pRasDialDlg || !m_pRasEntryDlg)
goto failure;
}
// Make sure all functions have been loaded
if (m_pRasDial &&
m_pRasEnumConnections &&
m_pRasEnumEntries &&
m_pRasGetConnectStatus &&
m_pRasGetErrorString &&
m_pRasHangup &&
m_pRasSetEntryDialParams &&
m_pRasGetEntryDialParams &&
m_pRasEditPhonebookEntry)
{
// Protected
LeaveCriticalSection(&m_cs);
// Success
return S_OK;
}
failure:
m_fRASLoadFailed = TRUE;
// Protected
LeaveCriticalSection(&m_cs);
// Otherwise, were hosed
return (hrRasInitFailure);
}
//
// FUNCTION: CConnectionManager::EnumerateConnections()
//
// PURPOSE: Asks RAS for the list of active RAS connections.
//
// PARAMETERS:
// <out> ppRasConn - Returns an array of RASCONN structures for the
// list of active connections.
// <out> pcConnections - Number of structures in ppRasCon.
//
// RETURN VALUE:
// S_OK - The data in ppRasConn and pcConnections is valid
//
HRESULT CConnectionManager::EnumerateConnections(LPRASCONN *ppRasConn,
ULONG *pcConnections)
{
// Locals
DWORD dw,
dwSize;
BOOL fResult=FALSE;
HRESULT hr;
// Check Params
Assert(ppRasConn && pcConnections);
// Make sure RAS is loaded
if (FAILED(hr = VerifyRasLoaded()))
return (hr);
// Init
*ppRasConn = NULL;
*pcConnections = 0;
// Sizeof my buffer
dwSize = sizeof(RASCONN) * 2;
// Allocate enough for 1 ras connection info object
if (!MemAlloc((LPVOID *)ppRasConn, dwSize))
{
TRAPHR(hrMemory);
return (E_OUTOFMEMORY);
}
ZeroMemory(*ppRasConn, dwSize);
// Buffer size
//(*ppRasConn)->dwSize = dwSize;
(*ppRasConn)->dwSize = sizeof(RASCONN);
// Enumerate ras connections
dw = RasEnumConnections(*ppRasConn, &dwSize, pcConnections);
// Not enough memory ?
if ((dw == ERROR_BUFFER_TOO_SMALL) || (dw == ERROR_NOT_ENOUGH_MEMORY))
{
// Reallocate
if (!MemRealloc((LPVOID *)ppRasConn, dwSize))
{
TRAPHR(hrMemory);
goto exit;
}
// Call enumerate again
*pcConnections = 0;
(*ppRasConn)->dwSize = sizeof(RASCONN);
dw = RasEnumConnections(*ppRasConn, &dwSize, pcConnections);
}
// If still failed
if (dw)
{
AssertSz(FALSE, "RasEnumConnections failed");
return E_FAIL;
}
// Success
hr = S_OK;
exit:
// Done
return S_OK;
}
//
// FUNCTION: CConnectionManager::StartRasDial()
//
// PURPOSE: Called when the client actually wants to establish a RAS
// connection.
//
// PARAMETERS:
// <in> hwndParent - Handle of the window to parent any UI
// <in> pszConnection - Name of the connection to establish
//
// RETURN VALUE:
// HRESULT
//
HRESULT CConnectionManager::StartRasDial(HWND hwndParent, LPTSTR pszConnection)
{
HRESULT hr = S_OK;
// Refresh ConnInfo
CHECKHR(hr = RefreshConnInfo());
// Check to see if we need to ask the user for information or credentials
// before we attempt to dial
CHECKHR (hr = RasLogon(hwndParent, pszConnection, FALSE));
// If we can use a system dialog for this, do so.
if (m_pRasDialDlg)
{
RASDIALDLG rdd = {0};
BOOL fRet;
rdd.dwSize = sizeof(rdd);
rdd.hwndOwner = hwndParent;
#if (WINVER >= 0x401)
rdd.dwSubEntry = m_rdp.dwSubEntry;
#else
rdd.dwSubEntry = 0;
#endif
fRet = RasDialDlg(NULL, m_rdp.szEntryName,
lstrlen(m_rdp.szPhoneNumber) ? m_rdp.szPhoneNumber : NULL,
&rdd);
if (fRet)
{
// Need to get the current connection handle
LPRASCONN pConnections = NULL;
ULONG cConnections = 0;
if (SUCCEEDED(EnumerateConnections(&pConnections, &cConnections)))
{
for (UINT i = 0; i < cConnections; i++)
{
if (0 == lstrcmpi(pConnections[i].szEntryName, m_rdp.szEntryName))
{
EnterCriticalSection(&m_cs);
m_rConnInfo.hRasConn = pConnections[i].hrasconn;
LeaveCriticalSection(&m_cs);
break;
}
}
SafeMemFree(pConnections);
}
hr = S_OK;
}
else
hr = E_FAIL;
}
else
{
// We need to use our own RAS UI.
hr = (HRESULT) DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddRasProgress),
hwndParent, RasProgressDlgProc,
(LPARAM) this);
}
exit:
// Done
return hr;
}
//
// FUNCTION: CConnectionManager::RasLogon()
//
// PURPOSE: Attempts to load the RAS phonebook entry for the requested
// connection. If it doesn't exist or there isn't enough info,
// we present UI to the user to request that information.
//
// PARAMETERS:
// <in> hwnd - Handle to display UI over.
// <in> pszConnection - Name of the connection to load info for.
// <in> fForcePrompt - Forces the UI to be displayed.
//
// RETURN VALUE:
// S_OK - prdp contains the requested information
// hrGetDialParmasFailed - Couldn't get the phonebook entry from RAS
// hrUserCancel - User canceled
//
//
HRESULT CConnectionManager::RasLogon(HWND hwnd, LPTSTR pszConnection,
BOOL fForcePrompt)
{
// Locals
HRESULT hr = S_OK;
DWORD dwRasError;
// Do we need to prompt for logon information first ?
ZeroMemory(&m_rdp, sizeof(RASDIALPARAMS));
m_rdp.dwSize = sizeof(RASDIALPARAMS);
StrCpyN(m_rdp.szEntryName, pszConnection, ARRAYSIZE(m_rdp.szEntryName));
// See if we can get the information from RAS
dwRasError = RasGetEntryDialParams(NULL, &m_rdp, &m_fSavePassword);
if (dwRasError)
{
TCHAR szRes[CCHMAX_STRINGRES], szBuf[CCHMAX_STRINGRES];
AthLoadString(idshrGetDialParamsFailed, szRes, ARRAYSIZE(szRes));
wnsprintf(szBuf, ARRAYSIZE(szBuf), szRes, pszConnection);
AthMessageBox(hwnd, MAKEINTRESOURCE(idsRasError), szBuf, 0, MB_OK | MB_ICONSTOP);
hr = TRAPHR(hrGetDialParamsFailed);
goto exit;
}
// NT Supports the UI we need to display. If this exists, then
// RasDialDlg will take it from here
if (m_pRasDialDlg)
{
goto exit;
}
// Do we need to get password / account information?
if (fForcePrompt || m_fSavePassword == FALSE ||
FIsStringEmpty(m_rdp.szUserName) || FIsStringEmpty(m_rdp.szPassword))
{
// RAS Logon
hr = (HRESULT) DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddRasLogon), hwnd,
RasLogonDlgProc, (LPARAM) this);
if (hr == hrUserCancel)
{
DisplayRasError(hwnd, hrUserCancel, 0);
hr = hrUserCancel;
goto exit;
}
}
exit:
// Done
return hr;
}
//
// FUNCTION: CConnectionManager::DisplayRasError()
//
// PURPOSE: Displays a message box describing the error that occured while
// dealing with connections etc.
//
// PARAMETERS:
// <in> hwnd - Handle of the window to display UI over
// <in> hrRasError - HRESULT to display the error for
// <in> dwRasError - Error code returned from RAS to display the error for
//
void CConnectionManager::DisplayRasError(HWND hwnd, HRESULT hrRasError,
DWORD dwRasError)
{
// Locals
TCHAR szRasError[256];
BOOL fRasError = FALSE;
// No Error
if (SUCCEEDED(hrRasError))
return;
// Look up RAS error
if (dwRasError)
{
if (RasGetErrorString(dwRasError, szRasError, sizeof(szRasError)) == 0)
fRasError = TRUE;
else
*szRasError = _T('\0');
}
// General Error
switch (hrRasError)
{
case hrUserCancel:
break;
case hrMemory:
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsRasError), MAKEINTRESOURCEW(idsMemory), 0, MB_OK | MB_ICONSTOP);
break;
case hrRasInitFailure:
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsRasError), MAKEINTRESOURCEW(hrRasInitFailure), 0, MB_OK | MB_ICONSTOP);
break;
case hrRasDialFailure:
if (fRasError)
CombinedRasError(hwnd, HR_CODE(hrRasDialFailure), szRasError, dwRasError);
else
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsRasError), MAKEINTRESOURCEW(hrRasDialFailure), 0, MB_OK | MB_ICONSTOP);
break;
case hrRasServerNotFound:
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsRasError), MAKEINTRESOURCEW(hrRasServerNotFound), 0, MB_OK | MB_ICONSTOP);
break;
case hrGetDialParamsFailed:
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsRasError), MAKEINTRESOURCEW(hrGetDialParamsFailed), 0, MB_OK | MB_ICONSTOP);
break;
case E_FAIL:
default:
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsRasError), MAKEINTRESOURCEW(idsRasErrorGeneral), 0, MB_OK | MB_ICONSTOP);
break;
}
}
//
// FUNCTION: CConnectionManager::PromptCloseConn()
//
// PURPOSE: Asks the user if they want to close the current connection or
// try to use it.
//
// PARAMETERS:
// <in> hwnd - Parent for the dialog
//
// RETURN VALUE:
// Returns the button that closed the dialog
//
UINT CConnectionManager::PromptCloseConnection(HWND hwnd)
{
RefreshConnInfo();
if (DwGetOption(OPT_DIALUP_WARN_SWITCH))
{
if (0 == lstrcmpi(m_rConnInfo.szCurrentConnectionName, m_szConnectName))
return (idrgUseCurrent);
else
return (UINT) DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddRasCloseConn), hwnd,
RasCloseConnDlgProc, (LPARAM) this);
}
else
return (idrgDialNew);
}
INT_PTR CALLBACK CConnectionManager::RasCloseConnDlgProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
// Locals
CConnectionManager *pThis = NULL;
TCHAR szRes[255],
szMsg[255+RAS_MaxEntryName+1];
TCHAR szConn[CCHMAX_CONNECTOID + 2];
switch(uMsg)
{
case WM_INITDIALOG:
// The LPARAM contains our this pointer
pThis = (CConnectionManager*) lParam;
if (!pThis)
{
Assert(pThis);
EndDialog(hwnd, E_FAIL);
return (TRUE);
}
// Center
CenterDialog(hwnd);
// Refresh Connection Info
pThis->RefreshConnInfo();
// Set Text
GetWindowText(GetDlgItem(hwnd, idcCurrentMsg), szRes, sizeof(szRes)/sizeof(TCHAR));
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, PszEscapeMenuStringA(pThis->m_rConnInfo.szCurrentConnectionName, szConn, sizeof(szConn) / sizeof(TCHAR)));
SetWindowText(GetDlgItem(hwnd, idcCurrentMsg), szMsg);
// Set control
GetWindowText(GetDlgItem(hwnd, idrgDialNew), szRes, sizeof(szRes)/sizeof(TCHAR));
wnsprintf(szMsg, ARRAYSIZE(szMsg), szRes, PszEscapeMenuStringA(pThis->m_szConnectName, szConn, sizeof(szConn) / sizeof(TCHAR)));
SetWindowText(GetDlgItem(hwnd, idrgDialNew), szMsg);
// Set Default
CheckDlgButton(hwnd, idrgDialNew, TRUE);
return (TRUE);
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDOK:
{
if (BST_CHECKED == Button_GetCheck(GetDlgItem(hwnd, idcDontWarnCheck)))
{
// If the user has this checked, we reset the "Warn before..." option
SetDwOption(OPT_DIALUP_WARN_SWITCH, 0, NULL, 0);
}
EndDialog(hwnd, IsDlgButtonChecked(hwnd, idrgDialNew) ? idrgDialNew : idrgUseCurrent);
return (TRUE);
}
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
return (TRUE);
}
return (TRUE);
}
return (FALSE);
}
//
// FUNCTION: CConnectionMAanger::CombinedRasError()
//
// PURPOSE: <???>
//
// PARAMETERS:
// <???>
//
void CConnectionManager::CombinedRasError(HWND hwnd, UINT unids,
LPTSTR pszRasError, DWORD dwRasError)
{
// Locals
TCHAR szRes[255],
sz[30];
LPTSTR pszError=NULL;
// Load string
AthLoadString(unids, szRes, sizeof(szRes));
// Allocate memory for errors
DWORD cc = lstrlen(szRes) + lstrlen(pszRasError) + 100;
pszError = SzStrAlloc(cc);
// Out of Memory ?
if (!pszError)
AthMessageBox(hwnd, MAKEINTRESOURCE(idsRasError), szRes, 0, MB_OK | MB_ICONSTOP);
// Build Error message
else
{
AthLoadString(idsErrorText, sz, sizeof(sz));
wnsprintf(pszError, cc, "%s\n\n%s %d: %s", szRes, sz, dwRasError, pszRasError);
AthMessageBox(hwnd, MAKEINTRESOURCE(idsRasError), pszError, 0, MB_OK | MB_ICONSTOP);
MemFree(pszError);
}
}
//
// FUNCTION: CConnectionManager::RasHangupAndWait()
//
// PURPOSE: Hangs up on a RAS connection and waits for it to finish before
// returning.
//
// PARAMETERS:
// <in> hRasConn - Handle of the connection to hang up.
// <in> dwMaxWaitSeconds - Amount of time to wait.
//
// RETURN VALUE:
// TRUE if we disconnected, FALSE otherwise.
//
BOOL CConnectionManager::RasHangupAndWait(HRASCONN hRasConn, DWORD dwMaxWaitSeconds)
{
// Locals
RASCONNSTATUS rcs;
DWORD dwTicks=GetTickCount();
// Check Params
if (!hRasConn)
return 0;
// Make sure RAS is loaded
if (FAILED (VerifyRasLoaded()))
return FALSE;
// Call Ras hangup
if (RasHangup(hRasConn))
return FALSE;
// Wait for connection to really close
ZeroMemory(&rcs, sizeof(RASCONNSTATUS));
rcs.dwSize = sizeof(RASCONNSTATUS);
while (RasGetConnectStatus(hRasConn, &rcs) != ERROR_INVALID_HANDLE && rcs.rasconnstate != RASCS_Disconnected)
{
// Wait timeout
if (GetTickCount() - dwTicks >= dwMaxWaitSeconds * 1000)
break;
// Sleep and yields
Sleep(0);
}
// Wait 2 seconds for modem to reset
Sleep(2000);
// Done
return TRUE;
}
DWORD CConnectionManager::InternetHangUpAndWait(DWORD_PTR hRasConn, DWORD dwMaxWaitSeconds)
{
// Locals
RASCONNSTATUS rcs;
DWORD dwTicks=GetTickCount();
DWORD dwret;
// Check Params
if (!hRasConn)
return 0;
// Make sure RAS is loaded
if (FAILED (VerifyRasLoaded()))
return FALSE;
dwret = InternetHangUp(m_dwConnId, 0);
if (dwret)
{
DebugTrace("InternetHangup failed: %d\n", dwret);
goto exit;
}
// Wait for connection to really close
ZeroMemory(&rcs, sizeof(RASCONNSTATUS));
rcs.dwSize = sizeof(RASCONNSTATUS);
while (RasGetConnectStatus((HRASCONN)hRasConn, &rcs) != ERROR_INVALID_HANDLE && rcs.rasconnstate != RASCS_Disconnected)
{
// Wait timeout
if (GetTickCount() - dwTicks >= dwMaxWaitSeconds * 1000)
break;
// Sleep and yields
Sleep(0);
}
// Wait 2 seconds for modem to reset
Sleep(2000);
exit:
return dwret;
}
INT_PTR CALLBACK CConnectionManager::RasLogonDlgProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
// Locals
TCHAR sz[255],
szText[255 + RAS_MaxEntryName + 1];
DWORD dwRasError;
CConnectionManager *pThis = (CConnectionManager *)GetWndThisPtr(hwnd);
switch (uMsg)
{
case WM_INITDIALOG:
// Get lparam
pThis = (CConnectionManager *)lParam;
if (!pThis)
{
Assert (FALSE);
EndDialog(hwnd, E_FAIL);
return (TRUE);
}
// Center the window
CenterDialog(hwnd);
// Get Window Title
GetWindowText(hwnd, sz, sizeof(sz));
wnsprintf(szText, ARRAYSIZE(szText), sz, pThis->m_szConnectName);
SetWindowText(hwnd, szText);
// Word Default
AthLoadString(idsDefault, sz, sizeof(sz));
// Set Fields
Edit_LimitText(GetDlgItem(hwnd, ideUserName), UNLEN);
Edit_LimitText(GetDlgItem(hwnd, idePassword), PWLEN);
Edit_LimitText(GetDlgItem(hwnd, idePhone), RAS_MaxPhoneNumber);
SetDlgItemText(hwnd, ideUserName, pThis->m_rdp.szUserName);
SetDlgItemText(hwnd, idePassword, pThis->m_rdp.szPassword);
if (FIsStringEmpty(pThis->m_rdp.szPhoneNumber))
SetDlgItemText(hwnd, idePhone, sz);
else
SetDlgItemText(hwnd, idePhone, pThis->m_rdp.szPhoneNumber);
CheckDlgButton(hwnd, idchSavePassword, pThis->m_fSavePassword);
// Save pRas
SetWndThisPtr(hwnd, pThis);
return 1;
case WM_COMMAND:
switch(GET_WM_COMMAND_ID(wParam, lParam))
{
case idbEditConnection:
pThis->EditPhonebookEntry(hwnd, (pThis->m_szConnectName));
return 1;
case IDCANCEL:
EndDialog(hwnd, hrUserCancel);
return 1;
case IDOK:
AthLoadString(idsDefault, sz, sizeof(sz));
// Set Fields
GetDlgItemText(hwnd, ideUserName, pThis->m_rdp.szUserName, UNLEN+1);
GetDlgItemText(hwnd, idePassword, pThis->m_rdp.szPassword, PWLEN+1);
GetDlgItemText(hwnd, idePhone, pThis->m_rdp.szPhoneNumber, RAS_MaxPhoneNumber+1);
if (lstrcmp(pThis->m_rdp.szPhoneNumber, sz) == 0)
*pThis->m_rdp.szPhoneNumber = _T('\0');
pThis->m_fSavePassword = IsDlgButtonChecked(hwnd, idchSavePassword);
// Save Dial Parameters
dwRasError = (pThis->m_pRasSetEntryDialParams)(NULL, &(pThis->m_rdp), !(pThis->m_fSavePassword));
if (dwRasError)
{
pThis->DisplayRasError(hwnd, hrSetDialParamsFailed, dwRasError);
return 1;
}
EndDialog(hwnd, S_OK);
return 1;
}
break;
case WM_DESTROY:
SetWndThisPtr (hwnd, NULL);
break;
}
return 0;
}
INT_PTR CALLBACK CConnectionManager::RasProgressDlgProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
// Locals
CConnectionManager *pThis = (CConnectionManager *) GetWndThisPtr(hwnd);
TCHAR szText[255+RAS_MaxEntryName+1],
sz[255];
static TCHAR s_szCancel[40];
static UINT s_unRasEventMsg=0;
static BOOL s_fDetails=FALSE;
static RECT s_rcDialog;
static BOOL s_fAuthStarted=FALSE;
DWORD dwRasError,
cyDetails;
RASCONNSTATUS rcs;
RECT rcDetails,
rcDlg;
switch (uMsg)
{
case WM_INITDIALOG:
// Get lparam
pThis = (CConnectionManager *)lParam;
if (!pThis)
{
Assert (FALSE);
EndDialog(hwnd, E_FAIL);
return 1;
}
// Save this pointer
SetWndThisPtr (hwnd, pThis);
// Save Original Size of the dialog
GetWindowRect (hwnd, &s_rcDialog);
// Refresh Connection Info
pThis->RefreshConnInfo();
// Details enabled
s_fDetails = DwGetOption(OPT_RASCONNDETAILS);
// Hide details drop down
if (s_fDetails == FALSE)
{
// Hid
GetWindowRect (GetDlgItem (hwnd, idcSplitter), &rcDetails);
// Height of details
cyDetails = s_rcDialog.bottom - rcDetails.top;
// Re-size
MoveWindow (hwnd, s_rcDialog.left,
s_rcDialog.top,
s_rcDialog.right - s_rcDialog.left,
s_rcDialog.bottom - s_rcDialog.top - cyDetails - 1,
FALSE);
}
else
{
AthLoadString (idsHideDetails, sz, sizeof (sz));
SetWindowText (GetDlgItem (hwnd, idbDet), sz);
}
// Get registered RAS event message id
s_unRasEventMsg = RegisterWindowMessageA(RASDIALEVENT);
if (s_unRasEventMsg == 0)
s_unRasEventMsg = WM_RASDIALEVENT;
// Center the window
CenterDialog (hwnd);
SetForegroundWindow(hwnd);
// Get Window Title
GetWindowText(hwnd, sz, sizeof(sz));
wnsprintf(szText, ARRAYSIZE(szText), sz, pThis->m_szConnectName);
SetWindowText(hwnd, szText);
// Dialog Xxxxxxx.....
if (pThis->m_rdp.szPhoneNumber[0])
{
AthLoadString(idsRas_Dialing_Param, sz, sizeof(sz)/sizeof(TCHAR));
wnsprintf(szText, ARRAYSIZE(szText), sz, pThis->m_rdp.szPhoneNumber);
}
else
AthLoadString(idsRas_Dialing, szText, ARRAYSIZE(szText));
SetWindowText(GetDlgItem(hwnd, ideProgress), szText);
// Get Cancel Text
GetWindowText(GetDlgItem(hwnd, IDCANCEL), s_szCancel, sizeof(s_szCancel));
// Give the list box and hscroll
SendMessage(GetDlgItem(hwnd, idlbDetails), LB_SETHORIZONTALEXTENT, 600, 0);
// Dial the connection
pThis->m_rConnInfo.hRasConn = NULL;
dwRasError = (pThis->m_pRasDial)(NULL, NULL, &(pThis->m_rdp), 0xFFFFFFFF, hwnd, &(pThis->m_rConnInfo.hRasConn));
if (dwRasError)
{
pThis->FailedRasDial(hwnd, hrRasDialFailure, dwRasError);
if (!pThis->LogonRetry(hwnd, s_szCancel))
{
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDCANCEL,IDCANCEL), NULL);
return 1;
}
}
return 1;
case WM_COMMAND:
switch(GET_WM_COMMAND_ID(wParam,lParam))
{
case IDCANCEL:
SetDwOption(OPT_RASCONNDETAILS, s_fDetails, NULL, 0);
EnableWindow(GetDlgItem(hwnd, IDCANCEL), FALSE);
if (pThis)
pThis->FailedRasDial(hwnd, hrUserCancel, 0);
EndDialog(hwnd, hrUserCancel);
return 1;
case idbDet:
// Get current location of the dialog
GetWindowRect (hwnd, &rcDlg);
// If currently hidden
if (s_fDetails == FALSE)
{
// Re-size
MoveWindow (hwnd, rcDlg.left,
rcDlg.top,
s_rcDialog.right - s_rcDialog.left,
s_rcDialog.bottom - s_rcDialog.top,
TRUE);
AthLoadString (idsHideDetails, sz, sizeof (sz));
SetWindowText (GetDlgItem (hwnd, idbDet), sz);
s_fDetails = TRUE;
}
else
{
// Size of details
GetWindowRect (GetDlgItem (hwnd, idcSplitter), &rcDetails);
cyDetails = rcDlg.bottom - rcDetails.top;
MoveWindow (hwnd, rcDlg.left,
rcDlg.top,
s_rcDialog.right - s_rcDialog.left,
s_rcDialog.bottom - s_rcDialog.top - cyDetails - 1,
TRUE);
AthLoadString (idsShowDetails, sz, sizeof (sz));
SetWindowText (GetDlgItem (hwnd, idbDet), sz);
s_fDetails = FALSE;
}
break;
}
break;
case WM_DESTROY:
SetWndThisPtr (hwnd, NULL);
break;
case CM_INTERNALRECONNECT:
if (!pThis->LogonRetry(hwnd, s_szCancel))
{
SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDCANCEL,IDCANCEL), NULL);
return 1;
}
break;
default:
if (!pThis)
break;
pThis->RefreshConnInfo();
if (uMsg == s_unRasEventMsg)
{
HWND hwndLB = GetDlgItem(hwnd, idlbDetails);
// Error ?
if (lParam)
{
// Disconnected
AthLoadString(idsRASCS_Disconnected, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
// Log Error
TCHAR szRasError[512];
if ((pThis->m_pRasGetErrorString)((UINT) lParam, szRasError, sizeof(szRasError)) == 0)
{
TCHAR szError[512 + 255];
AthLoadString(idsErrorText, sz, sizeof(sz));
wnsprintf(szError, ARRAYSIZE(szError), "%s %d: %s", sz, lParam, szRasError);
ListBox_AddString(hwndLB, szError);
}
// Select last item
SendMessage(hwndLB, LB_SETCURSEL, ListBox_GetCount(hwndLB)-1, 0);
// Show Error
pThis->FailedRasDial(hwnd, hrRasDialFailure, (DWORD) lParam);
// Re logon
PostMessage(hwnd, CM_INTERNALRECONNECT, 0, 0);
}
// Otherwise, process RAS event
else
{
switch(wParam)
{
case RASCS_OpenPort:
AthLoadString(idsRASCS_OpenPort, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_PortOpened:
AthLoadString(idsRASCS_PortOpened, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_ConnectDevice:
rcs.dwSize = sizeof(RASCONNSTATUS);
if (pThis->m_rConnInfo.hRasConn && (pThis->m_pRasGetConnectStatus)(pThis->m_rConnInfo.hRasConn, &rcs) == 0)
{
AthLoadString(idsRASCS_ConnectDevice, sz, sizeof(sz)/sizeof(TCHAR));
wnsprintf(szText, ARRAYSIZE(szText), sz, rcs.szDeviceName, rcs.szDeviceType);
ListBox_AddString(hwndLB, szText);
}
break;
case RASCS_DeviceConnected:
rcs.dwSize = sizeof(RASCONNSTATUS);
if (pThis->m_rConnInfo.hRasConn && (pThis->m_pRasGetConnectStatus)(pThis->m_rConnInfo.hRasConn, &rcs) == 0)
{
AthLoadString(idsRASCS_DeviceConnected, sz, sizeof(sz)/sizeof(TCHAR));
wnsprintf(szText, ARRAYSIZE(szText), sz, rcs.szDeviceName, rcs.szDeviceType);
ListBox_AddString(hwndLB, szText);
}
break;
case RASCS_AllDevicesConnected:
AthLoadString(idsRASCS_AllDevicesConnected, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_Authenticate:
if (s_fAuthStarted == FALSE)
{
AthLoadString(idsRas_Authentication, sz, sizeof(sz)/sizeof(TCHAR));
SetWindowText(GetDlgItem(hwnd, ideProgress), sz);
ListBox_AddString(hwndLB, sz);
s_fAuthStarted = TRUE;
}
break;
case RASCS_AuthNotify:
rcs.dwSize = sizeof(RASCONNSTATUS);
if (pThis->m_rConnInfo.hRasConn && (pThis->m_pRasGetConnectStatus)(pThis->m_rConnInfo.hRasConn, &rcs) == 0)
{
AthLoadString(idsRASCS_AuthNotify, sz, sizeof(sz)/sizeof(TCHAR));
wnsprintf(szText, ARRAYSIZE(szText), sz, rcs.dwError);
ListBox_AddString(hwndLB, szText);
if (rcs.dwError)
{
pThis->FailedRasDial(hwnd, hrRasDialFailure, rcs.dwError);
PostMessage(hwnd, CM_INTERNALRECONNECT, 0, 0);
}
}
break;
case RASCS_AuthRetry:
AthLoadString(idsRASCS_AuthRetry, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_AuthCallback:
AthLoadString(idsRASCS_AuthCallback, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_AuthChangePassword:
AthLoadString(idsRASCS_AuthChangePassword, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_AuthProject:
AthLoadString(idsRASCS_AuthProject, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_AuthLinkSpeed:
AthLoadString(idsRASCS_AuthLinkSpeed, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_AuthAck:
AthLoadString(idsRASCS_AuthAck, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_ReAuthenticate:
AthLoadString(idsRas_Authenticated, sz, sizeof(sz)/sizeof(TCHAR));
SetWindowText(GetDlgItem(hwnd, ideProgress), sz);
AthLoadString(idsRASCS_Authenticated, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_PrepareForCallback:
AthLoadString(idsRASCS_PrepareForCallback, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_WaitForModemReset:
AthLoadString(idsRASCS_WaitForModemReset, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_WaitForCallback:
AthLoadString(idsRASCS_WaitForCallback, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_Projected:
AthLoadString(idsRASCS_Projected, sz, sizeof(sz)/sizeof(TCHAR));
ListBox_AddString(hwndLB, sz);
break;
case RASCS_Disconnected:
AthLoadString(idsRASCS_Disconnected, sz, sizeof(sz)/sizeof(TCHAR));
SetWindowText(GetDlgItem(hwnd, ideProgress), sz);
ListBox_AddString(hwndLB, sz);
pThis->FailedRasDial(hwnd, hrRasDialFailure, 0);
PostMessage(hwnd, CM_INTERNALRECONNECT, 0, 0);
break;
case RASCS_Connected:
SetDwOption(OPT_RASCONNDETAILS, s_fDetails, NULL, 0);
AthLoadString(idsRASCS_Connected, sz, sizeof(sz)/sizeof(TCHAR));
SetWindowText(GetDlgItem(hwnd, ideProgress), sz);
ListBox_AddString(hwndLB, sz);
EndDialog(hwnd, S_OK);
break;
}
// Select last lb item
SendMessage(hwndLB, LB_SETCURSEL, ListBox_GetCount(hwndLB)-1, 0);
}
return 1;
}
break;
}
// Done
return 0;
}
BOOL CConnectionManager::LogonRetry(HWND hwnd, LPTSTR pszCancel)
{
// Locals
DWORD dwRasError;
// Refresh
RefreshConnInfo();
// Reset Cancel button
SetWindowText(GetDlgItem(hwnd, IDCANCEL), pszCancel);
// Empty the listbox
ListBox_ResetContent(GetDlgItem(hwnd, idlbDetails));
while(1)
{
// If failed...
if (FAILED(RasLogon(hwnd, m_szConnectName, TRUE)))
return FALSE;
// Dial the connection
m_rConnInfo.hRasConn = NULL;
dwRasError = RasDial(NULL, NULL, &m_rdp, 0xFFFFFFFF, hwnd, &m_rConnInfo.hRasConn);
if (dwRasError)
{
FailedRasDial(hwnd, hrRasDialFailure, dwRasError);
continue;
}
// Success
break;
}
// Done
return TRUE;
}
// =====================================================================================
// CConnectionManager::FailedRasDial
// =====================================================================================
VOID CConnectionManager::FailedRasDial(HWND hwnd, HRESULT hrRasError, DWORD dwRasError)
{
// Locals
TCHAR sz[255];
// Refresh
RefreshConnInfo();
// Hangup the connection
if (m_rConnInfo.hRasConn)
RasHangupAndWait(m_rConnInfo.hRasConn, DEF_HANGUP_WAIT);
// Disconnected
AthLoadString(idsRASCS_Disconnected, sz, sizeof(sz)/sizeof(TCHAR));
SetWindowText(GetDlgItem(hwnd, ideProgress), sz);
// Save dwRasError
DisplayRasError(hwnd, hrRasError, dwRasError);
// NULL it
m_rConnInfo.hRasConn = NULL;
// Change dialog button to OK
AthLoadString(idsOK, sz, sizeof(sz)/sizeof(TCHAR));
SetWindowText(GetDlgItem(hwnd, IDCANCEL), sz);
}
DWORD CConnectionManager::EditPhonebookEntry(HWND hwnd, LPTSTR pszEntryName)
{
if (FAILED(VerifyRasLoaded()))
return (DWORD)E_FAIL;
if (FIsPlatformWinNT() && m_hInstRasDlg && m_pRasEntryDlg)
{
RASENTRYDLG info;
ZeroMemory(&info, sizeof(RASENTRYDLG));
info.dwSize = sizeof(RASENTRYDLG);
info.hwndOwner = hwnd;
m_pRasEntryDlg(NULL, pszEntryName, &info);
return info.dwError;
}
else
{
return RasEditPhonebookEntry(hwnd, NULL, pszEntryName);
}
}
//
// FUNCTION: CConnectionNotify::SendAdvise()
//
// PURPOSE: Sends the specified notification to all the clients that have
// requested notifications.
//
// PARAMETERS:
// <in> nCode - Notification code to send.
// <in> pvData - Data to send with the notificaiton. Can be NULL.
//
void CConnectionManager::SendAdvise(CONNNOTIFY nCode, LPVOID pvData)
{
if (nCode == CONNNOTIFY_CONNECTED)
DoOfflineTransactions();
// Loop through each interface and send the notification
EnterCriticalSection(&m_cs);
NOTIFYHWND *pTemp = m_pNotifyList;
while (pTemp)
{
Assert(IsWindow(pTemp->hwnd));
DWORD dwThread = GetCurrentThreadId();
PostMessage(pTemp->hwnd, CM_NOTIFY, (WPARAM) nCode, (LPARAM) pvData);
pTemp = pTemp->pNext;
}
LeaveCriticalSection(&m_cs);
}
void CConnectionManager::FreeNotifyList(void)
{
// Loop through the notify windows we own
NOTIFYHWND *pTemp;
while (m_pNotifyList)
{
// Get the list of notify callbacks for this window
if (IsWindow(m_pNotifyList->hwnd))
{
NOTIFYLIST *pList = (NOTIFYLIST *) GetWindowLongPtr(m_pNotifyList->hwnd, GWLP_USERDATA);
NOTIFYLIST *pListT;
// Loop through the callbacks freeing each one
while (pList)
{
pListT = pList->pNext;
SafeMemFree(pList);
pList = pListT;
}
SetWindowLong(m_pNotifyList->hwnd, GWLP_USERDATA, NULL);
RemoveProp(m_pNotifyList->hwnd, NOTIFY_HWND);
if (GetCurrentThreadId() == GetWindowThreadProcessId(m_pNotifyList->hwnd, NULL))
{
DestroyWindow(m_pNotifyList->hwnd);
}
else
PostMessage(m_pNotifyList->hwnd, WM_CLOSE, 0, 0L);
}
pTemp = m_pNotifyList;
m_pNotifyList = m_pNotifyList->pNext;
SafeMemFree(pTemp);
}
}
LRESULT CALLBACK CConnectionManager::NotifyWndProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
//CConnectionManager *pThis = (CConnectionManager *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
CConnectionManager *pThis = (CConnectionManager *)GetProp(hwnd, NOTIFY_HWND);
// If we're idle, then we should not process any notifications
if (uMsg != WM_NCCREATE && !pThis)
return (DefWindowProc(hwnd, uMsg, wParam, lParam));
switch (uMsg)
{
case WM_NCCREATE:
pThis = (CConnectionManager *) ((LPCREATESTRUCT) lParam)->lpCreateParams;
//SetWindowLong(hwnd, GWLP_USERDATA, (LONG) pThis);
SetProp(hwnd, NOTIFY_HWND, (HANDLE)pThis);
return (TRUE);
case CM_NOTIFY:
// This doesn't need to be critsec'd since the message is sent from
// within a critsec.
NOTIFYLIST *pList = (NOTIFYLIST *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
while (pList)
{
pList->pNotify->OnConnectionNotify((CONNNOTIFY) wParam, (LPVOID) lParam, pThis);
pList = pList->pNext;
}
return (0);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
HRESULT CConnectionManager::GetDefaultConnection(IImnAccount *pAccount,
IImnAccount **ppDefault)
{
TCHAR szDefault[CCHMAX_ACCOUNT_NAME];
ACCTTYPE acctType;
HRESULT hr = S_OK;
// Get the type of account from the original account
if (FAILED(hr = pAccount->GetAccountType(&acctType)))
{
// How can an account have no account type?
Assert(FALSE);
return (hr);
}
// Ask the account manager for the default account of this type
if (FAILED(hr = g_pAcctMan->GetDefaultAccount(acctType, ppDefault)))
{
// No default account of this type?
Assert(FALSE);
return (hr);
}
return (S_OK);
}
BOOL CConnectionManager::IsConnectionUsed(LPTSTR pszConn)
{
IImnEnumAccounts *pEnum = NULL;
IImnAccount *pAcct = NULL;
DWORD dwConn = 0;
TCHAR szConn[CCHMAX_CONNECTOID];
BOOL fFound = FALSE;
// Get the enumerator from the account manager
if (SUCCEEDED(m_pAcctMan->Enumerate(SRV_ALL, &pEnum)))
{
pEnum->Reset();
// Walk through all the accounts
while (!fFound && SUCCEEDED(pEnum->GetNext(&pAcct)))
{
// Get the connection type for this account
if (SUCCEEDED(pAcct->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConn)))
{
// If the account is a RAS account, ask for the connectoid name
// and the account name.
if (dwConn == CONNECTION_TYPE_RAS)
{
pAcct->GetPropSz(AP_RAS_CONNECTOID, szConn, ARRAYSIZE(szConn));
// Check to see if this connection matches
if (0 == lstrcmpi(szConn, pszConn))
{
fFound = TRUE;
}
}
}
SafeRelease(pAcct);
}
SafeRelease(pEnum);
}
return (fFound);
}
HRESULT CConnectionManager::ConnectActual(LPTSTR pszRasConn, HWND hwndParent, BOOL fShowUI)
{
HRESULT hr;
StrCpyN(m_szConnectName, pszRasConn, ARRAYSIZE(m_szConnectName));
// RefreshConnInfo
CHECKHR(hr = RefreshConnInfo());
// Make sure the RAS DLL is loaded before we try this
if (FAILED(VerifyRasLoaded()))
{
hr = HR_E_UNINITIALIZED;
goto exit;
}
// Check to see if we even can connect
hr = CanConnectActual(pszRasConn);
// If we can connect using the current connection, return success
if (S_OK == hr)
{
m_rConnInfo.fConnected = TRUE;
hr = S_OK;
goto exit;
}
// There is another connection already established ask the user if they
// want to change.
if (!m_fDialerUI)
{
m_fDialerUI = TRUE;
if (E_FAIL == hr)
{
UINT uAnswer;
uAnswer = idrgUseCurrent;
// Check to see if this a voodoo Connection Manager autodialer thing
if (!ConnectionManagerVoodoo(pszRasConn))
{
if (fShowUI)
uAnswer = PromptCloseConnection(hwndParent);
// The user canceled from the dialog. Therefore we give up.
if (IDCANCEL == uAnswer || IDNO == uAnswer)
{
hr = hrUserCancel;
goto exit;
}
// The user said they wanted to hang up and dial a new connection.
else if (idrgDialNew == uAnswer || IDYES == uAnswer)
{
Disconnect(hwndParent, fShowUI, TRUE, FALSE);
}
// The user said to try to use the current connection.
else if (idrgUseCurrent == uAnswer)
{
// Who are we to tell the user what to do...
//Save the conn info so we can return true for this connection in CanConnectActual
AddToConnList(pszRasConn);
// Send a connect notification since we are getting connected and then return
hr = S_OK;
goto NotifyAndExit;
}
}
}
else
{
//I don't see any reason as to why this is there.
// If we started RAS, then we can close it on a whim.
Disconnect(hwndParent, fShowUI, FALSE, FALSE);
}
// Only one caller can be dialing the phone at a time.
if (WAIT_TIMEOUT == WaitForSingleObject(m_hMutexDial, 0))
{
hr = HR_E_DIALING_INPROGRESS;
goto exit;
}
if (S_FALSE == (hr = DoAutoDial(hwndParent, pszRasConn, TRUE)))
{
DWORD dwReturn;
DWORD dwLanFlags = 0;
DWORD dwDialFlags = 0;
dwDialFlags = INTERNET_AUTODIAL_FORCE_ONLINE;
if (VerifyMobilityPackLoaded() == S_OK)
{
if (!IsNetworkAlive(&dwLanFlags) || (!(dwLanFlags & NETWORK_ALIVE_LAN)))
dwDialFlags |= INTERNET_DIAL_SHOW_OFFLINE;
}
dwReturn = InternetDialA(hwndParent, pszRasConn, dwDialFlags,
&m_dwConnId, 0);
/*
// Dial the new connection
if (SUCCEEDED(hr = StartRasDial(hwndParent, pszRasConn)))
*/
if (dwReturn == 0)
{
m_rConnInfo.fConnected = TRUE;
m_rConnInfo.fIStartedRas = TRUE;
m_rConnInfo.fAutoDial = FALSE;
m_rConnInfo.hRasConn = (HRASCONN)m_dwConnId;
StrCpyN(m_rConnInfo.szCurrentConnectionName, pszRasConn, ARRAYSIZE(m_rConnInfo.szCurrentConnectionName));
hr = S_OK;
}
else
{
if (dwReturn == ERROR_USER_DISCONNECTION)
{
hr = HR_E_USER_CANCEL_CONNECT;
if (!!(dwDialFlags & INTERNET_DIAL_SHOW_OFFLINE))
SetGlobalOffline(TRUE);
}
else
{
DebugTrace("Error dialing: %d\n", GetLastError());
hr = E_FAIL;
}
}
}
ReleaseMutex(m_hMutexDial);
NotifyAndExit:
// Send the advise after we leave the critsec to make sure we don't deadlock
if (hr == S_OK)
{
SendAdvise(CONNNOTIFY_CONNECTED, NULL);
}
exit:
m_fDialerUI = FALSE;
}
return (hr);
}
HRESULT CConnectionManager::CanConnectActual(LPTSTR pszRasConn)
{
LPRASCONN pConnections = NULL;
ULONG cConnections = 0;
BOOL fFound = 0;
HRESULT hr = E_FAIL;
TCHAR pszCurConn[CCHMAX_CONNECTOID];
DWORD dwFlags;
//Look in our Conection list first
hr = SearchConnList(pszRasConn);
if (hr == S_OK)
return hr;
// Make sure the RAS DLL is loaded before we try this
if (FAILED(VerifyRasLoaded()))
{
hr = HR_E_UNINITIALIZED;
goto exit;
}
// Find out what we're currently connected to
if (SUCCEEDED(EnumerateConnections(&pConnections, &cConnections)))
{
// If no connections exist, then just exit
if (0 == cConnections)
{
SafeMemFree(pConnections);
hr = S_FALSE;
goto exit;
}
// Walk through the existing connections and see if we can find the
// one we're looking for.
for (ULONG i = 0; i < cConnections; i++)
{
if (0 == lstrcmpi(pszRasConn, pConnections[i].szEntryName))
{
// Found it. Return success.
fFound = TRUE;
break;
}
}
// Free the list of connections returned from the enumerator
SafeMemFree(pConnections);
hr = (fFound ? S_OK : E_FAIL);
goto exit;
}
exit:
if ((hr != S_OK) && (m_fDialerUI))
hr = HR_E_DIALING_INPROGRESS;
return (hr);
}
INT_PTR CALLBACK CConnectionManager::RasStartupDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// Locals
CConnectionManager *pThis = (CConnectionManager *) GetWndThisPtr(hwnd);
TCHAR szConn[CCHMAX_CONNECTOID];
DWORD dwOpt = OPT_DIALUP_LAST_START;
switch (uMsg)
{
case WM_INITDIALOG:
pThis = (CConnectionManager *)lParam;
if (!pThis)
{
Assert (FALSE);
EndDialog(hwnd, E_FAIL);
return 1;
}
// Save this pointer
SetWndThisPtr (hwnd, pThis);
// Fill in the combo box
pThis->FillRasCombo(GetDlgItem(hwnd, idcDialupCombo), TRUE);
// If there are no RAS connections, then don't show the dialog
if (ComboBox_GetCount(GetDlgItem(hwnd, idcDialupCombo)) <= 1)
{
EndDialog(hwnd, 0);
return (TRUE);
}
// If the reason that we're in this dialog is because the user usually autodial's
// on startup but is now offline, then we should display the normal autodial
// connectoid
if (START_CONNECT == DwGetOption(OPT_DIALUP_START))
dwOpt = OPT_DIALUP_CONNECTION;
// Initialize the combo box to the last connection
*szConn = 0;
GetOption(dwOpt, szConn, ARRAYSIZE(szConn));
if (0 != *szConn)
{
// If we can't find it any longer, then according to the spec, we're
// supposed to default to the "Ask me" option
if (CB_ERR == ComboBox_SelectString(GetDlgItem(hwnd, idcDialupCombo), -1, szConn))
{
ComboBox_SetCurSel(GetDlgItem(hwnd, idcDialupCombo), 0);
}
}
else
ComboBox_SetCurSel(GetDlgItem(hwnd, idcDialupCombo), 0);
CenterDialog(hwnd);
return (TRUE);
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
// Get the connection name from the combo box
ComboBox_GetText(GetDlgItem(hwnd, idcDialupCombo), szConn, ARRAYSIZE(szConn));
// Check to see if it's the "Don't dial..." string
TCHAR szRes[CCHMAX_STRINGRES];
AthLoadString(idsConnNoDial, szRes, ARRAYSIZE(szRes));
if (0 == lstrcmp(szRes, szConn))
{
// It's the don't dial string, so clear the history in the registry
SetOption(OPT_DIALUP_LAST_START, _T(""), sizeof(TCHAR), NULL, 0);
// See if the user checked the "Set as default..."
if (BST_CHECKED == Button_GetCheck(GetDlgItem(hwnd, idcDefaultCheck)))
{
// If don't dial is set as default, we clear the startup prompt option
SetDwOption(OPT_DIALUP_START, START_NO_CONNECT, NULL, 0);
}
}
else
{
// Save this connection in the history
SetOption(OPT_DIALUP_LAST_START, szConn, lstrlen(szConn) + 1, NULL, 0);
if (BST_CHECKED == Button_GetCheck(GetDlgItem(hwnd, idcDefaultCheck)))
{
// If the user want's this as default, then we change the startup
// option to auto connect to this connection.
SetDwOption(OPT_DIALUP_START, START_CONNECT, NULL, 0);
SetOption(OPT_DIALUP_CONNECTION, szConn, lstrlen(szConn) + 1, NULL, 0);
}
// Dial the phone
pThis->ConnectActual(szConn, hwnd, FALSE);
}
EndDialog(hwnd, 0);
return (TRUE);
case IDCANCEL:
EndDialog(hwnd, 0);
return (TRUE);
}
break;
case WM_CLOSE:
SendMessage(hwnd, WM_COMMAND, IDCANCEL, 0);
return (TRUE);
}
return (FALSE);
}
//-------------------------------------------------------------------------------------------
// Function: FIsPlatformWinNT() - checks if we are running on NT or Win95
//-------------------------------------------------------------------------------------------
BOOL FIsPlatformWinNT()
{
return (g_OSInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
}
HRESULT CConnectionManager::RefreshConnInfo(BOOL fSendAdvise)
{
// Locals
HRESULT hr=S_OK;
LPRASCONN pConnections=NULL;
ULONG cConnections=0;
BOOL fFound=FALSE;
ULONG i;
// Thread Safety
EnterCriticalSection(&m_cs);
// No Refresh needed
if (CIS_REFRESH != m_rConnInfo.state)
goto exit;
// Set this here to prevent an infinite loop and thus a stack fault.
m_rConnInfo.state = CIS_CLEAN;
// Make sure the RAS DLL is loaded before we try this
CHECKHR(hr = VerifyRasLoaded());
// Find out what we're currently connected to
CHECKHR(hr = EnumerateConnections(&pConnections, &cConnections));
// Walk through the existing connections and see if we can find the
// one we're looking for.
for (i = 0; i < cConnections; i++)
{
// if (m_rConnInfo.hRasConn == pConnections[i].hrasconn)
//To get around a problem in ConnectActual when we dial using InternetDial
if (lstrcmp(m_rConnInfo.szCurrentConnectionName, pConnections[i].szEntryName) == 0)
{
// Found it. Return success.
fFound = TRUE;
m_rConnInfo.fConnected = TRUE;
m_rConnInfo.fIStartedRas = TRUE;
m_rConnInfo.hRasConn = pConnections[0].hrasconn;
m_dwConnId = (DWORD_PTR) m_rConnInfo.hRasConn;
break;
}
}
// If we didn't find our connection
if (!fFound)
{
// The user hung up. We need to put ourselves in a disconnected
// state.
if (cConnections == 0)
{
Disconnect(NULL, FALSE, TRUE, FALSE);
}
else
{
StrCpyN(m_rConnInfo.szCurrentConnectionName, pConnections[0].szEntryName, ARRAYSIZE(m_rConnInfo.szCurrentConnectionName));
m_rConnInfo.fConnected = TRUE;
m_rConnInfo.fIStartedRas = FALSE;
m_rConnInfo.hRasConn = pConnections[0].hrasconn;
m_dwConnId = (DWORD_PTR) m_rConnInfo.hRasConn;
if (fSendAdvise)
SendAdvise(CONNNOTIFY_CONNECTED, NULL);
}
}
exit:
// Thread Safety
LeaveCriticalSection(&m_cs);
// Free the list of connections returned from the enumerator
SafeMemFree(pConnections);
// Done
return hr;
}
//
// FUNCTION: CConnectionManager::IsGlobalOffline()
//
// PURPOSE: Checks the state of the WININET global offline setting.
// Note - this is copied from shdocvw
//
// PARAMETERS:
// void
//
// RETURN VALUE:
// BOOL
//
BOOL CConnectionManager::IsGlobalOffline(void)
{
DWORD dwState = 0, dwSize = sizeof(DWORD);
BOOL fRet = FALSE;
if (InternetQueryOptionA(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState,
&dwSize))
{
if (dwState & INTERNET_STATE_DISCONNECTED_BY_USER)
fRet = TRUE;
}
return (fRet);
}
//
// FUNCTION: CConnectionManager::SetGlobalOffline()
//
// PURPOSE: Sets the global offline state for Athena and IE. Note - this
// function is copied from shdocvw.
//
// PARAMETERS:
// <in> fOffline - TRUE to disconnect, FALSE to allow connections.
//
// RETURN VALUE:
// void
//
void CConnectionManager::SetGlobalOffline(BOOL fOffline, HWND hwndParent)
{
DWORD dwReturn;
if (fOffline)
{
if (hwndParent)
{
//Offer to hangup
RefreshConnInfo(FALSE);
if (m_rConnInfo.hRasConn)
{
dwReturn = AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(idsWorkOfflineHangup), 0,
MB_YESNOCANCEL);
if (dwReturn == IDCANCEL)
return;
if (dwReturn == IDYES)
{
Disconnect(hwndParent, FALSE, TRUE, FALSE);
}
}
}
}
SetShellOfflineState(fOffline);
m_fOffline = fOffline;
if (!m_fOffline)
DoOfflineTransactions();
SendAdvise(CONNNOTIFY_WORKOFFLINE, (LPVOID) IntToPtr(fOffline));
}
typedef BOOL (WINAPI *PFNINETDIALHANDLER)(HWND,LPCSTR, DWORD, LPDWORD);
HRESULT CConnectionManager::DoAutoDial(HWND hwndParent, LPTSTR pszConnectoid, BOOL fDial)
{
TCHAR szAutodialDllName[MAX_PATH];
TCHAR szAutodialFcnName[MAX_PATH];
HRESULT hr = S_FALSE;
UINT uError;
HINSTANCE hInstDialer = 0;
PFNINETDIALHANDLER pfnDialHandler = NULL;
DWORD dwRasError = 0;
BOOL f = 0;
TCHAR szRegPath[MAX_PATH];
LPRASCONN pConnections = NULL;
ULONG cConnections = 0;
DWORD dwDialFlags = fDial ? INTERNET_CUSTOMDIAL_CONNECT : INTERNET_CUSTOMDIAL_DISCONNECT;
// Check to see if this connectoid has the autodial values
if (FAILED(LookupAutoDialHandler(pszConnectoid, szAutodialDllName, szAutodialFcnName)))
goto exit;
// If we were able to load those two values, then we're going to let the
// autodialer take care of dialing the phone.
uError = SetErrorMode(SEM_NOOPENFILEERRORBOX);
// Try to load the library that contains the autodialer
hInstDialer = LoadLibrary(szAutodialDllName);
SetErrorMode(uError);
if (!hInstDialer)
{
goto exit;
}
// Try to load the function address
pfnDialHandler = (PFNINETDIALHANDLER) GetProcAddress(hInstDialer,
szAutodialFcnName);
if (!pfnDialHandler)
goto exit;
// Call the dialer
f = (*pfnDialHandler)(hwndParent, pszConnectoid, dwDialFlags,
&dwRasError);
hr = f ? S_OK : E_FAIL;
m_rConnInfo.fConnected = fDial && f;
m_rConnInfo.fIStartedRas = TRUE;
m_rConnInfo.fAutoDial = TRUE;
if (f && fDial)
{
// Need to get the current connection handle
if (SUCCEEDED(EnumerateConnections(&pConnections, &cConnections)))
{
for (UINT i = 0; i < cConnections; i++)
{
if (0 == lstrcmpi(pConnections[i].szEntryName, pszConnectoid))
{
EnterCriticalSection(&m_cs);
m_rConnInfo.hRasConn = pConnections[i].hrasconn;
m_rConnInfo.state = CIS_REFRESH; // new connection, must refresh conn info
LeaveCriticalSection(&m_cs);
break;
}
}
SafeMemFree(pConnections);
}
}
exit:
if (hInstDialer)
FreeLibrary(hInstDialer);
return (hr);
}
HRESULT CConnectionManager::LookupAutoDialHandler(LPTSTR pszConnectoid, LPTSTR pszAutodialDllName,
LPTSTR pszAutodialFcnName)
{
HRESULT hr = E_FAIL;
DWORD dwEntryInfoSize = 0;
LPRASENTRY pRasEntry = NULL;
*pszAutodialDllName = 0;
*pszAutodialFcnName = 0;
if (m_pRasGetEntryProperties)
{
// Find out how big the struct we need to pass in should be
RasGetEntryProperties(NULL, pszConnectoid, NULL, &dwEntryInfoSize, NULL, NULL);
if (dwEntryInfoSize)
{
// Allocate a buffer big enough for this structure
if (!MemAlloc((LPVOID*) &pRasEntry, dwEntryInfoSize))
return (E_OUTOFMEMORY);
// Request the RASENTRY properties
pRasEntry->dwSize = sizeof(RASENTRY);
if (0 != RasGetEntryProperties(NULL, pszConnectoid, pRasEntry, &dwEntryInfoSize, NULL, NULL))
goto exit;
// Copy the autodial info to the provided buffers
if (pRasEntry->szAutodialDll[0])
StrCpyN(pszAutodialDllName, pRasEntry->szAutodialDll, MAX_PATH);
if (pRasEntry->szAutodialFunc[0])
StrCpyN(pszAutodialFcnName, pRasEntry->szAutodialFunc, MAX_PATH);
// If we got here, we have all the data we need
if (*pszAutodialDllName && *pszAutodialFcnName)
hr = S_OK;
}
}
exit:
SafeMemFree(pRasEntry);
return (hr);
}
// If the current connection is a CM connection, and the target connection is
// a CM connection, then we let the CM do whatever it is that they do.
BOOL CConnectionManager::ConnectionManagerVoodoo(LPTSTR pszConnection)
{
TCHAR szAutodialDllName[MAX_PATH];
TCHAR szAutodialFcnName[MAX_PATH];
// Check to see if the target is a CM connectoid
if (FAILED(LookupAutoDialHandler(pszConnection, szAutodialDllName, szAutodialFcnName)))
return (FALSE);
// Find out if the current connection is a CM connectoid
if (FAILED(LookupAutoDialHandler(m_rConnInfo.szCurrentConnectionName, szAutodialDllName,
szAutodialFcnName)))
return (FALSE);
return (TRUE);
}
HRESULT CConnectionManager::OEIsDestinationReachable(IImnAccount *pAccount, DWORD dwConnType)
{
char szServerName[256];
HRESULT hr = S_FALSE;
/*
if ((VerifyMobilityPackLoaded() == S_OK) &&
(GetServerName(pAccount, szServerName, ARRAYSIZE(szServerName)) == S_OK))
{
if (IsDestinationReachable(szServerName, NULL) &&
(GetLastError() == 0))
{
hr = S_OK;
}
}
else
{
*/
DWORD dw;
if (SUCCEEDED(pAccount->GetPropDw(AP_HTTPMAIL_DOMAIN_MSN, &dw)) && dw)
{
if(HideHotmail())
return(hr);
}
hr = IsInternetReachable(pAccount, dwConnType);
/*
}
*/
return hr;
}
HRESULT CConnectionManager::IsInternetReachable(IImnAccount *pAccount, DWORD dwConnType)
{
TCHAR szConnectionName[CCHMAX_CONNECTOID];
HRESULT hr = S_FALSE;
DWORD dwFlags;
switch (dwConnType)
{
case CONNECTION_TYPE_RAS:
{
if (FAILED(hr = pAccount->GetPropSz(AP_RAS_CONNECTOID, szConnectionName, ARRAYSIZE(szConnectionName))))
{
AssertSz(FALSE, _T("CConnectionManager::Connect() - No connection name."));
break;
}
hr = CanConnectActual(szConnectionName);
break;
}
case CONNECTION_TYPE_LAN:
{
if (VerifyMobilityPackLoaded() == S_OK)
{
if (IsNetworkAlive(&dwFlags) && (!!(dwFlags & NETWORK_ALIVE_LAN)))
{
hr = S_OK;
}
}
else
{
//If Mobility pack is not loaded we can't figure out if lan indeed present, so like
//everywhere else we just assume that lan is present
hr = S_OK;
}
break;
}
case CONNECTION_TYPE_INETSETTINGS:
default:
{
if (InternetGetConnectedStateExA(&dwFlags, szConnectionName, ARRAYSIZE(szConnectionName), 0))
hr = S_OK;
break;
}
}
return hr;
}
HRESULT CConnectionManager::GetServerName(IImnAccount *pAcct, LPSTR pServerName, DWORD size)
{
HRESULT hr = E_FAIL;
DWORD dwSrvrType;
ACCTTYPE accttype;
//This function will be called only for LAN accounts to avoid confusion with POP accounts having two servers
// an incoming and an outgoing.
if (SUCCEEDED(pAcct->GetAccountType(&accttype)))
{
switch (accttype)
{
case ACCT_MAIL:
dwSrvrType = AP_IMAP_SERVER;
break;
case ACCT_NEWS:
dwSrvrType = AP_NNTP_SERVER;
break;
case ACCT_DIR_SERV:
dwSrvrType = AP_LDAP_SERVER;
break;
default:
Assert(FALSE);
goto exit;
}
if ((hr = pAcct->GetPropSz(dwSrvrType, pServerName, size)) != S_OK)
{
//If the account type is MAIL, we try to get the name of POP server
//For POP accounts we just try to ping the POP3 server as in most of the cases
//POP server and SMTP servers are the same. Even if they are not, we assume that if
//one is reachable the connection is dialed and ISPs network is reachable and hence the other
//server is reachable too.
if (accttype == ACCT_MAIL)
{
hr = pAcct->GetPropSz(AP_POP3_SERVER, pServerName, size);
// look for an httpmail server
if (FAILED(hr))
hr = pAcct->GetPropSz(AP_HTTPMAIL_SERVER, pServerName, size);
}
}
}
exit:
return hr;
}
BOOLEAN CConnectionManager::IsSameDestination(LPSTR pszConnectionName, LPSTR pszServerName)
{
//We need to find an account with pszConnectionName as the connectoid and pszServerName
//Return TRUE if we find one FALSE otherwise
IImnAccount *pAcct;
BOOLEAN fret = FALSE;
if (g_pAcctMan && (g_pAcctMan->FindAccount(AP_RAS_CONNECTOID, pszConnectionName, &pAcct) == S_OK))
{
//Now check if its server name is what we want.
//Althoug findAccount finds first account that satisfies the searchdata, this should work fine for a
//typical OE user. Even if there are two accounts with same connectoids and different servers and if
//we miss to find the one we want,at the most we will be putting up a connect dialog.
char myServerName[MAX_PATH];
if (SUCCEEDED(GetServerName(pAcct, myServerName, sizeof(myServerName))))
{
if (lstrcmp(myServerName, pszServerName) == 0)
{
fret = TRUE;
}
}
}
return fret;
}
HRESULT CConnectionManager::VerifyMobilityPackLoaded()
{
HRESULT hr = REGDB_E_CLASSNOTREG;
uCLSSPEC classpec;
if (!m_fMobilityPackFailed)
{
HWND hwnd;
if (!m_hInstSensDll)
{
// figure out struct and flags
classpec.tyspec = TYSPEC_CLSID;
classpec.tagged_union.clsid = CLSID_MobilityFeature;
// call jit code
if (!g_pBrowser)
{
goto exit;
}
IOleWindow *pOleWnd;
if (FAILED(g_pBrowser->QueryInterface(IID_IAthenaBrowser, (LPVOID*)&pOleWnd)))
{
goto exit;
}
pOleWnd->GetWindow(&hwnd);
hr = FaultInIEFeature(hwnd, &classpec, NULL, FIEF_FLAG_PEEK);
pOleWnd->Release();
if(S_OK == hr)
{
// Mobile pack is installed
m_hInstSensDll = LoadLibrary(szSensApiDll);
if (m_hInstSensDll)
{
m_pIsDestinationReachable = (ISDESTINATIONREACHABLE)GetProcAddress(m_hInstSensDll, szIsDestinationReachable);
m_pIsNetworkAlive = (ISNETWORKALIVE)GetProcAddress(m_hInstSensDll, szIsNetworkAlive);
}
if (!m_hInstSensDll || !m_pIsDestinationReachable || !m_pIsNetworkAlive)
{
m_fMobilityPackFailed = TRUE;
}
else
{
m_fMobilityPackFailed = FALSE;
hr = S_OK;
}
}
}
else
hr = S_OK;
}
return hr;
exit:
m_fMobilityPackFailed = TRUE;
return hr;
}
void CConnectionManager::DoOfflineTransactions()
{
char szId[CCHMAX_ACCOUNT_NAME];
IImnEnumAccounts *pEnum;
HRESULT hr;
FOLDERID id, *pid;
ULONG iAcct, cAcct;
IImnAccount *pAccount;
DWORD dwConnection;
HWND hwnd;
DWORD cRecords;
pid = NULL;
iAcct = 0;
// If this is getting hit through a news article URL, we won't have a browser and
// should not play back.
if (!g_pBrowser || !g_pSync)
return;
// Get Record Count
g_pSync->GetRecordCount(&cRecords);
// sbailey: perf. fix. - prevent doing that expensive stuff below if there are no transactions.
if (0 == cRecords)
return;
hr = g_pAcctMan->Enumerate(SRV_NNTP | SRV_IMAP | SRV_HTTPMAIL, &pEnum);
if (SUCCEEDED(hr))
{
hr = pEnum->GetCount(&cAcct);
if (SUCCEEDED(hr) &&
cAcct > 0 &&
MemAlloc((void **)&pid, cAcct * sizeof(FOLDERID)))
{
while (SUCCEEDED(pEnum->GetNext(&pAccount)))
{
hr = pAccount->GetPropDw(AP_RAS_CONNECTION_TYPE, &dwConnection);
if (SUCCEEDED(hr))
{
hr = OEIsDestinationReachable(pAccount, dwConnection);
if (hr == S_OK)
{
hr = pAccount->GetPropSz(AP_ACCOUNT_ID, szId, ARRAYSIZE(szId));
if (SUCCEEDED(hr))
{
hr = g_pStore->FindServerId(szId, &id);
if (SUCCEEDED(hr))
{
pid[iAcct] = id;
iAcct++;
}
}
}
}
pAccount->Release();
}
}
pEnum->Release();
}
if (iAcct > 0)
{
g_pBrowser->GetWindow(&hwnd);
g_pBrowser->GetCurrentFolder(&id);
g_pSync->DoPlayback(hwnd, pid, iAcct, id);
}
if (pid != NULL)
MemFree(pid);
}
HRESULT CConnectionManager::ConnectUsingIESettings(HWND hwndParent, BOOL fShowUI)
{
TCHAR lpConnection[CCHMAX_CONNECTOID];
DWORD dwFlags = 0;
DWORD dwReturn;
HRESULT hr = E_FAIL;
if (InternetGetConnectedStateExA(&dwFlags, lpConnection, ARRAYSIZE(lpConnection), 0))
{
m_fTryAgain = FALSE;
return S_OK;
}
// Only one caller can be dialing the phone at a time.
if (WAIT_TIMEOUT == WaitForSingleObject(m_hMutexDial, 0))
{
return (HR_E_DIALING_INPROGRESS);
}
if (!!(dwFlags & INTERNET_CONNECTION_MODEM) && (*lpConnection))
{
if (!m_fDialerUI)
{
m_fDialerUI = TRUE;
//A DEF CONNECTOID IS SET. Dial that one
if (IsGlobalOffline())
{
if (fShowUI)
{
if (IDNO == AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrWorkingOffline),
0, MB_YESNO | MB_ICONEXCLAMATION ))
{
hr = HR_E_OFFLINE;
goto DialExit;
}
else
g_pConMan->SetGlobalOffline(FALSE);
}
else
{
hr = HR_E_OFFLINE;
//m_fDialerUI = FALSE;
goto DialExit;
}
}
if ((hr = PromptCloseConnection(lpConnection, fShowUI, hwndParent)) != S_FALSE)
goto DialExit;
{
DWORD dwDialFlags = 0;
DWORD dwLanFlags = 0;
dwDialFlags = INTERNET_AUTODIAL_FORCE_ONLINE;
if (VerifyMobilityPackLoaded() == S_OK)
{
if (!IsNetworkAlive(&dwLanFlags) || (!(dwLanFlags & NETWORK_ALIVE_LAN)))
dwDialFlags |= INTERNET_DIAL_SHOW_OFFLINE;
}
dwReturn = InternetDialA(hwndParent, lpConnection, dwDialFlags,
&m_dwConnId, 0);
if (dwReturn == 0)
{
m_rConnInfo.fConnected = TRUE;
m_rConnInfo.fIStartedRas = TRUE;
m_rConnInfo.fAutoDial = FALSE;
m_rConnInfo.hRasConn = (HRASCONN)m_dwConnId;
StrCpyN(m_rConnInfo.szCurrentConnectionName, lpConnection, ARRAYSIZE(m_rConnInfo.szCurrentConnectionName));
SendAdvise(CONNNOTIFY_CONNECTED, NULL);
hr = S_OK;
}
else
{
if (dwReturn == ERROR_USER_DISCONNECTION)
{
hr = HR_E_USER_CANCEL_CONNECT;
if (!!(dwDialFlags & INTERNET_DIAL_SHOW_OFFLINE))
{
SetGlobalOffline(TRUE);
}
}
else
{
hr = E_FAIL;
DebugTrace("Error dialing: %d\n", GetLastError());
}
}
}
DialExit:
m_fDialerUI = FALSE;
}
else
{
hr = HR_E_USER_CANCEL_CONNECT;
}
}
else
{
if (!m_fTryAgain)
{
int err = (int) DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddOfferOffline), hwndParent,
OfferOfflineDlgProc, (LPARAM)this);
if (err == -1)
{
DWORD dwerr = GetLastError();
hr = S_OK;
}
if (!IsGlobalOffline())
hr = S_OK;
else
hr = HR_E_OFFLINE;
}
else
hr = S_OK;
}
ReleaseMutex(m_hMutexDial);
return hr;
}
void CConnectionManager::SetTryAgain(BOOL bval)
{
m_fTryAgain = bval;
}
INT_PTR CALLBACK CConnectionManager::OfferOfflineDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BOOL retval = 1;
CConnectionManager *pThis = (CConnectionManager*)GetWndThisPtr(hwnd);
switch (uMsg)
{
case WM_INITDIALOG:
{
// Get lparam
pThis = (CConnectionManager *)lParam;
if (!pThis)
{
Assert (FALSE);
EndDialog(hwnd, E_FAIL);
goto exit;
}
// Save this pointer
SetWndThisPtr (hwnd, pThis);
break;
}
case WM_COMMAND:
{
switch(GET_WM_COMMAND_ID(wParam, lParam))
{
case IDWorkOffline:
pThis->SetGlobalOffline(TRUE, NULL);
break;
case IDTryAgain:
pThis->SetGlobalOffline(FALSE);
pThis->SetTryAgain(TRUE);
break;
}
EndDialog(hwnd, S_OK);
break;
}
case WM_CLOSE:
pThis->SetGlobalOffline(TRUE, NULL);
EndDialog(hwnd, S_OK);
break;
case WM_DESTROY:
SetWndThisPtr(hwnd, NULL);
break;
default:
retval = 0;
break;
}
exit:
return retval;
}
HRESULT CConnectionManager::PromptCloseConnection(LPTSTR pszRasConn, BOOL fShowUI, HWND hwndParent)
{
HRESULT hr = S_FALSE;
UINT uAnswer;
LPRASCONN pConnections = NULL;
ULONG cConnections = 0;
uAnswer = idrgDialNew;
// Make sure the RAS DLL is loaded before we try this
if (FAILED(VerifyRasLoaded()))
{
hr = HR_E_UNINITIALIZED;
goto exit;
}
StrCpyN(m_szConnectName, pszRasConn, ARRAYSIZE(m_szConnectName));
// RefreshConnInfo
CHECKHR(hr = RefreshConnInfo());
if (SUCCEEDED(EnumerateConnections(&pConnections, &cConnections)) && (cConnections > 0))
{
if (fShowUI)
uAnswer = PromptCloseConnection(hwndParent);
// The user canceled from the dialog. Therefore we give up.
if (IDCANCEL == uAnswer || IDNO == uAnswer)
{
hr = HR_E_USER_CANCEL_CONNECT;
goto exit;
}
// The user said they wanted to hang up and dial a new connection.
else if (idrgDialNew == uAnswer || IDYES == uAnswer)
{
Disconnect(hwndParent, fShowUI, TRUE, FALSE);
hr = S_FALSE;
goto exit;
}
// The user said to try to use the current connection.
else if (idrgUseCurrent == uAnswer)
{
//Save the conn info so we can return true for this connection in CanConnectActual
AddToConnList(pszRasConn);
hr = S_OK;
SendAdvise(CONNNOTIFY_CONNECTED, NULL);
goto exit;
}
}
else
{
Disconnect(NULL, FALSE, TRUE, FALSE);
hr = S_FALSE;
}
exit:
SafeMemFree(pConnections);
return hr;
}