Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

10700 lines
287 KiB

// Copyright (c) 1995, Microsoft Corporation, all rights reserved
//
// dial.c
// Remote Access Common Dialog APIs
// RasDialDlg APIs
//
// 11/19/95 Steve Cobb
#include "rasdlgp.h"
#include "raseapif.h"
#include "inetcfgp.h"
#include "netconp.h"
// Posted message codes for tasks that should not or cannot occur in the
// RasDial callback.
//
#define WM_RASEVENT 0xCCCC
#define WM_RASERROR 0xCCCD
#define WM_RASDIAL 0xCCCE
#define WM_RASBUNDLEERROR 0xCCCF
// Dialer dialog mode bits
//
#define DR_U 0x00000001 // Username and password present
#define DR_D 0x00000002 // Domain present
#define DR_N 0x00000004 // Phone number present
#define DR_L 0x00000008 // Location controls present
#define DR_I 0x00000010 // Eap identity dialog
// Internal constants used by DrXxx routines to implement the "manual edit"
// combo-box.
//
#define DR_WM_SETTEXT 0xCCC0
#define DR_BOGUSWIDTH 19591
#define EAP_RASTLS 13
//----------------------------------------------------------------------------
// Help maps
//----------------------------------------------------------------------------
static DWORD g_adwDrHelp[] =
{
CID_DR_BM_Useless, HID_DR_BM_Useless,
CID_DR_ST_User, HID_DR_EB_User,
CID_DR_EB_User, HID_DR_EB_User,
CID_DR_ST_Password, HID_DR_EB_Password,
CID_DR_EB_Password, HID_DR_EB_Password,
CID_DR_ST_Domain, HID_DR_EB_Domain,
CID_DR_EB_Domain, HID_DR_EB_Domain,
CID_DR_CB_SavePassword, HID_DR_CB_SavePassword,
CID_DR_ST_Numbers, HID_DR_CLB_Numbers,
CID_DR_CLB_Numbers, HID_DR_CLB_Numbers,
CID_DR_ST_Locations, HID_DR_LB_Locations,
CID_DR_LB_Locations, HID_DR_LB_Locations,
CID_DR_PB_Rules, HID_DR_PB_Rules,
CID_DR_PB_Properties, HID_DR_PB_Properties,
CID_DR_PB_DialConnect, HID_DR_PB_DialConnect,
CID_DR_PB_Cancel, HID_DR_PB_Cancel,
CID_DR_PB_Help, HID_DR_PB_Help,
CID_DR_RB_SaveForMe, HID_DR_RB_SaveForMe,
CID_DR_RB_SaveForEveryone, HID_DR_RB_SaveForEveryone,
0, 0
};
static DWORD g_adwCpHelp[] =
{
CID_CP_ST_Explain, HID_CP_ST_Explain,
CID_CP_ST_OldPassword, HID_CP_EB_OldPassword,
CID_CP_EB_OldPassword, HID_CP_EB_OldPassword,
CID_CP_ST_Password, HID_CP_EB_Password,
CID_CP_EB_Password, HID_CP_EB_Password,
CID_CP_ST_ConfirmPassword, HID_CP_EB_ConfirmPassword,
CID_CP_EB_ConfirmPassword, HID_CP_EB_ConfirmPassword,
0, 0
};
static DWORD g_adwDcHelp[] =
{
CID_DC_ST_Explain, HID_DC_ST_Explain,
CID_DC_ST_Number, HID_DC_EB_Number,
CID_DC_EB_Number, HID_DC_EB_Number,
0, 0
};
static DWORD g_adwDeHelp[] =
{
CID_DE_PB_More, HID_DE_PB_More,
IDOK, HID_DE_PB_Redial,
0, 0
};
static DWORD g_adwPrHelp[] =
{
CID_PR_ST_Text, HID_PR_ST_Text,
CID_PR_CB_DisableProtocols, CID_PR_CB_DisableProtocols,
IDOK, HID_PR_PB_Accept,
IDCANCEL, HID_PR_PB_HangUp,
0, 0
};
static DWORD g_adwUaHelp[] =
{
CID_UA_ST_UserName, HID_UA_EB_UserName,
CID_UA_EB_UserName, HID_UA_EB_UserName,
CID_UA_ST_Password, HID_UA_EB_Password,
CID_UA_EB_Password, HID_UA_EB_Password,
CID_UA_ST_Domain, HID_UA_EB_Domain,
CID_UA_EB_Domain, HID_UA_EB_Domain,
CID_UA_CB_SavePassword, HID_UA_CB_SavePassword,
0, 0
};
CONST WCHAR g_pszSavedPasswordToken[] = L"****************";
#define g_dwSavedPasswordTokenLength \
( sizeof(g_pszSavedPasswordToken) / sizeof(TCHAR) )
// Save password macro, determines if either User or Global password is saved
// (p) must be a pointer to a DINFO struct (see dial.c)
//
// Whistler bug: 288234 When switching back and forth from "I connect" and
// "Any user connects" password is not caching correctly
//
#define HaveSavedPw(p) \
((p)->fHaveSavedPwUser || (p)->fHaveSavedPwGlobal)
//----------------------------------------------------------------------------
// Local datatypes
//----------------------------------------------------------------------------
// Dial dialogs common context block. This block contains information common
// to more than one dialog in the string of dial-related dialogs.
//
typedef struct
_DINFO
{
// Caller's arguments to the RAS API. Outputs in 'pArgs' are visible to
// the API which has the address of same. Careful using 'pszEntry' as
// 'pEntry->pszEntryName' is generally more appropriate, the latter
// reflecting the name of any prerequisite entry while the prequisite is
// being dialed.
//
LPTSTR pszPhonebook;
LPTSTR pszEntry;
LPTSTR pszPhoneNumber;
RASDIALDLG* pArgs;
// Phonebook settings read from the phonebook file. All access should be
// thru 'pFile'. 'PFile' is set to either '&filePrereq' or 'pFileMain'
// depending on 'fFilePrereqOpen'. 'File' will only be used in cases
// where the open phonebook is not passed thru the reserved word hack, and
// in that case 'pFileMain' will point to it. 'FilePrereq' is the
// phonebook file of the prequisite entry which may be different from the
// main entry. During prerequisite dial 'pFile' points to 'filePrereq'
// rather than 'file' and 'fFilePrereqOpen is true. Otherwise, 'pFile'
// points to whatever 'pFileMain' points at.
//
PBFILE* pFile;
PBFILE* pFileMain;
PBFILE file;
PBFILE filePrereq;
BOOL fFilePrereqOpen;
BOOL fIsPublicPbk;
// Global preferences read via phonebook library. All access should be
// thru 'pUser' as 'user' will only be used in cases where the preferences
// are not passed thru the reserved word hack.
//
PBUSER* pUser;
PBUSER user;
// User credentials provided by API caller for "during logon" dialing
// where there is no current user. If user changes the credentials
// *pfNoUserChanged is set and the 'pNoUser' credentials updated.
//
RASNOUSER* pNoUser;
BOOL* pfNoUserChanged;
// Set if the call is unattended, i.e. a call by RASAUTO to redial a
// failed link.
//
BOOL fUnattended;
// Private flags from calling RAS API, the first informing us he wants to
// be hidden off the desktop while we dial, and the second that he will
// close if we return "connected" so we can avoid flicker and not bother
// restoring him.
//
BOOL fMoveOwnerOffDesktop;
BOOL fForceCloseOnDial;
// Set when something occurs during dial that affects the phonebook entry.
// The entry is re-read after a successful connection.
//
BOOL fResetAutoLogon;
DWORD dwfExcludedProtocols;
DTLLIST* pListPortsToDelete;
// The entry node and a shortcut pointer to the entry inside.
//
DTLNODE* pNode;
PBENTRY* pEntry;
// The entry of the main entry that referred to any prerequisite entry
// that might be contained by 'pEntry'. If no prerequisite entry is
// involved this is the same as 'pEntry'.
//
PBENTRY* pEntryMain;
// Set is admin has disabled the save password feature in the registry.
//
BOOL fDisableSavePw;
// Set true if a cached password is available for the entry.
//
BOOL fHaveSavedPwUser; // whether there are saved per-user creds
BOOL fHaveSavedPwGlobal; // whether there are saved per-connect creds
// Set when the dial in progress is the prerequisite entry, rather than
// the main entry.
//
BOOL fPrerequisiteDial;
// Set when calling RasDial on a connected entry to add a reference only.
// All interaction with user is skipped in this case. See bug 272794.
//
BOOL fDialForReferenceOnly;
// The dial parameters used on this connection attempt. Initialized in
// RasDialDlgW. Credentials are updated by DialerDlg. Callback number is
// updated by DialProgressDlg.
//
RASDIALPARAMS rdp; // actual dial parameters passed to RasDial
RASDIALPARAMS rdpu; // per-user credentials
RASDIALPARAMS rdpg; // per-connection credentials
// The dial parameter extensions used on this connection attempt. Set in
// RasDialDlgW, except hwndOwner which is set in DialProgressDlg.
//
RASDIALEXTENSIONS rde;
}
DINFO;
// Dialer dialogs argument block. Used for all 5 variations of the dialer.
//
typedef struct
_DRARGS
{
DINFO* pDinfo;
DWORD dwfMode;
DWORD fReload;
}
DRARGS;
// Dialer dialogs context block. Used for all 5 variations of the dialer.
//
typedef struct
DRINFO
{
// Common dial context information including the RAS API arguments.
//
DRARGS* pArgs;
// Handle of the dialog and some of it's controls.
//
HWND hwndDlg;
HWND hwndEbUser;
HWND hwndEbPw;
HWND hwndEbDomain;
HWND hwndCbSavePw;
HWND hwndRbSaveForMe;
HWND hwndRbSaveForEveryone;
HWND hwndClbNumbers;
HWND hwndStLocations;
HWND hwndLbLocations;
HWND hwndPbRules;
HWND hwndPbProperties;
HWND hwndBmDialer;
// Whistler bug: 195480 Dial-up connection dialog - Number of
// asterisks does not match the length of the password and causes
// confusion
//
WCHAR szPasswordChar;
HFONT hNormalFont;
HFONT hItalicFont;
// TAPI session handle.
//
HLINEAPP hlineapp;
// The phonebook entry link containing the displayed phone number list.
// Set up only when DR_N mode bit is set.
//
DTLNODE* pLinkNode;
PBLINK* pLink;
// The index of the item initially selected in the phone number list.
//
DWORD iFirstSelectedPhone;
// Window handles and original window procedure of the subclassed
// 'hwndClbNumbers' control's edit-box and list-box child windows.
//
HWND hwndClbNumbersEb;
HWND hwndClbNumbersLb;
WNDPROC wndprocClbNumbersEb;
WNDPROC wndprocClbNumbersLb;
INetConnectionUiUtilities * pNetConUtilities;
// Set if COM has been initialized (necessary for calls to netshell).
//
BOOL fComInitialized;
// Handle to the original bitmap for the dialer if it is modified
// in DrSetBitmap
//
HBITMAP hbmOrig;
}
DRINFO;
// Context of an item in the dialer's 'ClbNumbers' list.
//
typedef struct
_DRNUMBERSITEM
{
TCHAR* pszNumber;
PBPHONE* pPhone;
}
DRNUMBERSITEM;
// Subentry state information.
//
typedef struct
_DPSTATE
{
RASCONNSTATE state;
DWORD dwError;
DWORD dwExtendedError;
TCHAR szExtendedError[ NETBIOS_NAME_LEN + 1 ];
TCHAR* pszStatusArg;
TCHAR* pszFormatArg;
PBDEVICETYPE pbdt;
DWORD sidState;
DWORD sidFormatMsg;
DWORD sidPrevState;
BOOL fNotPreSwitch;
HRASCONN hrasconnLink;
}
DPSTATE;
// Dial Progress dialog context block.
//
typedef struct
_DPINFO
{
// When the block is valid contains the value 0xC0BBC0DE, otherwise 0.
// Used as a workaround until RasDial is fixed to stop calling
// RasDialFunc2 after being told not to, see bug 49469.
//
DWORD dwValid;
// RAS API arguments.
//
DINFO* pArgs;
// Handle of this dialog and some of it's controls.
//
HWND hwndDlg;
HWND hwndStState;
// The saved username and password that authenticated but resulted in a
// change password event. If the change password operation fails these
// are restored to make the redial button work properly.
//
TCHAR* pszGoodUserName;
TCHAR* pszGoodPassword;
// The handle to the RAS connection being initiated.
//
HRASCONN hrasconn;
// The original window proc we subclassed.
//
WNDPROC pOldWndProc;
// Number of auto-redials not yet attempted on the connection.
//
DWORD dwRedialAttemptsLeft;
// Array of RasDial states, one per subentry, set by DpRasDialFunc2 and
// used by DpRasDialEvent.
//
DPSTATE* pStates;
DWORD cStates;
// The number of the most advanced subentry and the "latest" state it has
// reached. Note that certain states, like RASCS_AuthNotify, are
// revisited after reaching a "later" state. Such changes are ignored.
//
RASCONNSTATE state;
DWORD dwSubEntry;
// Flag indicating that RasDial callbacks are active. The callback
// context must not be destroyed when this flag is set. Access to this
// field is protected by 'g_hmutexCallbacks'. See DpCallbacksFlag().
//
BOOL fCallbacksActive;
//Add a per-thread Terminate flag for whistler bug 277365,291613 gangz
//
BOOL fTerminateAsap;
LONG ulCallbacksActive;
//for whistler bug 381337
//
BOOL fCancelPressed;
}
DPINFO;
// Dial Error dialog argument block.
//
typedef struct
_DEARGS
{
TCHAR* pszEntry;
DWORD dwError;
DWORD sidState;
TCHAR* pszStatusArg;
DWORD sidFormatMsg;
TCHAR* pszFormatArg;
LONG lRedialCountdown;
BOOL fPopupOnTop;
}
DEARGS;
// Dial Error dialog context block.
//
typedef struct
_DEINFO
{
// Caller's arguments to the stub API.
//
DEARGS* pArgs;
// Handle of dialog and controls.
//
HWND hwndDlg;
HWND hwndStText;
HWND hwndPbRedial;
HWND hwndPbCancel;
HWND hwndPbMore;
// Number of seconds remaining in "Redial=x" countdown or -1 if inactive.
//
LONG lRedialCountdown;
}
DEINFO;
// Projection Result dialog argument block.
//
typedef struct
_PRARGS
{
TCHAR* pszLines;
BOOL* pfDisableFailedProtocols;
}
PRARGS;
// Change Password dialog argument block.
//
typedef struct
_CPARGS
{
BOOL fOldPassword;
TCHAR* pszOldPassword;
TCHAR* pszNewPassword;
}
CPARGS;
// Change Password dialog context block.
// (unconventional name because CPINFO conflicts with a system header)
//
typedef struct
_CPWINFO
{
// Caller's arguments to the stub API.
//
CPARGS* pArgs;
// Handle of dialog and controls.
//
HWND hwndDlg;
HWND hwndEbOldPassword;
HWND hwndEbNewPassword;
HWND hwndEbNewPassword2;
}
CPWINFO;
// Retry Authentication dialog context block.
//
typedef struct
UAINFO
{
// Commond dial context including original RAS API arguments.
//
DINFO* pArgs;
// Handle of this dialog and some of it's controls.
//
HWND hwndDlg;
HWND hwndEbUserName;
HWND hwndEbPassword;
HWND hwndEbDomain;
HWND hwndCbSavePw;
// Set when the password field contains a phony password in place of the
// "" one we don't really know.
//
BOOL fAutoLogonPassword;
// Set when the Domain field is present.
//
BOOL fDomain;
}
UAINFO;
//-----------------------------------------------------------------------------
// Local prototypes (alphabetically)
//-----------------------------------------------------------------------------
BOOL
BeCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
INT_PTR CALLBACK
BeDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
VOID
BeFillLvErrors(
IN HWND hwndLv,
IN DPINFO* pInfo );
TCHAR*
BeGetErrorPsz(
IN DWORD dwError );
BOOL
BeInit(
IN HWND hwndDlg,
IN DPINFO* pArgs );
LVXDRAWINFO*
BeLvErrorsCallback(
IN HWND hwndLv,
IN DWORD dwItem );
BOOL
BundlingErrorsDlg(
IN OUT DPINFO* pInfo );
BOOL
ChangePasswordDlg(
IN HWND hwndOwner,
IN BOOL fOldPassword,
OUT TCHAR* pszOldPassword,
OUT TCHAR* pszNewPassword );
BOOL
CpCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
INT_PTR CALLBACK
CpDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
BOOL
CpInit(
IN HWND hwndDlg,
IN CPARGS* pArgs );
BOOL
CcCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
INT_PTR CALLBACK
CcDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
BOOL
CcInit(
IN HWND hwndDlg,
IN DINFO* pInfo );
VOID
ConnectCompleteDlg(
IN HWND hwndOwner,
IN DINFO* pInfo );
BOOL
DcCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
INT_PTR CALLBACK
DcDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
BOOL
DcInit(
IN HWND hwndDlg,
IN TCHAR* pszNumber );
VOID
DeAdjustPbRedial(
IN DEINFO* pInfo );
BOOL
DeCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
INT_PTR CALLBACK
DeDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
BOOL
DeInit(
IN HWND hwndDlg,
IN DEARGS* pArgs );
DWORD
DeleteSavedCredentials(
IN DINFO* pDinfo,
IN HWND hwndDlg,
IN BOOL fDefault,
IN BOOL fDeleteIdentity );
VOID
DeTerm(
IN HWND hwndDlg );
BOOL
DialCallbackDlg(
IN HWND hwndOwner,
IN OUT TCHAR* pszNumber );
BOOL
DialErrorDlg(
IN HWND hwndOwner,
IN TCHAR* pszEntry,
IN DWORD dwError,
IN DWORD sidState,
IN TCHAR* pszStatusArg,
IN DWORD sidFormatMsg,
IN TCHAR* pszFormatArg,
IN LONG lRedialCountdown,
IN BOOL fPopupOnTop );
BOOL
DialerDlg(
IN HWND hwndOwner,
IN OUT DINFO* pInfo );
BOOL
DialProgressDlg(
IN DINFO* pInfo );
VOID
DpAppendBlankLine(
IN OUT TCHAR* pszLines );
VOID
DpAppendConnectErrorLine(
IN OUT TCHAR* pszLines,
IN DWORD sidProtocol,
IN DWORD dwError );
VOID
DpAppendConnectOkLine(
IN OUT TCHAR* pszLines,
IN DWORD sidProtocol );
VOID
DpAppendFailCodeLine(
IN OUT TCHAR* pszLines,
IN DWORD dw );
VOID
DpAppendNameLine(
IN OUT TCHAR* pszLines,
IN TCHAR* psz );
VOID
DpAuthNotify(
IN DPINFO* pInfo,
IN DPSTATE* pState );
VOID
DpCallbackSetByCaller(
IN DPINFO* pInfo,
IN DPSTATE* pState );
BOOL
DpCallbacksFlag(
IN DPINFO* pInfo,
IN INT nSet );
VOID
DpCancel(
IN DPINFO* pInfo );
BOOL
DpCommand(
IN DPINFO* pInfo,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
VOID
DpConnectDevice(
IN DPINFO* pInfo,
IN DPSTATE* pState );
VOID
DpDeviceConnected(
IN DPINFO* pInfo,
IN DPSTATE* pState );
VOID
DpDial(
IN DPINFO* pInfo,
IN BOOL fPauseRestart );
INT_PTR CALLBACK
DpDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
VOID
DpError(
IN DPINFO* pInfo,
IN DPSTATE* pState );
DWORD
DpEvent(
IN DPINFO* pInfo,
IN DWORD dwSubEntry );
BOOL
DpInit(
IN HWND hwndDlg,
IN DINFO* pArgs );
VOID
DpInitStates(
DPINFO* pInfo );
BOOL
DpInteractive(
IN DPINFO* pInfo,
IN DPSTATE* pState,
OUT BOOL* pfChange );
BOOL
DpIsLaterState(
IN RASCONNSTATE stateNew,
IN RASCONNSTATE stateOld );
BOOL
DpPasswordExpired(
IN DPINFO* pInfo,
IN DPSTATE* pState );
BOOL
DpProjected(
IN DPINFO* pInfo,
IN DPSTATE* pState );
BOOL
DpProjectionError(
IN RASPPPNBF* pnbf,
IN RASPPPIPX* pipx,
IN RASPPPIP* pip,
OUT BOOL* pfIncomplete,
OUT DWORD* pdwfFailedProtocols,
OUT TCHAR** ppszLines,
OUT DWORD* pdwError );
DWORD WINAPI
DpRasDialFunc2(
ULONG_PTR dwCallbackId,
DWORD dwSubEntry,
HRASCONN hrasconn,
UINT unMsg,
RASCONNSTATE state,
DWORD dwError,
DWORD dwExtendedError );
VOID
DpTerm(
IN HWND hwndDlg );
INT_PTR CALLBACK
DrDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
BOOL CALLBACK
DrClbNumbersEnumChildProc(
IN HWND hwnd,
IN LPARAM lparam );
BOOL CALLBACK
DrClbNumbersEnumWindowsProc(
IN HWND hwnd,
IN LPARAM lparam );
BOOL
DrCommand(
IN DRINFO* pInfo,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
VOID
DrEditSelectedLocation(
IN DRINFO* pInfo );
DWORD
DrFillLocationList(
IN DRINFO* pInfo );
VOID
DrFillNumbersList(
IN DRINFO* pInfo );
DWORD
DrFindAndSubclassClbNumbersControls(
IN DRINFO* pInfo );
VOID
DrFreeClbNumbers(
IN DRINFO* pInfo );
BOOL
DrInit(
IN HWND hwndDlg,
IN DRARGS* pArgs );
VOID
DrLocationsSelChange(
IN DRINFO* pInfo );
VOID
DrNumbersSelChange(
IN DRINFO* pInfo );
DWORD
DrPopulateIdentificationFields(
IN DRINFO* pInfo,
IN BOOL fForMe);
DWORD
DrPopulatePasswordField(
IN DRINFO* pInfo,
IN BOOL fInit,
IN BOOL fDisable );
VOID
DrProperties(
IN DRINFO* pInfo );
VOID
DrSave(
IN DRINFO* pInfo );
DWORD
DrSetBitmap(
IN DRINFO* pInfo);
VOID
DrSetClbNumbersText(
IN DRINFO* pInfo,
IN TCHAR* pszText );
VOID
DrTerm(
IN HWND hwndDlg );
LRESULT APIENTRY
DpWndProc(
HWND hwnd,
UINT unMsg,
WPARAM wParam,
LPARAM lParam );
DWORD
FindEntryAndSetDialParams(
IN DINFO* pInfo );
INT_PTR CALLBACK
PrDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
BOOL
PrCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
BOOL
PrInit(
IN HWND hwndDlg,
IN PRARGS* pArgs );
BOOL
ProjectionResultDlg(
IN HWND hwndOwner,
IN TCHAR* pszLines,
OUT BOOL* pfDisableFailedProtocols );
BOOL
RetryAuthenticationDlg(
IN HWND hwndOwner,
IN DINFO* pDinfo );
INT_PTR CALLBACK
UaDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
BOOL
UaCommand(
IN UAINFO* pInfo,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
BOOL
UaInit(
IN HWND hwndDlg,
IN DINFO* pArgs );
VOID
UaSave(
IN UAINFO* pInfo );
VOID
UaTerm(
IN HWND hwndDlg );
BOOL
VpnDoubleDialDlg(
IN HWND hwndOwner,
IN DINFO* pInfo );
INT_PTR CALLBACK
ViDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam );
BOOL
ViCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl );
BOOL
ViInit(
IN HWND hwndDlg,
IN DINFO* pInfo );
//-----------------------------------------------------------------------------
// External entry points
//-----------------------------------------------------------------------------
typedef struct EAPFREE_DATA {
BOOL bInitialized;
HINSTANCE hLib;
RASEAPFREE pFreeFunc;
} EAPFREE_DATA;
//Add those OutputDebug_XXXX() functions for debug use when debugging 291613
// gangz
//
void OutputDebug_DWCODE(DWORD dwCode)
{
WCHAR tmpBuf[100];
wsprintf(tmpBuf,
L"The dwCode returned is %x\n", dwCode);
OutputDebugStringW(tmpBuf);
}
void OutputDebug_NumOfCallbacksActive(ULONG ulCallbacksActive)
{
WCHAR tmpBuf[100];
wsprintf(tmpBuf,
L"Current CallbacksActive is %x\n",
ulCallbacksActive);
OutputDebugStringW(tmpBuf);
}
void OutputDebug_ThreadId()
{
DWORD dwId;
WCHAR tmpBuf[100];
dwId = GetCurrentThreadId();
wsprintf(tmpBuf, L"Current Thread is %x\n", dwId);
OutputDebugStringW(tmpBuf);
}
void OutputDebug_ProcessThreadId()
{
DWORD dwIdProc, dwIdThread;
WCHAR tmpBuf[100];
dwIdProc = GetCurrentProcessId();
dwIdThread = GetCurrentThreadId();
wsprintf(tmpBuf, L"Current Proc is: %x , Thread is: %x\n", dwIdProc, dwIdThread);
OutputDebugStringW(tmpBuf);
}
//
// Raises the appriate eap indentity dialog
//
DWORD
DialerDlgEap (
IN HWND hwndOwner,
IN PWCHAR lpszPhonebook,
IN PWCHAR lpszEntry,
IN PBENTRY * pEntry,
IN DINFO *pInfo,
OUT PBYTE * ppUserDataOut,
OUT DWORD * lpdwSizeOfUserDataOut,
OUT LPWSTR * lplpwszIdentity,
OUT PHANDLE phFree
)
{
DWORD dwErr, dwInSize = 0;
PBYTE pbUserIn = NULL;
HINSTANCE hLib = NULL;
EAPFREE_DATA * pFreeData = NULL;
DTLLIST * pListEaps = NULL;
DTLNODE * pEapcfgNode = NULL;
EAPCFG * pEapcfg = NULL;
RASEAPFREE pFreeFunc = NULL;
RASEAPGETIDENTITY pIdenFunc = NULL;
DWORD dwFlags;
DWORD cbData = 0;
PBYTE pbData = NULL;
// Initialize the free data handle we'll return
pFreeData = Malloc ( sizeof(EAPFREE_DATA) );
if (pFreeData == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
ZeroMemory( pFreeData, sizeof(EAPFREE_DATA) );
// Make sure we're configured with some list of
// eap configuration options
pListEaps = ReadEapcfgList( NULL );
if (pListEaps == NULL)
{
Free(pFreeData);
return ERROR_CAN_NOT_COMPLETE;
}
__try {
// Find the eap node we're interested in
pEapcfgNode = EapcfgNodeFromKey(
pListEaps,
pEntry->dwCustomAuthKey );
if (pEapcfgNode)
pEapcfg = (EAPCFG*)DtlGetData( pEapcfgNode );
else
return ERROR_CAN_NOT_COMPLETE;
// Only call eap identity ui if we're told not to
// get the user name through the standard credentials
// dialog
if (pEapcfg->dwStdCredentialFlags &
EAPCFG_FLAG_RequireUsername)
{
return NO_ERROR;
}
if(!pInfo->pNoUser)
{
// Get the size of the input user data
dwErr = RasGetEapUserData(
NULL,
lpszPhonebook,
lpszEntry,
NULL,
&dwInSize);
// Read in the user data
if (dwErr != NO_ERROR) {
if (dwErr == ERROR_BUFFER_TOO_SMALL) {
if (dwInSize == 0)
{
pbUserIn = NULL;
// return ERROR_CAN_NOT_COMPLETE;
}
else
{
// Allocate a blob to hold the data
pbUserIn = Malloc (dwInSize);
if (pbUserIn == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// Read in the new blob
dwErr = RasGetEapUserData(
NULL,
lpszPhonebook,
lpszEntry,
pbUserIn,
&dwInSize);
if (dwErr != NO_ERROR)
return dwErr;
}
}
else
return dwErr;
}
}
else
{
INTERNALARGS *piargs;
piargs = (INTERNALARGS *) pInfo->pArgs->reserved;
if( (NULL != piargs)
&& (NULL != piargs->pvEapInfo)
// pmay: 386489
//
&& (pEntry->dwCustomAuthKey == EAPCFG_DefaultKey))
{
pbUserIn = (BYTE *) piargs->pvEapInfo;
dwInSize = ((EAPLOGONINFO *) piargs->pvEapInfo)->dwSize;
}
else
{
pbUserIn = NULL;
dwInSize = 0;
}
}
// Load the identity library
hLib = LoadLibrary (pEapcfg->pszIdentityDll);
if (hLib == NULL)
return GetLastError();
// Get pointers to the functions we'll be needing
pIdenFunc = (RASEAPGETIDENTITY)
GetProcAddress(hLib, "RasEapGetIdentity");
pFreeFunc = (RASEAPFREE) GetProcAddress(hLib, "RasEapFreeMemory");
if ( (pFreeFunc == NULL) || (pIdenFunc == NULL) )
return ERROR_CAN_NOT_COMPLETE;
dwFlags = (pInfo->pNoUser) ? RAS_EAP_FLAG_LOGON : 0;
if (!pEntry->fAutoLogon && pEntry->fPreviewUserPw)
{
dwFlags |= RAS_EAP_FLAG_PREVIEW;
}
if(pInfo->fUnattended)
{
dwFlags &= ~RAS_EAP_FLAG_PREVIEW;
}
dwErr = DwGetCustomAuthData(
pEntry,
&cbData,
&pbData);
if(ERROR_SUCCESS != dwErr)
{
return dwErr;
}
// Call the eap-provided identity UI
dwErr = (*(pIdenFunc))(
pEntry->dwCustomAuthKey,
hwndOwner,
dwFlags,
lpszPhonebook,
lpszEntry,
pbData,
cbData,
pbUserIn,
dwInSize,
ppUserDataOut,
lpdwSizeOfUserDataOut,
lplpwszIdentity);
if (dwErr != NO_ERROR)
return dwErr;
// Assign the data used to cleanup later
pFreeData->bInitialized = TRUE;
pFreeData->hLib = hLib;
pFreeData->pFreeFunc = pFreeFunc;
*phFree = (HANDLE)pFreeData;
}
__finally {
if (pListEaps)
DtlDestroyList(pListEaps, NULL);
if ( (!pInfo->pNoUser)
&& (pbUserIn))
{
Free0(pbUserIn);
}
if ((pFreeData) && (!pFreeData->bInitialized))
{
Free(pFreeData);
if(NULL != hLib)
{
FreeLibrary(hLib);
}
}
}
return NO_ERROR;
}
DWORD
DialerEapCleanup (
IN HANDLE hEapFree,
IN PBYTE pUserDataOut,
IN LPWSTR lpwszIdentity)
{
EAPFREE_DATA * pFreeData = (EAPFREE_DATA*)hEapFree;
if (pFreeData == NULL)
return ERROR_INVALID_PARAMETER;
if (pFreeData->pFreeFunc) {
if (pUserDataOut)
(*(pFreeData->pFreeFunc))(pUserDataOut);
if (lpwszIdentity)
(*(pFreeData->pFreeFunc))((BYTE*)lpwszIdentity);
}
if (pFreeData->hLib)
FreeLibrary(pFreeData->hLib);
Free (pFreeData);
return NO_ERROR;
}
//
// Customizes the dialer flags for the eap provider
// of the given entry;
//
// TODO -- try to optimize this. The list of eaps
// may not need to be read if we keep enough state
// in the phonebook.
//
DWORD DialerEapAssignMode(
IN DINFO* pInfo,
OUT LPDWORD lpdwfMode)
{
DWORD dwfMode = *lpdwfMode;
DTLLIST * pListEaps;
DTLNODE * pEapcfgNode;
EAPCFG * pEapcfg;
// If eap is not used in this entry,
// then no action is required
if (! (pInfo->pEntry->dwAuthRestrictions & AR_F_AuthEAP))
return NO_ERROR;
// Make sure we're configured with some list of
// eap configuration options
pListEaps = ReadEapcfgList( NULL );
if (pListEaps == NULL)
return ERROR_CAN_NOT_COMPLETE;
// Find the eap node we're interested in
pEapcfgNode = EapcfgNodeFromKey(
pListEaps,
pInfo->pEntry->dwCustomAuthKey );
if (pEapcfgNode)
pEapcfg = (EAPCFG*)DtlGetData( pEapcfgNode );
else
{
if (pListEaps)
DtlDestroyList(pListEaps, NULL);
return ERROR_CAN_NOT_COMPLETE;
}
// If eap provider requests user name then
// request identity.
if (pEapcfg->dwStdCredentialFlags &
EAPCFG_FLAG_RequireUsername
)
{
// Use the "I" flavors if the eap wants a user
// name but no password.
//
if (!(pEapcfg->dwStdCredentialFlags &
EAPCFG_FLAG_RequirePassword)
)
{
// Clear the username+password property (DR_U) if it
// exists and replace it with the username property
// (DR_I). Only do this if DR_U is already set. It
// wont be set for autodial connections or for connections
// where that option was specifically disabled as can
// be seen in the DialerDlg function.
//
// See whistler bug 30841
//
if (dwfMode & DR_U)
{
dwfMode &= ~DR_U;
dwfMode |= DR_I;
}
}
}
else
{
// Otherwise, make sure that we request neither user name nor password
// Since domain cannot appear without username clear that also.
//
dwfMode &= ~(DR_U | DR_D);
}
// Cleanup
if (pListEaps)
DtlDestroyList(pListEaps, NULL);
// Assign the correct mode
*lpdwfMode = dwfMode;
return NO_ERROR;
}
BOOL APIENTRY
RasDialDlgA(
IN LPSTR lpszPhonebook,
IN LPSTR lpszEntry,
IN LPSTR lpszPhoneNumber,
IN OUT LPRASDIALDLG lpInfo )
// Win32 ANSI entrypoint that displays the dial progress and related
// dialogs, including authentication, error w/redial, callback, and retry
// authentication. 'LpszPhonebook' is the full path the phonebook or NULL
// indicating the default phonebook. 'LpszEntry' is the entry to dial.
// 'LpszPhoneNumber' is caller's override phone number or NULL to use the
// one in the entry. 'LpInfo' is caller's additional input/output
// parameters.
//
// Returns true if user establishes a connection, false otherwise.
//
{
WCHAR* pszPhonebookW;
WCHAR* pszEntryW;
WCHAR* pszPhoneNumberW;
BOOL fStatus;
TRACE( "RasDialDlgA" );
if (!lpInfo)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (!lpszEntry)
{
lpInfo->dwError = ERROR_INVALID_PARAMETER;
return FALSE;
}
if (lpInfo->dwSize != sizeof(RASDIALDLG))
{
lpInfo->dwError = ERROR_INVALID_SIZE;
return FALSE;
}
// Thunk "A" arguments to "W" arguments.
//
if (lpszPhonebook)
{
pszPhonebookW = StrDupTFromAUsingAnsiEncoding( lpszPhonebook );
if (!pszPhonebookW)
{
lpInfo->dwError = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
}
else
{
pszPhonebookW = NULL;
}
pszEntryW = StrDupTFromAUsingAnsiEncoding( lpszEntry );
if (!pszEntryW)
{
Free0( pszPhonebookW );
lpInfo->dwError = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
if (lpszPhoneNumber)
{
pszPhoneNumberW = StrDupTFromAUsingAnsiEncoding( lpszPhoneNumber );
if (!pszPhoneNumberW)
{
Free0( pszPhonebookW );
Free( pszEntryW );
lpInfo->dwError = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
}
else
{
pszPhoneNumberW = NULL;
}
// Thunk to the equivalent "W" API.
//
fStatus = RasDialDlgW( pszPhonebookW, pszEntryW, pszPhoneNumberW, lpInfo );
Free0( pszPhonebookW );
Free( pszEntryW );
return fStatus;
}
DWORD
DoEapProcessing(
LPRASDIALDLG lpInfo,
DINFO *pInfo,
PBYTE *ppbEapUserData,
WCHAR **ppwszEapIdentity,
HANDLE *phEapFree,
BOOL *pfStatus
)
{
// If this is an eap connection, then use the eap identity
// ui to get the user name and password.
//
DWORD dwSize = 0;
DWORD dwErr = NO_ERROR;
*pfStatus = TRUE;
// Bring up the Eap dialer dialog
dwErr = DialerDlgEap(
lpInfo->hwndOwner,
pInfo->pFile->pszPath,
pInfo->pEntry->pszEntryName,
pInfo->pEntry,
pInfo,
ppbEapUserData,
&dwSize,
ppwszEapIdentity,
phEapFree);
if (dwErr != NO_ERROR)
{
if (ERROR_CANCELLED == dwErr)
{
dwErr = NO_ERROR;
}
*pfStatus = FALSE;
goto done;
}
if(!pInfo->pNoUser)
{
// Set the extended dial params accordingly
pInfo->rde.RasEapInfo.dwSizeofEapInfo = dwSize;
pInfo->rde.RasEapInfo.pbEapInfo = *ppbEapUserData;
}
else if ( (*ppbEapUserData != NULL)
&& (dwSize != 0))
{
pInfo->rde.RasEapInfo.dwSizeofEapInfo = dwSize;
pInfo->rde.RasEapInfo.pbEapInfo = *ppbEapUserData;
}
else
{
INTERNALARGS *piargs;
piargs = (INTERNALARGS *) (pInfo->pArgs->reserved);
if( (NULL != piargs)
&& (NULL != piargs->pvEapInfo)
// pmay: 386489
//
&& (pInfo->pEntry->dwCustomAuthKey == EAPCFG_DefaultKey))
{
pInfo->rde.RasEapInfo.dwSizeofEapInfo =
((EAPLOGONINFO *) piargs->pvEapInfo)->dwSize;
pInfo->rde.RasEapInfo.pbEapInfo = (BYTE *) piargs->pvEapInfo;
}
else
{
pInfo->rde.RasEapInfo.dwSizeofEapInfo = 0;
pInfo->rde.RasEapInfo.pbEapInfo = NULL;
}
}
if (*ppwszEapIdentity)
{
DWORD dwSize =
sizeof(pInfo->rdp.szUserName) / sizeof(WCHAR);
wcsncpy(pInfo->rdp.szUserName, *ppwszEapIdentity,
dwSize - 1);
pInfo->rdp.szUserName[dwSize - 1] = 0;
// Ignore the domain setting if the EAP supplied the
// identity.
pInfo->rdp.szDomain[ 0 ] = L'\0';
}
done:
return dwErr;
}
INT
DialDlgDisplayError(
IN LPRASDIALDLG pInfo,
IN HWND hwndOwner,
IN DWORD dwSid,
IN DWORD dwError,
IN ERRORARGS* pArgs)
{
if (pInfo->dwFlags & RASDDFLAG_NoPrompt)
{
return 0;
}
return ErrorDlg(hwndOwner, dwSid, dwError, pArgs);
}
BOOL APIENTRY
RasDialDlgW(
IN LPWSTR lpszPhonebook,
IN LPWSTR lpszEntry,
IN LPWSTR lpszPhoneNumber,
IN OUT LPRASDIALDLG lpInfo )
// Win32 UNICODE entrypoint that displays the dial progress and related
// dialogs, including authentication, error w/redial, callback, and retry
// authentication. 'LpszPhonebook' is the full path the phonebook or NULL
// indicating the default phonebook. 'LpszEntry' is the entry to dial.
// 'LpszPhoneNumber' is caller's override phone number or NULL to use the
// one in the entry. 'LpInfo' is caller's additional input/output
// parameters.
//
// Returns true if user establishes a connection, false otherwise. If
// 'RASDDFLAG_AutoDialQueryOnly' is set, returns true if user pressed
// "Dial", false otherwise.
//
{
DWORD dwErr;
BOOL fStatus;
BOOL fFirstPass;
DINFO* pInfo;
LPWSTR pwszEapIdentity = NULL;
PBYTE pbEapUserData = NULL;
HANDLE hEapFree = NULL;
BOOL fCustom = FALSE;
PVOID pvInfo = NULL;
HRASCONN hrasconnPrereq = NULL;
TRACE( "RasDialDlgW" );
if (!lpInfo)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (!lpszEntry)
{
lpInfo->dwError = ERROR_INVALID_PARAMETER;
return FALSE;
}
if (lpInfo->dwSize != sizeof(RASDIALDLG))
{
lpInfo->dwError = ERROR_INVALID_SIZE;
return FALSE;
}
if (lpszPhoneNumber && lstrlen( lpszPhoneNumber ) > RAS_MaxPhoneNumber)
{
lpInfo->dwError = ERROR_INVALID_PARAMETER;
return FALSE;
}
// Load RAS DLL entrypoints which starts RASMAN, if necessary.
//
lpInfo->dwError = LoadRas( g_hinstDll, lpInfo->hwndOwner );
if (lpInfo->dwError != 0)
{
// Whistler bug 301784
//
// Check specifically for access denied.
//
if (lpInfo->dwError == ERROR_ACCESS_DENIED)
{
DialDlgDisplayError(
lpInfo,
lpInfo->hwndOwner,
SID_OP_LoadRasAccessDenied,
lpInfo->dwError,
NULL );
}
else
{
DialDlgDisplayError(
lpInfo,
lpInfo->hwndOwner,
SID_OP_LoadRas,
lpInfo->dwError,
NULL );
}
return FALSE;
}
// Allocate the context information block and initialize it enough so that
// it can be destroyed properly.
//
pInfo = Malloc( sizeof(*pInfo) );
if (!pInfo)
{
DialDlgDisplayError(
lpInfo,
lpInfo->hwndOwner,
SID_OP_LoadDlg,
ERROR_NOT_ENOUGH_MEMORY,
NULL );
lpInfo->dwError = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
ZeroMemory( pInfo, sizeof(*pInfo) );
pInfo->pszPhonebook = lpszPhonebook;
pInfo->pszEntry = lpszEntry;
pInfo->pszPhoneNumber = lpszPhoneNumber;
pInfo->pArgs = lpInfo;
fStatus = FALSE;
dwErr = 0;
do
{
// Load the phonebook file and user preferences, or figure out that
// caller has already loaded them.
//
if (lpInfo->reserved)
{
INTERNALARGS* piargs;
// We've received an open phonebook file and user preferences via
// the secret hack.
//
piargs = (INTERNALARGS* )lpInfo->reserved;
pInfo->pFile = pInfo->pFileMain = piargs->pFile;
pInfo->pUser = piargs->pUser;
pInfo->pNoUser = piargs->pNoUser;
pInfo->pfNoUserChanged = &piargs->fNoUserChanged;
pInfo->fMoveOwnerOffDesktop = piargs->fMoveOwnerOffDesktop;
pInfo->fForceCloseOnDial = piargs->fForceCloseOnDial;
}
else
{
// Read user preferences from registry.
//
dwErr = g_pGetUserPreferences( NULL, &pInfo->user, UPM_Normal );
if (dwErr != 0)
{
DialDlgDisplayError(
lpInfo,
lpInfo->hwndOwner,
SID_OP_LoadPrefs,
dwErr,
NULL );
break;
}
pInfo->pUser = &pInfo->user;
// Load and parse the phonebook file.
//
dwErr = ReadPhonebookFile(
lpszPhonebook, &pInfo->user, NULL, 0, &pInfo->file );
if (dwErr != 0)
{
DialDlgDisplayError(
lpInfo,
lpInfo->hwndOwner,
SID_OP_LoadPhonebook,
dwErr,
NULL );
break;
}
pInfo->pFile = pInfo->pFileMain = &pInfo->file;
}
// Record whether this is a for-all-users phonebook
//
// Whistler bug 288596 Autodial has wrong save password option marked -
// prompts user to save password for all users
//
pInfo->fIsPublicPbk =
(!pInfo->pszPhonebook) || IsPublicPhonebook(pInfo->pszPhonebook);
if (!pInfo->pNoUser)
{
DWORD dwErrR;
HKEY hkey;
// See if admin has disabled the "save password" feature.
//
pInfo->fDisableSavePw = FALSE;
dwErrR = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
TEXT("SYSTEM\\CurrentControlSet\\Services\\RasMan\\Parameters"),
0, KEY_READ, &hkey );
if (dwErrR == 0)
{
DWORD dwResult;
dwResult = (DWORD )pInfo->fDisableSavePw;
GetRegDword( hkey, TEXT("DisableSavePassword"), &dwResult );
pInfo->fDisableSavePw = (BOOL )dwResult;
RegCloseKey( hkey );
}
}
// Hide parent dialog when initiated by another RAS API that requests
// it. This is the first stage of "close on dial" behavior, allowing
// the parent to appear closed to user though, as owner, it must
// really stay open until the dial dialogs complete. At that point it
// can silently close or reappear as desired.
//
if (lpInfo->hwndOwner && pInfo->fMoveOwnerOffDesktop)
{
SetOffDesktop( lpInfo->hwndOwner, SOD_MoveOff, NULL );
}
// Set true initially, but will be set false by
// FindEntryAndSetDialParams if the entry has no "dial first" entry
// associated with it.
//
pInfo->fPrerequisiteDial = TRUE;
fFirstPass = TRUE;
for (;;)
{
pInfo->fDialForReferenceOnly = FALSE;
// Look up the entry and fill in the RASDIALPARAMS structure
// accordingly. This done as a routine so it can be re-done
// should user press the Properties button.
//
dwErr = FindEntryAndSetDialParams( pInfo );
if (dwErr != 0)
{
// we need to maintain 2 phonebooks
// but we need to do this in case we break existing
// apps which look specifically in system\ras dir.
// Feel free to rip this code off, if you feel
// strongly about it.
//
if( (ERROR_CANNOT_FIND_PHONEBOOK_ENTRY == dwErr)
&& (NULL == lpszPhonebook))
{
DTLNODE *pNode;
//
// Close the all users phonebook file
//
ClosePhonebookFile(&pInfo->file);
dwErr = GetPbkAndEntryName(
lpszPhonebook,
lpszEntry,
0,
&pInfo->file,
&pNode);
if( (NULL == pNode)
|| (ERROR_SUCCESS != dwErr))
{
dwErr = ERROR_CANNOT_FIND_PHONEBOOK_ENTRY;
break;
}
pInfo->pFile = pInfo->pFileMain = &pInfo->file;
dwErr = FindEntryAndSetDialParams(pInfo);
if(dwErr != 0)
{
break;
}
}
else
{
break;
}
}
if(lpInfo->reserved)
{
INTERNALARGS *piargs = (INTERNALARGS *) lpInfo->reserved;
if (pInfo->pEntry->dwAuthRestrictions & AR_F_AuthEAP)
{
pvInfo = piargs->pvEapInfo;
}
else
{
pvInfo = piargs->pNoUser;
}
}
if(pInfo->fPrerequisiteDial
&& (NULL != pInfo->pEntry->pszCustomDialerName)
&& (TEXT('\0') != pInfo->pEntry->pszCustomDialerName[0]))
{
RASDIALDLG Info;
DWORD dwCustomFlags = 0;
RASNOUSER nouser, *pNoUser = NULL;
ZeroMemory(&Info, sizeof(RASDIALDLG));
ZeroMemory(&nouser, sizeof(RASNOUSER));
Info.dwSize = sizeof(RASDIALDLG);
Info.hwndOwner = lpInfo->hwndOwner;
Info.xDlg = lpInfo->xDlg;
Info.yDlg = lpInfo->yDlg;
fCustom = TRUE;
if(pInfo->pEntry->dwAuthRestrictions & AR_F_AuthEAP)
{
dwCustomFlags |= RCD_Eap;
}
if( (NULL != pInfo->pNoUser)
&& (RASNOUSER_SmartCard & pInfo->pNoUser->dwFlags)
&& ( (0 == (dwCustomFlags & RCD_Eap))
|| (EAP_RASTLS != pInfo->pEntry->dwCustomAuthKey)
))
{
CopyMemory(&nouser, pInfo->pNoUser, sizeof(RASNOUSER));
ZeroMemory(nouser.szPassword, (PWLEN+1) * sizeof(TCHAR));
pvInfo = &nouser;
}
// DwCustomDialDlg returns ERROR_SUCCESS if it handled
// the CustomRasDial. returns E_NOINTERFACE otherwise
// which implies that there is no custom dlg interface
// supported for this entry and the default dial should
// happen
//
// Whistler bug 314578 When connecting with CM via Winlogon I
// get the following error "Error 1: Incorrect function"
//
// This is a case where we call into a custom dialer, ie CM,
// and we are using creds that we got from winlogon. They are
// currently encoded and must be decoded before we call out.
// We have to assume that the Custom Dialer leaves the password
// un-encoded upon return.
//
if ( !(pInfo->pEntry->dwAuthRestrictions & AR_F_AuthEAP) )
{
// pNoUser is used to encode/decode passwords. If this
// is an EAP connection, then pvInfo will point to an
// eap blob, not a "no user" blob.
//
pNoUser = pvInfo;
}
if ( pNoUser )
{
DecodePassword( pNoUser->szPassword );
}
if(pInfo->pNoUser)
{
dwCustomFlags |= RCD_Logon;
}
dwErr = DwCustomDialDlg(pInfo->pFile->pszPath,
pInfo->pEntry->pszEntryName,
NULL,
&Info,
dwCustomFlags,
&fStatus,
pvInfo,
pInfo->pEntry->pszCustomDialerName);
if ( pNoUser )
{
EncodePassword( pNoUser->szPassword );
}
if(!fStatus)
{
lpInfo->dwError = Info.dwError;
break;
}
else
{
pInfo->fPrerequisiteDial = FALSE;
fCustom = FALSE;
continue;
}
}
else if ((NULL != pInfo->pEntry->pszCustomDialerName)
&& (TEXT('\0') != pInfo->pEntry->pszCustomDialerName[0]))
{
DWORD dwCustomFlags = 0;
RASNOUSER nouser, *pNoUser = NULL;
ZeroMemory(&nouser, sizeof(RASNOUSER));
if(pInfo->pEntry->dwAuthRestrictions & AR_F_AuthEAP)
{
dwCustomFlags |= RCD_Eap;
}
if( (NULL != pInfo->pNoUser)
&& (RASNOUSER_SmartCard & pInfo->pNoUser->dwFlags)
&& ( (0 == (dwCustomFlags & RCD_Eap))
|| (EAP_RASTLS != pInfo->pEntry->dwCustomAuthKey))
)
{
CopyMemory(&nouser, pInfo->pNoUser, sizeof(RASNOUSER));
ZeroMemory(nouser.szPassword, (PWLEN+1) * sizeof(TCHAR));
pvInfo = &nouser;
}
fCustom = TRUE;
// DwCustomDialDlg returns ERROR_SUCCESS if it handled
// the CustomRasDial. returns E_NOINTERFACE otherwise
// which implies that there is no custom dlg interface
// supported for this entry and the default dial should
// happen
//
// Whistler bug 314578 When connecting with CM via Winlogon I
// get the following error "Error 1: Incorrect function"
//
// This is a case where we call into a custom dialer, ie CM,
// and we are using creds that we got from winlogon. They are
// currently encoded and must be decoded before we call out.
// We have to assume that the Custom Dialer leaves the password
// un-encoded upon return.
//
if ( !(pInfo->pEntry->dwAuthRestrictions & AR_F_AuthEAP) )
{
// pNoUser is used to encode/decode passwords. If this
// is an EAP connection, then pvInfo will point to an
// eap blob, not a "no user" blob.
//
pNoUser = pvInfo;
}
if ( pNoUser )
{
DecodePassword( pNoUser->szPassword );
}
if(pInfo->pNoUser)
{
dwCustomFlags |= RCD_Logon;
}
dwErr = DwCustomDialDlg(lpszPhonebook,
lpszEntry,
lpszPhoneNumber,
lpInfo,
dwCustomFlags,
&fStatus,
pvInfo,
pInfo->pEntry->pszCustomDialerName);
if ( pNoUser )
{
EncodePassword( pNoUser->szPassword );
}
break;
}
// If a prerequisite entry is already connected, there's no need
// for any UI but the dial must occur to set the reference in the
// RASAPI level.
//
if (pInfo->fPrerequisiteDial
&& HrasconnFromEntry(
pInfo->pFile->pszPath, pInfo->pEntry->pszEntryName ))
{
pInfo->fDialForReferenceOnly = TRUE;
}
// Set up extension parameter block, except 'hwndOwner' which is
// set to the Dial Progress dialog window later.
//
{
RASDIALEXTENSIONS* prde = &pInfo->rde;
ZeroMemory( prde, sizeof(*prde) );
prde->dwSize = sizeof(*prde);
prde->dwfOptions = RDEOPT_PausedStates | RDEOPT_PauseOnScript;
if (pInfo->pNoUser)
{
prde->dwfOptions |= RDEOPT_NoUser;
}
if (!pInfo->pszPhoneNumber)
{
prde->dwfOptions |= RDEOPT_UsePrefixSuffix;
}
}
if ( (pInfo->fUnattended)
&& ((HaveSavedPw( pInfo ))
|| (pInfo->pEntry->dwAuthRestrictions & AR_F_AuthEAP)))
{
// Popup the countdown to link failure redial version of the
// dial error dialog, which will lead to a dial unless user
// stops it.
//
fStatus = DialErrorDlg(
lpInfo->hwndOwner, pInfo->pEntry->pszEntryName,
0, 0, NULL, 0, NULL,
GetOverridableParam(
pInfo->pUser, pInfo->pEntry, RASOR_RedialSeconds ),
GetOverridableParam(
pInfo->pUser, pInfo->pEntry,
RASOR_PopupOnTopWhenRedialing ) );
if(!fStatus)
{
break;
}
if (pInfo->pEntry->dwAuthRestrictions & AR_F_AuthEAP)
{
dwErr = DoEapProcessing(
lpInfo,
pInfo,
&pbEapUserData,
&pwszEapIdentity,
&hEapFree,
&fStatus);
if( (NO_ERROR != dwErr)
|| (!fStatus))
{
break;
}
}
}
else if (!pInfo->fDialForReferenceOnly)
{
if (!pInfo->fUnattended && fFirstPass)
{
// Warn about active NWC LAN connections being blown away,
// if indicated.
//
if (!NwConnectionCheck(
lpInfo->hwndOwner,
(pInfo->pArgs->dwFlags & RASDDFLAG_PositionDlg),
pInfo->pArgs->xDlg, pInfo->pArgs->yDlg,
pInfo->pFile, pInfo->pEntry ))
{
break;
}
// Popup the double-dial help popup, if indicated.
//
if (!VpnDoubleDialDlg( lpInfo->hwndOwner, pInfo ))
{
break;
}
}
// Check to see if its smartcardlogon case and blank
// out the password if its not an eap tls connectoid
//
if( (NULL != pInfo->pNoUser)
&& (RASNOUSER_SmartCard & pInfo->pNoUser->dwFlags)
&& (pInfo->pEntry->dwCustomAuthKey != EAP_RASTLS))
{
ZeroMemory(pInfo->rdp.szPassword, (PWLEN+1) * sizeof(TCHAR));
}
// Prompt for credentials and/or phone number (or not)
// as configured in the entry properties.
//
if (!DialerDlg( lpInfo->hwndOwner, pInfo ))
{
if(!fFirstPass)
{
fStatus = FALSE;
}
break;
}
if (pInfo->pEntry->dwAuthRestrictions & AR_F_AuthEAP)
{
dwErr = DoEapProcessing(
lpInfo,
pInfo,
&pbEapUserData,
&pwszEapIdentity,
&hEapFree,
&fStatus);
if( (NO_ERROR != dwErr)
|| (!fStatus))
{
break;
}
}
fStatus = TRUE;
}
else
{
fStatus = TRUE;
}
// Dial and show progress.
//
if (fStatus
&& !fCustom)
{
// Clear this here because beyond this rasman
// will take care of dropping the prereq link
// since beyond this point rasdial api will get
// called. [raos]
//
hrasconnPrereq = NULL;
fStatus = DialProgressDlg( pInfo );
// Show connect complete dialog unless user has nixed it or
// it's a prerequisite dial.
// (AboladeG) Also suppress the dialog in no-prompt mode.
//
if (!pInfo->fPrerequisiteDial
&& fStatus
&& !pInfo->pUser->fSkipConnectComplete
&& !(pInfo->pArgs->dwFlags & RASDDFLAG_NoPrompt))
{
//For whistler bug 378078 gangz
//We will comment out this status explaination dialog
//box because some users complained that it is confusing
//
// ConnectCompleteDlg( lpInfo->hwndOwner, pInfo );
}
}
// Don't loop a second time to dial the main entry if the
// prerequisite dial failed.
//
if (!fStatus || !pInfo->fPrerequisiteDial)
{
break;
}
// Save the rasconn of the prereq dial in case we need to hang
// it up for the case where the vpn dialog fails before rasdial
// gets called. [raos]
//
if (pInfo->fPrerequisiteDial)
{
hrasconnPrereq = HrasconnFromEntry(
pInfo->pFile->pszPath, pInfo->pEntry->pszEntryName);
}
pInfo->fPrerequisiteDial = FALSE;
fFirstPass = FALSE;
// Cleanup eap stuff
if (hEapFree)
{
DialerEapCleanup(hEapFree, pbEapUserData, pwszEapIdentity);
hEapFree = NULL;
pbEapUserData = NULL;
pwszEapIdentity = NULL;
}
}
}
while (FALSE);
// Unhide parent dialog when initiated by another RAS API.
//
if (lpInfo->hwndOwner && pInfo->fMoveOwnerOffDesktop
&& (!fStatus
|| !(pInfo->pUser->fCloseOnDial || pInfo->fForceCloseOnDial)))
{
SetOffDesktop( lpInfo->hwndOwner, SOD_MoveBackFree, NULL );
}
if(!fCustom)
{
// Save the several little user preferences adjustments we may have made.
//
g_pSetUserPreferences(
NULL, pInfo->pUser, (pInfo->pNoUser) ? UPM_Logon : UPM_Normal );
// Report error, if any.
//
if (dwErr)
{
DialDlgDisplayError(
lpInfo,
lpInfo->hwndOwner,
SID_OP_LoadDlg,
dwErr,
NULL );
lpInfo->dwError = dwErr;
}
TRACE1("hrasconnPrereq=0x%x",hrasconnPrereq);
//
// Drop the connection if we failed to connect the vpn connection
//
if( !fStatus
&& (NULL != hrasconnPrereq)
&& (pInfo->pEntry)
&& (pInfo->pEntry->pszPrerequisiteEntry)
&& *(pInfo->pEntry->pszPrerequisiteEntry))
{
g_pRasHangUp(hrasconnPrereq);
}
}
// Clean up.
//
if (!lpInfo->reserved)
{
if (pInfo->pFileMain)
{
ClosePhonebookFile( pInfo->pFileMain );
}
if (pInfo->pUser)
{
DestroyUserPreferences( pInfo->pUser );
}
}
if (pInfo->fFilePrereqOpen)
{
ClosePhonebookFile( &pInfo->filePrereq );
}
ZeroMemory( pInfo->rdp.szPassword, sizeof(pInfo->rdp.szPassword) );
if (pInfo->pListPortsToDelete)
{
DtlDestroyList( pInfo->pListPortsToDelete, DestroyPszNode );
}
if (hEapFree)
DialerEapCleanup(hEapFree, pbEapUserData, pwszEapIdentity);
Free( pInfo );
return fStatus;
}
//----------------------------------------------------------------------------
// Local utilities
// Listed alphabetically
//----------------------------------------------------------------------------
DWORD
RasCredToDialParam(
IN TCHAR* pszDefaultUserName,
IN TCHAR* pszDefaultDomain,
IN RASCREDENTIALS* pCreds,
OUT RASDIALPARAMS* pParams)
{
TCHAR* pszComputer = NULL;
TCHAR* pszLogonDomain = NULL;
TCHAR* pszUser = NULL;
// Set the user name, defaulting it if needed
//
if (pCreds->dwMask & RASCM_UserName)
{
lstrcpyn(
pParams->szUserName,
pCreds->szUserName,
sizeof(pParams->szUserName) / sizeof(TCHAR));
}
else if (pszDefaultUserName)
{
lstrcpyn(
pParams->szUserName,
pszDefaultUserName,
sizeof(pParams->szUserName) / sizeof(TCHAR));
}
else
{
pszUser = GetLogonUser();
if (pszUser)
{
lstrcpyn(
pParams->szUserName,
pszUser,
sizeof(pParams->szUserName) / sizeof(TCHAR));
}
}
// Set the domain name, defaulting it if needed
//
if (pCreds->dwMask & RASCM_Domain)
{
lstrcpyn(
pParams->szDomain,
pCreds->szDomain,
sizeof(pParams->szDomain) / sizeof(TCHAR));
}
else if ( pszDefaultDomain )
{
lstrcpyn(
pParams->szDomain,
pszDefaultDomain,
sizeof(pParams->szDomain) / sizeof(TCHAR));
}
else
{
pszComputer = GetComputer();
pszLogonDomain = GetLogonDomain();
if ( (pszComputer) &&
(pszLogonDomain) &&
(lstrcmp( pszComputer, pszLogonDomain ) != 0))
{
lstrcpyn(
pParams->szDomain,
pszLogonDomain,
sizeof(pParams->szDomain) / sizeof(TCHAR));
}
}
// Fill in the password field
//
if (pCreds->dwMask & RASCM_Password)
{
// Whistler bug 254385 encode password when not being used
// Assumed password was encoded previously
//
DecodePassword( pCreds->szPassword );
lstrcpyn(
pParams->szPassword,
pCreds->szPassword,
sizeof(pParams->szPassword) / sizeof(TCHAR) );
EncodePassword( pCreds->szPassword );
EncodePassword( pParams->szPassword );
}
return NO_ERROR;
}
DWORD
FindEntryCredentials(
IN TCHAR* pszPath,
IN TCHAR* pszEntryName,
IN TCHAR* pszDefaultUserName,
IN TCHAR* pszDefaultDomain,
OUT RASDIALPARAMS* pUser, // per user credentials
OUT RASDIALPARAMS* pGlobal, // global credentials
OUT BOOL* pfUser, // set true if per user creds found
OUT BOOL* pfGlobal // set true if global creds found
)
// Loads the credentials for the given entry into memory. This routine
// determines whether per-user or per-connection credentials exist or
// both.
//
// The logic is a little complicated because RasGetCredentials had to
// support legacy usage of the API.
//
// Here's how it works. If only one set of credentials is stored for a
// connection, then RasGetCredentials will return that set regardless of
// whether the RASCM_DefalutCreds flag is set. If two sets of credentials
// are saved, then RasGetCredentials will return the per-user credentials
// if the RASCM_DefaultCreds bit is set, and the per-connection credentials
// otherwise.
//
// Here is the algorithm for loading the credentials
//
// 1. Call RasGetCredentials with the RASCM_DefaultCreds bit cleared
// 1a. If nothing is returned, no credentials are saved
// 1b. If the RASCM_DefaultCreds bit is set on return, then only
// global credentials are saved.
//
// 2. Call RasGetCredentials with the RASCM_DefaultCreds bit set
// 2a. If the RASCM_DefaultCreds bit is set on return, then
// both global and per-connection credentials are saved.
// 2b. Otherwise, only per-user credentials are saved.
//
{
DWORD dwErr;
RASCREDENTIALS rc1, rc2;
BOOL fUseLogonDomain;
TRACE( "FindEntryCredentials" );
// Initialize
//
*pfUser = FALSE;
*pfGlobal = FALSE;
ZeroMemory( &rc1, sizeof(rc1) );
ZeroMemory( &rc2, sizeof(rc2) );
rc1.dwSize = sizeof(rc1);
rc2.dwSize = sizeof(rc2);
do
{
// Look up per-user cached username, password, and domain.
// See comment '1.' in the function header
//
rc1.dwMask = RASCM_UserName | RASCM_Password | RASCM_Domain;
ASSERT( g_pRasGetCredentials );
TRACE( "RasGetCredentials per-user" );
dwErr = g_pRasGetCredentials(pszPath, pszEntryName, &rc1 );
TRACE2( "RasGetCredentials=%d,m=%d", dwErr, rc1.dwMask );
if (dwErr != NO_ERROR)
{
break;
}
// See 1a. in the function header comments
//
if (rc1.dwMask == 0)
{
dwErr = NO_ERROR;
break;
}
// See 1b. in the function header comments
//
else if (rc1.dwMask & RASCM_DefaultCreds)
{
*pfGlobal = TRUE;
// Whistler bug 254385 encode password when not being used
// Assumed password was not encoded by RasGetCredentials()
//
EncodePassword( rc1.szPassword );
RasCredToDialParam(
pszDefaultUserName,
pszDefaultDomain,
&rc1,
pGlobal );
dwErr = NO_ERROR;
break;
}
// Look up global per-user cached username, password, domain.
// See comment 2. in the function header
//
rc2.dwMask =
RASCM_UserName | RASCM_Password | RASCM_Domain | RASCM_DefaultCreds;
ASSERT( g_pRasGetCredentials );
TRACE( "RasGetCredentials global" );
dwErr = g_pRasGetCredentials(pszPath, pszEntryName, &rc2 );
TRACE2( "RasGetCredentials=%d,m=%d", dwErr, rc2.dwMask );
if (dwErr != NO_ERROR)
{
break;
}
// See 2a. in the function header comments
//
if (rc2.dwMask & RASCM_DefaultCreds)
{
*pfGlobal = TRUE;
if (rc1.dwMask & RASCM_Password)
{
*pfUser = TRUE;
}
// Whistler bug 254385 encode password when not being used
// Assumed password was not encoded by RasGetCredentials()
//
EncodePassword( rc1.szPassword );
RasCredToDialParam(
pszDefaultUserName,
pszDefaultDomain,
&rc1,
pUser );
EncodePassword( rc2.szPassword );
RasCredToDialParam(
pszDefaultUserName,
pszDefaultDomain,
&rc2,
pGlobal );
}
// See 2b. in the function header comments
//
else
{
if (rc1.dwMask & RASCM_Password)
{
*pfUser = TRUE;
}
// Whistler bug 254385 encode password when not being used
// Assumed password was not encoded by RasGetCredentials()
//
EncodePassword( rc1.szPassword );
RasCredToDialParam(
pszDefaultUserName,
pszDefaultDomain,
&rc1,
pUser );
}
}while (FALSE);
// Cleanup
//
{
// Whistler bug 254385 encode password when not being used
//
ZeroMemory( rc1.szPassword, sizeof(rc1.szPassword) );
ZeroMemory( rc2.szPassword, sizeof(rc2.szPassword) );
}
return dwErr;
}
DWORD
FindEntryAndSetDialParams(
IN DINFO* pInfo )
// Look up the entry and fill in the RASDIALPARAMS parameters accordingly.
// This routine contains all DINFO context initialization that can be
// affected by user actions on the property sheet. 'PInfo' is the
// partially initialized common dial dialog context.
//
// 'pInfo->fPrerequisiteDial'is set at entry if the prerequisite entry, if
// any, should be dialed first. If there is no prerequisite entry, the
// flag is cleared and the main entry dialed.
//
{
DWORD dwErr;
RASDIALPARAMS* prdp, *prdpu, *prdpg;
if (pInfo->fFilePrereqOpen)
{
ClosePhonebookFile( pInfo->pFile );
pInfo->pFile = pInfo->pFileMain;
pInfo->fFilePrereqOpen = FALSE;
}
// Lookup entry node specified by caller and save reference for
// convenience elsewhere.
//
pInfo->pNode = EntryNodeFromName(
pInfo->pFile->pdtllistEntries, pInfo->pszEntry );
if (!pInfo->pNode)
{
dwErr = ERROR_CANNOT_FIND_PHONEBOOK_ENTRY;
return dwErr;
}
pInfo->pEntry = pInfo->pEntryMain = (PBENTRY* )DtlGetData( pInfo->pNode );
ASSERT( pInfo->pEntry );
// Switch to the prerequisite entry, if indicated.
//
if (pInfo->fPrerequisiteDial)
{
if (pInfo->pEntry->pszPrerequisiteEntry
&& *(pInfo->pEntry->pszPrerequisiteEntry))
{
ASSERT( !pInfo->fFilePrereqOpen );
// GetPbkAndEntryName first looks in the All Users phonebook file
// if a phonebook file is not specified. If the entry is not
// found there it looks in files present in the Users profile.
// This needs to be done since we are discontinuing the per-user
// pbk file being set through user preferences.
//
dwErr = GetPbkAndEntryName(
pInfo->pEntry->pszPrerequisitePbk,
pInfo->pEntry->pszPrerequisiteEntry,
0,
&pInfo->filePrereq,
&pInfo->pNode);
if (dwErr != 0)
{
return dwErr;
}
pInfo->pFile = &pInfo->filePrereq;
pInfo->fFilePrereqOpen = TRUE;
pInfo->pEntry = (PBENTRY* )DtlGetData( pInfo->pNode );
ASSERT( pInfo->pEntry );
}
else
{
pInfo->fPrerequisiteDial = FALSE;
}
}
// Set up RasDial parameter blocks.
//
prdp = &pInfo->rdp;
prdpu = &pInfo->rdpu;
prdpg = &pInfo->rdpg;
ZeroMemory( prdp, sizeof(*prdp) );
pInfo->fUnattended = FALSE;
prdp->dwSize = sizeof(*prdp);
lstrcpyn(
prdp->szEntryName,
pInfo->pEntry->pszEntryName,
sizeof(prdp->szEntryName) / sizeof(TCHAR));
if (pInfo->pszPhoneNumber)
{
lstrcpyn(
prdp->szPhoneNumber,
pInfo->pszPhoneNumber,
RAS_MaxPhoneNumber + 1);
}
// Whistler bug 272819 Not prompted for callback number
// We must do this before the init of per-user and global variants
//
if (!pInfo->fUnattended)
{
// '*' means "behave as defined in user preferences", while leaving it
// zero would mean "don't request callback if server offers".
//
// Whistler bug 224074 use only lstrcpyn's to prevent maliciousness
//
lstrcpyn(
prdp->szCallbackNumber,
TEXT("*"),
sizeof(prdp->szCallbackNumber) / sizeof(TCHAR) );
}
// Initialze the per-user and global variants
//
CopyMemory(prdpu, prdp, sizeof(*prdp));
CopyMemory(prdpg, prdp, sizeof(*prdp));
// Set the subentry link to whatever the RasDialDlg caller specified. See
// bug 200351.
//
prdp->dwSubEntry = pInfo->pArgs->dwSubEntry;
// If running in "unattended" mode, i.e. called by RASAUTO to redial on
// link failure, read the user/password/domain and callback number used on
// the original call. (Actually found a use for the crappy
// RasGetEntryDialParams API)
//
if (pInfo->pArgs->dwFlags & RASDDFLAG_LinkFailure)
{
RASDIALPARAMS rdp;
BOOL fSavedPw = HaveSavedPw( pInfo );
ZeroMemory( &rdp, sizeof(rdp) );
rdp.dwSize = sizeof(rdp);
lstrcpyn(
rdp.szEntryName,
pInfo->pEntry->pszEntryName,
sizeof(rdp.szEntryName) / sizeof(TCHAR)
);
//For whistler bug 313509 gangz
//We use FindEntryCredentials() to get saved password perUser and
//perConnection inforation, use RasGetEntryDialParams() to get back
//Callback Numbers
//
{
RASDIALPARAMS rdTemp;
TCHAR * pszTempUser, * pszTempDomain;
DWORD dwErr = NO_ERROR;
pszTempUser = pszTempDomain = NULL;
dwErr = FindEntryCredentials(
pInfo->pFile->pszPath,
pInfo->pEntry->pszEntryName,
pszTempUser,
pszTempDomain,
&rdTemp,
&rdTemp,
&(pInfo->fHaveSavedPwUser),
&(pInfo->fHaveSavedPwGlobal));
ZeroMemory( &rdTemp, sizeof(rdTemp) );
Free0(pszTempUser);
Free0(pszTempDomain);
}
TRACE( "RasGetEntryDialParams" );
ASSERT( g_pRasGetEntryDialParams );
dwErr = g_pRasGetEntryDialParams(
pInfo->pFile->pszPath, &rdp, &fSavedPw );
TRACE2( "RasGetEntryDialParams=%d,f=%d", dwErr, &fSavedPw );
TRACEW1( "u=%s", rdp.szUserName );
//TRACEW1( "p=%s", rdp.szPassword );
TRACEW1( "d=%s", rdp.szDomain );
TRACEW1( "c=%s", rdp.szCallbackNumber );
if (dwErr == 0)
{
lstrcpyn(
prdp->szUserName,
rdp.szUserName,
sizeof(prdp->szUserName) / sizeof(TCHAR));
// Whistler bug 254385 encode password when not being used
// Assumed password was not encoded by RasGetEntryDialParams()
//
lstrcpyn(
prdp->szPassword,
rdp.szPassword,
sizeof(prdp->szPassword) / sizeof(TCHAR) );
EncodePassword( prdp->szPassword );
lstrcpyn(
prdp->szDomain,
rdp.szDomain,
sizeof(prdp->szDomain) / sizeof(TCHAR));
lstrcpyn(
prdp->szCallbackNumber,
rdp.szCallbackNumber,
sizeof(prdp->szCallbackNumber) / sizeof(TCHAR));
pInfo->fUnattended = TRUE;
}
ZeroMemory( rdp.szPassword, sizeof(rdp.szPassword) );
}
if (pInfo->pNoUser)
{
// Use the credentials we got from API caller, presumably the ones
// entered at Ctrl-Alt-Del.
//
lstrcpyn(
prdp->szUserName,
pInfo->pNoUser->szUserName,
sizeof(prdp->szUserName) / sizeof(TCHAR));
//
// Don't copy the password if its smartcard logon
// and the entry being used is a non-eap connectoid
//
// Whistler bug 254385 encode password when not being used
// Assumed password was encoded by caller of RasDialDlg()
//
DecodePassword( pInfo->pNoUser->szPassword );
lstrcpyn(
prdp->szPassword,
pInfo->pNoUser->szPassword,
sizeof(prdp->szPassword) / sizeof(TCHAR) );
EncodePassword( pInfo->pNoUser->szPassword );
EncodePassword( prdp->szPassword );
if (pInfo->pEntry->fPreviewDomain)
{
lstrcpyn(
prdp->szDomain,
pInfo->pNoUser->szDomain,
sizeof(prdp->szDomain) / sizeof(TCHAR));
}
else
{
// Don't use Winlogon domain unless "include domain" option is
// selected. See bug 387266.
//
// Whistler bug 224074 use only lstrcpyn's to prevent maliciousness
//
lstrcpyn(
prdp->szDomain,
TEXT(""),
sizeof(prdp->szDomain) / sizeof(TCHAR) );
}
}
else if (!pInfo->fUnattended)
{
DWORD dwErrRc;
BOOL fUseLogonDomain;
TCHAR* pszDefaultUser;
dwErrRc = FindEntryCredentials(
pInfo->pFile->pszPath,
pInfo->pEntry->pszEntryName,
pInfo->pEntry->pszOldUser,
pInfo->pEntry->pszOldDomain,
prdpu,
prdpg,
&(pInfo->fHaveSavedPwUser),
&(pInfo->fHaveSavedPwGlobal));
if (! pInfo->pEntry->fAutoLogon)
{
// If saved passwords are disabled, clear here
//
if (pInfo->fDisableSavePw)
{
pInfo->fHaveSavedPwUser = FALSE;
pInfo->fHaveSavedPwGlobal = FALSE;
ZeroMemory(prdp->szPassword, sizeof(prdp->szPassword));
ZeroMemory(prdpu->szPassword, sizeof(prdpu->szPassword));
ZeroMemory(prdpg->szPassword, sizeof(prdpg->szPassword));
}
// If including domains is disabled, clear here
//
if (! pInfo->pEntry->fPreviewDomain)
{
// (SteveC) Don't do this in the 'fAutoLogon' case. See bug
// 207611.
//
ZeroMemory(prdp->szDomain, sizeof(prdp->szDomain));
ZeroMemory(prdpu->szDomain, sizeof(prdpu->szDomain));
ZeroMemory(prdpg->szDomain, sizeof(prdpg->szDomain));
}
}
if(!pInfo->pEntry->fAutoLogon)
{
// Initialize the dial params that will be passed to RasDial.
//
// Note that per-user credentials are always used when both
// per-user and global credentials are saved. The per-user
// credentials should be copied even if there is no saved
// password since there may be a saved identity.
//
CopyMemory(prdp, prdpu, sizeof(*prdp));
if (pInfo->fHaveSavedPwGlobal && !pInfo->fHaveSavedPwUser)
{
CopyMemory(prdp, prdpg, sizeof(*prdp));
}
}
}
return 0;
}
//----------------------------------------------------------------------------
// Bundling Errors dialog
// Listed alphabetically following stub API and dialog proc
//----------------------------------------------------------------------------
BOOL
BundlingErrorsDlg(
IN OUT DPINFO* pInfo )
// Popup the Bundling Errors dialog. 'PInfo' is the dialing progress
// dialog context.
//
// Returns true if user chooses to accept the results or false if he
// chooses to hang up.
//
{
INT_PTR nStatus;
TRACE( "BundlingErrorsDlg" );
nStatus =
(BOOL )DialogBoxParam(
g_hinstDll,
MAKEINTRESOURCE( DID_BE_BundlingErrors ),
pInfo->hwndDlg,
BeDlgProc,
(LPARAM )pInfo );
if (nStatus == -1)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
nStatus = FALSE;
}
return (BOOL )nStatus;
}
INT_PTR CALLBACK
BeDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the Bundling Errors dialog. Parameters and
// return value are as described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "BeDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
if (ListView_OwnerHandler(
hwnd, unMsg, wparam, lparam, BeLvErrorsCallback ))
{
return TRUE;
}
switch (unMsg)
{
case WM_INITDIALOG:
{
return BeInit( hwnd, (DPINFO* )lparam );
}
case WM_COMMAND:
{
return BeCommand(
hwnd, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
}
return FALSE;
}
BOOL
BeCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'Hwnd' is the dialog window. 'WNotification' is
// the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
DWORD dwErr;
TRACE3( "BeCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
switch (wId)
{
case IDOK:
case IDCANCEL:
{
TRACE1( "%s pressed", (wId==IDOK) ? "OK" : "Cancel" );
if (IsDlgButtonChecked( hwnd, CID_BE_CB_DisableLink ))
{
DWORD i;
DPINFO* pInfo;
DPSTATE* pState;
// Caller says to delete the links that failed in the entry.
// Create a list of Psz nodes containing the unique port name
// of each failed link so they can be removed after the state
// information is freed.
//
pInfo = (DPINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
for (i = 0, pState = pInfo->pStates;
i < pInfo->cStates;
++i, ++pState)
{
DTLNODE* pNode;
DTLNODE* pNodePtd;
PBLINK* pLink;
if (pState->dwError != 0)
{
if (!pInfo->pArgs->pListPortsToDelete)
{
pInfo->pArgs->pListPortsToDelete =
DtlCreateList( 0L );
if (!pInfo->pArgs->pListPortsToDelete)
{
continue;
}
}
pNode = DtlNodeFromIndex(
pInfo->pArgs->pEntry->pdtllistLinks, (LONG )i );
if (!pNode)
{
continue;
}
pLink = (PBLINK* )DtlGetData( pNode );
pNodePtd = CreatePszNode( pLink->pbport.pszPort );
if (!pNodePtd)
{
continue;
}
DtlAddNodeLast(
pInfo->pArgs->pListPortsToDelete, pNodePtd );
}
}
}
EndDialog( hwnd, (wId == IDOK) );
return TRUE;
}
}
return FALSE;
}
VOID
BeFillLvErrors(
IN HWND hwndLv,
IN DPINFO* pInfo )
// Fill the listview 'hwndLv' with devices and error strings and select
// the first item. 'PInfo' is the dialing progress dialog context.
//
{
INT iItem;
DWORD i;
DPSTATE* pState;
TRACE( "BeFillLvErrors" );
ListView_DeleteAllItems( hwndLv );
// Add columns.
//
{
LV_COLUMN col;
TCHAR* pszHeader0;
TCHAR* pszHeader1;
pszHeader0 = PszFromId( g_hinstDll, SID_DeviceColHead );
pszHeader1 = PszFromId( g_hinstDll, SID_StatusColHead );
ZeroMemory( &col, sizeof(col) );
col.mask = LVCF_FMT + LVCF_TEXT;
col.fmt = LVCFMT_LEFT;
col.pszText = (pszHeader0) ? pszHeader0 : TEXT("");
ListView_InsertColumn( hwndLv, 0, &col );
ZeroMemory( &col, sizeof(col) );
col.mask = LVCF_FMT + LVCF_SUBITEM + LVCF_TEXT;
col.fmt = LVCFMT_LEFT;
col.pszText = (pszHeader1) ? pszHeader1 : TEXT("");
col.iSubItem = 1;
ListView_InsertColumn( hwndLv, 1, &col );
Free0( pszHeader0 );
Free0( pszHeader1 );
}
// Add the modem and adapter images.
//
ListView_SetDeviceImageList( hwndLv, g_hinstDll );
// Load listview with device/status pairs.
//
iItem = 0;
for (i = 0, pState = pInfo->pStates; i < pInfo->cStates; ++i, ++pState)
{
LV_ITEM item;
DTLNODE* pNode;
PBLINK* pLink;
TCHAR* psz;
pNode = DtlNodeFromIndex(
pInfo->pArgs->pEntry->pdtllistLinks, (LONG )i );
if (pNode)
{
pLink = (PBLINK* )DtlGetData( pNode );
psz = DisplayPszFromDeviceAndPort(
pLink->pbport.pszDevice, pLink->pbport.pszPort );
if (psz)
{
ZeroMemory( &item, sizeof(item) );
item.mask = LVIF_TEXT + LVIF_IMAGE;
item.iItem = iItem;
item.pszText = psz;
item.iImage =
(pLink->pbport.pbdevicetype == PBDT_Modem)
? DI_Modem : DI_Adapter;
ListView_InsertItem( hwndLv, &item );
Free( psz );
if (pState->dwError == 0)
{
psz = PszFromId( g_hinstDll, SID_Connected );
ListView_SetItemText( hwndLv, iItem, 1, psz );
Free( psz );
}
else
{
psz = BeGetErrorPsz( pState->dwError );
ListView_SetItemText( hwndLv, iItem, 1, psz );
LocalFree( psz );
}
++iItem;
}
}
}
// Auto-size columns to look good with the text they contain.
//
ListView_SetColumnWidth( hwndLv, 0, LVSCW_AUTOSIZE_USEHEADER );
ListView_SetColumnWidth( hwndLv, 1, LVSCW_AUTOSIZE_USEHEADER );
// Select the first item.
//
ListView_SetItemState( hwndLv, 0, LVIS_SELECTED, LVIS_SELECTED );
}
TCHAR*
BeGetErrorPsz(
IN DWORD dwError )
// Returns a string suitable for the Status column with error 'dwError' or
// NULL on error. 'DwError' is assumed to be non-0. It is caller's
// responsiblility to LocalFree the returned string.
//
{
TCHAR* pszErrStr;
TCHAR szErrNumBuf[ MAXLTOTLEN + 1 ];
TCHAR* pszLineFormat;
TCHAR* pszLine;
TCHAR* apszArgs[ 2 ];
LToT( dwError, szErrNumBuf, 10 );
pszErrStr = NULL;
GetErrorText( dwError, &pszErrStr );
pszLine = NULL;
pszLineFormat = PszFromId( g_hinstDll, SID_FMT_Error );
if (pszLineFormat)
{
apszArgs[ 0 ] = szErrNumBuf;
apszArgs[ 1 ] = (pszErrStr) ? pszErrStr : TEXT("");
FormatMessage(
FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszLineFormat, 0, 0, (LPTSTR )&pszLine, 1,
(va_list* )apszArgs );
Free( pszLineFormat );
}
Free0( pszErrStr );
return pszLine;
}
BOOL
BeInit(
IN HWND hwndDlg,
IN DPINFO* pArgs )
// Called on WM_INITDIALOG. 'hwndDlg' is the handle of the owning window.
// 'PArgs' is caller's arguments to the stub API.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
DWORD dwErr;
HWND hwndLvErrors;
HWND hwndCbDisableLink;
TRACE( "BeInit" );
hwndLvErrors = GetDlgItem( hwndDlg, CID_BE_LV_Errors );
ASSERT( hwndLvErrors );
hwndCbDisableLink = GetDlgItem( hwndDlg, CID_BE_CB_DisableLink );
ASSERT( hwndCbDisableLink );
// Save Dial Progress context as dialog context.
//
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pArgs );
// Load listview with device/error information.
//
BeFillLvErrors( hwndLvErrors, pArgs );
// Display the finished window above all other windows. The window
// position is set to "topmost" then immediately set to "not topmost"
// because we want it on top but not always-on-top. Always-on-top alone
// is incredibly annoying, e.g. it is always on top of the on-line help if
// user presses the Help button.
//
SetWindowPos(
hwndDlg, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
CenterWindow( hwndDlg, GetParent( hwndDlg ) );
ShowWindow( hwndDlg, SW_SHOW );
SetWindowPos(
hwndDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
SetFocus( hwndCbDisableLink );
return FALSE;
}
LVXDRAWINFO*
BeLvErrorsCallback(
IN HWND hwndLv,
IN DWORD dwItem )
// Enhanced list view callback to report drawing information. 'HwndLv' is
// the handle of the list view control. 'DwItem' is the index of the item
// being drawn.
//
// Returns the address of the column information.
//
{
// Use "wide selection bar" feature and the other recommended options.
//
// Fields are 'nCols', 'dxIndent', 'dwFlags', 'adwFlags[]'.
//
static LVXDRAWINFO info =
{ 2, 0, LVXDI_Blend50Dis + LVXDI_DxFill, { 0, 0 } };
return &info;
}
//----------------------------------------------------------------------------
// Change Password dialog
// Listed alphabetically following stub API and dialog proc
//----------------------------------------------------------------------------
BOOL
ChangePasswordDlg(
IN HWND hwndOwner,
IN BOOL fOldPassword,
OUT TCHAR* pszOldPassword,
OUT TCHAR* pszNewPassword )
// Popup the Change Password dialog. 'HwndOwner' is the owning window.
// 'FOldPassword' is set true if user must supply an old password, false
// if no old password is required. 'PszOldPassword' and 'pszNewPassword'
// are caller's buffers for the returned passwords.
//
// Returns true if user presses OK and succeeds, false otherwise.
//
{
INT_PTR nStatus;
CPARGS args;
TRACE( "ChangePasswordDlg" );
args.fOldPassword = fOldPassword;
args.pszOldPassword = pszOldPassword;
args.pszNewPassword = pszNewPassword;
nStatus =
(BOOL )DialogBoxParam(
g_hinstDll,
(fOldPassword)
? MAKEINTRESOURCE( DID_CP_ChangePassword2 )
: MAKEINTRESOURCE( DID_CP_ChangePassword ),
hwndOwner,
CpDlgProc,
(LPARAM )&args );
if (nStatus == -1)
{
ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
nStatus = FALSE;
}
return (BOOL )nStatus;
}
INT_PTR CALLBACK
CpDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the Change Password dialog. Parameters and
// return value are as described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "CpDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
switch (unMsg)
{
case WM_INITDIALOG:
{
return CpInit( hwnd, (CPARGS* )lparam );
}
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp( g_adwCpHelp, hwnd, unMsg, wparam, lparam );
break;
}
case WM_COMMAND:
{
return CpCommand(
hwnd, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
}
return FALSE;
}
BOOL
CpCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'Hwnd' is the dialog window. 'WNotification' is
// the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
DWORD dwErr;
TRACE3( "CpCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
switch (wId)
{
case IDOK:
{
CPWINFO* pInfo;
TCHAR szNewPassword[ PWLEN + 1 ];
TCHAR szNewPassword2[ PWLEN + 1 ];
TRACE( "OK pressed" );
pInfo = (CPWINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
szNewPassword[ 0 ] = TEXT('\0');
GetWindowText(
pInfo->hwndEbNewPassword, szNewPassword, PWLEN + 1 );
szNewPassword2[ 0 ] = TEXT('\0');
GetWindowText(
pInfo->hwndEbNewPassword2, szNewPassword2, PWLEN + 1 );
if (lstrcmp( szNewPassword, szNewPassword2 ) != 0)
{
// The two passwords don't match, i.e. user made a typo. Make
// him re-enter.
//
MsgDlg( hwnd, SID_PasswordsDontMatch, NULL );
SetWindowText( pInfo->hwndEbNewPassword, TEXT("") );
SetWindowText( pInfo->hwndEbNewPassword2, TEXT("") );
SetFocus( pInfo->hwndEbNewPassword );
ZeroMemory( szNewPassword, sizeof(szNewPassword) );
ZeroMemory( szNewPassword2, sizeof(szNewPassword2) );
return TRUE;
}
if (pInfo->pArgs->fOldPassword)
{
pInfo->pArgs->pszOldPassword[ 0 ] = TEXT('\0');
// Whistler bug 254385 encode password when not being used
// Assumed password was not encoded by GetWindowText()
//
GetWindowText(
pInfo->hwndEbOldPassword,
pInfo->pArgs->pszOldPassword,
PWLEN + 1 );
EncodePassword( pInfo->pArgs->pszOldPassword );
}
// Whistler bug 224074 use only lstrcpyn's to prevent maliciousness
//
// pInfo->pArgs->pszNewPassword points back to RASDIALPARAMS->
// szPassword[ PWLEN + 1 ]
//
// Whistler bug 254385 encode password when not being used
// Assumed password was not encoded by GetWindowText()
//
lstrcpyn(
pInfo->pArgs->pszNewPassword,
szNewPassword,
PWLEN + 1 );
EncodePassword( pInfo->pArgs->pszNewPassword );
ZeroMemory( szNewPassword, sizeof(szNewPassword) );
ZeroMemory( szNewPassword2, sizeof(szNewPassword2) );
EndDialog( hwnd, TRUE );
return TRUE;
}
case IDCANCEL:
{
TRACE( "Cancel pressed" );
EndDialog( hwnd, FALSE );
return TRUE;
}
}
return FALSE;
}
BOOL
CpInit(
IN HWND hwndDlg,
IN CPARGS* pArgs )
// Called on WM_INITDIALOG. 'HwndDlg' is the handle of the dialog window.
// 'PArgs' is caller's arguments to the stub API.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
DWORD dwErr;
CPWINFO* pInfo;
TRACE( "CpInit" );
// Allocate the dialog context block. Initialize minimally for proper
// cleanup, then attach to the dialog window.
//
{
pInfo = Malloc( sizeof(*pInfo) );
if (!pInfo)
{
ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
EndDialog( hwndDlg, FALSE );
return TRUE;
}
ZeroMemory( pInfo, sizeof(*pInfo) );
pInfo->pArgs = pArgs;
pInfo->hwndDlg = hwndDlg;
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
TRACE( "Context set" );
}
if (pArgs->fOldPassword)
{
pInfo->hwndEbOldPassword =
GetDlgItem( hwndDlg, CID_CP_EB_OldPassword );
ASSERT( pInfo->hwndEbOldPassword );
Edit_LimitText( pInfo->hwndEbOldPassword, PWLEN );
}
pInfo->hwndEbNewPassword =
GetDlgItem( hwndDlg, CID_CP_EB_Password );
ASSERT( pInfo->hwndEbNewPassword );
Edit_LimitText( pInfo->hwndEbNewPassword, PWLEN );
pInfo->hwndEbNewPassword2 =
GetDlgItem( hwndDlg, CID_CP_EB_ConfirmPassword );
ASSERT( pInfo->hwndEbNewPassword2 );
Edit_LimitText( pInfo->hwndEbNewPassword2, PWLEN );
// Add context help button to title bar.
//
AddContextHelpButton( hwndDlg );
// Display finished window.
//
CenterWindow( hwndDlg, GetParent( hwndDlg ) );
SetForegroundWindow( hwndDlg );
return TRUE;
}
//----------------------------------------------------------------------------
// Connect Complete dialog
// Listed alphabetically following stub API and dialog proc
//----------------------------------------------------------------------------
VOID
ConnectCompleteDlg(
IN HWND hwndOwner,
IN DINFO* pInfo )
// Popup the connection complete dialog. 'HwndOwner' is the owning
// window. 'PUser' is the user preferences.
//
{
INT_PTR nStatus;
TRACE( "ConnectCompleteDlg" );
nStatus =
(BOOL )DialogBoxParam(
g_hinstDll,
MAKEINTRESOURCE( DID_CC_ConnectComplete ),
hwndOwner,
CcDlgProc,
(LPARAM )pInfo );
}
INT_PTR CALLBACK
CcDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the dialog. Parameters and return value are as
// described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "CcDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
switch (unMsg)
{
case WM_INITDIALOG:
{
return CcInit( hwnd, (DINFO* )lparam );
}
case WM_COMMAND:
{
return CcCommand(
hwnd, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
case WM_DESTROY:
//For whistler bug 372078
//GetCurrentIconEntryType() loads Icon from netshell where the icon is loaded
//by LoadImage() without LR_SHARED, so I have to destroy it when we are done
//with it
//
{
HICON hIcon=NULL;
hIcon = (HICON)SendMessage( GetDlgItem( hwnd, CID_CC_I_Rasmon ),
STM_GETICON,
(WPARAM)0,
(LPARAM)0);
ASSERT(hIcon);
if( hIcon )
{
DestroyIcon(hIcon);
}
else
{
TRACE("CcDlgProc:Destroy Icon");
}
}
break;
}
return FALSE;
}
BOOL
CcCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'Hwnd' is the dialog window. 'WNotification' is
// the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
TRACE3( "CcCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
switch (wId)
{
case IDOK:
{
DINFO * pInfo = (DINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
PBUSER* pUser = pInfo->pUser;
ASSERT( pUser );
if (IsDlgButtonChecked( hwnd, CID_CC_CB_SkipMessage ))
{
pUser->fSkipConnectComplete = TRUE;
pUser->fDirty = TRUE;
}
}
// ...fall thru...
case IDCANCEL:
{
EndDialog( hwnd, TRUE );
return TRUE;
}
}
return FALSE;
}
BOOL
CcInit(
IN HWND hwndDlg,
IN DINFO* pInfo )
// Called on WM_INITDIALOG. 'HwndDlg' is the handle of dialog. 'PUser'
// is caller's argument to the stub API.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
TRACE( "CcInit" );
// Set the dialog context.
//
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
// Set the explanatory text.
//
{
MSGARGS msgargs;
ZeroMemory( &msgargs, sizeof(msgargs) );
msgargs.apszArgs[ 0 ] = pInfo->pEntry->pszEntryName;
msgargs.fStringOutput = TRUE;
MsgDlgUtil( NULL, SID_ConnectComplete, &msgargs, g_hinstDll, 0 );
if (msgargs.pszOutput)
{
SetDlgItemText( hwndDlg, CID_CC_ST_Text, msgargs.pszOutput );
Free( msgargs.pszOutput );
}
}
// Set the correct icon. For whistler bug 372078
//
SetIconFromEntryType(
GetDlgItem( hwndDlg, CID_CC_I_Rasmon ),
pInfo->pEntry->dwType,
FALSE); //FALSE means Large Icon
// Display finished window.
//
CenterWindow( hwndDlg, GetParent( hwndDlg ) );
SetForegroundWindow( hwndDlg );
return TRUE;
}
//----------------------------------------------------------------------------
// Dial Callback dialog
// Listed alphabetically following stub API and dialog proc
//----------------------------------------------------------------------------
BOOL
DialCallbackDlg(
IN HWND hwndOwner,
IN OUT TCHAR* pszNumber )
// Popup the Dial Callback dialog. 'HwndOwner' is the owning window.
// 'PszNumber' is caller's buffer for the number of the local machine that
// the server will be told to callback. It contains the default number on
// entry and the user-edited number on exit.
//
// Returns true if user OK and succeeds, false if Cancel or error.
//
{
INT_PTR nStatus;
TRACE( "DialCallbackDlg" );
nStatus =
(BOOL )DialogBoxParam(
g_hinstDll,
MAKEINTRESOURCE( DID_DC_DialCallback ),
hwndOwner,
DcDlgProc,
(LPARAM )pszNumber );
if (nStatus == -1)
{
ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
nStatus = FALSE;
}
return (BOOL )nStatus;
}
INT_PTR CALLBACK
DcDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the Dial Callback dialog. Parameters and
// return value are as described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "DcDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
switch (unMsg)
{
case WM_INITDIALOG:
{
return DcInit( hwnd, (TCHAR* )lparam );
}
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp( g_adwDcHelp, hwnd, unMsg, wparam, lparam );
break;
}
case WM_COMMAND:
{
return DcCommand(
hwnd, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
}
return FALSE;
}
BOOL
DcCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'Hwnd' is the dialog window. 'WNotification' is
// the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
DWORD dwErr;
TRACE3( "DcCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
switch (wId)
{
case IDOK:
{
BOOL fStatus;
HWND hwndEbNumber;
TCHAR* pszNumber;
TRACE( "OK pressed" );
hwndEbNumber = GetDlgItem( hwnd, CID_DC_EB_Number );
ASSERT( hwndEbNumber );
pszNumber = (TCHAR* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pszNumber );
GetWindowText( hwndEbNumber, pszNumber, RAS_MaxCallbackNumber + 1 );
if (IsAllWhite( pszNumber ))
{
// OK with blank callback number is same as Cancel.
//
TRACE( "Blank number cancel" );
fStatus = FALSE;
}
else
{
fStatus = TRUE;
}
EndDialog( hwnd, fStatus );
return TRUE;
}
case IDCANCEL:
{
TRACE( "Cancel pressed" );
EndDialog( hwnd, FALSE );
return TRUE;
}
}
return FALSE;
}
BOOL
DcInit(
IN HWND hwndDlg,
IN TCHAR* pszNumber )
// Called on WM_INITDIALOG. 'hwndDlg' is the handle of the owning window.
// 'PszNumber' is the callback number.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
DWORD dwErr;
HWND hwndEbNumber;
TRACE( "DcInit" );
// Stash address of caller's buffer for OK processing.
//
ASSERT( pszNumber );
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pszNumber );
// Initialize edit field to caller's default.
//
hwndEbNumber = GetDlgItem( hwndDlg, CID_DC_EB_Number );
ASSERT( hwndEbNumber );
Edit_LimitText( hwndEbNumber, RAS_MaxCallbackNumber );
SetWindowText( hwndEbNumber, pszNumber );
// Add context help button to title bar.
//
AddContextHelpButton( hwndDlg );
// Display finished window.
//
CenterWindow( hwndDlg, GetParent( hwndDlg ) );
SetForegroundWindow( hwndDlg );
return TRUE;
}
//----------------------------------------------------------------------------
// Dial Error dialog
// Listed alphabetically following stub API and dialog proc
//----------------------------------------------------------------------------
BOOL
DialErrorDlg(
IN HWND hwndOwner,
IN TCHAR* pszEntry,
IN DWORD dwError,
IN DWORD sidState,
IN TCHAR* pszStatusArg,
IN DWORD sidFormatMsg,
IN TCHAR* pszFormatArg,
IN LONG lRedialCountdown,
IN BOOL fPopupOnTop )
// Popup the Dial Error dialog. 'HwndOwner' is the owning window.
// 'PszEntry' is the entry being dialed. 'DwError' is the error that
// occurred or 0 if redialing after a link failure. 'sidStatusArg' is the
// argument to the 'sidState' 'SidState' is the string ID of the dial
// state executing when the error occurred. string or NULL if none.
// 'SidFormatMsg' is the string containing the format of the error message
// or 0 to use the default. 'PszFormatArg' is the additional argument to
// the format message or NULL if none. 'LRedialCountdown' is the number
// of seconds before auto-redial, or -1 to disable countdown, or -2 to
// hide the "Redial" button entirely. 'FPopupOnTop' indicates the status
// window should be brought to the front when redialing.
//
// Returns true if user chooses to redial or lets it timeout, false if
// cancels.
//
{
INT_PTR nStatus;
DEARGS args;
TRACE( "DialErrorDlg" );
args.pszEntry = pszEntry;
args.dwError = dwError;
args.sidState = sidState;
args.pszStatusArg = pszStatusArg;
args.sidFormatMsg = sidFormatMsg;
args.pszFormatArg = pszFormatArg;
args.lRedialCountdown = lRedialCountdown;
args.fPopupOnTop = fPopupOnTop;
nStatus =
(BOOL )DialogBoxParam(
g_hinstDll,
MAKEINTRESOURCE( DID_DE_DialError ),
hwndOwner,
DeDlgProc,
(LPARAM )&args );
if (nStatus == -1)
{
ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
nStatus = FALSE;
}
return (BOOL )nStatus;
}
INT_PTR CALLBACK
DeDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the Dial Error dialog. Parameters and return
// value are as described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "DeDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
switch (unMsg)
{
case WM_INITDIALOG:
{
return DeInit( hwnd, (DEARGS* )lparam );
}
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp( g_adwDeHelp, hwnd, unMsg, wparam, lparam );
break;
}
case WM_COMMAND:
{
return DeCommand(
hwnd, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
case WM_TIMER:
{
DEINFO* pInfo = (DEINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
KillTimer( pInfo->hwndDlg, 1 );
if (pInfo->lRedialCountdown > 0)
{
--pInfo->lRedialCountdown;
}
DeAdjustPbRedial( pInfo );
if (pInfo->lRedialCountdown == 0)
{
// Fake a press of the Redial button. Note that BM_CLICK
// cannot be used because it doesn't generate the WM_COMMAND
// when the thread is not the foreground window, due to
// SetCapture use and restriction.
//
SendMessage( pInfo->hwndDlg, WM_COMMAND,
MAKEWPARAM( IDOK, BN_CLICKED ),
(LPARAM )pInfo->hwndPbRedial );
}
else
{
SetTimer( pInfo->hwndDlg, 1, 1000L, NULL );
}
return TRUE;
}
case WM_DESTROY:
{
DeTerm( hwnd );
break;
}
}
return FALSE;
}
VOID
DeAdjustPbRedial(
IN DEINFO* pInfo )
// Set the label of the Redial button or disable it as indicated by the
// redial countdown. If enabled, the button shows the number of seconds
// to auto-redial unless this is not the final redial. 'PInfo' is the
// dialog context block.
//
{
TCHAR* psz;
if (pInfo->lRedialCountdown == -2)
{
// Redial button is to be hidden. See bug 230594.
//
SetFocus( pInfo->hwndPbCancel );
ShowWindow( pInfo->hwndPbRedial, SW_HIDE );
EnableWindow( pInfo->hwndPbRedial, FALSE );
}
else
{
// Go ahead and change the label "Redial" or "Redial=%d" as
// appropriate.
//
psz = PszFromId( g_hinstDll, SID_RedialLabel );
if (psz)
{
TCHAR szBuf[ 128 ];
lstrcpyn(
szBuf,
psz,
(sizeof(szBuf) / sizeof(TCHAR)) - 4);
Free( psz );
if (pInfo->lRedialCountdown >= 0)
{
TCHAR szNum[ MAXLTOTLEN + 1 ];
DWORD dwLen, dwSize = sizeof(szBuf)/sizeof(TCHAR);
LToT( pInfo->lRedialCountdown, szNum, 10 );
lstrcat( szBuf, TEXT(" = ") );
dwLen = lstrlen(szBuf) + 1;
lstrcpyn( szBuf + (dwLen - 1), szNum, dwSize - dwLen );
}
SetWindowText( pInfo->hwndPbRedial, szBuf );
}
}
}
BOOL
DeCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'Hwnd' is the dialog window. 'WNotification' is
// the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
DWORD dwErr;
TRACE3( "DeCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
TRACE2("Current proces:(0x%d), Current Thread:(0x%d)",
GetCurrentProcessId(),
GetCurrentThreadId());
switch (wId)
{
case IDOK:
{
TRACE( "Redial pressed" );
EndDialog( hwnd, TRUE );
return TRUE;
}
case IDCANCEL:
{
TRACE( "Cancel pressed" );
EndDialog( hwnd, FALSE );
return TRUE;
}
case CID_DE_PB_More:
{
DEINFO* pInfo;
DWORD dwContext;
pInfo = (DEINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
if (pInfo->pArgs->dwError >= RASBASE
&& pInfo->pArgs->dwError <= RASBASEEND)
{
dwContext = HID_RASERRORBASE - RASBASE + pInfo->pArgs->dwError;
}
else if (pInfo->pArgs->dwError == 0)
{
dwContext = HID_RECONNECTING;
}
else
{
dwContext = HID_NONRASERROR;
}
WinHelp( hwnd, g_pszHelpFile, HELP_CONTEXTPOPUP, dwContext );
}
}
return FALSE;
}
BOOL
DeInit(
IN HWND hwndDlg,
IN DEARGS* pArgs )
// Called on WM_INITDIALOG. 'hwndDlg' is the handle of the owning window.
// 'PArgs' is caller's arguments to the stub API.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
DWORD dwErr;
DEINFO* pInfo;
TRACE( "DeInit" );
// Allocate the dialog context block. Initialize minimally for proper
// cleanup, then attach to the dialog window.
//
{
pInfo = Malloc( sizeof(*pInfo) );
if (!pInfo)
{
ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
EndDialog( hwndDlg, FALSE );
return TRUE;
}
ZeroMemory( pInfo, sizeof(*pInfo) );
pInfo->pArgs = pArgs;
pInfo->hwndDlg = hwndDlg;
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
TRACE( "Context set" );
}
pInfo->hwndStText = GetDlgItem( hwndDlg, CID_DE_ST_Text );
ASSERT( pInfo->hwndStText );
pInfo->hwndPbRedial = GetDlgItem( hwndDlg, IDOK );
ASSERT( pInfo->hwndPbRedial );
pInfo->hwndPbCancel = GetDlgItem( hwndDlg, IDCANCEL );
ASSERT( pInfo->hwndPbCancel );
pInfo->hwndPbMore = GetDlgItem( hwndDlg, CID_DE_PB_More );
ASSERT( pInfo->hwndPbMore );
// Hide/disable "more info" button if WinHelp won't work. See
// common\uiutil\ui.c.
//
{
extern BOOL g_fNoWinHelp;
if (g_fNoWinHelp)
{
ShowWindow( pInfo->hwndPbMore, SW_HIDE );
EnableWindow( pInfo->hwndPbMore, FALSE );
}
}
if (pArgs->dwError == 0)
{
TCHAR* pszFormat;
TCHAR* psz;
TCHAR* apszArgs[ 1 ];
// Redialing on link failure. Set title to "Dial-Up Networking".
//
psz = PszFromId( g_hinstDll, SID_PopupTitle );
if (psz)
{
SetWindowText( hwndDlg, psz );
Free( psz );
}
// Set static placeholder text control to "Link to <entry> failed.
// Reconnect pending...".
//
pszFormat = PszFromId( g_hinstDll, SID_DE_LinkFailed );
if (pszFormat)
{
apszArgs[ 0 ] = pArgs->pszEntry;
psz = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszFormat, 0, 0, (LPTSTR )&psz, 1,
(va_list* )apszArgs );
Free( pszFormat );
if (psz)
{
SetWindowText( pInfo->hwndStText, psz );
LocalFree( psz );
}
}
}
else
{
TCHAR* pszTitleFormat;
TCHAR* pszTitle;
TCHAR* apszArgs[ 1 ];
ERRORARGS args;
// Set title to "Error Connecting to <entry>".
//
pszTitleFormat = GetText( hwndDlg );
if (pszTitleFormat)
{
apszArgs[ 0 ] = pArgs->pszEntry;
pszTitle = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszTitleFormat, 0, 0, (LPTSTR )&pszTitle, 1,
(va_list* )apszArgs );
Free( pszTitleFormat );
if (pszTitle)
{
SetWindowText( hwndDlg, pszTitle );
LocalFree( pszTitle );
}
}
// Build the error text and load it into the placeholder text control.
//
ZeroMemory( &args, sizeof(args) );
if (pArgs->pszStatusArg)
args.apszOpArgs[ 0 ] = pArgs->pszStatusArg;
if (pArgs->pszFormatArg)
args.apszAuxFmtArgs[ 0 ] = pArgs->pszFormatArg;
args.fStringOutput = TRUE;
ErrorDlgUtil( hwndDlg,
pArgs->sidState, pArgs->dwError, &args, g_hinstDll, 0,
(pArgs->sidFormatMsg) ? pArgs->sidFormatMsg : SID_FMT_ErrorMsg );
if (args.pszOutput)
{
SetWindowText( pInfo->hwndStText, args.pszOutput );
LocalFree( args.pszOutput );
}
}
// Stretch the dialog window to a vertical size appropriate for the text
// we loaded.
//
{
HDC hdc;
RECT rect;
RECT rectNew;
HFONT hfont;
LONG dyGrow;
TCHAR* psz;
psz = GetText( pInfo->hwndStText );
if (psz)
{
GetClientRect( pInfo->hwndStText, &rect );
hdc = GetDC( pInfo->hwndStText );
if(NULL != hdc)
{
hfont = (HFONT )SendMessage( pInfo->hwndStText,
WM_GETFONT, 0, 0 );
if (hfont)
{
SelectObject( hdc, hfont );
}
rectNew = rect;
DrawText( hdc, psz, -1, &rectNew,
DT_CALCRECT | DT_WORDBREAK | DT_EXPANDTABS | DT_NOPREFIX );
ReleaseDC( pInfo->hwndStText, hdc );
}
dyGrow = rectNew.bottom - rect.bottom;
ExpandWindow( pInfo->hwndDlg, 0, dyGrow );
ExpandWindow( pInfo->hwndStText, 0, dyGrow );
SlideWindow( pInfo->hwndPbRedial, pInfo->hwndDlg, 0, dyGrow );
SlideWindow( pInfo->hwndPbCancel, pInfo->hwndDlg, 0, dyGrow );
SlideWindow( pInfo->hwndPbMore, pInfo->hwndDlg, 0, dyGrow );
Free( psz );
}
}
// Set Redial button label or disable the button. Always choose to redial
// after 5 seconds for the biplex error, since this will normally solve
// the problem. Otherwise, no countdown is used.
//
if (pArgs->dwError == ERROR_BIPLEX_PORT_NOT_AVAILABLE)
{
pInfo->lRedialCountdown = 5;
}
else
{
pInfo->lRedialCountdown = pArgs->lRedialCountdown;
}
DeAdjustPbRedial( pInfo );
if (pInfo->lRedialCountdown >= 0)
{
SetTimer( pInfo->hwndDlg, 1, 1000L, NULL );
}
// Add context help button to title bar.
//
AddContextHelpButton( hwndDlg );
if (pArgs->fPopupOnTop)
{
// Display the finished window above all other windows. The window
// position is set to "topmost" then immediately set to "not topmost"
// because we want it on top but not always-on-top. Always-on-top
// alone is too annoying.
//
SetWindowPos(
hwndDlg, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
}
CenterWindow( hwndDlg, GetParent( hwndDlg ) );
ShowWindow( hwndDlg, SW_SHOW );
if (pArgs->fPopupOnTop)
{
SetForegroundWindow( hwndDlg );
SetWindowPos(
hwndDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
}
return TRUE;
}
// Helper function to delete credentials
//
// fDeleteDefault specifies whether it is the default credentials that
// should be deleted.
//
// fDeleteIdentity specifies whether to delete the user and domain names
// in addition to the password.
//
DWORD
DeleteSavedCredentials(
IN DINFO* pDinfo,
IN HWND hwndDlg,
IN BOOL fDefault,
IN BOOL fDeleteIdentity )
{
RASCREDENTIALS rc;
DWORD dwErr = NO_ERROR;
TRACE2( "DeleteSavedCredentials: %d %d", fDefault, fDeleteIdentity );
ZeroMemory(&rc, sizeof(rc));
rc.dwSize = sizeof(RASCREDENTIALS);
rc.dwMask = RASCM_Password;
if (fDeleteIdentity)
{
rc.dwMask |= (RASCM_UserName | RASCM_Domain);
}
if ( (fDefault)
&& (IsPublicPhonebook(pDinfo->pFile->pszPath)))
{
rc.dwMask |= RASCM_DefaultCreds;
}
dwErr = g_pRasSetCredentials(
pDinfo->pFile->pszPath,
pDinfo->pEntry->pszEntryName,
&rc,
TRUE );
if (dwErr != 0)
{
ErrorDlg( hwndDlg, SID_OP_UncachePw, dwErr, NULL );
}
TRACE1( "DeleteSavedCredentials: RasSetCredentials=%d", dwErr );
return dwErr;
}
VOID
DeTerm(
IN HWND hwndDlg )
// Called on WM_DESTROY. 'HwndDlg' is that handle of the dialog window.
//
{
DEINFO* pInfo = (DEINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER );
TRACE( "DeTerm" );
if (pInfo)
{
Free( pInfo );
}
}
//----------------------------------------------------------------------------
// Dial Progress dialog
// Listed alphabetically following stub API dialog proc
//----------------------------------------------------------------------------
BOOL
DialProgressDlg(
IN DINFO* pInfo )
// Popup the Dial Progress dialog. 'PInfo' is the dialog context.
//
// Returns true if user connected successfully, false is he cancelled or
// hit an error.
//
{
INT_PTR nStatus;
// Run the dialog.
//
nStatus =
DialogBoxParam(
g_hinstDll,
MAKEINTRESOURCE( DID_DP_DialProgress ),
pInfo->pArgs->hwndOwner,
DpDlgProc,
(LPARAM )pInfo );
if (nStatus == -1)
{
ErrorDlg( pInfo->pArgs->hwndOwner, SID_OP_LoadDlg,
ERROR_UNKNOWN, NULL );
pInfo->pArgs->dwError = ERROR_UNKNOWN;
nStatus = FALSE;
}
if (nStatus)
{
DWORD dwErr;
PBFILE file;
// Connected successfully, so read possible changes to the entry made
// by RasDial.
//
dwErr = ReadPhonebookFile( pInfo->pFile->pszPath, pInfo->pUser,
pInfo->pEntry->pszEntryName, RPBF_ReadOnly, &file );
if (dwErr == 0)
{
DTLNODE* pNodeNew;
pNodeNew = DtlGetFirstNode( file.pdtllistEntries );
if (pNodeNew)
{
DtlRemoveNode( pInfo->pFile->pdtllistEntries, pInfo->pNode );
DestroyEntryNode( pInfo->pNode );
DtlRemoveNode( file.pdtllistEntries, pNodeNew );
DtlAddNodeLast( pInfo->pFile->pdtllistEntries, pNodeNew );
pInfo->pNode = pNodeNew;
pInfo->pEntry = (PBENTRY* )DtlGetData( pNodeNew );
}
ClosePhonebookFile( &file );
}
}
// See if we need to change the entry based on what happened while
// dialing.
//
{
BOOL fChange = FALSE;
if (pInfo->fResetAutoLogon)
{
ASSERT( !pInfo->pNoUser );
pInfo->pEntry->fAutoLogon = FALSE;
fChange = TRUE;
}
if (pInfo->dwfExcludedProtocols)
{
pInfo->pEntry->dwfExcludedProtocols
|= pInfo->dwfExcludedProtocols;
fChange = TRUE;
}
if (pInfo->pListPortsToDelete)
{
DTLNODE* pNode;
pNode = DtlGetFirstNode( pInfo->pEntry->pdtllistLinks );
while (pNode)
{
DTLNODE* pNodeNext;
DTLNODE* pNodePtd;
PBLINK* pLink;
TCHAR* pszPort;
pNodeNext = DtlGetNextNode( pNode );
pLink = (PBLINK* )DtlGetData( pNode );
pszPort = pLink->pbport.pszPort;
for (pNodePtd = DtlGetFirstNode( pInfo->pListPortsToDelete );
pNodePtd;
pNodePtd = DtlGetNextNode( pNodePtd ))
{
TCHAR* pszPtd = (TCHAR* )DtlGetData( pNodePtd );
if (lstrcmp( pszPtd, pszPort ) == 0)
{
pNode = DtlRemoveNode(
pInfo->pEntry->pdtllistLinks, pNode );
DestroyLinkNode( pNode );
fChange = TRUE;
break;
}
}
pNode = pNodeNext;
}
}
if (fChange)
{
pInfo->pEntry->fDirty = TRUE;
WritePhonebookFile( pInfo->pFile, NULL );
}
}
return (BOOL )nStatus;
}
INT_PTR CALLBACK
DpDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the User Authentication dialog. Parameters and
// return value are as described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "DpDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
switch (unMsg)
{
case WM_INITDIALOG:
{
return DpInit( hwnd, (DINFO* )lparam );
}
case WM_COMMAND:
{
DPINFO* pInfo = (DPINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
return DpCommand(
pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
case WM_RASDIAL:
{
DPINFO* pInfo = (DPINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
Sleep( 0 );
DpDial( pInfo, (BOOL)wparam );
return TRUE;
}
case WM_RASERROR:
{
DPINFO* pInfo = (DPINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
Sleep( 0 );
//For whistler bug 381337
//
if ( !pInfo->fCancelPressed )
{
DpError( pInfo, (DPSTATE* )lparam );
}
else
{
TRACE("DpDlgProc is already canceled, wont respond to WM_RASERROR");
}
return TRUE;
}
case WM_RASBUNDLEERROR:
{
DPINFO* pInfo = (DPINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
Sleep( 0 );
if (BundlingErrorsDlg( pInfo ))
{
EndDialog( pInfo->hwndDlg, TRUE );
}
else
{
DpCancel( pInfo );
}
return TRUE;
}
case WM_DESTROY:
{
DPINFO* pInfo = (DPINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
// Whistler Bugs: 344019 SECBUGBASH: leaving leaked password in
// memory when user changes password over RAS
//
// 289587 Failed RAS connections reset password to blank
//
if (pInfo->pszGoodPassword)
{
ZeroMemory(
pInfo->pszGoodPassword,
(lstrlen( pInfo->pszGoodPassword ) + 1) * sizeof(TCHAR) );
Free( pInfo->pszGoodPassword );
pInfo->pszGoodPassword = NULL;
}
if (pInfo->pszGoodUserName)
{
Free( pInfo->pszGoodUserName );
pInfo->pszGoodUserName = NULL;
}
if (DpCallbacksFlag( pInfo, -1 ))
{
// Callbacks are active. Stall until they complete.
//
TRACE( "Stall until callbacks disabled" );
PostMessage( hwnd, WM_DESTROY, wparam, lparam );
return TRUE;
}
DpTerm( hwnd );
break;
}
}
return FALSE;
}
VOID
DpAppendBlankLine(
IN OUT TCHAR* pszLines )
// Append a blank line on the end of 'pszLines'.
//
{
lstrcat( pszLines, TEXT("\n") );
}
VOID
DpAppendConnectErrorLine(
IN OUT TCHAR* pszLines,
IN DWORD sidProtocol,
IN DWORD dwError )
// Append a connect error line for protocol 'sidProtocol' and error
// 'dwError' onto the end of 'pszLines'.
//
{
#define MAXRASERRORLEN 256
TCHAR* pszProtocol;
TCHAR* pszErrStr;
TCHAR szErrNumBuf[ MAXLTOTLEN + 1 ];
// Gather the argument strings.
//
pszProtocol = PszFromId( g_hinstDll, sidProtocol );
if (!pszProtocol)
{
return;
}
LToT( dwError, szErrNumBuf, 10 );
pszErrStr = NULL;
GetErrorText( dwError, &pszErrStr );
// Format the line and append it to caller's line buffer.
//
{
TCHAR* pszLineFormat;
TCHAR* pszLine;
TCHAR* apszArgs[ 3 ];
pszLineFormat = PszFromId( g_hinstDll, SID_FMT_ProjectError );
if (pszLineFormat)
{
apszArgs[ 0 ] = pszProtocol;
apszArgs[ 1 ] = szErrNumBuf;
apszArgs[ 2 ] = (pszErrStr) ? pszErrStr : TEXT("");
pszLine = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszLineFormat, 0, 0, (LPTSTR )&pszLine, 1,
(va_list* )apszArgs );
Free( pszLineFormat );
if (pszLine)
{
lstrcat( pszLines, pszLine );
LocalFree( pszLine );
}
}
}
Free( pszProtocol );
Free0( pszErrStr );
}
VOID
DpAppendConnectOkLine(
IN OUT TCHAR* pszLines,
IN DWORD sidProtocol )
// Append a "connected successfully" line for protocol 'sidProtocol' onto
// the end of 'pszLines'.
//
{
TCHAR* pszProtocol;
// Get the argument string.
//
pszProtocol = PszFromId( g_hinstDll, sidProtocol );
if (!pszProtocol)
{
return;
}
// Format the line and append it to caller's line buffer.
//
{
TCHAR* pszLineFormat;
TCHAR* pszLine;
TCHAR* apszArgs[ 1 ];
pszLineFormat = PszFromId( g_hinstDll, SID_FMT_ProjectOk );
if (pszLineFormat)
{
apszArgs[ 0 ] = pszProtocol;
pszLine = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszLineFormat, 0, 0, (LPTSTR )&pszLine, 1,
(va_list* )apszArgs );
Free( pszLineFormat );
if (pszLine)
{
lstrcat( pszLines, pszLine );
LocalFree( pszLine );
}
}
}
Free( pszProtocol );
}
VOID
DpAppendFailCodeLine(
IN OUT TCHAR* pszLines,
IN DWORD dw )
// Append hexidecimal fail code 'dw' as an extended error line on the end
// of 'pszLines'.
//
{
TCHAR szNumBuf[ MAXLTOTLEN + 1 ];
// Get the argument string.
//
LToT( dw, szNumBuf, 16 );
// Format the line and append it to caller's line buffer.
//
{
TCHAR* pszLineFormat;
TCHAR* pszLine;
TCHAR* apszArgs[ 1 ];
pszLineFormat = PszFromId( g_hinstDll, SID_FMT_FailCode );
if (pszLineFormat)
{
apszArgs[ 0 ] = szNumBuf;
pszLine = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszLineFormat, 0, 0, (LPTSTR )&pszLine, 1,
(va_list* )apszArgs );
Free( pszLineFormat );
if (pszLine)
{
lstrcat( pszLines, pszLine );
LocalFree( pszLine );
}
}
}
}
VOID
DpAppendNameLine(
IN OUT TCHAR* pszLines,
IN TCHAR* psz )
// Append NetBIOS name 'psz' as an extended error line on the end of
// 'pszLines'.
//
{
TCHAR* pszLineFormat;
TCHAR* pszLine;
TCHAR* apszArgs[ 1 ];
pszLineFormat = PszFromId( g_hinstDll, SID_FMT_Name );
if (pszLineFormat)
{
apszArgs[ 0 ] = psz;
pszLine = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszLineFormat, 0, 0, (LPTSTR )&pszLine, 1,
(va_list* )apszArgs );
Free( pszLineFormat );
if (pszLine)
{
lstrcat( pszLines, pszLine );
LocalFree( pszLine );
}
}
}
VOID
DpAuthNotify(
IN DPINFO* pInfo,
IN DPSTATE* pState )
// Called on an authentication notify, i.e. a message from RASCAUTH.DLL or
// RASPPPEN.DLL. 'PInfo' is the dialog context. 'PState' is the current
// link's context.
//
{
PBENTRY* pEntry;
TRACE( "DpAuthNotify" );
pEntry = pInfo->pArgs->pEntry;
if (pState->dwError == ERROR_ACCESS_DENIED && pEntry->fAutoLogon)
{
// A third party box has negotiated an authentication protocol that
// can't deal with the NT one-way-hashed password, i.e. something
// besides MS-extended CHAP or AMB. Map the error to a more
// informative error message.
//
pState->dwError = ERROR_CANNOT_USE_LOGON_CREDENTIALS;
if (!pInfo->pArgs->pNoUser)
{
TRACE( "Disable auto-logon" );
pEntry->fAutoLogon = FALSE;
pInfo->pArgs->fResetAutoLogon = TRUE;
}
}
if (pState->dwError == ERROR_CHANGING_PASSWORD)
{
TRACE( "DpAuthNotify - ERROR_CHANGING_PASSWORD" );
// Change password failed. Restore the password that worked for the
// "button" redial.
//
if (pInfo->pszGoodPassword)
{
// Whistler bug 254385 encode password when not being used
// Assumed password was encoded by DpPasswordExpired()
//
DecodePassword( pInfo->pszGoodPassword );
lstrcpyn(
pInfo->pArgs->rdp.szPassword,
pInfo->pszGoodPassword,
sizeof(pInfo->pArgs->rdp.szPassword) / sizeof(TCHAR) );
EncodePassword( pInfo->pArgs->rdp.szPassword );
ZeroMemory(
pInfo->pszGoodPassword,
(lstrlen( pInfo->pszGoodPassword ) + 1) * sizeof(TCHAR) );
Free( pInfo->pszGoodPassword );
pInfo->pszGoodPassword = NULL;
}
if (pInfo->pszGoodUserName)
{
lstrcpyn(
pInfo->pArgs->rdp.szUserName,
pInfo->pszGoodUserName,
sizeof(pInfo->pArgs->rdp.szUserName) / sizeof(TCHAR) );
Free( pInfo->pszGoodUserName );
pInfo->pszGoodUserName = NULL;
}
}
// Update cached credentials, if any, with new password.
//
// Whistler Bugs: 344019 SECBUGBASH: leaving leaked password in memory when
// user changes password over RAS
//
// 289587 Failed RAS connections reset password to blank
//
if ((pState->sidState == SID_S_Projected) &&
(pInfo->pszGoodPassword) &&
(pInfo->pszGoodUserName))
{
DWORD dwErr;
RASCREDENTIALS rc;
TRACE( "DpAuthNotify - Success changing password, caching if necessary" );
ZeroMemory( &rc, sizeof(rc) );
rc.dwSize = sizeof(rc);
// Look up cached password. Since we are only calling in with the
// RASCM_Password flag here, with the current implementation of
// RasGet/SetCredentials, this works for the Set below whether we are
// saving a Per-User, Global, or the special case of having both saved
// at the same time. Whew, complicated!
//
rc.dwMask = RASCM_Password;
ASSERT( g_pRasGetCredentials );
TRACE( "RasGetCredentials" );
dwErr = g_pRasGetCredentials(
pInfo->pArgs->pFile->pszPath,
pInfo->pArgs->pEntry->pszEntryName,
&rc );
TRACE2( "RasGetCredentials=%d,m=%x", dwErr, rc.dwMask );
if (dwErr == 0 && (rc.dwMask & RASCM_Password))
{
// Password was cached, so update it.
//
DecodePassword( pInfo->pArgs->rdp.szPassword );
lstrcpyn(
rc.szPassword,
pInfo->pArgs->rdp.szPassword,
sizeof(rc.szPassword) / sizeof(TCHAR) );
EncodePassword( pInfo->pArgs->rdp.szPassword );
ASSERT( g_pRasSetCredentials );
TRACE( "RasSetCredentials(p,FALSE)" );
dwErr = g_pRasSetCredentials(
pInfo->pArgs->pFile->pszPath,
pInfo->pArgs->pEntry->pszEntryName, &rc, FALSE );
TRACE1( "RasSetCredentials=%d", dwErr );
if (dwErr != 0)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_UncachePw, dwErr, NULL );
}
}
// Clean up
//
ZeroMemory( rc.szPassword, sizeof(rc.szPassword) );
ZeroMemory(
pInfo->pszGoodPassword,
(lstrlen( pInfo->pszGoodPassword ) + 1) * sizeof(TCHAR) );
Free( pInfo->pszGoodPassword );
pInfo->pszGoodPassword = NULL;
Free( pInfo->pszGoodUserName );
pInfo->pszGoodUserName = NULL;
}
}
VOID
DpCallbackSetByCaller(
IN DPINFO* pInfo,
IN DPSTATE* pState )
// RASCS_CallbackSetByCaller state handling. 'PInfo' is the dialog
// context. 'PState' is the subentry state.
//
// Returns true if successful, or an error code.
//
{
TCHAR* pszDefault;
TCHAR szNum[ RAS_MaxCallbackNumber + 1 ];
TRACE( "DpCallbackSetByCaller" );
pszDefault = pInfo->pArgs->pUser->pszLastCallbackByCaller;
if (!pszDefault)
{
pszDefault = TEXT("");
}
lstrcpyn( szNum, pszDefault, RAS_MaxCallbackNumber + 1 );
if (DialCallbackDlg( pInfo->hwndDlg, szNum ))
{
lstrcpyn( pInfo->pArgs->rdp.szCallbackNumber, szNum, RAS_MaxCallbackNumber + 1 );
if (lstrcmp( szNum, pszDefault ) != 0)
{
Free0( pInfo->pArgs->pUser->pszLastCallbackByCaller );
pInfo->pArgs->pUser->pszLastCallbackByCaller = StrDup( szNum );
pInfo->pArgs->pUser->fDirty = TRUE;
}
}
else
{
pInfo->pArgs->rdp.szCallbackNumber[ 0 ] = TEXT('\0');
}
pState->sidState = 0;
}
BOOL
DpCallbacksFlag(
IN DPINFO* pInfo,
IN INT nSet )
// If 'nSet' is not less than 0, the 'pInfo->fCallbacksActive' flag is set
// to the value 'nSet'.
//
// Returns true is callbacks are active false otherwise.
//
{
BOOL f;
TRACE1( "DpCallbacksFlag:nSet=(%d)", nSet );
f = FALSE;
if (WaitForSingleObject(
g_hmutexCallbacks, INFINITE ) == WAIT_OBJECT_0)
{
TRACE("DpCallbacksFlag begin:");
TRACE1("Global active:(%d)", g_ulCallbacksActive);
TRACE1("Current thread active:(%d)", pInfo->ulCallbacksActive);
f = pInfo->fCallbacksActive;
if (nSet > 0)
{
ASSERT( !pInfo->fCallbacksActive );
pInfo->fCallbacksActive = TRUE;
++g_ulCallbacksActive;
pInfo->ulCallbacksActive++;
}
else if (nSet == 0)
{
pInfo->fCallbacksActive = FALSE;
if ( 0 < pInfo->ulCallbacksActive )
{
// fix for whistler bug 341662 366237 gangz
//
if( 0 < g_ulCallbacksActive )
{
--g_ulCallbacksActive;
}
pInfo->ulCallbacksActive--;
}
}
TRACE("DpCallbacksFlag result:");
TRACE1("Global active:(%d)", g_ulCallbacksActive);
TRACE1("Current thread active:(%d)", pInfo->ulCallbacksActive);
ReleaseMutex( g_hmutexCallbacks );
}
TRACE1( "DpCallbacksFlag: This thread's active=%d", f );
return f;
}
VOID
DpCancel(
IN DPINFO* pInfo )
// Kill the dialog and any partially initiated call, as when cancel button
// is pressed. 'PInfo' is the dialog context block.
//
{
TRACE( "DpCancel" );
// Hide window to prevent visual complaints that arise if RasHangUp takes
// a long time to complete.
//
ShowWindow( pInfo->hwndDlg, SW_HIDE );
if (pInfo->hrasconn)
{
DWORD dwErr;
ASSERT( g_pRasHangUp );
TRACE( "RasHangUp" );
TRACE("DpCancel:call RasHangUp");
dwErr = g_pRasHangUp( pInfo->hrasconn );
TRACE1("DpCancel:get dwErr from RasHangUp:(%d)", dwErr);
TRACE1( "RasHangUp=%d", dwErr );
}
EndDialog( pInfo->hwndDlg, FALSE );
}
//return the pInfo->ulCallbacksActive, to get the g_ulCallbacksActive
//use CallbacksActive()
//
long
DpOnOffPerThreadTerminateFlag(
DPINFO *pInfo,
INT nSetTerminateAsap,
BOOL* pfTerminateAsap )
// If 'fSetTerminateAsap' >= 0, sets 'pInfo->fTerminateAsap' flag to 'nSetTerminateAsap'.
// If non-NULL, caller's '*pfTerminateAsap' is filled with the current value of
// 'pInfo->fTerminateAsap'.
//
// Returns the number of Rasdial callback threads active.
//
{
LONG ul;
TRACE1( "DpOnOffPerThreadTerminateFlag: Terminate=(%d)", nSetTerminateAsap );
ASSERT(pInfo);
ul = 0;
if (WaitForSingleObject( g_hmutexCallbacks, INFINITE ) == WAIT_OBJECT_0)
{
if( pInfo )
{
if (pfTerminateAsap)
{
*pfTerminateAsap = pInfo->fTerminateAsap;
}
if (nSetTerminateAsap >= 0)
{
pInfo->fTerminateAsap = (BOOL )nSetTerminateAsap;
}
}
else
{
TRACE( "DpOnOffPerThreadTerminateFlag: Invalid DPINFO input parameter" );
}
ul = pInfo->ulCallbacksActive;
ReleaseMutex( g_hmutexCallbacks );
}
TRACE1( "DpOnOffPerThreadTerminateFlag:Current Thread Active=%d", ul );
return ul;
}
BOOL
DpCommand(
IN DPINFO* pInfo,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'PInfo' is the dialog context. 'WNotification'
// is the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
DWORD dwErr;
TRACE3( "DpCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
TRACE2("DpCommand:pInfo address (0x%x), Dialog Handle (0x%x)",
pInfo,
pInfo->hwndDlg);
TRACE2("DpCommand:Current proces:(0x%d), Current Thread:(0x%d)",
GetCurrentProcessId(),
GetCurrentThreadId());
switch (wId)
{
case IDCANCEL:
{
ULONG ulCallbacksActive;
ShowWindow( pInfo->hwndDlg, SW_HIDE );
//For whistler bug 381337
//
if( !pInfo->fCancelPressed)
{
TRACE("DpCommand:Cancel pressed");
pInfo->fCancelPressed = TRUE;
}
if (pInfo->hrasconn)
{
DWORD dwErr;
ASSERT( g_pRasHangUp );
TRACE( "RasHangUp" );
dwErr = g_pRasHangUp( pInfo->hrasconn );
TRACE1( "RasHangUp=%d", dwErr );
}
//set pInfo->fTerminateAsap to Terminate the dial
//in the current thread, also return the pInfo->ulCallbacksActive,
//if it is already 0, then we dont need to post the CANCEL window
//Message again whistler bug#291613 gangz
//
ulCallbacksActive = DpOnOffPerThreadTerminateFlag(pInfo, 1, NULL );
if ( 0 < ulCallbacksActive )
{
TRACE1( "DpCommand stall, current thread's ulCallbacksActive n=%d", ulCallbacksActive );
PostMessage( pInfo->hwndDlg, WM_COMMAND,
MAKEWPARAM(wId, wNotification),
(LPARAM) hwndCtrl );
//For whistler bug 378086 gangz
//to sleep a bit to give the rasman a break to call our callback
//function DpRasDialFunc2()
//
Sleep(10);
return TRUE;
}
EndDialog( pInfo->hwndDlg, FALSE );
//Reset the pInfo->fTerminateAsap flag
//
DpOnOffPerThreadTerminateFlag(pInfo, 0, NULL );
return TRUE;
}
}
return FALSE;
}
VOID
DpConnectDevice(
IN DPINFO* pInfo,
IN DPSTATE* pState )
// RASCS_ConnectDevice state handling. 'PInfo' is the dialog context.
// 'PState' is the subentry state.
//
{
DWORD dwErr;
RASCONNSTATUS rcs;
DWORD cb;
HRASCONN hrasconn;
TCHAR* pszPhoneNumber;
TRACE( "DpConnectDevice" );
// Get fully translated phone number, if any.
//
ZeroMemory( &rcs, sizeof(rcs) );
rcs.dwSize = sizeof(rcs);
ASSERT( g_pRasGetConnectStatus );
TRACE1( "RasGetConnectStatus($%08x)", pState->hrasconnLink );
dwErr = g_pRasGetConnectStatus( pState->hrasconnLink, &rcs );
TRACE1( "RasGetConnectStatus=%d", dwErr );
TRACEW1( " dt=%s", rcs.szDeviceType );
TRACEW1( " dn=%s", rcs.szDeviceName );
TRACEW1( " pn=%s", rcs.szPhoneNumber );
if (dwErr != 0)
{
pState->pbdt = PBDT_None;
}
pState->pbdt = PbdevicetypeFromPszType( rcs.szDeviceType );
pszPhoneNumber = rcs.szPhoneNumber;
switch (pState->pbdt)
{
case PBDT_Modem:
{
Free0( pState->pszStatusArg );
pState->pszStatusArg = StrDup( pszPhoneNumber );
if (pInfo->pArgs->pUser->fOperatorDial
&& AllLinksAreModems( pInfo->pArgs->pEntry ))
{
pState->sidState = SID_S_ConnectModemOperator;
}
else if (pInfo->pArgs->pEntry->fPreviewPhoneNumber)
{
pState->sidState = SID_S_ConnectNumber;
}
else
{
pState->sidState = SID_S_ConnectModemNoNum;
}
break;
}
case PBDT_Pad:
{
Free0( pState->pszStatusArg );
pState->pszStatusArg = StrDup( rcs.szDeviceName );
pState->sidState = SID_S_ConnectPad;
if (pState->dwError == ERROR_X25_DIAGNOSTIC)
{
TCHAR* psz;
// Get the X.25 diagnostic string for display in the
// custom "diagnostics" error message format.
//
Free0( pState->pszFormatArg );
pState->pszFormatArg =
GetRasX25Diagnostic( pState->hrasconnLink );
}
break;
}
case PBDT_Switch:
{
Free0( pState->pszStatusArg );
pState->pszStatusArg = StrDup( rcs.szDeviceName );
pState->sidState =
(pState->fNotPreSwitch)
? SID_S_ConnectPostSwitch
: SID_S_ConnectPreSwitch;
break;
}
case PBDT_Null:
{
pState->sidState = SID_S_ConnectNull;
break;
}
case PBDT_Parallel:
{
pState->sidState = SID_S_ConnectParallel;
break;
}
case PBDT_Irda:
{
pState->sidState = SID_S_ConnectIrda;
break;
}
case PBDT_Isdn:
{
Free0( pState->pszStatusArg );
pState->pszStatusArg = StrDup( pszPhoneNumber );
pState->sidState = SID_S_ConnectNumber;
break;
}
case PBDT_Vpn:
{
Free0( pState->pszStatusArg );
pState->pszStatusArg = StrDup( pszPhoneNumber );
pState->sidState = SID_S_ConnectVpn;
break;
}
default:
{
Free0( pState->pszStatusArg );
if (pszPhoneNumber[ 0 ] != TEXT('\0'))
{
pState->pszStatusArg = StrDup( pszPhoneNumber );
pState->sidState = SID_S_ConnectNumber;
}
else
{
pState->pszStatusArg = StrDup( rcs.szDeviceName );
pState->sidState = SID_S_ConnectDevice;
}
break;
}
}
}
VOID
DpDeviceConnected(
IN DPINFO* pInfo,
IN DPSTATE* pState )
// RASCS_DeviceConnected state handling. 'PInfo' is the dialog context.
// 'PState' is the subentry state.
//
// Returns 0 if successful, or an error code.
//
{
TRACE( "DpDeviceConnected" );
switch (pState->pbdt)
{
case PBDT_Modem:
{
pState->sidState = SID_S_ModemConnected;
pState->fNotPreSwitch = TRUE;
break;
}
case PBDT_Pad:
{
pState->sidState = SID_S_PadConnected;
pState->fNotPreSwitch = TRUE;
break;
}
case PBDT_Switch:
{
pState->sidState =
(pState->fNotPreSwitch)
? SID_S_PostSwitchConnected
: SID_S_PreSwitchConnected;
pState->fNotPreSwitch = TRUE;
break;
}
case PBDT_Null:
{
pState->sidState = SID_S_NullConnected;
pState->fNotPreSwitch = TRUE;
break;
}
case PBDT_Parallel:
{
pState->sidState = SID_S_ParallelConnected;
pState->fNotPreSwitch = TRUE;
break;
}
case PBDT_Irda:
{
pState->sidState = SID_S_IrdaConnected;
pState->fNotPreSwitch = TRUE;
break;
}
default:
{
pState->sidState = SID_S_DeviceConnected;
break;
}
}
}
VOID
DpDial(
IN DPINFO* pInfo,
IN BOOL fPauseRestart )
// Dial with the parameters in the 'pInfo' dialog context block.
// 'FPausedRestart' indicates the dial is restarting from a paused state
// and dial states should not be reset.
//
{
DWORD dwErr;
TRACE1( "DpDial,fPauseRestart=%d", fPauseRestart );
if (!fPauseRestart)
{
DpInitStates( pInfo );
//comment for bug 277365, 291613 gangz
//Set the fCallbacksActive to be TRUE
//
TRACE("DpDial:Init global actives");
DpCallbacksFlag( pInfo, 1 );
}
else
{
TRACE("DpDial:WONT Init global actives for pausedRestart");
}
// Whistler bug 254385 encode password when not being used
// Assumed password was encoded previously
//
DecodePassword( pInfo->pArgs->rdp.szPassword );
TRACE1( "RasDial(h=$%08x)", pInfo->hrasconn );
ASSERT( g_pRasDial );
dwErr = g_pRasDial( &pInfo->pArgs->rde, pInfo->pArgs->pFile->pszPath,
&pInfo->pArgs->rdp, 2, (LPVOID )DpRasDialFunc2, &pInfo->hrasconn );
TRACE2( "RasDial=%d,h=$%08x", dwErr, pInfo->hrasconn );
EncodePassword( pInfo->pArgs->rdp.szPassword );
if (dwErr != 0)
{
// This same error will show up via the callback route on restarts
// from PAUSEd states so avoid double popups in that case. See bug
// 367482.
//
if (!fPauseRestart)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_RasDial, dwErr, NULL );
DpCallbacksFlag( pInfo, 0 );
}
// If we receive error 668 here, it means that a rasevent is currently
// posted for state RASCS_Disconnected. We shouldn't cancel in this
// case since we Normal processing of RASCS_Disconnected will allow the
// user to redial. Also, calling DpCancel below will insert
// WM_DESTROY which will process before the popup that the rasevent
// produces can display. 367482
//
if (dwErr != ERROR_NO_CONNECTION)
{
DpCancel( pInfo );
}
}
}
VOID
DpError(
IN DPINFO* pInfo,
IN DPSTATE* pState )
// Popup error dialog for error identified by 'pState' and cancel or
// redial as indicated by user. 'PInfo' is the dialog context.
//
{
DWORD dwErr;
DWORD dwRedialAttemptsLeft;
DWORD sidState;
TRACE( "DpError" );
// Retrieve additional text from RASMXS on those special errors where the
// device returned something useful to display.
//
if (pState->dwError == ERROR_FROM_DEVICE
|| pState->dwError == ERROR_UNRECOGNIZED_RESPONSE)
{
TCHAR* pszMessage;
dwErr = GetRasMessage( pInfo->hrasconn, &pszMessage );
if (dwErr == 0)
{
pState->sidFormatMsg = SID_FMT_ErrorMsgResp;
Free0( pState->pszFormatArg );
pState->pszFormatArg = pszMessage;
}
}
if (pState->sidFormatMsg == 0)
{
if (pState->dwExtendedError != 0)
{
// Translate extended error code into arguments.
//
TCHAR szNum[ 2 + MAXLTOTLEN + 1 ];
pState->sidFormatMsg = SID_FMT_ErrorMsgExt;
szNum[ 0 ] = TEXT('0');
szNum[ 1 ] = TEXT('x');
LToT( pState->dwExtendedError, szNum + 2, 16 );
Free0( pState->pszFormatArg );
pState->pszFormatArg = StrDup( szNum );
}
else if (pState->szExtendedError[ 0 ] != TEXT('\0'))
{
// Translate extended error string to argument. Currently, the
// string is always a NetBIOS name.
//
pState->sidFormatMsg = SID_FMT_ErrorMsgName;
Free0( pState->pszFormatArg );
pState->pszFormatArg = StrDup( pState->szExtendedError );
}
}
if (pInfo->hrasconn)
{
// Hang up before displaying error popup so server side resources are
// not tied up waiting for client to acknowledge error.
//
ASSERT( g_pRasHangUp );
TRACE( "RasHangUp" );
dwErr = g_pRasHangUp( pInfo->hrasconn );
TRACE1( "RasHangUp=%d", dwErr );
pInfo->hrasconn = NULL;
}
if (pInfo->pArgs->pEntry->pszPrerequisiteEntry
&& *pInfo->pArgs->pEntry->pszPrerequisiteEntry)
{
// Select "no Redial button" mode for entries that have prerequisite
// entries. This is because RASMAN drops the prerequisite entry as
// soon as the dependent entry fails, thus dooming to defeat a redial
// of only the dependent entry. Yes, it should really redial both
// entries here, but that is not really feasible with the current
// non-integrated serial implementation of prerequisite entries. This
// at least improves the poor behavior cited in bug 230594.
//
dwRedialAttemptsLeft = -2;
}
else if (pInfo->dwRedialAttemptsLeft <= 0)
{
// No auto-redial countdown, but "Redial" button does appear in place
// of the default "OK".
//
dwRedialAttemptsLeft = -1;
}
else
{
// Auto-redial countdown based on the entries configuration.
//
dwRedialAttemptsLeft =
GetOverridableParam(
pInfo->pArgs->pUser,
pInfo->pArgs->pEntry,
RASOR_RedialSeconds );
}
// This hack works around a bug in RasDial API. See bug 313102.
//
sidState = pState ->sidState;
if (!sidState)
{
sidState = SID_S_AuthNotify;
}
if (DialErrorDlg(
pInfo->hwndDlg,
pInfo->pArgs->pEntry->pszEntryName,
pState->dwError,
sidState,
pState->pszStatusArg,
pState->sidFormatMsg,
pState->pszFormatArg,
dwRedialAttemptsLeft,
GetOverridableParam(
pInfo->pArgs->pUser, pInfo->pArgs->pEntry,
RASOR_PopupOnTopWhenRedialing ) ))
{
TRACE( "User redials" );
if (pInfo->dwRedialAttemptsLeft > 0)
{
--pInfo->dwRedialAttemptsLeft;
}
TRACE(" Post(DIAL)" );
PostMessage( pInfo->hwndDlg, WM_RASDIAL, FALSE, 0 );
}
else
{
TRACE( "User cancels" );
DpCancel( pInfo );
}
//
// Set the error so that the error is propagated back
// to the caller of the RasDialDlg api.
//
TRACE2("DpError settings error (0x%x) to %d",
&pInfo->pArgs->pArgs->dwError,
pState->dwError);
pInfo->pArgs->pArgs->dwError = pState->dwError;
}
DWORD
DpEvent(
IN DPINFO* pInfo,
IN DWORD dwSubEntry )
// Handle a RasDial callback event on subentry 'dwSubEntry'. 'PInfo' is
// the dialog context.
//
// Return 0 to stop callbacks from RasDial, or 1 to continue callbacks
// (normal), or 2 to indicate that the phonebook entry has changed and
// should be re-read by RasDial.
//
{
DWORD dwErr;
DWORD dwCode;
BOOL fLeader;
DWORD dwcSuccessLinks, dwcFailedLinks, i;
DPSTATE* pState;
BOOL fPartialMultilink;
BOOL fIsLaterState;
TRACE( "DpEvent" );
// Default to "normal" return.
//
dwCode = 1;
fPartialMultilink = FALSE;
TRACE2("Current proces:(0x%d), Current Thread:(0x%d)",
GetCurrentProcessId(),
GetCurrentThreadId());
// Find the associated state information and figure out if this is the
// most advanced sub-entry.
//
pState = &pInfo->pStates[ dwSubEntry - 1 ];
fIsLaterState = DpIsLaterState( pState->state, pInfo->state );
if (dwSubEntry == pInfo->dwSubEntry || fIsLaterState)
{
fLeader = TRUE;
if (fIsLaterState)
{
pInfo->dwSubEntry = dwSubEntry;
pInfo->state = pState->state;
}
}
else
{
fLeader = FALSE;
TRACE( "Trailing" );
}
// Execute the state.
//
TRACE1("State is:(%d)", pState->state);
switch (pState->state)
{
case RASCS_OpenPort:
{
pState->pbdt = PBDT_None;
pState->sidState = SID_S_OpenPort;
break;
}
case RASCS_PortOpened:
{
// Should have an hrasconnLink for this subentry now. Look it up
// and stash it in our context.
//
ASSERT( g_pRasGetSubEntryHandle );
TRACE1( "RasGetSubEntryHandle(se=%d)", dwSubEntry );
dwErr = g_pRasGetSubEntryHandle(
pInfo->hrasconn, dwSubEntry, &pState->hrasconnLink );
TRACE2( "RasGetSubEntryHandle=%d,hL=$%08x",
dwErr, pState->hrasconnLink );
if (dwErr != 0)
{
pState->dwError = dwErr;
}
pState->sidState = SID_S_PortOpened;
break;
}
case RASCS_ConnectDevice:
{
DTLNODE* pNode;
PBLINK* pLink;
pNode = DtlNodeFromIndex(
pInfo->pArgs->pEntry->pdtllistLinks, dwSubEntry - 1 );
ASSERT( pNode );
if(NULL == pNode)
{
pState->dwError = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
pLink = (PBLINK* )DtlGetData( pNode );
}
if ((pState->dwError == ERROR_PORT_OR_DEVICE
&& (pLink->pbport.fScriptBeforeTerminal
|| pLink->pbport.fScriptBefore))
|| (pState->dwError == ERROR_USER_DISCONNECTION
&& (pInfo->pArgs->pUser->fOperatorDial
&& AllLinksAreModems( pInfo->pArgs->pEntry ))))
{
// This happens when user presses Cancel on the Unimodem
// "Pre-Dial Terminal Screen" or "Operator Assisted or Manual
// Dial" dialog.
//
TRACE("DpEvent:Call DpCancel() in connectDevice, but still return 1\n");
DpCancel( pInfo );
return dwCode;
}
DpConnectDevice( pInfo, pState );
break;
}
case RASCS_DeviceConnected:
{
DpDeviceConnected( pInfo, pState );
break;
}
case RASCS_AllDevicesConnected:
{
pState->sidState = SID_S_AllDevicesConnected;
break;
}
case RASCS_Authenticate:
{
pState->sidState = SID_S_Authenticate;
break;
}
case RASCS_AuthNotify:
{
DpAuthNotify( pInfo, pState );
break;
}
case RASCS_AuthRetry:
{
pState->sidState = SID_S_AuthRetry;
break;
}
case RASCS_AuthCallback:
{
pState->sidState = SID_S_AuthCallback;
break;
}
case RASCS_AuthChangePassword:
{
pState->sidState = SID_S_AuthChangePassword;
break;
}
case RASCS_AuthProject:
{
pState->sidState = SID_S_AuthProject;
break;
}
case RASCS_AuthLinkSpeed:
{
pState->sidState = SID_S_AuthLinkSpeed;
break;
}
case RASCS_AuthAck:
{
pState->sidState = SID_S_AuthAck;
break;
}
case RASCS_ReAuthenticate:
{
pState->sidState = SID_S_ReAuthenticate;
break;
}
case RASCS_Authenticated:
{
pState->sidState = SID_S_Authenticated;
break;
}
case RASCS_PrepareForCallback:
{
pState->sidState = SID_S_PrepareForCallback;
break;
}
case RASCS_WaitForModemReset:
{
pState->sidState = SID_S_WaitForModemReset;
break;
}
case RASCS_WaitForCallback:
{
pState->sidState = SID_S_WaitForCallback;
break;
}
case RASCS_Projected:
{
if (fLeader)
{
// If DpProjected returns FALSE, it detected a fatal error,
// and the dialing process will stop. If DpProjected returns
// with pState->dwError non-zero, we display the error in a
// redial dialog, if redial is configured.
//
if (!DpProjected( pInfo, pState ))
{
TRACE("DpEvent:Call DpCancel() in RASCS_Projected, but still return 1 to DpRasDialFunc2()\n");
DpCancel( pInfo );
return dwCode;
}
else if (pState->dwError)
{
TRACE("DpCancel() in RASCS_Projected,return 0 to DpRasDialFunc2()");
TRACE( "DpEvent:Post(ERROR), return 0 to DpRasDialFunc2()" );
PostMessage( pInfo->hwndDlg,
WM_RASERROR, 0, (LPARAM )pState );
return 0;
}
}
break;
}
case RASCS_Interactive:
{
BOOL fChange = FALSE;
if (!DpInteractive( pInfo, pState, &fChange ))
{
DpCancel( pInfo );
return dwCode;
}
if (fChange)
{
dwCode = 2;
}
break;
}
case RASCS_RetryAuthentication:
{
if (!RetryAuthenticationDlg(
pInfo->hwndDlg, pInfo->pArgs ))
{
DpCancel( pInfo );
return dwCode;
}
pState->sidState = 0;
break;
}
case RASCS_InvokeEapUI:
{
if (g_pRasInvokeEapUI(
pInfo->hrasconn, dwSubEntry,
&pInfo->pArgs->rde, pInfo->hwndDlg ))
{
DpCancel( pInfo );
return dwCode;
}
pState->sidState = 0;
break;
}
case RASCS_CallbackSetByCaller:
{
DpCallbackSetByCaller( pInfo, pState );
break;
}
case RASCS_PasswordExpired:
{
if (!DpPasswordExpired( pInfo, pState ))
{
DpCancel( pInfo );
return dwCode;
}
break;
}
case RASCS_SubEntryConnected:
{
if (pInfo->cStates > 1)
{
pState->sidState = SID_S_SubConnected;
}
break;
}
case RASCS_SubEntryDisconnected:
{
break;
}
case RASCS_Connected:
{
pState->sidState = SID_S_Connected;
break;
}
case RASCS_Disconnected:
{
pState->sidState = SID_S_Disconnected;
break;
}
default:
{
pState->sidState = SID_S_Unknown;
break;
}
}
// Count the successful and failed links.
//
{
DPSTATE* p;
dwcSuccessLinks = dwcFailedLinks = 0;
for (i = 0, p = pInfo->pStates; i < pInfo->cStates; ++i, ++p)
{
if (p->state == RASCS_SubEntryConnected)
{
++dwcSuccessLinks;
}
if (p->dwError)
{
++dwcFailedLinks;
}
}
}
TRACE3( "s=%d,f=%d,t=%d", dwcSuccessLinks, dwcFailedLinks, pInfo->cStates );
if (pState->dwError)
{
DTLNODE *pdtlnode = NULL;
DWORD dwIndex = pInfo->pArgs->rdp.dwSubEntry;
if(0 != dwIndex)
{
pdtlnode = DtlNodeFromIndex(
pInfo->pArgs->pEntry->pdtllistLinks,
dwIndex - 1);
}
if ( (dwcFailedLinks == pInfo->cStates)
|| ( (RASEDM_DialAll != pInfo->pArgs->pEntry->dwDialMode)
&& (dwcSuccessLinks == 0))
|| (NULL != pdtlnode))
{
// A terminal error state has occurred on all links. Post a
// message telling ourselves to popup an error, then release the
// callback so it doesn't hold the port open while the error popup
// is up,
//
TRACE( "Post(ERROR)" );
PostMessage( pInfo->hwndDlg, WM_RASERROR, 0, (LPARAM )pState );
return 0;
}
else if (dwcSuccessLinks + dwcFailedLinks == pInfo->cStates)
{
// An error occurred on the final link, but some link connected.
// It would be nice if RasDial would followup with a
// RASCS_Connected in that case, but it doesn't, so we duplicate
// the RASCS_Connected-style exit here.
//
TRACE( "Post(BUNDLEERROR)" );
PostMessage( pInfo->hwndDlg,
WM_RASBUNDLEERROR, 0, (LPARAM )pState );
return 0;
}
// A fatal error has occurred on a link, but there are other links
// still trying, so let it die quietly.
//
TRACE2( "Link %d fails, e=%d", dwSubEntry + 1, pState->dwError );
return dwCode;
}
// Display the status string for this state.
//
if (pState->sidState)
{
if (pState->sidState != pState->sidPrevState)
{
pState->sidPrevState = pState->sidState;
}
if (fLeader)
{
TCHAR* pszState = PszFromId( g_hinstDll, pState->sidState );
if ( (NULL != pszState)
&& pState->pszStatusArg)
{
TCHAR* pszFormattedState;
TCHAR* pszArg;
TCHAR* apszArgs[ 1 ];
DWORD cch;
pszArg = (pState->pszStatusArg)
? pState->pszStatusArg : TEXT("");
// Find length of formatted string with text argument (if any)
// inserted and any progress dots appended.
//
cch = lstrlen( pszState ) + lstrlen( pszArg ) + 1;
pszFormattedState = Malloc( cch * sizeof(TCHAR) );
if (pszFormattedState)
{
apszArgs[ 0 ] = pszArg;
*pszFormattedState = TEXT('\0');
FormatMessage(
FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszState, 0, 0, pszFormattedState, cch,
(va_list* )apszArgs );
Free( pszState );
pszState = pszFormattedState;
}
}
TRACE1("DpEvent:State:'%s'",pszState);
if (pszState)
{
SetWindowText( pInfo->hwndStState, pszState );
InvalidateRect( pInfo->hwndStState, NULL, TRUE );
UpdateWindow( pInfo->hwndStState );
LocalFree( pszState );
}
}
}
if (pState->state & RASCS_PAUSED)
{
// Paused state just processed. Release the callback, and dial again
// to resume.
//
TRACE("DpEvent:Paused, will dial again\nthe global callbacks wont init again");
TRACE( "Post(DIAL)" );
PostMessage( pInfo->hwndDlg, WM_RASDIAL, TRUE, 0 );
return dwCode;
}
if (pState->state & RASCS_DONE)
{
// Terminal state just processed.
//
if (pState->state == RASCS_Connected)
{
// For multi-link entries, if there is at least one successful
// line and at least one failed line, popup the bundling error
// dialog.
//
if (pInfo->cStates > 1)
{
DPSTATE* p;
dwcSuccessLinks = dwcFailedLinks = 0;
for (i = 0, p = pInfo->pStates; i < pInfo->cStates; ++i, ++p)
{
if (p->dwError == 0)
{
++dwcSuccessLinks;
}
else
{
++dwcFailedLinks;
}
}
if (dwcSuccessLinks > 0 && dwcFailedLinks > 0)
{
TRACE( "Post(BUNDLEERROR)" );
PostMessage( pInfo->hwndDlg,
WM_RASBUNDLEERROR, 0, (LPARAM )pState );
return 0;
}
}
EndDialog( pInfo->hwndDlg, TRUE );
}
else
{
DpCancel( pInfo );
}
return 0;
}
TRACE1("DpEvent:returned dwCode:(%d)", dwCode);
TRACE("End of DpEvent");
return dwCode;
}
BOOL
DpInit(
IN HWND hwndDlg,
IN DINFO* pArgs )
// Called on WM_INITDIALOG. 'hwndDlg' is the handle of the owning window.
// 'PArgs' is caller's arguments as passed to the stub API.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
DWORD dwErr;
DPINFO* pInfo;
PBENTRY* pEntry;
TRACE( "DpInit" );
// Allocate the dialog context block. Initialize minimally for proper
// cleanup, then attach to the dialog window.
//
{
pInfo = Malloc( sizeof(*pInfo) );
if (!pInfo)
{
ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
EndDialog( hwndDlg, FALSE );
return TRUE;
}
ZeroMemory( pInfo, sizeof(*pInfo) );
pInfo->dwValid = 0xC0BBC0DE;
pInfo->pArgs = pArgs;
pInfo->hwndDlg = hwndDlg;
//Add a per-thread Terminate flag for whistler bug 291613 gangz
//
pInfo->fTerminateAsap = FALSE;
pInfo->ulCallbacksActive = 0;
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
TRACE( "Context set" );
}
pInfo->hwndStState = GetDlgItem( hwndDlg, CID_DP_ST_State );
ASSERT( pInfo->hwndStState );
pEntry = pArgs->pEntry;
// Set up our context to be returned by the RasDialFunc2 callback.
//
pInfo->pArgs->rdp.dwCallbackId = (ULONG_PTR )pInfo;
// Subclass the dialog so we can get the result from
// SendMessage(WM_RASDIALEVENT) in RasDlgFunc2.
//
pInfo->pOldWndProc =
(WNDPROC )SetWindowLongPtr(
pInfo->hwndDlg, GWLP_WNDPROC, (ULONG_PTR )DpWndProc );
// Set the title.
//
{
TCHAR* pszTitleFormat;
TCHAR* pszTitle;
TCHAR* apszArgs[ 1 ];
pszTitleFormat = GetText( hwndDlg );
if (pszTitleFormat)
{
apszArgs[ 0 ] = pEntry->pszEntryName;
pszTitle = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszTitleFormat, 0, 0, (LPTSTR )&pszTitle, 1,
(va_list* )apszArgs );
Free( pszTitleFormat );
if (pszTitle)
{
SetWindowText( hwndDlg, pszTitle );
LocalFree( pszTitle );
}
}
}
// Set the correct icon. For whistler bug 372078 gangz
//
SetIconFromEntryType(
GetDlgItem( hwndDlg, CID_DP_Icon ),
pArgs->pEntry->dwType,
FALSE); //FALSE means large Icon
// Position the dialog per caller's instructions.
//
PositionDlg( hwndDlg,
pArgs->pArgs->dwFlags & RASDDFLAG_PositionDlg,
pArgs->pArgs->xDlg, pArgs->pArgs->yDlg );
// Hide the dialog if "no progress" user preference is set.
//
if (!pArgs->pEntry->fShowDialingProgress
|| pArgs->fDialForReferenceOnly)
{
SetOffDesktop( hwndDlg, SOD_MoveOff, NULL );
}
SetForegroundWindow( hwndDlg );
// Allocate subentry status array. It's initialized by DpDial.
//
{
DWORD cb;
ASSERT( pEntry->pdtllistLinks );
pInfo->cStates = DtlGetNodes( pEntry->pdtllistLinks );
cb = sizeof(DPSTATE) * pInfo->cStates;
pInfo->pStates = Malloc( cb );
if (!pInfo->pStates)
{
ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
EndDialog( hwndDlg, FALSE );
return TRUE;
}
pInfo->dwRedialAttemptsLeft =
GetOverridableParam(
pInfo->pArgs->pUser, pInfo->pArgs->pEntry,
RASOR_RedialAttempts );
}
//for whistler bug 316622 gangz
//The dwSubEntry is not initialized
//
pInfo->pArgs->rdp.dwSubEntry = pInfo->pArgs->pArgs->dwSubEntry;
// Rock and roll.
//
DpDial( pInfo, FALSE );
return TRUE;
}
VOID
DpInitStates(
DPINFO* pInfo )
// Resets 'pInfo->pStates' to initial values. 'PInfo' is the dialog
// context.
//
{
DWORD i;
DPSTATE* pState;
for (i = 0, pState = pInfo->pStates; i < pInfo->cStates; ++i, ++pState)
{
ZeroMemory( pState, sizeof(*pState) );
pInfo->state = (RASCONNSTATE )-1;
pState->dwError = 0;
}
}
BOOL
DpInteractive(
IN DPINFO* pInfo,
IN DPSTATE* pState,
OUT BOOL* pfChange )
// RASCS_Interactive handling. 'PInfo' is the dialog context. 'PState'
// is the subentry state. '*pfChange' is set true if the entry (i.e. SLIP
// address) was changed or false otherwise.
//
// Returns true if successful, false if cancel.
//
{
DWORD dwErr;
DWORD sidTitle;
TCHAR szIpAddress[ TERM_IpAddress ];
TCHAR* pszIpAddress;
PBENTRY* pEntry;
TRACE( "DpInteractive" );
*pfChange = FALSE;
pEntry = pInfo->pArgs->pEntry;
if (pEntry->dwBaseProtocol == BP_Slip)
{
lstrcpyn(
szIpAddress,
(pEntry->pszIpAddress) ? pEntry->pszIpAddress : TEXT("0.0.0.0"),
sizeof(szIpAddress) / sizeof(TCHAR));
pszIpAddress = szIpAddress;
sidTitle = SID_T_SlipTerminal;
}
else
{
szIpAddress[0] = TEXT('\0');
pszIpAddress = szIpAddress;
sidTitle =
(pState->sidState == SID_S_ConnectPreSwitch)
? SID_T_PreconnectTerminal
: (pState->sidState == SID_S_ConnectPostSwitch)
? SID_T_PostconnectTerminal
: SID_T_ManualDialTerminal;
}
if(1 == pEntry->dwCustomScript)
{
DWORD dwErr = SUCCESS;
dwErr = DwCustomTerminalDlg(
pInfo->pArgs->pFile->pszPath,
pInfo->hrasconn,
pEntry,
pInfo->hwndDlg,
&pInfo->pArgs->rdp,
NULL);
if(SUCCESS == dwErr)
{
#if 0
//
// Reread the phonebook file since the
// custom script could have written
// new information to the file.
//
ClosePhonebookFile(pInfo->pArgs->pFile);
dwErr = ReadPhonebookFile(
pInfo->pArgs->pszPhonebook,
&pInfo->pArgs->user,
NULL, 0, &pInfo->pArgs->file );
if(SUCCESS == dwErr)
{
pInfo->pArgs->pFile = &pInfo->pArgs->file;
}
#endif
}
if (dwErr != 0)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_ScriptHalted, dwErr, NULL );
}
return (ERROR_SUCCESS == dwErr);
}
if (!TerminalDlg(
pInfo->pArgs->pEntry, &pInfo->pArgs->rdp, pInfo->hwndDlg,
pState->hrasconnLink, sidTitle, pszIpAddress ))
{
TRACE( "TerminalDlg==FALSE" );
return FALSE;
}
TRACE2( "pszIpAddress=0x%08x(%ls)", pszIpAddress,
pszIpAddress ? pszIpAddress : TEXT("") );
TRACE2( "pEntry->pszIpAddress=0x%08x(%ls)", pEntry->pszIpAddress,
pEntry->pszIpAddress ? pEntry->pszIpAddress : TEXT("") );
if (pszIpAddress[0]
&& (!pEntry->pszIpAddress
|| lstrcmp( pszIpAddress, pEntry->pszIpAddress ) != 0))
{
Free0( pEntry->pszIpAddress );
pEntry->pszIpAddress = StrDup( szIpAddress );
pEntry->fDirty = TRUE;
*pfChange = TRUE;
dwErr = WritePhonebookFile( pInfo->pArgs->pFile, NULL );
if (dwErr != 0)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_WritePhonebook, dwErr, NULL );
}
}
pState->sidState = 0;
return TRUE;
}
BOOL
DpIsLaterState(
IN RASCONNSTATE stateNew,
IN RASCONNSTATE stateOld )
// Returns true if 'stateNew' is farther along in the connection than
// 'stateOld' false if the same or not as far along.
//
{
// This array is in the order events normally occur.
//
// !!! New EAP states?
//
static RASCONNSTATE aState[] =
{
(RASCONNSTATE )-1,
RASCS_OpenPort,
RASCS_PortOpened,
RASCS_ConnectDevice,
RASCS_DeviceConnected,
RASCS_Interactive,
RASCS_AllDevicesConnected,
RASCS_StartAuthentication,
RASCS_Authenticate,
RASCS_InvokeEapUI,
RASCS_AuthNotify,
RASCS_AuthRetry,
RASCS_AuthAck,
RASCS_PasswordExpired,
RASCS_AuthChangePassword,
RASCS_AuthCallback,
RASCS_CallbackSetByCaller,
RASCS_PrepareForCallback,
RASCS_WaitForModemReset,
RASCS_WaitForCallback,
RASCS_CallbackComplete,
RASCS_RetryAuthentication,
RASCS_ReAuthenticate,
RASCS_Authenticated,
RASCS_AuthLinkSpeed,
RASCS_AuthProject,
RASCS_Projected,
RASCS_LogonNetwork,
RASCS_SubEntryDisconnected,
RASCS_SubEntryConnected,
RASCS_Disconnected,
RASCS_Connected,
(RASCONNSTATE )-2,
};
RASCONNSTATE* pState;
for (pState = aState; *pState != (RASCONNSTATE )-2; ++pState)
{
if (*pState == stateNew)
{
return FALSE;
}
else if (*pState == stateOld)
{
return TRUE;
}
}
return FALSE;
}
BOOL
DpPasswordExpired(
IN DPINFO* pInfo,
IN DPSTATE* pState )
// RASCS_PasswordExpired state handling. 'PInfo' is the dialog context.
// 'PState' is the subentry state.
//
// Returns true if successful, false otherwise.
//
{
TCHAR szOldPassword[ PWLEN + 1 ];
BOOL fSuppliedOldPassword;
TRACE( "DpPasswordExpired" );
szOldPassword[ 0 ] = TEXT('\0');
// Stash "good" username and password which are restored if the password
// change fails.
//
pInfo->pszGoodUserName = StrDup( pInfo->pArgs->rdp.szUserName );
// Whistler bug 254385 encode password when not being used
// Assumed password was encoded previously
//
DecodePassword( pInfo->pArgs->rdp.szPassword );
pInfo->pszGoodPassword = StrDup( pInfo->pArgs->rdp.szPassword );
EncodePassword( pInfo->pArgs->rdp.szPassword );
EncodePassword( pInfo->pszGoodPassword );
fSuppliedOldPassword =
(!pInfo->pArgs->pEntry->fAutoLogon || pInfo->pArgs->pNoUser);
if (!ChangePasswordDlg(
pInfo->hwndDlg, !fSuppliedOldPassword,
szOldPassword, pInfo->pArgs->rdp.szPassword ))
{
// Whistler bug 254385 encode password when not being used
//
ZeroMemory( szOldPassword, sizeof(szOldPassword) );
return FALSE;
}
if (pInfo->pArgs->pNoUser)
{
// Whistler bug 254385 encode password when not being used
// Assumed password was encoded previously
//
DecodePassword( pInfo->pArgs->rdp.szPassword );
lstrcpyn(
pInfo->pArgs->pNoUser->szPassword,
pInfo->pArgs->rdp.szPassword,
PWLEN + 1);
EncodePassword( pInfo->pArgs->rdp.szPassword );
EncodePassword( pInfo->pArgs->pNoUser->szPassword );
*pInfo->pArgs->pfNoUserChanged = TRUE;
}
// The old password (in text form) is explicitly set, since in AutoLogon
// case a text form has not yet been specified. The old password in text
// form is required to change the password. The "old" private API expects
// an ANSI argument.
//
if (!fSuppliedOldPassword)
{
// Whistler bug 254385 encode password when not being used
// Assumed password was encoded by ChangePasswordDlg()
//
CHAR* pszOldPasswordA;
DecodePassword( szOldPassword );
pszOldPasswordA = StrDupAFromT( szOldPassword );
if (pszOldPasswordA)
{
ASSERT( g_pRasSetOldPassword );
g_pRasSetOldPassword( pInfo->hrasconn, pszOldPasswordA );
ZeroMemory( pszOldPasswordA, lstrlenA( pszOldPasswordA ) );
Free( pszOldPasswordA );
}
}
ZeroMemory( szOldPassword, sizeof(szOldPassword) );
if (pInfo->pArgs->rdp.szUserName[ 0 ] == TEXT('\0'))
{
// Explicitly set the username, effectively turning off AutoLogon for
// the "resume" password authentication, where the new password should
// be used.
//
lstrcpyn( pInfo->pArgs->rdp.szUserName, GetLogonUser(), UNLEN + 1 );
}
pState->sidState = 0;
return TRUE;
}
BOOL
DpProjected(
IN DPINFO* pInfo,
IN DPSTATE* pState )
// RASCS_Projected state handling. 'PInfo' is the dialog context.
// 'PState' is the subentry state.
//
// Returns true if successful, false otherwise.
//
{
DWORD dwErr;
RASAMB amb;
RASPPPNBF nbf;
RASPPPIPX ipx;
RASPPPIP ip;
RASPPPLCP lcp;
RASSLIP slip;
RASPPPCCP ccp;
BOOL fIncomplete;
DWORD dwfProtocols;
TCHAR* pszLines;
TRACE( "DpProjected" );
pState->sidState = SID_S_Projected;
//
// If PORT_NOT_OPEN is indicated, it probably means that the
// server disconnected the connection before result dialog
// was dismissed. In that case, this is the 2nd time DpProjected
// is called. This time, the error is indicated by ras and the
// state remains "projected".
//
// We need to return an error in this case so that the connection
// isn't hung since this is the last indication RAS will give us.
//
// See bug 382254
//
TRACE1("DpProjected: dwErr:(%d)", pState->dwError);
if ( (pState->dwError == ERROR_PORT_NOT_OPEN) ||
(pState->dwError == ERROR_NO_CONNECTION) ) //See bug 169111 whistler
{
return FALSE;
}
// Do this little dance to ignore the error that comes back from the
// "all-failed" projection since we detect this in the earlier
// notification where pState->dwError == 0. This avoids a race where the
// API comes back with the error before we can hang him up. This race
// would not occur if we called RasHangUp from within the callback thread
// (as recommended in our API doc). It's the price we pay for posting the
// error to the other thread in order to avoid holding the port open while
// an error dialog is up.
//
else if (pState->dwError != 0)
{
pState->dwError = 0;
DpCallbacksFlag( pInfo, 0 );
return TRUE;
}
// Read projection info for all protocols, translating "not requested"
// into an in-structure code for later reference.
//
dwErr = GetRasProjectionInfo(
pState->hrasconnLink, &amb, &nbf, &ip, &ipx, &lcp, &slip, &ccp );
if (dwErr != 0)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_RasGetProtocolInfo, dwErr, NULL );
return FALSE;
}
if (amb.dwError != ERROR_PROTOCOL_NOT_CONFIGURED)
{
// It's an AMB projection.
//
if (amb.dwError != 0)
{
// Translate AMB projection errors into regular error codes. AMB
// does not use the special PPP projection error mechanism.
//
pState->dwError = amb.dwError;
lstrcpyn(
pState->szExtendedError,
amb.szNetBiosError,
sizeof(pState->szExtendedError) / sizeof(TCHAR));
}
return TRUE;
}
// At this point, all projection information has been gathered
// successfully and we know it's a PPP-based projection. Now analyze the
// projection results...
//
dwfProtocols = 0;
fIncomplete = FALSE;
if (DpProjectionError(
&nbf, &ipx, &ip,
&fIncomplete, &dwfProtocols, &pszLines, &pState->dwError ))
{
// A projection error occurred.
//
if (fIncomplete)
{
BOOL fStatus;
BOOL fDisable;
// An incomplete projection occurred, i.e. some requested CPs
// connected and some did not. Ask the user if what worked is
// good enough or he wants to bail.
//
pState->dwError = 0;
fDisable = FALSE;
fStatus = ProjectionResultDlg(
pInfo->hwndDlg, pszLines, &fDisable );
Free( pszLines );
if (fDisable)
{
pInfo->pArgs->dwfExcludedProtocols = dwfProtocols;
}
// Return now if user chose to hang up.
//
if (!fStatus)
{
return FALSE;
}
}
else
{
// All CPs in the projection failed. Process as a regular fatal
// error with 'pState->dwError' set to the first error in NBF, IP,
// or IPX, but with a format that substitutes the status argument
// for the "Error nnn: Description" text. This lets us patch in
// the special multiple error projection text, while still giving
// a meaningful help context.
//
Free0( pState->pszFormatArg );
pState->pszFormatArg = pszLines;
pState->sidFormatMsg = SID_FMT_ErrorMsgProject;
}
}
//
// pmay: 190394
//
// If the admin has a message, display it.
//
if ( (pState->dwError == NO_ERROR) &&
(wcslen (lcp.szReplyMessage) != 0)
)
{
MSGARGS MsgArgs, *pMsgArgs = &MsgArgs;
ZeroMemory(pMsgArgs, sizeof(MSGARGS));
pMsgArgs->dwFlags = MB_OK | MB_ICONINFORMATION;
pMsgArgs->apszArgs[0] = lcp.szReplyMessage;
//MsgDlg(
// pInfo->hwndDlg,
// SID_ReplyMessageFmt,
// pMsgArgs);
}
pState->sidState = SID_S_Projected;
return TRUE;
}
BOOL
DpProjectionError(
IN RASPPPNBF* pnbf,
IN RASPPPIPX* pipx,
IN RASPPPIP* pip,
OUT BOOL* pfIncomplete,
OUT DWORD* pdwfFailedProtocols,
OUT TCHAR** ppszLines,
OUT DWORD* pdwError )
// Figure out if a projection error occurred and, if so, build the
// appropriate status/error text lines into '*ppszLines'. '*PfIncomlete'
// is set true if at least one CP succeeded and at least one failed.
// '*pdwfFailedProtocols' is set to the bit mask of NP_* that failed.
// '*pdwError' is set to the first error that occurred in NBF, IP, or IPX
// in that order or 0 if none. 'pnbf', 'pipx', and 'pip' are projection
// information for the respective protocols with dwError set to
// ERROR_PROTOCOL_NOT_CONFIGURED if the protocols was not requested.
//
// This routine assumes that at least one protocol was requested.
//
// Returns true if a projection error occurred, false if not. It's
// caller's responsiblity to free '*ppszLines'.
//
{
#define MAXPROJERRLEN 1024
TCHAR szLines[ MAXPROJERRLEN ];
BOOL fIp = (pip->dwError != ERROR_PROTOCOL_NOT_CONFIGURED);
BOOL fIpx = (pipx->dwError != ERROR_PROTOCOL_NOT_CONFIGURED);
BOOL fNbf = (pnbf->dwError != ERROR_PROTOCOL_NOT_CONFIGURED);
BOOL fIpBad = (fIp && pip->dwError != 0);
BOOL fIpxBad = (fIpx && pipx->dwError != 0);
BOOL fNbfBad = (fNbf && pnbf->dwError != 0);
TRACE( "DpProjectionError" );
*pdwfFailedProtocols = 0;
if (!fNbfBad && !fIpxBad && !fIpBad)
{
return FALSE;
}
if (fNbfBad)
{
*pdwfFailedProtocols |= NP_Nbf;
}
if (fIpxBad)
{
*pdwfFailedProtocols |= NP_Ipx;
}
if (fIpBad)
{
*pdwfFailedProtocols |= NP_Ip;
}
*pfIncomplete =
((fIp && pip->dwError == 0)
|| (fIpx && pipx->dwError == 0)
|| (fNbf && pnbf->dwError == 0));
szLines[ 0 ] = 0;
*ppszLines = NULL;
*pdwError = 0;
if (fIpBad || (*pfIncomplete && fIp))
{
if (fIpBad)
{
*pdwError = pip->dwError;
DpAppendConnectErrorLine( szLines, SID_Ip, pip->dwError );
}
else
{
DpAppendConnectOkLine( szLines, SID_Ip );
}
DpAppendBlankLine( szLines );
}
if (fIpxBad || (*pfIncomplete && fIpx))
{
if (fIpxBad)
{
*pdwError = pipx->dwError;
DpAppendConnectErrorLine( szLines, SID_Ipx, pipx->dwError );
}
else
{
DpAppendConnectOkLine( szLines, SID_Ipx );
}
DpAppendBlankLine( szLines );
}
if (fNbfBad || (*pfIncomplete && fNbf))
{
if (fNbfBad)
{
*pdwError = pnbf->dwError;
DpAppendConnectErrorLine( szLines, SID_Nbf, pnbf->dwError );
if (pnbf->dwNetBiosError)
{
DpAppendFailCodeLine( szLines, pnbf->dwNetBiosError );
}
if (pnbf->szNetBiosError[ 0 ] != '\0')
{
DpAppendNameLine( szLines, pnbf->szNetBiosError );
}
}
else
{
DpAppendConnectOkLine( szLines, SID_Nbf );
}
DpAppendBlankLine( szLines );
}
*ppszLines = StrDup( szLines );
return TRUE;
}
DWORD WINAPI
DpRasDialFunc2(
ULONG_PTR dwCallbackId,
DWORD dwSubEntry,
HRASCONN hrasconn,
UINT unMsg,
RASCONNSTATE state,
DWORD dwError,
DWORD dwExtendedError )
// RASDIALFUNC2 callback to receive RasDial events.
//
// Returns 0 to stop callbacks, 1 to continue callbacks (normal), and 2 to
// tell RAS API that relevant entry information (like SLIP IP address) has
// changed.
//
{
DWORD dwErr;
DWORD dwCode;
DPINFO* pInfo;
DPSTATE* pState;
BOOL fTerminateAsap;
TRACE4( "/DpRasDialFunc2(rcs=%d,s=%d,e=%d,x=%d)",
state, dwSubEntry, dwError, dwExtendedError );
pInfo = (DPINFO* )dwCallbackId;
if (pInfo->dwValid != 0xC0BBC0DE)
{
TRACE( "DpRasDialFunc2 returns for Late callback?" );
return 0;
}
if (dwSubEntry == 0 || dwSubEntry > pInfo->cStates)
{
TRACE( "DpRasDialFunc2 returns for Subentry out of range?" );
return 1;
}
pState = &pInfo->pStates[ dwSubEntry - 1 ];
pState->state = state;
pState->dwError = dwError;
pState->dwExtendedError = dwExtendedError;
// Post the event to the Dial Progress window and wait for it to be
// processed before returning. This avoids subtle problems with Z-order
// and focus when a window is manipulated from two different threads.
//
TRACE1("Send RasEvent to Dial Progress window, subEntry:(%d)", dwSubEntry);
TRACE1("Get dwError=(%d) from RasMan",pState->dwError);
TRACE2("DpRasDialFunc2:Process:(%x),Thread(%x)",
GetCurrentProcessId,
GetCurrentThreadId);
TRACE2("DpRasDialFunc2:pInfo address (0x%x), Dialog Handle (0x%x)",
pInfo,
pInfo->hwndDlg);
dwCode = (DWORD)SendMessage( pInfo->hwndDlg, WM_RASEVENT, dwSubEntry, 0 );
TRACE1( "\\DpRasDialFunc2: dwCode from SendMessage()=%d", dwCode );
TRACE1("dwCode returned:(%d)", dwCode);
// When callback function DpRasDialFunc2() returns 0, then RasMan wont
//call it again, so we wont return 0 unless all the message returned from
//RasMan has been processed for whislter bug 291613 gangz
//
{
long ulCallbacksActive;
//Check if current thread wants to terminate itself
//
ulCallbacksActive = DpOnOffPerThreadTerminateFlag(pInfo, -1, &fTerminateAsap );
TRACE1("Current thread's active:(%d)", ulCallbacksActive);
if ( fTerminateAsap )
{
//decrease pInfo->ulCallbacksActive and g_ulCallbacksActive
//if necessary
//
TRACE("Current Thread wants to terminate itself, its fterminateASSP=1!");
TRACE("Current thread will decrease its own and global active!");
DpCallbacksFlag( pInfo, 0 );
//reset per-thread terminateASAP flag
//
DpOnOffPerThreadTerminateFlag(pInfo, 0, NULL );
}
else
{
TRACE("Current Thread does NOT want to terminate itself,its fterminateASAP=0!");
}
//return the global number of active callbacks
//
ulCallbacksActive = CallbacksActive( -1, NULL );
TRACE1( "\\DpRasDialFunc2:g_ulCallbacksActive=%ld", ulCallbacksActive );
//if g_ulCallbacksActive is already zero, we must return 0 to RasMan
//
{
TRACE1("Global active:(%d)", ulCallbacksActive);
TRACE1("Current thread's active:(%d)",
DpOnOffPerThreadTerminateFlag(pInfo, -1, NULL ) );
}
if ( 0 == ulCallbacksActive )
{
if ( 0 == DpOnOffPerThreadTerminateFlag(pInfo, -1, NULL ) )
{
TRACE( "Will terminate Callbacks " );
dwCode = 0;
}
else
{
//For whistler bug 341662 366237 gangz
//Something messed up the g_ulCallbacksActive flag
// Now that g_ulCallbacksActive is 0, DpCallbacksFlag( pInfo, 0 ) wont
// decrease it now, it only decrease pInfo->ulCallbacksActive by 1
TRACE("ReSync accured!");
DpCallbacksFlag( pInfo, 0 );
//then call DpCallbacksFlag( pInfo, 1 ); to increase both the global
// callbacks active flag g_ulCallbacksActive and per thread
// pInfo->ulCallbacksActive
//
DpCallbacksFlag( pInfo, 1 );
}
}
else if ( 0 == dwCode )
{
//Other callbacks are still active, wait for them
//
dwCode = 1;
//Clear current pInfo->ulCallbacksActive if necessary when
//this dwCode is returned by SendMessage() at above
//
TRACE("Other callbacks are still active, wait for them");
TRACE("Just Clear current pInfo->ulCallbacksActive\n");
DpCallbacksFlag( pInfo, 0 );
//After cleared current pInfo->ulCallbacksActive, if the number
//of active callbacks becomes zero, then we should return 0 to RasMan
//
ulCallbacksActive = CallbacksActive( -1, &fTerminateAsap );
TRACE1( "\\DpRasDialFunc2:g_ulCallbacksActive after clearing cur-thread =%ld", ulCallbacksActive );
if ( 0 == ulCallbacksActive )
{
TRACE( "Will terminate Callbacks " );
dwCode = 0;
}
}
}
if (dwCode == 0)
{
// Set thread-safe flag indicating callbacks have terminated.
//
DpCallbacksFlag( pInfo, 0 );
}
// Note: If 'dwCode' is 0, the other thread is racing to terminate the
// dialog. Must not dereference 'pInfo' in this case.
TRACE1( "\\DpRasDialFunc2:final dwCode returned=%d", dwCode );
return dwCode;
}
VOID
DpTerm(
IN HWND hwndDlg )
// Called on WM_DESTROY. 'HwndDlg' is that handle of the dialog window.
//
{
DPINFO* pInfo = (DPINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER );
TRACE( "DpTerm" );
if (pInfo)
{
if (pInfo->pOldWndProc)
{
SetWindowLongPtr( pInfo->hwndDlg,
GWLP_WNDPROC, (ULONG_PTR )pInfo->pOldWndProc );
}
Free0( pInfo->pStates );
pInfo->dwValid = 0;
Free( pInfo );
}
//For whistler bug 372078 gangz
//
{
HICON hIcon=NULL;
hIcon = (HICON)SendMessage( GetDlgItem( hwndDlg, CID_DP_Icon ),
STM_GETICON,
0,
0);
ASSERT(hIcon);
if( hIcon )
{
DestroyIcon(hIcon);
}
else
{
TRACE("DpTerm:Destroy Icon failed");
}
}
}
LRESULT APIENTRY
DpWndProc(
HWND hwnd,
UINT unMsg,
WPARAM wParam,
LPARAM lParam )
// Subclassed dialog window procedure.
//
{
DPINFO* pInfo = (DPINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
if (unMsg == WM_RASEVENT)
{
return DpEvent( pInfo, (DWORD )wParam );
}
return
CallWindowProc(
pInfo->pOldWndProc, hwnd, unMsg, wParam, lParam );
}
//----------------------------------------------------------------------------
// Dialer dialogs
// Listed alphabetically following stub API and dialog proc
//----------------------------------------------------------------------------
BOOL
DialerDlg(
IN HWND hwndOwner,
IN OUT DINFO* pInfo )
// Determine if it's necessary, and if so, popup one of the variations of
// the dialer dialog, i.e. the prompter for user/password/domain, phone
// number, and location. 'HwndOwner' is the owning window. 'PInfo' is
// the dial dialog common context.
//
// Returns true if no dialog is needed or user chooses OK.
//
{
INT_PTR nStatus = FALSE;
int nDid;
DWORD dwfMode;
DRARGS args;
TRACE( "DialerDlg" );
do
{
dwfMode = 0;
if (!pInfo->pEntry->fAutoLogon
&& pInfo->pEntry->fPreviewUserPw
&& (!(pInfo->pArgs->dwFlags & RASDDFLAG_NoPrompt)
|| (pInfo->fUnattended && !HaveSavedPw( pInfo ))))
{
dwfMode |= DR_U;
if (pInfo->pEntry->fPreviewDomain)
{
dwfMode |= DR_D;
}
}
if (pInfo->pEntry->fPreviewPhoneNumber
&& (!(pInfo->pArgs->dwFlags & RASDDFLAG_NoPrompt)
|| (pInfo->fUnattended && !HaveSavedPw( pInfo ))))
{
DTLNODE* pNode;
PBLINK* pLink;
dwfMode |= DR_N;
// Location controls mode only when at least one phone number in
// the list is TAPI-enabled.
//
pNode = DtlGetFirstNode( pInfo->pEntry->pdtllistLinks );
pLink = (PBLINK* )DtlGetData( pNode );
for (pNode = DtlGetFirstNode( pLink->pdtllistPhones );
pNode;
pNode = DtlGetNextNode( pNode ))
{
PBPHONE* pPhone = (PBPHONE* )DtlGetData( pNode );
if (pPhone->fUseDialingRules)
{
dwfMode |= DR_L;
break;
}
}
}
// Customize the dialing flags for the type of eap authentication
// specified for this entry (if any)
if (DialerEapAssignMode(pInfo, &dwfMode) != NO_ERROR)
break;
if (dwfMode == DR_U)
{
nDid = DID_DR_DialerU;
}
else if (dwfMode == (DR_U | DR_D))
{
nDid = DID_DR_DialerUD;
}
else if (dwfMode == (DR_U | DR_N))
{
nDid = DID_DR_DialerUN;
}
else if (dwfMode == (DR_U | DR_N | DR_L))
{
nDid = DID_DR_DialerUNL;
}
else if (dwfMode == (DR_U | DR_D | DR_N))
{
nDid = DID_DR_DialerUDN;
}
else if (dwfMode == (DR_U | DR_D | DR_N | DR_L))
{
nDid = DID_DR_DialerUDNL;
}
else if (dwfMode == DR_N)
{
nDid = DID_DR_DialerN;
}
else if (dwfMode == (DR_N | DR_L))
{
nDid = DID_DR_DialerNL;
}
else if (dwfMode == DR_I) {
nDid = DID_DR_DialerI;
}
else if (dwfMode == (DR_I | DR_N)) {
nDid = DID_DR_DialerIN;
}
else if (dwfMode == (DR_I | DR_N | DR_L)) {
nDid = DID_DR_DialerINL;
}
// pmay: The following 3 permutations of the
// dialer dialog were added for bug 183577 which
// states that eap modules (that use DR_I) want to
// have the domain field available to them as well.
else if (dwfMode == (DR_I | DR_D)) {
nDid = DID_DR_DialerID;
}
else if (dwfMode == (DR_I | DR_D | DR_N)) {
nDid = DID_DR_DialerIDN;
}
else if (dwfMode == (DR_I | DR_D | DR_N | DR_L)) {
nDid = DID_DR_DialerIDNL;
}
else
{
ASSERT( dwfMode == 0 );
return TRUE;
}
args.pDinfo = pInfo;
args.dwfMode = dwfMode;
args.fReload = FALSE;
nStatus =
(BOOL )DialogBoxParam(
g_hinstDll,
MAKEINTRESOURCE( nDid ),
hwndOwner,
DrDlgProc,
(LPARAM )&args );
if (nStatus == -1)
{
ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
nStatus = FALSE;
}
}
while (args.fReload);
return (BOOL )nStatus;
}
INT_PTR CALLBACK
DrDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the dialer dialogs. Parameters and return
// value are as described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "DrDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
switch (unMsg)
{
case WM_INITDIALOG:
{
return DrInit( hwnd, (DRARGS* )lparam );
}
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp( g_adwDrHelp, hwnd, unMsg, wparam, lparam );
break;
}
case WM_COMMAND:
{
DRINFO* pInfo = (DRINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
return DrCommand(
pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
case WM_DESTROY:
{
DrTerm( hwnd );
break;
}
}
return FALSE;
}
VOID
DrGetFriendlyFont(
IN HWND hwnd,
IN BOOL fUpdate,
OUT HFONT* phFont )
// Whistler bug: 195480 Dial-up connection dialog - Number of asterisks
// does not match the length of the password and causes confusion
//
{
LOGFONT BoldLogFont;
HFONT hFont;
HDC hdc;
*phFont = NULL;
// Get the font used by the specified window
//
hFont = (HFONT)SendMessage( hwnd, WM_GETFONT, 0, 0L );
if (NULL == hFont)
{
// If not found then the control is using the system font
//
hFont = (HFONT)GetStockObject( SYSTEM_FONT );
}
if (hFont && GetObject( hFont, sizeof(BoldLogFont), &BoldLogFont ))
{
if (fUpdate)
{
BoldLogFont.lfItalic = TRUE;
}
hdc = GetDC( hwnd );
if (hdc)
{
*phFont = CreateFontIndirect( &BoldLogFont );
ReleaseDC( hwnd, hdc );
}
}
return;
}
DWORD
DrEnableDisablePwControls(
IN DRINFO* pInfo,
IN BOOL fEnable )
{
if (pInfo->pArgs->pDinfo->fIsPublicPbk)
{
EnableWindow( pInfo->hwndRbSaveForEveryone, fEnable );
}
else
{
EnableWindow( pInfo->hwndRbSaveForEveryone, FALSE );
}
EnableWindow( pInfo->hwndRbSaveForMe, fEnable );
return NO_ERROR;
}
VOID
DrClearFriendlyPassword(
IN DRINFO* pInfo,
IN BOOL fFocus )
{
SetWindowText( pInfo->hwndEbPw, L"" );
if (fFocus)
{
SendMessage( pInfo->hwndEbPw, EM_SETPASSWORDCHAR,
pInfo->szPasswordChar, 0 );
if (pInfo->hNormalFont)
{
SendMessage(
pInfo->hwndEbPw,
WM_SETFONT,
(WPARAM)pInfo->hNormalFont,
MAKELPARAM(TRUE, 0) );
}
SetFocus( pInfo->hwndEbPw );
}
return;
}
VOID
DrDisplayFriendlyPassword(
IN DRINFO* pInfo,
IN TCHAR* pszFriendly )
{
if (pszFriendly)
{
SendMessage( pInfo->hwndEbPw, EM_SETPASSWORDCHAR, 0, 0 );
SetWindowText( pInfo->hwndEbPw, pszFriendly );
}
else
{
SetWindowText( pInfo->hwndEbPw, L"" );
}
if (pInfo->hItalicFont)
{
SendMessage(
pInfo->hwndEbPw,
WM_SETFONT,
(WPARAM)pInfo->hItalicFont,
MAKELPARAM(TRUE, 0) );
}
return;
}
BOOL
DrIsPasswordStyleEnabled(
IN HWND hWnd )
{
return SendMessage( hWnd, EM_GETPASSWORDCHAR, 0, 0 ) ? TRUE : FALSE;
}
BOOL
DrCommand(
IN DRINFO* pInfo,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'PInfo' is the dialog context. 'WNotification'
// is the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
DWORD dwErr;
TRACE3( "DrCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
switch (wId)
{
case CID_DR_CLB_Numbers:
{
if (wNotification == CBN_SELCHANGE)
{
DrNumbersSelChange( pInfo );
return TRUE;
}
break;
}
case CID_DR_CB_SavePassword:
{
BOOL fEnable = Button_GetCheck( hwndCtrl );
DrEnableDisablePwControls( pInfo, fEnable );
DrPopulatePasswordField( pInfo, FALSE, FALSE );
return TRUE;
}
// Whistler bug: 195480 Dial-up connection dialog - Number of asterisks
// does not match the length of the password and causes confusion
//
case CID_DR_EB_Password:
{
// This is a hack really so that we restore the Tab Stop to the
// username field. The reason it had to be removed was because we
// were receiving complaints that the focus shouldn't always go to
// the username field if it's non-null. The only way to fix this,
// since windows sets the initial focus to the first visible non-
// hidden tab stopped field, is to remove the tab stop temporarily
// from the username field.
//
if (wNotification == EN_KILLFOCUS)
{
LONG lStyle = GetWindowLong( pInfo->hwndEbUser, GWL_STYLE );
if (!(lStyle & WS_TABSTOP))
{
// If we detect tap stop removed from the username field,
// restore it. Since this case only fires when the password
// was not previously saved on init, we can return here.
//
SetWindowLong( pInfo->hwndEbUser, GWL_STYLE,
lStyle | WS_TABSTOP );
return TRUE;
}
// If the user leaves the password field w/o typing a new
// password, and a saved password is present, restore the
// friendly password text.
//
DrPopulatePasswordField( pInfo, FALSE, FALSE );
return TRUE;
}
// If the password field ever receives the focus, clear the
// friendly password text if applicable.
//
else if (wNotification == EN_SETFOCUS &&
!DrIsPasswordStyleEnabled( pInfo->hwndEbPw ))
{
DrPopulatePasswordField( pInfo, FALSE, TRUE );
return TRUE;
}
break;
}
case CID_DR_LB_Locations:
{
if (wNotification == CBN_SELCHANGE)
{
DrLocationsSelChange( pInfo );
return TRUE;
}
break;
}
case CID_DR_PB_Rules:
{
DrEditSelectedLocation( pInfo );
return TRUE;
}
case CID_DR_PB_Properties:
{
DrProperties( pInfo );
DrPopulatePasswordField( pInfo, FALSE, FALSE );
return TRUE;
}
case CID_DR_RB_SaveForMe:
case CID_DR_RB_SaveForEveryone:
{
DrPopulatePasswordField( pInfo, FALSE, FALSE );
DrPopulateIdentificationFields( pInfo, (wId == CID_DR_RB_SaveForMe));
return TRUE;
}
case IDOK:
case CID_DR_PB_DialConnect:
{
DrSave( pInfo );
EndDialog( pInfo->hwndDlg, TRUE );
return TRUE;
}
case IDCANCEL:
case CID_DR_PB_Cancel:
{
EndDialog( pInfo->hwndDlg, FALSE );
return TRUE;
}
case IDHELP:
case CID_DR_PB_Help:
{
TCHAR* pszCmdLine;
// Help button now invokes troubleshooting help per bug 210247.
//
pszCmdLine = PszFromId( g_hinstDll, SID_DialerHelpCmdLine );
if (pszCmdLine)
{
STARTUPINFO sInfo;
PROCESS_INFORMATION pInfo;
ZeroMemory( &sInfo, sizeof(sInfo) );
sInfo.cb = sizeof(sInfo);
ZeroMemory( &pInfo, sizeof(pInfo) );
CreateProcess(
NULL, pszCmdLine, NULL, NULL, FALSE,
0, NULL, NULL, &sInfo, &pInfo );
Free( pszCmdLine );
}
return TRUE;
}
}
return FALSE;
}
BOOL CALLBACK
DrClbNumbersEnumChildProc(
IN HWND hwnd,
IN LPARAM lparam )
// Standard Windows EnumChildProc routine called back for each child
// window of the 'ClbNumbers' control.
//
{
DRINFO* pInfo;
LONG lId;
pInfo = (DRINFO* )lparam;
// There only one child window and it's the edit window.
//
pInfo->hwndClbNumbersEb = hwnd;
return FALSE;
}
BOOL CALLBACK
DrClbNumbersEnumWindowsProc(
IN HWND hwnd,
IN LPARAM lparam )
// Standard Windows EnumWindowsProc routine called back for each top-level
// window.
//
{
RECT rect;
GetWindowRect( hwnd, &rect );
if (rect.right - rect.left == DR_BOGUSWIDTH)
{
// This window has the unusual bogus width, so it must be the
// list-box.
//
((DRINFO* )lparam)->hwndClbNumbersLb = hwnd;
return FALSE;
}
return TRUE;
}
LRESULT APIENTRY
DrClbNumbersEbWndProc(
HWND hwnd,
UINT unMsg,
WPARAM wParam,
LPARAM lParam )
// Subclassed combo-box edit-box child window procedure providing "manual
// edit" behavior.
//
// Return value depends on message type.
//
{
DRINFO* pInfo;
switch (unMsg)
{
case WM_SETTEXT:
{
// Prevent the combo-box from setting the contents of the edit box
// by discarding the request and reporting success.
//
return TRUE;
}
case DR_WM_SETTEXT:
{
// Convert our private SETTEXT to a regular SETTEXT and pass it on
// to the edit control.
//
unMsg = WM_SETTEXT;
break;
}
}
// Call the previous window procedure for everything else.
//
pInfo = (DRINFO* )GetProp( hwnd, g_contextId );
ASSERT( pInfo );
return
CallWindowProc(
pInfo->wndprocClbNumbersEb, hwnd, unMsg, wParam, lParam );
}
LRESULT APIENTRY
DrClbNumbersLbWndProc(
HWND hwnd,
UINT unMsg,
WPARAM wParam,
LPARAM lParam )
// Subclassed combo-box list-box child window procedure providing "manual
// edit" behavior.
//
// Return value depends on message type.
//
{
DRINFO* pInfo;
pInfo = (DRINFO* )GetProp( hwnd, g_contextId );
ASSERT( pInfo );
switch (unMsg)
{
case LB_FINDSTRINGEXACT:
case LB_FINDSTRING:
{
// This prevents the edit-box "completion" behavior of the
// combo-box, i.e. it prevents the edit-box contents from being
// extended to the closest match in the list.
//
return -1;
}
case LB_SETCURSEL:
case LB_SETTOPINDEX:
{
// Prevent the "match selection to edit-box" combo-box behavior by
// discarding any attempts to set the selection or top index to
// anything other than what we set.
//
if (wParam != pInfo->pLink->iLastSelectedPhone)
{
return -1;
}
break;
}
}
// Call the previous window procedure for everything else.
//
return
CallWindowProc(
pInfo->wndprocClbNumbersLb, hwnd, unMsg, wParam, lParam );
}
VOID
DrEditSelectedLocation(
IN DRINFO* pInfo )
// Called when the Dialing Rules button is pressed. 'PInfo' is the dialog
// context.
//
{
DWORD dwErr;
INT iSel;
DRNUMBERSITEM* pItem;
TRACE( "DrEditSelectedLocation" );
// Look up the phone number information for the selected number.
//
pItem = (DRNUMBERSITEM* )ComboBox_GetItemDataPtr(
pInfo->hwndClbNumbers, ComboBox_GetCurSel( pInfo->hwndClbNumbers ) );
ASSERT( pItem );
if(NULL == pItem)
{
return;
}
ASSERT( pItem->pPhone->fUseDialingRules );
// Popup TAPI dialing rules dialog.
//
dwErr = TapiLocationDlg(
g_hinstDll,
&pInfo->hlineapp,
pInfo->hwndDlg,
pItem->pPhone->dwCountryCode,
pItem->pPhone->pszAreaCode,
pItem->pPhone->pszPhoneNumber,
0 );
if (dwErr != 0)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_LoadTapiInfo, dwErr, NULL );
}
// Might have changed the location list so re-fill it.
//
DrFillLocationList( pInfo );
}
DWORD
DrFillLocationList(
IN DRINFO* pInfo )
// Fills the dropdown list of locations and sets the current selection.
//
// Returns 0 if successful, or an error code.
//
{
DWORD dwErr;
LOCATION* pLocations;
LOCATION* pLocation;
DWORD cLocations;
DWORD dwCurLocation;
DWORD i;
TRACE( "DrFillLocationList" );
ComboBox_ResetContent( pInfo->hwndLbLocations );
pLocations = NULL;
cLocations = 0;
dwCurLocation = 0xFFFFFFFF;
dwErr = GetLocationInfo(
g_hinstDll, &pInfo->hlineapp,
&pLocations, &cLocations, &dwCurLocation );
if (dwErr != 0)
{
return dwErr;
}
for (i = 0, pLocation = pLocations;
i < cLocations;
++i, ++pLocation)
{
INT iItem;
iItem = ComboBox_AddItem(
pInfo->hwndLbLocations, pLocation->pszName,
(VOID* )UlongToPtr(pLocation->dwId ));
if (pLocation->dwId == dwCurLocation)
{
ComboBox_SetCurSelNotify( pInfo->hwndLbLocations, iItem );
}
}
FreeLocationInfo( pLocations, cLocations );
ComboBox_AutoSizeDroppedWidth( pInfo->hwndLbLocations );
return dwErr;
}
VOID
DrFillNumbersList(
IN DRINFO* pInfo )
// Fill the "Dial" combo-box with phone numbers and comments, and
// re-select the selected item in the list, or if none, the last one
// selected as specified in the PBLINK.
//
{
DTLNODE* pNode;
PBLINK* pLink;
PBPHONE* pPhone;
INT cItems;
INT i;
DrFreeClbNumbers( pInfo );
for (pNode = DtlGetFirstNode( pInfo->pLink->pdtllistPhones ), i = 0;
pNode;
pNode = DtlGetNextNode( pNode ), ++i)
{
TCHAR szBuf[ RAS_MaxPhoneNumber + RAS_MaxDescription + 3 + 1 ];
DRNUMBERSITEM* pItem;
pPhone = (PBPHONE* )DtlGetData( pNode );
ASSERT( pPhone );
pItem = Malloc( sizeof(DRNUMBERSITEM) );
if (!pItem)
{
break;
}
// Build the "<number> - <comment>" string in 'szBuf'.
//
pItem->pszNumber =
LinkPhoneNumberFromParts(
g_hinstDll, &pInfo->hlineapp,
pInfo->pArgs->pDinfo->pUser, pInfo->pArgs->pDinfo->pEntry,
pInfo->pLink, i, NULL, FALSE );
if (!pItem->pszNumber)
{
// Should not happen.
//
Free( pItem );
break;
}
lstrcpyn( szBuf, pItem->pszNumber, RAS_MaxPhoneNumber);
if (pPhone->pszComment && !IsAllWhite( pPhone->pszComment ))
{
DWORD dwLen, dwSize = sizeof(szBuf) / sizeof(TCHAR);
lstrcat( szBuf, TEXT(" - ") );
dwLen = lstrlen(szBuf) + 1;
lstrcpyn(
szBuf + (dwLen - 1),
pPhone->pszComment,
dwSize - dwLen );
}
pItem->pPhone = pPhone;
ComboBox_AddItem( pInfo->hwndClbNumbers, szBuf, pItem );
}
// Make the selection and trigger the update of the edit-box to the number
// without the comment.
//
cItems = ComboBox_GetCount( pInfo->hwndClbNumbers );
if (cItems > 0)
{
if ((INT )pInfo->pLink->iLastSelectedPhone >= cItems)
{
pInfo->pLink->iLastSelectedPhone = 0;
}
ListBox_SetTopIndex(
pInfo->hwndClbNumbersLb, pInfo->pLink->iLastSelectedPhone );
ComboBox_SetCurSelNotify(
pInfo->hwndClbNumbers, pInfo->pLink->iLastSelectedPhone );
}
ComboBox_AutoSizeDroppedWidth( pInfo->hwndClbNumbers );
}
VOID
DrFreeClbNumbers(
IN DRINFO* pInfo )
// Free up the displayable number string associated with each entry of the
// phone number combo-box leaving the box empty.
//
{
DRNUMBERSITEM* pItem;
while (pItem = ComboBox_GetItemDataPtr( pInfo->hwndClbNumbers, 0 ))
{
ComboBox_DeleteString( pInfo->hwndClbNumbers, 0 );
Free( pItem->pszNumber );
Free( pItem );
}
}
DWORD
DrFindAndSubclassClbNumbersControls(
IN DRINFO* pInfo )
// Locate and sub-class the edit-box and list-box child controls of the
// phone number combo-box. This is necessary to get "manual edit"
// behavior, i.e. prevent the combo-box from automatically updating the
// edit box at various times. We need this because the phone number
// comments are to be appended in the list, but not in the edit box.
// 'PInfo' is the dialog context.
//
// Returns 0 if successful or an error code.
//
{
DWORD dxOld;
// Find the edit window which is simply a child enumeration.
//
EnumChildWindows(
pInfo->hwndClbNumbers,
DrClbNumbersEnumChildProc,
(LPARAM)pInfo );
if (!pInfo->hwndClbNumbersEb)
{
return ERROR_NOT_FOUND;
}
// Find the list window which *sigh* doesn't show up in the child
// enumeration though it has WS_CHILD style because Windows sets it's
// parent window to NULL after it is created. To find it, we set the
// dropped width to an unusual bogus value, then search all windows for
// one with that width.
//
dxOld = (DWORD )SendMessage(
pInfo->hwndClbNumbers, CB_GETDROPPEDWIDTH, 0, 0 );
SendMessage( pInfo->hwndClbNumbers,
CB_SETDROPPEDWIDTH, (WPARAM )DR_BOGUSWIDTH, 0 );
EnumWindows( DrClbNumbersEnumWindowsProc, (LPARAM)pInfo );
SendMessage( pInfo->hwndClbNumbers,
CB_SETDROPPEDWIDTH, (WPARAM )dxOld, 0 );
if (!pInfo->hwndClbNumbersLb)
{
return ERROR_NOT_FOUND;
}
// Subclass the windows after associating the dialog context with them for
// retrieval in the WndProcs.
//
SetProp( pInfo->hwndClbNumbersEb, g_contextId, pInfo );
SetProp( pInfo->hwndClbNumbersLb, g_contextId, pInfo );
pInfo->wndprocClbNumbersEb =
(WNDPROC )SetWindowLongPtr(
pInfo->hwndClbNumbersEb,
GWLP_WNDPROC, (ULONG_PTR )DrClbNumbersEbWndProc );
pInfo->wndprocClbNumbersLb =
(WNDPROC )SetWindowLongPtr(
pInfo->hwndClbNumbersLb,
GWLP_WNDPROC, (ULONG_PTR )DrClbNumbersLbWndProc );
return 0;
}
void
DrEnsureNetshellLoaded (
IN DRINFO* pInfo)
{
// Load the netshell utilities interface. The interface is freed in PeTerm.
//
if (!pInfo->pNetConUtilities)
{
// Initialize the NetConnectionsUiUtilities
//
HrCreateNetConnectionUtilities( &pInfo->pNetConUtilities );
}
}
BOOL
DrInit(
IN HWND hwndDlg,
IN DRARGS* pArgs )
// Called on WM_INITDIALOG. 'hwndDlg' is the handle of the owning window.
// 'PArgs' is caller's arguments to the stub API.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
DWORD dwErr;
DRINFO* pInfo;
PBENTRY* pEntry;
BOOL fEnableProperties;
TRACE( "DrInit" );
// Allocate the dialog context block. Initialize minimally for proper
// cleanup, then attach to the dialog window.
//
{
pInfo = Malloc( sizeof(*pInfo) );
if (!pInfo)
{
ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
EndDialog( hwndDlg, FALSE );
return TRUE;
}
ZeroMemory( pInfo, sizeof(*pInfo) );
pInfo->pArgs = pArgs;
pInfo->hwndDlg = hwndDlg;
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
TRACE( "Context set" );
}
pEntry = pArgs->pDinfo->pEntry;
pInfo->hwndBmDialer = GetDlgItem( hwndDlg, CID_DR_BM_Useless );
ASSERT( pInfo->hwndBmDialer );
// Look up control handles.
//
if ((pArgs->dwfMode & DR_U) ||
(pArgs->dwfMode & DR_I))
{
pInfo->hwndEbUser = GetDlgItem( hwndDlg, CID_DR_EB_User );
ASSERT( pInfo->hwndEbUser );
if (pArgs->dwfMode & DR_U)
{
pInfo->hwndEbPw = GetDlgItem( hwndDlg, CID_DR_EB_Password );
ASSERT( pInfo->hwndEbPw );
pInfo->hwndCbSavePw = GetDlgItem( hwndDlg, CID_DR_CB_SavePassword );
ASSERT( pInfo->hwndCbSavePw );
pInfo->hwndRbSaveForMe = GetDlgItem( hwndDlg, CID_DR_RB_SaveForMe );
ASSERT( pInfo->hwndRbSaveForMe );
pInfo->hwndRbSaveForEveryone =
GetDlgItem( hwndDlg, CID_DR_RB_SaveForEveryone );
ASSERT( pInfo->hwndRbSaveForEveryone );
}
if (pArgs->dwfMode & DR_D)
{
pInfo->hwndEbDomain = GetDlgItem( hwndDlg, CID_DR_EB_Domain );
ASSERT( pInfo->hwndEbDomain );
}
}
if (pArgs->dwfMode & DR_N)
{
pInfo->hwndClbNumbers = GetDlgItem( hwndDlg, CID_DR_CLB_Numbers );
ASSERT( pInfo->hwndClbNumbers );
if (pArgs->dwfMode & DR_L)
{
pInfo->hwndStLocations = GetDlgItem( hwndDlg, CID_DR_ST_Locations );
ASSERT( pInfo->hwndStLocations );
pInfo->hwndLbLocations = GetDlgItem( hwndDlg, CID_DR_LB_Locations );
ASSERT( pInfo->hwndLbLocations );
pInfo->hwndPbRules = GetDlgItem( hwndDlg, CID_DR_PB_Rules );
ASSERT( pInfo->hwndPbRules );
}
}
pInfo->hwndPbProperties = GetDlgItem( hwndDlg, CID_DR_PB_Properties );
ASSERT( pInfo->hwndPbProperties );
// In location-enabled mode, popup TAPI's "first location" dialog if they
// are uninitialized. Typically, this will do nothing.
//
if (pArgs->dwfMode & DR_L)
{
dwErr = TapiNoLocationDlg( g_hinstDll, &pInfo->hlineapp, hwndDlg );
if (dwErr != 0)
{
// Error here is treated as a "cancel" per bug 288385.
//
pArgs->pDinfo->pArgs->dwError = 0;
EndDialog( hwndDlg, FALSE );
return TRUE;
}
}
// Set the title.
//
{
TCHAR* pszTitleFormat;
TCHAR* pszTitle;
TCHAR* apszArgs[ 1 ];
if (pArgs->pDinfo->fUnattended)
{
pszTitleFormat = PszFromId( g_hinstDll, SID_DR_ReconnectTitle );
}
else
{
pszTitleFormat = GetText( hwndDlg );
}
if (pszTitleFormat)
{
apszArgs[ 0 ] = pEntry->pszEntryName;
pszTitle = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszTitleFormat, 0, 0, (LPTSTR )&pszTitle, 1,
(va_list* )apszArgs );
Free( pszTitleFormat );
if (pszTitle)
{
SetWindowText( hwndDlg, pszTitle );
LocalFree( pszTitle );
}
}
}
// Change the Dial button to Connect for non-phone devices.
//
if (pEntry->dwType != RASET_Phone)
{
TCHAR* psz;
psz = PszFromId( g_hinstDll, SID_ConnectButton );
if (psz)
{
SetWindowText( GetDlgItem( hwndDlg, CID_DR_PB_DialConnect ), psz );
Free( psz );
}
}
// Initialize credentials section.
//
if (pArgs->dwfMode & DR_U)
{
ASSERT( !pEntry->fAutoLogon );
// Fill credential fields with initial values.
//
Edit_LimitText( pInfo->hwndEbUser, UNLEN );
SetWindowText( pInfo->hwndEbUser, pArgs->pDinfo->rdp.szUserName );
Edit_LimitText( pInfo->hwndEbPw, PWLEN );
if (pArgs->dwfMode & DR_D)
{
Edit_LimitText( pInfo->hwndEbDomain, DNLEN );
SetWindowText( pInfo->hwndEbDomain, pArgs->pDinfo->rdp.szDomain );
}
if (pArgs->pDinfo->pNoUser || pArgs->pDinfo->fDisableSavePw)
{
// Can't stash password without a logon context, so hide the
// checkbox.
//
ASSERT( !HaveSavedPw( pArgs->pDinfo )) ;
EnableWindow( pInfo->hwndCbSavePw, FALSE );
EnableWindow( pInfo->hwndRbSaveForMe, FALSE );
EnableWindow( pInfo->hwndRbSaveForEveryone, FALSE );
// Whistler bug 400714 RAS does not grab password at winlogon time
// when Connect dialog is displayed
//
// Whistler bug 254385 encode password when not being used
// Assumed password was encoded previously
//
DecodePassword( pArgs->pDinfo->rdp.szPassword );
SetWindowText( pInfo->hwndEbPw, pArgs->pDinfo->rdp.szPassword );
EncodePassword( pArgs->pDinfo->rdp.szPassword );
}
else
{
// Whistler bug: 195480 Dial-up connection dialog - Number of
// asterisks does not match the length of the password and causes
// confusion
//
// Init the password character. Default to the round dot if we fail
// to get it.
//
pInfo->szPasswordChar = (WCHAR) SendMessage( pInfo->hwndEbPw,
EM_GETPASSWORDCHAR, 0, 0 );
if (!pInfo->szPasswordChar)
{
pInfo->szPasswordChar = 0x25CF;
}
// Init the fonts for the password field
//
DrGetFriendlyFont( hwndDlg, TRUE, &(pInfo->hItalicFont) );
DrGetFriendlyFont( hwndDlg, FALSE, &(pInfo->hNormalFont) );
// Check "save password" and render the type of saved
// password.
//
Button_SetCheck(
pInfo->hwndCbSavePw,
HaveSavedPw( pArgs->pDinfo ));
if ((!pArgs->pDinfo->fIsPublicPbk) ||
(!HaveSavedPw( pArgs->pDinfo )))
{
// If this is a for-me-only connection or if
// there is no saved password, then initialize the
// pw save type to save-for-me
//
Button_SetCheck( pInfo->hwndRbSaveForMe, TRUE );
}
else
{
// Check the appropriate radio button
// Note that a per-user password is always used if
// both a per-user and global password are saved.
// Dont check global password if its a per-user connectoid
//
Button_SetCheck(
(pArgs->pDinfo->fHaveSavedPwUser) ?
pInfo->hwndRbSaveForMe :
pInfo->hwndRbSaveForEveryone,
TRUE);
}
DrEnableDisablePwControls( pInfo, HaveSavedPw( pArgs->pDinfo ) );
// Whistler bug: 195480 Dial-up connection dialog - Number of
// asterisks does not match the length of the password and causes
// confusion
//
DrPopulatePasswordField( pInfo, TRUE, FALSE );
}
}
if (pArgs->dwfMode & DR_N)
{
pInfo->pLinkNode = NULL;
if (pArgs->pDinfo->pArgs->dwSubEntry > 0)
{
// Look up the API caller specified link.
//
pInfo->pLinkNode =
DtlNodeFromIndex(
pArgs->pDinfo->pEntry->pdtllistLinks,
pArgs->pDinfo->pArgs->dwSubEntry - 1 );
}
if (!pInfo->pLinkNode)
{
// Look up the default (first) link.
//
pInfo->pLinkNode =
DtlGetFirstNode( pArgs->pDinfo->pEntry->pdtllistLinks );
}
ASSERT( pInfo->pLinkNode );
pInfo->pLink = (PBLINK* )DtlGetData( pInfo->pLinkNode );
dwErr = DrFindAndSubclassClbNumbersControls( pInfo );
if (dwErr != 0)
{
pArgs->pDinfo->pArgs->dwError = ERROR_NOT_FOUND;
EndDialog( hwndDlg, FALSE );
return TRUE;
}
// Ignore any "last selected" information when the "try next on fail"
// flag is set. New entries will not have "last selected" non-0 in
// this case but pre-existing entries might, so double-check here.
// See bug 150958.
//
if (pInfo->pLink->fTryNextAlternateOnFail)
{
pInfo->pLink->iLastSelectedPhone = 0;
}
// Record the initially selected phone number, used to determine
// whether user has changed the selection.
//
pInfo->iFirstSelectedPhone = pInfo->pLink->iLastSelectedPhone;
DrFillNumbersList( pInfo );
if (pArgs->dwfMode & DR_L)
{
DrFillLocationList( pInfo );
}
}
// danielwe: Bug #222744, scottbri Bug #245310
// Disable Properties... button if user does not have sufficent rights.
//
{
HRESULT hr;
hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
if (hr == RPC_E_CHANGED_MODE)
{
hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
}
if (hr == S_OK || hr == S_FALSE)
{
pInfo->fComInitialized = TRUE;
}
}
fEnableProperties = FALSE;
DrEnsureNetshellLoaded (pInfo);
if (NULL != pInfo->pNetConUtilities)
{
//For whislter bug 409504 gangz
//for a VPN double dial scenario,if now it is in the prerequiste dial
//process, we should use DINFO->pEntryMain->pszPrerequisitePbk to check
//if it is a publicPhonebook
//
BOOL fAllUsers = TRUE;
if( pArgs->pDinfo->fPrerequisiteDial )
{
fAllUsers =
IsPublicPhonebook(pArgs->pDinfo->pEntryMain->pszPrerequisitePbk);
}
else
{
fAllUsers = IsPublicPhonebook(pArgs->pDinfo->pszPhonebook);
}
if (((fAllUsers && INetConnectionUiUtilities_UserHasPermission(
pInfo->pNetConUtilities,
NCPERM_RasAllUserProperties)) ||
(!fAllUsers && INetConnectionUiUtilities_UserHasPermission(
pInfo->pNetConUtilities,
NCPERM_RasMyProperties))) &&
(NULL == pArgs->pDinfo->pNoUser))
{
fEnableProperties = TRUE;
}
// We only needed it breifly, release it
INetConnectionUiUtilities_Release(pInfo->pNetConUtilities);
pInfo->pNetConUtilities = NULL;
}
// stevec: 267157-Allow access at win-login if admin enables.
//
if (NULL != pArgs->pDinfo->pNoUser
&& pArgs->pDinfo->pUser->fAllowLogonPhonebookEdits)
{
fEnableProperties = TRUE;
}
EnableWindow( pInfo->hwndPbProperties, fEnableProperties );
// The help engine doesn't work at win-logon as it requires a user
// context, so disable the Help button in that case. See bug 343030.
//
if (pArgs->pDinfo->pNoUser)
{
HWND hwndPbHelp;
hwndPbHelp = GetDlgItem( hwndDlg, CID_DR_PB_Help );
ASSERT( hwndPbHelp );
EnableWindow( hwndPbHelp, FALSE );
ShowWindow( hwndPbHelp, SW_HIDE );
}
// Set the bitmap to the low res version if that is appropriate
//
// Ignore the error -- it is non-critical
//
DrSetBitmap(pInfo);
// Position the dialog per caller's instructions.
//
PositionDlg( hwndDlg,
!!(pArgs->pDinfo->pArgs->dwFlags & RASDDFLAG_PositionDlg),
pArgs->pDinfo->pArgs->xDlg, pArgs->pDinfo->pArgs->yDlg );
//Add this function for whislter bug 320863 gangz
//To adjust the bitmap's position and size
//
CenterExpandWindowRemainLeftMargin( pInfo->hwndBmDialer,
hwndDlg,
TRUE,
TRUE,
pInfo->hwndEbUser);
// Adjust the title bar widgets.
//
//TweakTitleBar( hwndDlg );
AddContextHelpButton( hwndDlg );
return TRUE;
}
VOID
DrLocationsSelChange(
IN DRINFO* pInfo )
// Called when a location is selected from the list. 'PInfo' is the
// dialog context.
//
{
DWORD dwErr;
DWORD dwLocationId;
TRACE("DuLocationChange");
// Set global TAPI location based on user's selection.
//
dwLocationId = (DWORD )ComboBox_GetItemData(
pInfo->hwndLbLocations, ComboBox_GetCurSel( pInfo->hwndLbLocations ) );
dwErr = SetCurrentLocation( g_hinstDll, &pInfo->hlineapp, dwLocationId );
if (dwErr != 0)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_SaveTapiInfo, dwErr, NULL );
}
// Location change may cause changes in built numbers so re-fill the
// numbers combo-box.
//
DrFillNumbersList( pInfo );
}
VOID
DrNumbersSelChange(
IN DRINFO* pInfo )
// Called when a phone number is selected from the list. 'PInfo' is the
// dialog context.
//
{
INT iSel;
BOOL fEnable;
DRNUMBERSITEM* pItem;
iSel = ComboBox_GetCurSel( pInfo->hwndClbNumbers );
if (iSel >= 0)
{
if (iSel != (INT )pInfo->pLink->iLastSelectedPhone)
{
pInfo->pArgs->pDinfo->pEntry->fDirty = TRUE;
}
pInfo->pLink->iLastSelectedPhone = (DWORD )iSel;
}
pItem = (DRNUMBERSITEM* )ComboBox_GetItemDataPtr(
pInfo->hwndClbNumbers, iSel );
ASSERT( pItem );
if(NULL == pItem)
{
return;
}
// Enable/disable the location fields based on whether they are relevant
// to the selected number.
//
if (pInfo->pArgs->dwfMode & DR_L)
{
fEnable = pItem->pPhone->fUseDialingRules;
EnableWindow( pInfo->hwndStLocations, fEnable );
EnableWindow( pInfo->hwndLbLocations, fEnable );
EnableWindow( pInfo->hwndPbRules, fEnable );
}
DrSetClbNumbersText( pInfo, pItem->pszNumber );
}
DWORD
DrPopulateIdentificationFields(
IN DRINFO* pInfo,
IN BOOL fForMe )
// Updates the identification fields in the dialer
// UI according to whether the all-user or per-user
// dialparms should be used.
//
{
RASDIALPARAMS* prdp, *prdpOld;
BOOL fUpdate;
TCHAR pszUser[UNLEN + 1];
INT iCount;
prdp = (fForMe)
? &(pInfo->pArgs->pDinfo->rdpu) : &(pInfo->pArgs->pDinfo->rdpg);
prdpOld = (fForMe)
? &(pInfo->pArgs->pDinfo->rdpg) : &(pInfo->pArgs->pDinfo->rdpu);
iCount = GetWindowText(
pInfo->hwndEbUser,
pszUser,
UNLEN + 1);
if (iCount == 0)
{
fUpdate = TRUE;
}
else
{
if (lstrcmp(prdpOld->szUserName, pszUser) == 0)
{
fUpdate = TRUE;
}
else
{
fUpdate = FALSE;
}
}
if (fUpdate)
{
if (pInfo->hwndEbUser && *(prdp->szUserName))
{
SetWindowText(pInfo->hwndEbUser, prdp->szUserName);
}
if (pInfo->hwndEbDomain && *(prdp->szDomain))
{
SetWindowText(pInfo->hwndEbDomain, prdp->szDomain);
}
}
return NO_ERROR;
}
DWORD
DrPopulatePasswordField(
IN DRINFO* pInfo,
IN BOOL fInit,
IN BOOL fDisable )
{
BOOL fSave, fMeOnly;
TCHAR* pszFriendly = NULL;
// Whistler bug: 195480 Dial-up connection dialog - Number of asterisks
// does not match the length of the password and causes confusion
//
// Case 1. The user has clicked on the password field. We clear the
// friendly password and set the font back to normal.
//
if (fDisable)
{
DrClearFriendlyPassword( pInfo, TRUE );
return NO_ERROR;
}
// Initialze
//
fSave = Button_GetCheck( pInfo->hwndCbSavePw );
fMeOnly = Button_GetCheck( pInfo->hwndRbSaveForMe );
pszFriendly = PszFromId( g_hinstDll, SID_SavePasswordFrndly );
// Case 2. Clear the password field if the user a) choose not to save the
// password and b) has not manually entered a password.
//
if ( (!fSave) && !DrIsPasswordStyleEnabled( pInfo->hwndEbPw ) )
{
DrClearFriendlyPassword( pInfo, FALSE );
}
// Case 3. Show the friendly saved password text if the user a) choose to
// save the password of himself only and b) there is a per-user password
// saved and c) the user has not entered a password manually.
//
else if ( (fSave) && (fMeOnly) &&
((fInit) || ( !DrIsPasswordStyleEnabled( pInfo->hwndEbPw ))) )
{
// Whistler bug: 288234 When switching back and forth from
// "I connect" and "Any user connects" password is not
// caching correctly
//
if (pInfo->pArgs->pDinfo->fHaveSavedPwUser)
{
DrDisplayFriendlyPassword(pInfo, pszFriendly );
}
else
{
DrClearFriendlyPassword( pInfo, FALSE );
}
}
// Case 4. Show the friendly saved password text if the user a) choose to
// save the password for everyone and b) there is a default password saved
// and c) the user has not entered a password manually.
//
else if ( (fSave) && (!fMeOnly) &&
((fInit) || ( !DrIsPasswordStyleEnabled( pInfo->hwndEbPw ))) )
{
if (pInfo->pArgs->pDinfo->fHaveSavedPwGlobal)
{
DrDisplayFriendlyPassword( pInfo, pszFriendly );
}
else
{
DrClearFriendlyPassword( pInfo, FALSE );
}
}
// Case 5. Show the friendly saved password text if the user a) choose to
// save the password for everyone or himself and b) there is a
// corresponding password saved and c) the user has not entered a password
// manually.
//
// This case catches a) when the user is switching between "me" and
// "everyone" and b) when the user leaves the focus of the password field
// but hasn't changed the password
//
else if ( (fSave) && !GetWindowTextLength( pInfo->hwndEbPw ) &&
DrIsPasswordStyleEnabled( pInfo->hwndEbPw ) &&
((pInfo->pArgs->pDinfo->fHaveSavedPwGlobal && !fMeOnly) ||
(pInfo->pArgs->pDinfo->fHaveSavedPwUser && fMeOnly)) )
{
DrDisplayFriendlyPassword( pInfo, pszFriendly );
}
// NT5 bug: 215432, Whistler bug: 364341
//
// Whistler bug: 195480 Dial-up connection dialog - Number of asterisks
// does not match the length of the password and causes confusion
//
// Set focus appropiately
//
if (fInit)
{
if (!GetWindowTextLength( pInfo->hwndEbUser ))
{
SetFocus( pInfo->hwndEbUser );
}
else if (!GetWindowTextLength( pInfo->hwndEbPw ))
{
SetFocus( pInfo->hwndEbPw );
// This removes the tab stop property from the username field. This
// is a hack so we can set the focus properly. Tab stop is put back
// in DrCommand.
//
SetWindowLong( pInfo->hwndEbUser, GWL_STYLE,
GetWindowLong( pInfo->hwndEbUser, GWL_STYLE ) & ~WS_TABSTOP );
}
else
{
SetFocus( pInfo->hwndEbUser );
}
}
// Clean up
//
Free0( pszFriendly );
return NO_ERROR;
}
VOID
DrProperties(
IN DRINFO* pInfo )
// Called when the Properties button is pressed. 'PInfo' is the dialog
// context.
//
{
BOOL fOk;
RASENTRYDLG info;
INTERNALARGS iargs;
DINFO* pDinfo;
// First, save any entry related changes user has made on the dial dialog.
//
DrSave( pInfo );
// Set up for parameters for call to RasEntryDlg.
//
ZeroMemory( &info, sizeof(info) );
info.dwSize = sizeof(info);
info.hwndOwner = pInfo->hwndDlg;
{
RECT rect;
info.dwFlags = RASEDFLAG_PositionDlg;
GetWindowRect( pInfo->hwndDlg, &rect );
info.xDlg = rect.left + DXSHEET;
info.yDlg = rect.top + DYSHEET;
}
// The secret hack to share information already loaded with the entry API.
//
pDinfo = pInfo->pArgs->pDinfo;
ZeroMemory( &iargs, sizeof(iargs) );
iargs.pFile = pDinfo->pFile;
iargs.pUser = pDinfo->pUser;
iargs.pNoUser = pDinfo->pNoUser;
iargs.fNoUser = !!(pDinfo->pNoUser);
//For whislter bug 234515 set fDisableFirstConnect to be FALSE
//
iargs.fDisableFirstConnect = FALSE;
info.reserved = (ULONG_PTR )&iargs;
TRACE( "RasEntryDlg" );
fOk = RasEntryDlg(
pDinfo->pszPhonebook, pDinfo->pEntry->pszEntryName, &info );
TRACE1( "RasEntryDlg=%d", fOk );
if (fOk)
{
DWORD dwErr;
// Reload when user presses OK on properties since that may change the
// appearance and content of this dialog. Must first reset the DINFO
// context parameters based on the replaced PBENTRY from the property
// sheet.
//
dwErr = FindEntryAndSetDialParams( pInfo->pArgs->pDinfo );
if (dwErr != 0)
{
// Should not happen.
//
EndDialog( pInfo->hwndDlg, FALSE );
}
pInfo->pArgs->fReload = TRUE;
EndDialog( pInfo->hwndDlg, FALSE );
}
}
VOID
DrSave(
IN DRINFO* pInfo )
// Saves dialog field contents to RASDIALPARAMS, and if appropriate to LSA
// secret area or NOUSER output argument. 'PInfo' is the dialog context.
//
{
DWORD dwErr;
RASDIALPARAMS* prdp;
RASCREDENTIALS rc;
DINFO* pDinfo;
pDinfo = pInfo->pArgs->pDinfo;
if ((pInfo->pArgs->dwfMode & DR_U) ||
(pInfo->pArgs->dwfMode & DR_I))
{
// Save credentials into parameter block to be passed to RasDial.
//
prdp = &pDinfo->rdp;
GetWindowText( pInfo->hwndEbUser, prdp->szUserName, UNLEN + 1 );
if (pInfo->pArgs->dwfMode & DR_U)
{
// Whistler bug 254385 encode password when not being used
// Assumed password was not encoded by GetWindowText()
//
// Whistler bug: 195480 Dial-up connection dialog - Number of
// asterisks does not match the length of the password and causes
// confusion
//
if (!DrIsPasswordStyleEnabled( pInfo->hwndEbPw ))
{
lstrcpyn( prdp->szPassword, g_pszSavedPasswordToken,
g_dwSavedPasswordTokenLength );
}
else
{
GetWindowText( pInfo->hwndEbPw, prdp->szPassword, PWLEN + 1 );
}
SetWindowText( pInfo->hwndEbPw, L"" );
EncodePassword( prdp->szPassword );
}
if (pInfo->pArgs->dwfMode & DR_D)
{
GetWindowText( pInfo->hwndEbDomain, prdp->szDomain, DNLEN + 1 );
}
ZeroMemory( &rc, sizeof(rc) );
rc.dwSize = sizeof(rc);
lstrcpyn( rc.szUserName, prdp->szUserName, UNLEN + 1 );
// Whistler bug 254385 encode password when not being used
// Assumed password was encoded previously
//
DecodePassword( prdp->szPassword );
lstrcpyn( rc.szPassword, prdp->szPassword, PWLEN + 1 );
EncodePassword( prdp->szPassword );
lstrcpyn( rc.szDomain, prdp->szDomain, DNLEN + 1);
if (pDinfo->pNoUser)
{
// Save credentials into output block for return to caller,
// typically WinLogon.
//
lstrcpyn( pDinfo->pNoUser->szUserName, rc.szUserName, UNLEN + 1 );
// Whistler bug 254385 encode password when not being used
// Assumed password was not encoded previously
//
lstrcpyn( pDinfo->pNoUser->szPassword, rc.szPassword, PWLEN + 1 );
EncodePassword( pDinfo->pNoUser->szPassword );
lstrcpyn( pDinfo->pNoUser->szDomain, rc.szDomain, DNLEN + 1 );
*(pDinfo->pfNoUserChanged) = TRUE;
}
else if (pInfo->pArgs->dwfMode & DR_I)
{
// Nothing to do
}
else if (!pDinfo->fDisableSavePw)
{
BOOL fGlobalCreds = FALSE;
ASSERT( g_pRasSetCredentials );
if (Button_GetCheck( pInfo->hwndCbSavePw ))
{
rc.dwMask = 0;
// If the user elected to save the credentials for
// everybody, then clear any previously saved per-user
// credentials
//
fGlobalCreds = Button_GetCheck( pInfo->hwndRbSaveForEveryone );
if( (fGlobalCreds)
&& IsPublicPhonebook(pDinfo->pFile->pszPath))
{
DeleteSavedCredentials(
pDinfo,
pInfo->hwndDlg,
FALSE,
TRUE );
pDinfo->fHaveSavedPwUser = FALSE;
rc.dwMask = RASCM_DefaultCreds;
}
// If there is currently no saved per-user password and the user
// opts to save the password himself, then ask whetehr the global
// password should be deleted if it exists.
//
else if (pDinfo->fHaveSavedPwGlobal && !pDinfo->fHaveSavedPwUser)
{
MSGARGS msgargs;
ZeroMemory( &msgargs, sizeof(msgargs) );
msgargs.dwFlags = MB_ICONQUESTION | MB_YESNO;
// Delete the default credentials if the user answers yes
//
if (IDYES ==
MsgDlg(pInfo->hwndDlg, SID_DR_GlobalPassword, &msgargs))
{
DeleteSavedCredentials(
pDinfo,
pInfo->hwndDlg,
TRUE,
TRUE );
pDinfo->fHaveSavedPwGlobal = FALSE;
}
}
// User chose to save password. Cache username, password, and
// domain.
//
rc.dwMask |= RASCM_UserName |
RASCM_Password | RASCM_Domain;
TRACE( "RasSetCredentials(u|p|d,FALSE)" );
dwErr = g_pRasSetCredentials(
pDinfo->pFile->pszPath, pDinfo->pEntry->pszEntryName,
&rc, FALSE );
TRACE1( "RasSetCredentials=%d", dwErr );
if (dwErr != 0)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_CachePw, dwErr, NULL );
}
else
{
if (fGlobalCreds)
{
pDinfo->fHaveSavedPwGlobal = TRUE;
}
else
{
// Whistler bug: 288234 When switching back and forth
// from "I connect" and "Any user connects" password is
// not caching correctly
//
pDinfo->fHaveSavedPwUser = TRUE;
}
}
}
else
{
// Delete the global credentials.
//
// Note that we have to delete the global identity
// as well because we do not support deleting
// just the global password. This is so that
// RasSetCredentials can emulate RasSetDialParams.
//
DeleteSavedCredentials(
pDinfo,
pInfo->hwndDlg,
TRUE,
TRUE );
// Delete the password saved per-user. Keep the user name
// and domain saved, however.
//
DeleteSavedCredentials(
pDinfo,
pInfo->hwndDlg,
FALSE,
FALSE );
pDinfo->fHaveSavedPwUser = FALSE;
pDinfo->fHaveSavedPwGlobal = FALSE;
}
}
ZeroMemory( rc.szPassword, sizeof(rc.szPassword) );
}
if (pInfo->pArgs->dwfMode & DR_N)
{
TCHAR* pszNumber;
TCHAR* pszOriginal;
DTLNODE* pPhoneNode;
DRNUMBERSITEM* pItem;
PBPHONE* pPhone;
BOOL fUserChange;
pszNumber = GetText( pInfo->hwndClbNumbers );
if (!pszNumber)
{
return;
}
pItem = (DRNUMBERSITEM* )ComboBox_GetItemDataPtr(
pInfo->hwndClbNumbers, pInfo->pLink->iLastSelectedPhone );
if (pItem)
{
pszOriginal = pItem->pszNumber;
}
else
{
pszOriginal = TEXT("");
}
if (lstrcmp( pszNumber, pszOriginal ) != 0
|| (pInfo->pLink->iLastSelectedPhone != pInfo->iFirstSelectedPhone))
{
MSGARGS msgargs;
BOOL fMultiLink;
BOOL fSingleNumber;
// The phone number was edited by user to something not originally
// on the list OR the user selected a different item on the list.
//
fSingleNumber = (DtlGetNodes( pInfo->pLink->pdtllistPhones ) == 1);
fMultiLink = (DtlGetNodes( pDinfo->pEntry->pdtllistLinks ) > 1);
ZeroMemory( &msgargs, sizeof(msgargs) );
msgargs.dwFlags = MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2;
if (fSingleNumber
&& (!fMultiLink || pDinfo->pEntry->fSharedPhoneNumbers)
&& MsgDlg( pInfo->hwndDlg,
SID_SavePreview, &msgargs ) == IDYES)
{
// User says he wants to make the change permanent.
//
pDinfo->pEntry->fDirty = TRUE;
if (pItem)
{
pPhone = pItem->pPhone;
Free0( pItem->pszNumber );
pItem->pszNumber = StrDup( pszNumber );
}
else
{
pPhoneNode = CreatePhoneNode();
if (pPhoneNode)
{
DtlAddNodeFirst(
pInfo->pLink->pdtllistPhones, pPhoneNode );
pPhone = (PBPHONE* )DtlGetData( pPhoneNode );
}
}
if (pItem)
{
ASSERT( pItem->pPhone );
Free0( pPhone->pszPhoneNumber );
pPhone->pszPhoneNumber = StrDup( pszNumber );
pPhone->fUseDialingRules = FALSE;
if (fMultiLink)
{
DTLNODE* pNode;
for (pNode = DtlGetFirstNode(
pDinfo->pEntry->pdtllistLinks );
pNode;
pNode = DtlGetNextNode( pNode ))
{
PBLINK* pLink = (PBLINK* )DtlGetData( pNode );
ASSERT( pLink );
ASSERT( pLink->fEnabled );
CopyLinkPhoneNumberInfo( pNode, pInfo->pLinkNode );
}
}
}
}
fUserChange = TRUE;
}
else
{
fUserChange = FALSE;
}
if (fUserChange || !pInfo->pLink->fTryNextAlternateOnFail)
{
if (!*pszNumber)
{
TCHAR* psz;
// We have a problem when user edits in an empty string,
// because the RasDial API does not accept an empty override
// phone number. Convert it to a single blank string in this
// case, which is as good as we can do. If user really needs
// to dial an empty string they can enter one as the entry's
// permanent phone number. See bug 179561.
//
psz = StrDup( TEXT(" ") );
if (psz)
{
Free( pszNumber );
pszNumber = psz;
}
}
// Set the override phone number to what user typed or selected.
//
lstrcpyn(
pDinfo->rdp.szPhoneNumber,
pszNumber,
RAS_MaxPhoneNumber + 1);
}
Free( pszNumber );
}
if (pDinfo->pEntry->fDirty)
{
// Write the new phone number and/or "last selected phone number" to
// the phonebook.
//
dwErr = WritePhonebookFile( pDinfo->pFile, NULL );
if (dwErr != 0)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_WritePhonebook, dwErr, NULL );
}
}
}
DWORD
DrSetBitmap(
IN DRINFO* pInfo)
// Set the appropriate bitmap for this dialer.
//
{
DWORD dwErr = NO_ERROR;
HBITMAP hbmNew = NULL;
HDC hdc = NULL;
INT iDepth = 0;
do
{
if (pInfo->hwndBmDialer == NULL)
{
dwErr = ERROR_CAN_NOT_COMPLETE;
break;
}
// Get the device context for the window
//
hdc = GetDC( pInfo->hwndBmDialer );
if (hdc == NULL)
{
dwErr = GetLastError();
break;
}
// If the color depth >= 8bit, the current bitmap
// is fine (high res is default)
//
iDepth = GetDeviceCaps(hdc, NUMCOLORS);
if ( (iDepth == -1) || (iDepth == 256) )
{
dwErr = NO_ERROR;
break;
}
// Load in the low-res bitmap
//
hbmNew = LoadBitmap(g_hinstDll, MAKEINTRESOURCE( BID_Dialer ));
if (hbmNew == NULL)
{
dwErr = GetLastError();
break;
}
// Set the low-res bitmap
//
pInfo->hbmOrig = (HBITMAP)
SendMessage(
pInfo->hwndBmDialer,
STM_SETIMAGE,
IMAGE_BITMAP,
(LPARAM )hbmNew );
} while (FALSE);
// Cleanup
//
{
if (hdc)
{
ReleaseDC(pInfo->hwndBmDialer, hdc);
}
}
return dwErr;
}
VOID
DrSetClbNumbersText(
IN DRINFO* pInfo,
IN TCHAR* pszText )
// Set the text of the 'ClbNumbers' edit box to 'pszText'. See
// DrClbNumbersEbWndProc. 'PInfo' is the dialog context.
//
{
ASSERT( pInfo->hwndClbNumbersEb );
SendMessage( pInfo->hwndClbNumbersEb, DR_WM_SETTEXT, 0, (LPARAM )pszText );
}
VOID
DrTerm(
IN HWND hwndDlg )
// Called on WM_DESTROY. 'HwndDlg' is that handle of the dialog window.
//
{
DRINFO* pInfo = (DRINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER );
HBITMAP hbmNew = NULL;
TRACE( "DrTerm" );
if (pInfo)
{
// Note: Don't use 'pInfo->pLinkNode' or 'pInfo->pLink' here as they
// are not currently restored prior to exit for post-Property
// button reloading.
//
if (pInfo->hwndClbNumbers)
{
DrFreeClbNumbers( pInfo );
if (pInfo->wndprocClbNumbersEb)
{
SetWindowLongPtr( pInfo->hwndClbNumbersEb,
GWLP_WNDPROC, (ULONG_PTR )pInfo->wndprocClbNumbersEb );
}
if (pInfo->wndprocClbNumbersLb)
{
SetWindowLongPtr( pInfo->hwndClbNumbersLb,
GWLP_WNDPROC, (ULONG_PTR )pInfo->wndprocClbNumbersLb );
}
}
// Whistler bug: 195480 Dial-up connection dialog - Number of
// asterisks does not match the length of the password and causes
// confusion
//
if (pInfo->hItalicFont)
{
DeleteObject( pInfo->hItalicFont );
}
if (pInfo->hNormalFont)
{
DeleteObject( pInfo->hNormalFont );
}
if (pInfo->fComInitialized)
{
CoUninitialize();
}
// Clean up the low-res bitmap if appropriate
//
if ( pInfo->hbmOrig )
{
hbmNew = (HBITMAP)
SendMessage(
pInfo->hwndBmDialer,
STM_SETIMAGE,
IMAGE_BITMAP,
(LPARAM ) pInfo->hbmOrig );
if (hbmNew)
{
DeleteObject(hbmNew);
}
}
Free( pInfo );
}
}
//----------------------------------------------------------------------------
// Projection Result dialog
// Listed alphabetically following stub API and dialog proc
//----------------------------------------------------------------------------
BOOL
ProjectionResultDlg(
IN HWND hwndOwner,
IN TCHAR* pszLines,
OUT BOOL* pfDisableFailedProtocols )
// Popup the Projection Result dialog. 'HwndOwner' is the owning window.
// 'PszLines' is the status line text to display. See DpProjectionError.
// 'DwfDisableFailedProtocols' indicates user chose to disable the failed
// protocols.
//
// Returns true if user chooses to redial or lets it timeout, false if
// cancels.
//
{
INT_PTR nStatus;
PRARGS args;
TRACE( "ProjectionResultDlg" );
args.pszLines = pszLines;
args.pfDisableFailedProtocols = pfDisableFailedProtocols;
nStatus =
DialogBoxParam(
g_hinstDll,
MAKEINTRESOURCE( DID_PR_ProjectionResult ),
hwndOwner,
PrDlgProc,
(LPARAM )&args );
if (nStatus == -1)
{
ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
nStatus = FALSE;
}
return (nStatus) ? TRUE : FALSE;
}
INT_PTR CALLBACK
PrDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the Projection Result dialog. Parameters and
// return value are as described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "PrDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
switch (unMsg)
{
case WM_INITDIALOG:
{
return PrInit( hwnd, (PRARGS* )lparam );
}
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp( g_adwPrHelp, hwnd, unMsg, wparam, lparam );
break;
}
case WM_COMMAND:
{
return PrCommand(
hwnd, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
}
return FALSE;
}
BOOL
PrCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'Hwnd' is the dialog window. 'WNotification' is
// the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
DWORD dwErr;
TRACE3( "PrCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
switch (wId)
{
case IDOK:
case IDCANCEL:
{
BOOL fCb;
BOOL* pfDisable;
TRACE1( "%s pressed", (wId==IDOK) ? "OK" : "Cancel" );
fCb = IsDlgButtonChecked( hwnd, CID_PR_CB_DisableProtocols );
pfDisable = (BOOL* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pfDisable );
*pfDisable = fCb;
EndDialog( hwnd, (wId == IDOK) );
return TRUE;
}
}
return FALSE;
}
BOOL
PrInit(
IN HWND hwndDlg,
IN PRARGS* pArgs )
// Called on WM_INITDIALOG. 'hwndDlg' is the handle of the owning window.
// 'PArgs' is caller's arguments to the stub API.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
DWORD dwErr;
HWND hwndStText;
HWND hwndPbAccept;
HWND hwndPbHangUp;
HWND hwndCbDisable;
TRACE( "PrInit" );
hwndStText = GetDlgItem( hwndDlg, CID_PR_ST_Text );
ASSERT( hwndStText );
hwndPbAccept = GetDlgItem( hwndDlg, IDOK );
ASSERT( hwndPbAccept );
hwndPbHangUp = GetDlgItem( hwndDlg, IDCANCEL );
ASSERT( hwndPbHangUp );
hwndCbDisable = GetDlgItem( hwndDlg, CID_PR_CB_DisableProtocols );
ASSERT( hwndCbDisable );
{
TCHAR szBuf[ 1024 ];
TCHAR* psz;
// Build the message text.
//
szBuf[ 0 ] = TEXT('\0');
psz = PszFromId( g_hinstDll, SID_ProjectionResult1 );
if (psz)
{
lstrcat( szBuf, psz );
Free( psz );
}
lstrcat( szBuf, pArgs->pszLines );
psz = PszFromId( g_hinstDll, SID_ProjectionResult2 );
if (psz)
{
lstrcat( szBuf, psz );
Free( psz );
}
// Load the text into the static control, then stretch the window to a
// vertical size appropriate for the text.
//
{
HDC hdc;
RECT rect;
RECT rectNew;
HFONT hfont;
LONG dyGrow;
SetWindowText( hwndStText, szBuf );
GetClientRect( hwndStText, &rect );
hdc = GetDC( hwndStText );
if(NULL != hdc)
{
hfont = (HFONT )SendMessage( hwndStText, WM_GETFONT, 0, 0 );
if (hfont)
SelectObject( hdc, hfont );
rectNew = rect;
DrawText( hdc, szBuf, -1, &rectNew,
DT_CALCRECT | DT_WORDBREAK | DT_EXPANDTABS | DT_NOPREFIX );
ReleaseDC( hwndStText, hdc );
}
dyGrow = rectNew.bottom - rect.bottom;
ExpandWindow( hwndDlg, 0, dyGrow );
ExpandWindow( hwndStText, 0, dyGrow );
SlideWindow( hwndPbAccept, hwndDlg, 0, dyGrow );
SlideWindow( hwndPbHangUp, hwndDlg, 0, dyGrow );
SlideWindow( hwndCbDisable, hwndDlg, 0, dyGrow );
}
}
// Save address of caller's BOOL as the dialog context.
//
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pArgs->pfDisableFailedProtocols );
// Add context help button to title bar.
//
AddContextHelpButton( hwndDlg );
// Display the finished window above all other windows. The window
// position is set to "topmost" then immediately set to "not topmost"
// because we want it on top but not always-on-top. Always-on-top alone
// is incredibly annoying, e.g. it is always on top of the on-line help if
// user presses the Help button.
//
SetWindowPos(
hwndDlg, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
CenterWindow( hwndDlg, GetParent( hwndDlg ) );
ShowWindow( hwndDlg, SW_SHOW );
SetWindowPos(
hwndDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
return TRUE;
}
//----------------------------------------------------------------------------
// Retry Authentication dialog
// Listed alphabetically following stub API and dialog proc
//----------------------------------------------------------------------------
BOOL
RetryAuthenticationDlg(
IN HWND hwndOwner,
IN DINFO* pDinfo )
// Pops up the retry authentication dialog. 'PDinfo' is the dial dialog
// common context.
//
// Returns true if user presses OK, false if Cancel or an error occurs.
//
{
INT_PTR nStatus;
TRACE( "RetryAuthenticationDlg" );
nStatus =
(BOOL )DialogBoxParam(
g_hinstDll,
MAKEINTRESOURCE( DID_UA_RetryAuthenticationUD ),
hwndOwner,
UaDlgProc,
(LPARAM )pDinfo );
if (nStatus == -1)
{
ErrorDlg( hwndOwner, SID_OP_LoadDlg, ERROR_UNKNOWN, NULL );
nStatus = FALSE;
}
return (BOOL )nStatus;
}
INT_PTR CALLBACK
UaDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the User Authentication dialog. Parameters and
// return value are as described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "UaDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
switch (unMsg)
{
case WM_INITDIALOG:
{
return UaInit( hwnd, (DINFO* )lparam );
}
case WM_HELP:
case WM_CONTEXTMENU:
{
ContextHelp( g_adwUaHelp, hwnd, unMsg, wparam, lparam );
break;
}
case WM_COMMAND:
{
UAINFO* pInfo = (UAINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
if (!pInfo)
{
// This happened in stress one night. Don't understand how
// unless it was a WinUser bug or something. Anyhow, this
// avoids an AV in such case.
//
break;
}
return UaCommand(
pInfo, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
case WM_DESTROY:
{
UaTerm( hwnd );
break;
}
}
return FALSE;
}
BOOL
UaCommand(
IN UAINFO* pInfo,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'PInfo' is the dialog context. 'WNotification'
// is the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
TRACE3( "UaCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
switch (wId)
{
case CID_UA_EB_UserName:
{
if (pInfo->fAutoLogonPassword && wNotification == EN_CHANGE)
{
// User's changing the username in auto-logon retry mode,
// which means we have to admit we don't really have the text
// password and force him to re-enter it.
//
pInfo->fAutoLogonPassword = FALSE;
SetWindowText( pInfo->hwndEbPassword, TEXT("") );
}
break;
}
case CID_UA_EB_Password:
{
if (wNotification == EN_CHANGE)
{
pInfo->fAutoLogonPassword = FALSE;
}
break;
}
case IDOK:
{
UaSave( pInfo );
EndDialog( pInfo->hwndDlg, TRUE );
return TRUE;
}
case IDCANCEL:
{
TRACE( "Cancel pressed" );
EndDialog( pInfo->hwndDlg, FALSE );
return TRUE;
}
}
return FALSE;
}
BOOL
UaInit(
IN HWND hwndDlg,
IN DINFO* pArgs )
// Called on WM_INITDIALOG. 'hwndDlg' is the handle of the owning window.
// 'PArgs' is caller's arguments as passed to the stub API.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
DWORD dwErr;
UAINFO* pInfo;
PBENTRY* pEntry;
TRACE( "UaInit" );
// Allocate the dialog context block. Initialize minimally for proper
// cleanup, then attach to the dialog window.
//
{
pInfo = Malloc( sizeof(*pInfo) );
if (!pInfo)
{
ErrorDlg( hwndDlg, SID_OP_LoadDlg, ERROR_NOT_ENOUGH_MEMORY, NULL );
EndDialog( hwndDlg, FALSE );
return TRUE;
}
ZeroMemory( pInfo, sizeof(*pInfo) );
pInfo->pArgs = pArgs;
pInfo->hwndDlg = hwndDlg;
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
TRACE( "Context set" );
}
pInfo->fDomain = TRUE;
pInfo->hwndEbUserName = GetDlgItem( hwndDlg, CID_UA_EB_UserName );
ASSERT( pInfo->hwndEbUserName );
pInfo->hwndEbPassword = GetDlgItem( hwndDlg, CID_UA_EB_Password );
ASSERT( pInfo->hwndEbPassword );
if (pInfo->fDomain)
{
pInfo->hwndEbDomain = GetDlgItem( hwndDlg, CID_UA_EB_Domain );
ASSERT( pInfo->hwndEbDomain );
}
pInfo->hwndCbSavePw = GetDlgItem( hwndDlg, CID_UA_CB_SavePassword );
ASSERT( pInfo->hwndCbSavePw );
pEntry = pArgs->pEntry;
// Set the title.
//
{
TCHAR* pszTitleFormat;
TCHAR* pszTitle;
TCHAR* apszArgs[ 1 ];
pszTitleFormat = GetText( hwndDlg );
if (pszTitleFormat)
{
apszArgs[ 0 ] = pEntry->pszEntryName;
pszTitle = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_STRING
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
pszTitleFormat, 0, 0, (LPTSTR )&pszTitle, 1,
(va_list* )apszArgs );
Free( pszTitleFormat );
if (pszTitle)
{
SetWindowText( hwndDlg, pszTitle );
LocalFree( pszTitle );
}
}
}
// Fill edit fields with initial values.
//
Edit_LimitText( pInfo->hwndEbUserName, UNLEN );
Edit_LimitText( pInfo->hwndEbPassword, PWLEN );
if (pInfo->fDomain)
{
Edit_LimitText( pInfo->hwndEbDomain, DNLEN );
}
{
BOOL fUserNameSet = FALSE;
BOOL fPasswordSet = FALSE;
if (pEntry->fAutoLogon && !pInfo->pArgs->pNoUser)
{
// On the first retry use the logged on user's name. Act like the
// user's password is in the edit box. If he changes the username
// or password we'll have to admit we don't have it, but he'll
// probably just change the domain.
//
if (pArgs->rdp.szUserName[ 0 ] == TEXT('\0'))
{
SetWindowText( pInfo->hwndEbUserName, GetLogonUser() );
fUserNameSet = TRUE;
}
if (pArgs->rdp.szPassword[ 0 ] == TEXT('\0'))
{
SetWindowText( pInfo->hwndEbPassword, TEXT("********") );
pInfo->fAutoLogonPassword = TRUE;
fPasswordSet = TRUE;
}
}
if (!fUserNameSet)
{
SetWindowText( pInfo->hwndEbUserName, pArgs->rdp.szUserName );
}
if (!fPasswordSet)
{
// Whistler bug 254385 encode password when not being used
// Assumed password was encoded previously
//
DecodePassword( pArgs->rdp.szPassword );
SetWindowText( pInfo->hwndEbPassword, pArgs->rdp.szPassword );
EncodePassword( pArgs->rdp.szPassword );
}
if (pInfo->fDomain)
{
SetWindowText( pInfo->hwndEbDomain, pArgs->rdp.szDomain );
}
}
if (pArgs->pNoUser || pArgs->fDisableSavePw)
{
// Can't stash password without a logon context, so hide the checkbox.
//
ASSERT( !HaveSavedPw( pArgs ) );
EnableWindow( pInfo->hwndCbSavePw, FALSE );
ShowWindow( pInfo->hwndCbSavePw, SW_HIDE );
}
else
{
// Check "save password" if a password was previously cached. Maybe
// he changed the password while on the LAN.
//
Button_SetCheck( pInfo->hwndCbSavePw, HaveSavedPw( pArgs ) );
}
// Position the dialog per caller's instructions.
//
PositionDlg( hwndDlg,
(pArgs->pArgs->dwFlags & RASDDFLAG_PositionDlg),
pArgs->pArgs->xDlg, pArgs->pArgs->yDlg );
SetForegroundWindow( hwndDlg );
// Add context help button to title bar.
//
AddContextHelpButton( hwndDlg );
// Set focus to the empty username or empty password, or if both are
// present to the domain if auto-logon or the password if not.
//
if (Edit_GetTextLength( pInfo->hwndEbUserName ) == 0)
{
Edit_SetSel( pInfo->hwndEbUserName, 0, -1 );
SetFocus( pInfo->hwndEbUserName );
}
else if (Edit_GetTextLength( pInfo->hwndEbPassword ) == 0
|| !pEntry->fAutoLogon
|| !pInfo->fDomain)
{
Edit_SetSel( pInfo->hwndEbPassword, 0, -1 );
SetFocus( pInfo->hwndEbPassword );
}
else
{
ASSERT( pInfo->fDomain );
Edit_SetSel( pInfo->hwndEbDomain, 0, -1 );
SetFocus( pInfo->hwndEbDomain );
}
// Hide the Dial Progress dialog.
//
SetOffDesktop( GetParent( hwndDlg ), SOD_MoveOff, NULL );
return FALSE;
}
VOID
UaSave(
IN UAINFO* pInfo )
// Called when the OK button is pressed.
//
// Returns true if user presses OK, false if Cancel or an error occurs.
//
{
DWORD dwErr;
PBENTRY* pEntry;
BOOL fSavePw;
RASDIALPARAMS* prdp;
RASCREDENTIALS rc;
TRACE( "UaSave" );
prdp = &pInfo->pArgs->rdp;
GetWindowText( pInfo->hwndEbUserName, prdp->szUserName, UNLEN + 1 );
// Whistler bug 254385 encode password when not being used
// Assumed password was not encoded by GetWindowText()
//
GetWindowText( pInfo->hwndEbPassword, prdp->szPassword, PWLEN + 1 );
EncodePassword( prdp->szPassword );
if (pInfo->fDomain)
{
GetWindowText( pInfo->hwndEbDomain, prdp->szDomain, DNLEN + 1 );
//
//if the Domain is not empty, set the "include Windows Logon Domain check box on Option Tab"
// for bug 167229 whistler
//
if ( ( 0 < lstrlen ( prdp->szDomain ) ) && (!pInfo->pArgs->pEntry->fPreviewDomain ))
{
pInfo->pArgs->pEntry->fPreviewDomain = TRUE;
pInfo->pArgs->pEntry->fDirty = TRUE;
dwErr = WritePhonebookFile( pInfo->pArgs->pFile, NULL );
if (dwErr != 0)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_WritePhonebook, dwErr, NULL );
}
}
}
pEntry = pInfo->pArgs->pEntry;
if (pEntry->fAutoLogon && !pInfo->pArgs->pNoUser)
{
if (pInfo->fAutoLogonPassword)
{
// User did not change username or password, so continue to
// retrieve logon username and password credentials.
//
TRACE( "Retain auto-logon" );
prdp->szUserName[ 0 ] = TEXT('\0');
prdp->szPassword[ 0 ] = TEXT('\0');
}
else
{
// User changed username and/or password so we can no longer
// retrieve the logon username and password credentials from the
// system. Switch the entry to non-auto-logon mode.
//
TRACE( "Disable auto-logon" );
pEntry->fAutoLogon = FALSE;
pInfo->pArgs->fResetAutoLogon = TRUE;
}
}
ZeroMemory( &rc, sizeof(rc) );
rc.dwSize = sizeof(rc);
lstrcpyn( rc.szUserName, prdp->szUserName, UNLEN + 1 );
// Whistler bug 254385 encode password when not being used
// Assumed password was encoded previously
//
DecodePassword( prdp->szPassword );
lstrcpyn( rc.szPassword, prdp->szPassword, PWLEN + 1 );
EncodePassword( prdp->szPassword );
lstrcpyn( rc.szDomain, prdp->szDomain, DNLEN + 1 );
if (pInfo->pArgs->pNoUser)
{
lstrcpyn( pInfo->pArgs->pNoUser->szUserName, rc.szUserName, UNLEN + 1 );
// Whistler bug 254385 encode password when not being used
// Assumed password was not encoded previously
//
lstrcpyn( pInfo->pArgs->pNoUser->szPassword, rc.szPassword, PWLEN + 1 );
EncodePassword( pInfo->pArgs->pNoUser->szPassword );
lstrcpyn( pInfo->pArgs->pNoUser->szDomain, rc.szDomain, DNLEN + 1 );
*pInfo->pArgs->pfNoUserChanged = TRUE;
}
else if (!pInfo->pArgs->fDisableSavePw)
{
ASSERT( g_pRasSetCredentials );
if (Button_GetCheck( pInfo->hwndCbSavePw ))
{
// User chose "save password". Cache username, password, and
// domain.
//
rc.dwMask = RASCM_UserName | RASCM_Password | RASCM_Domain;
// Whistler bug: 288234 When switching back and forth from
// "I connect" and "Any user connects" password is not
// caching correctly
//
if( (pInfo->pArgs->fHaveSavedPwGlobal)
&& !pInfo->pArgs->fHaveSavedPwUser
&& IsPublicPhonebook(pInfo->pArgs->pFile->pszPath))
{
rc.dwMask |= RASCM_DefaultCreds;
}
TRACE( "RasSetCredentials(u|p|d,FALSE)" );
dwErr = g_pRasSetCredentials(
pInfo->pArgs->pFile->pszPath,
pInfo->pArgs->pEntry->pszEntryName,
&rc, FALSE );
TRACE1( "RasSetCredentials=%d", dwErr );
if (dwErr != 0)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_CachePw, dwErr, NULL );
}
}
else
{
// Whistler bug: 288234 When switching back and forth from
// "I connect" and "Any user connects" password is not
// caching correctly
//
// User chose not to save password; Cache username and domain only
//
rc.dwMask = RASCM_UserName | RASCM_Domain;
TRACE( "RasSetCredentials(u|d,FALSE)" );
dwErr = g_pRasSetCredentials(
pInfo->pArgs->pFile->pszPath,
pInfo->pArgs->pEntry->pszEntryName,
&rc, FALSE );
TRACE1( "RasSetCredentials=%d", dwErr );
if (dwErr != 0)
{
ErrorDlg( pInfo->hwndDlg, SID_OP_UncachePw, dwErr, NULL );
}
// Whistler bug: 288234 When switching back and forth from
// "I connect" and "Any user connects" password is not
// caching correctly
//
// Delete the password saved per-user; Keep the user name
// and domain saved, however.
//
if (pInfo->pArgs->fHaveSavedPwUser)
{
DeleteSavedCredentials(
pInfo->pArgs,
pInfo->hwndDlg,
FALSE,
FALSE );
pInfo->pArgs->fHaveSavedPwUser = FALSE;
}
// Delete the global credentials.
//
// Note that we have to delete the global identity
// as well because we do not support deleting
// just the global password. This is so that
// RasSetCredentials can emulate RasSetDialParams.
//
else if (pInfo->pArgs->fHaveSavedPwGlobal)
{
DeleteSavedCredentials(
pInfo->pArgs,
pInfo->hwndDlg,
TRUE,
TRUE );
pInfo->pArgs->fHaveSavedPwGlobal = FALSE;
}
}
}
ZeroMemory( rc.szPassword, sizeof(rc.szPassword) );
}
VOID
UaTerm(
IN HWND hwndDlg )
// Called on WM_DESTROY. 'HwndDlg' is that handle of the dialog window.
//
{
UAINFO* pInfo = (UAINFO* )GetWindowLongPtr( hwndDlg, DWLP_USER );
TRACE( "UaTerm" );
if (pInfo)
{
// Restore the Dial Progress dialog.
//
SetOffDesktop( GetParent( hwndDlg ), SOD_MoveBackFree, NULL );
Free( pInfo );
}
}
//----------------------------------------------------------------------------
// VPN Double Dial help dialog
// Listed alphabetically following stub API and dialog proc
//----------------------------------------------------------------------------
BOOL
VpnDoubleDialDlg(
IN HWND hwndOwner,
IN DINFO* pInfo )
// Popup the VPN double dial help dialog. 'HwndOwner' is the owning
// window. 'PInfo' is the dialing context information.
//
// Returns false if user sees the dialog and decides not to continue, true
// otherwise.
//
{
INT_PTR nStatus;
TRACE( "VpnDoubleDialDlg" );
if (pInfo->pEntryMain->dwType != RASET_Vpn
|| !pInfo->fPrerequisiteDial
|| pInfo->pEntryMain->fSkipDoubleDialDialog)
{
return TRUE;
}
nStatus =
(BOOL )DialogBoxParam(
g_hinstDll,
MAKEINTRESOURCE( DID_VI_VpnInitial ),
hwndOwner,
ViDlgProc,
(LPARAM )pInfo );
if (nStatus == -1)
{
nStatus = FALSE;
}
return !!(nStatus);
}
INT_PTR CALLBACK
ViDlgProc(
IN HWND hwnd,
IN UINT unMsg,
IN WPARAM wparam,
IN LPARAM lparam )
// DialogProc callback for the dialog. Parameters and return value are as
// described for standard windows 'DialogProc's.
//
{
#if 0
TRACE4( "ViDlgProc(h=$%x,m=$%x,w=$%x,l=$%x)",
(DWORD )hwnd, (DWORD )unMsg, (DWORD )wparam, (DWORD )lparam );
#endif
switch (unMsg)
{
case WM_INITDIALOG:
{
return ViInit( hwnd, (DINFO* )lparam );
}
case WM_COMMAND:
{
return ViCommand(
hwnd, HIWORD( wparam ), LOWORD( wparam ), (HWND )lparam );
}
}
return FALSE;
}
BOOL
ViCommand(
IN HWND hwnd,
IN WORD wNotification,
IN WORD wId,
IN HWND hwndCtrl )
// Called on WM_COMMAND. 'Hwnd' is the dialog window. 'WNotification' is
// the notification code of the command. 'wId' is the control/menu
// identifier of the command. 'HwndCtrl' is the control window handle of
// the command.
//
// Returns true if processed message, false otherwise.
//
{
TRACE3( "ViCommand(n=%d,i=%d,c=$%x)",
(DWORD )wNotification, (DWORD )wId, (ULONG_PTR )hwndCtrl );
switch (wId)
{
case IDYES:
case IDNO:
{
// Per bug 261955, the box setting is saved when either the Yes or
// No, but not the 'X' button, is pressed.
//
DINFO* pInfo = (DINFO* )GetWindowLongPtr( hwnd, DWLP_USER );
ASSERT( pInfo );
if (IsDlgButtonChecked( hwnd, CID_VI_CB_SkipMessage ))
{
pInfo->pEntryMain->fSkipDoubleDialDialog = TRUE;
pInfo->pEntryMain->fDirty = TRUE;
WritePhonebookFile( pInfo->pFileMain, NULL );
}
EndDialog( hwnd, (wId == IDYES) );
return TRUE;
}
case IDCANCEL:
{
EndDialog( hwnd, FALSE );
return TRUE;
}
}
return FALSE;
}
BOOL
ViInit(
IN HWND hwndDlg,
IN DINFO* pInfo )
// Called on WM_INITDIALOG. 'HwndDlg' is the handle of dialog. 'PUser'
// is caller's argument to the stub API.
//
// Return false if focus was set, true otherwise, i.e. as defined for
// WM_INITDIALOG.
//
{
TRACE( "ViInit" );
// Set the dialog context.
//
SetWindowLongPtr( hwndDlg, DWLP_USER, (ULONG_PTR )pInfo );
// Set the explanatory text.
//
{
MSGARGS msgargs;
ZeroMemory( &msgargs, sizeof(msgargs) );
msgargs.apszArgs[ 0 ] = pInfo->pEntryMain->pszEntryName;
msgargs.apszArgs[ 1 ] = pInfo->pEntry->pszEntryName;
msgargs.fStringOutput = TRUE;
MsgDlgUtil( NULL, SID_VI_ST_Explain, &msgargs, g_hinstDll, 0 );
if (msgargs.pszOutput)
{
SetDlgItemText( hwndDlg, CID_VI_ST_Explain, msgargs.pszOutput );
Free( msgargs.pszOutput );
}
}
// Display finished window.
//
CenterWindow( hwndDlg, GetParent( hwndDlg ) );
SetForegroundWindow( hwndDlg );
return TRUE;
}
DWORD
DwTerminalDlg(
LPCWSTR lpszPhonebook,
LPCWSTR lpszEntry,
RASDIALPARAMS *prdp,
HWND hwndOwner,
HRASCONN hRasconn)
{
DWORD dwErr = ERROR_SUCCESS;
PBENTRY *pEntry = NULL;
PBFILE pbfile;
DTLNODE *pNode = NULL;
WCHAR szIpAddress[ TERM_IpAddress ];
DWORD sidTitle;
WCHAR *pszIpAddress;
//
//Initialize memory for Whistler bug 160888
//
ZeroMemory(&pbfile, sizeof(PBFILE));
pbfile.hrasfile = -1;
dwErr = LoadRas( g_hinstDll, hwndOwner );
if (ERROR_SUCCESS != dwErr)
{
goto done;
}
dwErr = GetPbkAndEntryName(
lpszPhonebook,
lpszEntry,
0,
&pbfile,
&pNode);
if( (NULL == pNode)
|| (ERROR_SUCCESS != dwErr))
{
dwErr = ERROR_CANNOT_FIND_PHONEBOOK_ENTRY;
goto done;
}
pEntry = (PBENTRY *) DtlGetData(pNode);
ASSERT(NULL != pEntry);
if(NULL == pEntry)
{
goto done;
}
if (pEntry->dwBaseProtocol == BP_Slip)
{
lstrcpyn(
szIpAddress,
(pEntry->pszIpAddress) ? pEntry->pszIpAddress : TEXT("0.0.0.0"),
sizeof(szIpAddress) / sizeof(TCHAR));
pszIpAddress = szIpAddress;
sidTitle = SID_T_SlipTerminal;
}
else
{
szIpAddress[0] = TEXT('\0');
pszIpAddress = szIpAddress;
sidTitle = SID_T_PostconnectTerminal;
}
if (!TerminalDlg(
pEntry, prdp, hwndOwner,
hRasconn, sidTitle, pszIpAddress ))
{
TRACE( "TerminalDlg==FALSE" );
dwErr = E_FAIL;
goto done;
}
TRACE2( "pszIpAddress=0x%08x(%ls)", pszIpAddress,
pszIpAddress ? pszIpAddress : TEXT("") );
TRACE2( "pEntry->pszIpAddress=0x%08x(%ls)", pEntry->pszIpAddress,
pEntry->pszIpAddress ? pEntry->pszIpAddress : TEXT("") );
if (pszIpAddress[0]
&& (!pEntry->pszIpAddress
|| lstrcmp( pszIpAddress, pEntry->pszIpAddress ) != 0))
{
Free0( pEntry->pszIpAddress );
pEntry->pszIpAddress = StrDup( szIpAddress );
pEntry->fDirty = TRUE;
dwErr = WritePhonebookFile( &pbfile, NULL );
if (dwErr != 0)
{
ErrorDlg( hwndOwner, SID_OP_WritePhonebook, dwErr, NULL );
}
}
done:
ClosePhonebookFile(&pbfile);
return dwErr;
}