mirror of https://github.com/tongzx/nt5src
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
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;
|
|
|
|
}
|