856 lines
15 KiB
C++
856 lines
15 KiB
C++
/*++
|
|
|
|
Copyright (c) 1994-1998 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
facc.cpp
|
|
|
|
Abstract:
|
|
|
|
FTP Accounts Property Page
|
|
|
|
Author:
|
|
|
|
Ronald Meijer (ronaldm)
|
|
|
|
Project:
|
|
|
|
Internet Services Manager
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
//
|
|
// Include Files
|
|
//
|
|
#include "stdafx.h"
|
|
#include "common.h"
|
|
#include "inetprop.h"
|
|
#include "InetMgrApp.h"
|
|
#include "supdlgs.h"
|
|
#include "shts.h"
|
|
#include "ftpsht.h"
|
|
#include "facc.h"
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
|
|
IMPLEMENT_DYNCREATE(CFtpAccountsPage, CInetPropertyPage)
|
|
|
|
|
|
|
|
CFtpAccountsPage::CFtpAccountsPage(
|
|
IN CInetPropertySheet * pSheet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor for FTP service property page
|
|
|
|
Arguments:
|
|
|
|
CInetPropertySheet * pSheet : Associated property sheet
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: CInetPropertyPage(CFtpAccountsPage::IDD, pSheet),
|
|
m_ListBoxRes(
|
|
IDB_ACLUSERS,
|
|
CAccessEntryListBox::nBitmaps
|
|
),
|
|
m_oblSID(),
|
|
m_fPasswordSyncChanged(FALSE),
|
|
m_fUserNameChanged(FALSE),
|
|
m_fPasswordSyncMsgShown(FALSE)
|
|
{
|
|
#ifdef _DEBUG
|
|
|
|
afxMemDF |= checkAlwaysMemDF;
|
|
|
|
#endif // _DEBUG
|
|
|
|
#if 0 // Keep Class Wizard happy
|
|
|
|
//{{AFX_DATA_INIT(CFtpAccountsPage)
|
|
m_strUserName = _T("");
|
|
m_fAllowAnonymous = TRUE;
|
|
m_fOnlyAnonymous = FALSE;
|
|
m_fPasswordSync = FALSE;
|
|
//}}AFX_DATA_INIT
|
|
|
|
#endif // 0
|
|
|
|
m_list_Administrators.AttachResources(&m_ListBoxRes);
|
|
}
|
|
|
|
|
|
|
|
CFtpAccountsPage::~CFtpAccountsPage()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor
|
|
|
|
Arguments:
|
|
|
|
N/A
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
{
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::DoDataExchange(
|
|
IN CDataExchange * pDX
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialise/Store control data
|
|
|
|
Arguments:
|
|
|
|
CDataExchange * pDX - DDX/DDV control structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
CInetPropertyPage::DoDataExchange(pDX);
|
|
|
|
//{{AFX_DATA_MAP(CFtpAccountsPage)
|
|
DDX_Check(pDX, IDC_CHECK_ALLOW_ANONYMOUS, m_fAllowAnonymous);
|
|
DDX_Check(pDX, IDC_CHECK_ONLY_ANYMOUS, m_fOnlyAnonymous);
|
|
DDX_Check(pDX, IDC_CHECK_ENABLE_PW_SYNCHRONIZATION, m_fPasswordSync);
|
|
DDX_Control(pDX, IDC_BUTTON_ADD, m_button_Add);
|
|
DDX_Control(pDX, IDC_EDIT_PASSWORD, m_edit_Password);
|
|
DDX_Control(pDX, IDC_EDIT_USERNAME, m_edit_UserName);
|
|
DDX_Control(pDX, IDC_STATIC_PW, m_static_Password);
|
|
DDX_Control(pDX, IDC_STATIC_USERNAME, m_static_UserName);
|
|
DDX_Control(pDX, IDC_STATIC_ACCOUNT_PROMPT, m_static_AccountPrompt);
|
|
DDX_Control(pDX, IDC_BUTTON_CHECK_PASSWORD, m_button_CheckPassword);
|
|
DDX_Control(pDX, IDC_BUTTON_BROWSE_USER, m_button_Browse);
|
|
DDX_Control(pDX, IDC_BUTTON_DELETE, m_button_RemoveAdministrator);
|
|
DDX_Control(pDX, IDC_CHECK_ENABLE_PW_SYNCHRONIZATION, m_chk_PasswordSync);
|
|
DDX_Control(pDX, IDC_CHECK_ALLOW_ANONYMOUS, m_chk_AllowAnymous);
|
|
DDX_Control(pDX, IDC_CHECK_ONLY_ANYMOUS, m_chk_OnlyAnonymous);
|
|
//}}AFX_DATA_MAP
|
|
|
|
//
|
|
// Private DDX/DDV Routines
|
|
//
|
|
DDX_Control(pDX, IDC_LIST_ADMINISTRATORS, m_list_Administrators);
|
|
|
|
//
|
|
// Set password/username only during load stage,
|
|
// or if saving when allowing anonymous logons
|
|
//
|
|
if (!pDX->m_bSaveAndValidate || m_fAllowAnonymous)
|
|
{
|
|
DDX_Text(pDX, IDC_EDIT_USERNAME, m_strUserName);
|
|
DDV_MinMaxChars(pDX, m_strUserName, 1, UNLEN);
|
|
|
|
//
|
|
// Some people have a tendency to add "\\" before
|
|
// the computer name in user accounts. Fix this here.
|
|
//
|
|
m_strUserName.TrimLeft();
|
|
|
|
while (*m_strUserName == '\\')
|
|
{
|
|
m_strUserName = m_strUserName.Mid(2);
|
|
}
|
|
|
|
|
|
//
|
|
// Display the remote password sync message if
|
|
// password sync is on, the account is not local,
|
|
// password sync has changed or username has changed
|
|
// and the message hasn't already be shown.
|
|
//
|
|
if (pDX->m_bSaveAndValidate && m_fPasswordSync
|
|
&& !IsLocalAccount(m_strUserName)
|
|
&& (m_fPasswordSyncChanged || m_fUserNameChanged)
|
|
&& !m_fPasswordSyncMsgShown
|
|
)
|
|
{
|
|
if (!NoYesMessageBox(IDS_WRN_PWSYNC))
|
|
{
|
|
pDX->Fail();
|
|
}
|
|
|
|
//
|
|
// Don't show it again
|
|
//
|
|
m_fPasswordSyncMsgShown = TRUE;
|
|
}
|
|
|
|
if (!m_fPasswordSync || !pDX->m_bSaveAndValidate)
|
|
{
|
|
DDX_Password(
|
|
pDX,
|
|
IDC_EDIT_PASSWORD,
|
|
m_strPassword,
|
|
g_lpszDummyPassword
|
|
);
|
|
}
|
|
|
|
if (!m_fPasswordSync)
|
|
{
|
|
DDV_MaxChars(pDX, m_strPassword, PWLEN);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Message Map
|
|
//
|
|
BEGIN_MESSAGE_MAP(CFtpAccountsPage, CInetPropertyPage)
|
|
//{{AFX_MSG_MAP(CFtpAccountsPage)
|
|
ON_BN_CLICKED(IDC_BUTTON_CHECK_PASSWORD, OnButtonCheckPassword)
|
|
ON_BN_CLICKED(IDC_BUTTON_ADD, OnButtonAdd)
|
|
ON_CBN_SELCHANGE(IDC_LIST_ADMINISTRATORS, OnSelchangeListAdministrators)
|
|
ON_BN_CLICKED(IDC_BUTTON_DELETE, OnButtonDelete)
|
|
ON_BN_CLICKED(IDC_CHECK_ENABLE_PW_SYNCHRONIZATION, OnCheckEnablePwSynchronization)
|
|
ON_EN_CHANGE(IDC_EDIT_USERNAME, OnChangeEditUsername)
|
|
//}}AFX_MSG_MAP
|
|
|
|
ON_EN_CHANGE(IDC_EDIT_PASSWORD, OnItemChanged)
|
|
ON_BN_CLICKED(IDC_CHECK_ALLOW_ANONYMOUS, OnCheckAllowAnonymous)
|
|
ON_BN_CLICKED(IDC_CHECK_ONLY_ANYMOUS, OnCheckAllowOnlyAnonymous)
|
|
ON_BN_CLICKED(IDC_BUTTON_BROWSE_USER, OnButtonBrowseUser)
|
|
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::SetControlStates(
|
|
IN BOOL fAllowAnonymous
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the states of the dialog control depending on its current
|
|
values.
|
|
|
|
Arguments:
|
|
|
|
BOOL fAllowAnonymous : If TRUE, 'allow anonymous' is on.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
m_static_Password.EnableWindow(
|
|
fAllowAnonymous
|
|
&& !m_fPasswordSync
|
|
&& HasAdminAccess()
|
|
);
|
|
|
|
m_edit_Password.EnableWindow(
|
|
fAllowAnonymous
|
|
&& !m_fPasswordSync
|
|
&& HasAdminAccess()
|
|
);
|
|
|
|
m_button_CheckPassword.EnableWindow(
|
|
fAllowAnonymous
|
|
&& !m_fPasswordSync
|
|
&& HasAdminAccess()
|
|
);
|
|
|
|
m_static_AccountPrompt.EnableWindow(fAllowAnonymous);
|
|
m_static_UserName.EnableWindow(fAllowAnonymous && HasAdminAccess());
|
|
m_edit_UserName.EnableWindow(fAllowAnonymous && HasAdminAccess());
|
|
m_button_Browse.EnableWindow(fAllowAnonymous && HasAdminAccess());
|
|
m_chk_PasswordSync.EnableWindow(fAllowAnonymous && HasAdminAccess());
|
|
m_chk_OnlyAnonymous.EnableWindow(fAllowAnonymous);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CFtpAccountsPage::SetAdminRemoveState()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set the state of the remove button depending on the selection in the
|
|
administrators listbox. Remove is only enabled if ALL selected
|
|
items are removable.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if the remove button is enabled.
|
|
|
|
--*/
|
|
{
|
|
int nSel = 0;
|
|
int cSelectedItems = 0;
|
|
BOOL fAllDeletable = TRUE;
|
|
CAccessEntry * pAccess;
|
|
|
|
while ((pAccess = m_list_Administrators.GetNextSelectedItem(&nSel)) != NULL)
|
|
{
|
|
++cSelectedItems;
|
|
|
|
if (!pAccess->IsDeletable())
|
|
{
|
|
fAllDeletable = FALSE;
|
|
break;
|
|
}
|
|
|
|
++nSel;
|
|
}
|
|
|
|
fAllDeletable = fAllDeletable && (cSelectedItems > 0);
|
|
|
|
m_button_RemoveAdministrator.EnableWindow(
|
|
fAllDeletable
|
|
&& HasOperatorList()
|
|
&& HasAdminAccess()
|
|
);
|
|
|
|
return fAllDeletable;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Message Handlers
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
BOOL
|
|
CFtpAccountsPage::OnInitDialog()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
WM_INITDIALOG handler. Initialize the dialog.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if no focus is to be set automatically, FALSE if the focus
|
|
is already set.
|
|
|
|
--*/
|
|
{
|
|
CInetPropertyPage::OnInitDialog();
|
|
|
|
m_list_Administrators.Initialize();
|
|
|
|
CWaitCursor wait;
|
|
|
|
//
|
|
// Build the ACL list
|
|
//
|
|
CError err(BuildAclOblistFromBlob(
|
|
((CFtpSheet *)GetSheet())->GetInstanceProperties().m_acl,
|
|
m_oblSID
|
|
));
|
|
|
|
err.MessageBoxOnFailure();
|
|
|
|
m_list_Administrators.FillAccessListBox(m_oblSID);
|
|
|
|
//
|
|
// check if the operators controls are accessible
|
|
//
|
|
m_button_Add.EnableWindow(HasOperatorList() && HasAdminAccess());
|
|
m_list_Administrators.EnableWindow(HasOperatorList() && HasAdminAccess());
|
|
|
|
GetDlgItem(IDC_STATIC_OPERATOR_PROMPT1)->EnableWindow(
|
|
HasOperatorList()
|
|
&& HasAdminAccess()
|
|
);
|
|
|
|
GetDlgItem(IDC_STATIC_OPERATOR_PROMPT2)->EnableWindow(
|
|
HasOperatorList()
|
|
&& HasAdminAccess()
|
|
);
|
|
|
|
SetControlStates(m_fAllowAnonymous);
|
|
SetAdminRemoveState();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CFtpAccountsPage::FetchLoadedValues()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Move configuration data from sheet to dialog controls
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
CError err;
|
|
|
|
BEGIN_META_INST_READ(CFtpSheet)
|
|
FETCH_INST_DATA_FROM_SHEET(m_strUserName);
|
|
FETCH_INST_DATA_FROM_SHEET(m_strPassword);
|
|
FETCH_INST_DATA_FROM_SHEET(m_fAllowAnonymous);
|
|
FETCH_INST_DATA_FROM_SHEET(m_fOnlyAnonymous);
|
|
FETCH_INST_DATA_FROM_SHEET(m_fPasswordSync);
|
|
END_META_INST_READ(err)
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
HRESULT
|
|
CFtpAccountsPage::SaveInfo()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Save the information on this property page
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Error return code
|
|
|
|
--*/
|
|
{
|
|
ASSERT(IsDirty());
|
|
|
|
TRACEEOLID("Saving FTP service page now...");
|
|
|
|
//
|
|
// Use m_ notation because the message crackers require it
|
|
//
|
|
CBlob m_acl;
|
|
BOOL fAclDirty = BuildAclBlob(m_oblSID, m_acl);
|
|
|
|
CError err;
|
|
|
|
BeginWaitCursor();
|
|
BEGIN_META_INST_WRITE(CFtpSheet)
|
|
STORE_INST_DATA_ON_SHEET(m_strUserName)
|
|
STORE_INST_DATA_ON_SHEET(m_fOnlyAnonymous)
|
|
STORE_INST_DATA_ON_SHEET(m_fAllowAnonymous)
|
|
STORE_INST_DATA_ON_SHEET(m_fPasswordSync)
|
|
if (fAclDirty)
|
|
{
|
|
STORE_INST_DATA_ON_SHEET(m_acl)
|
|
}
|
|
if (m_fPasswordSync)
|
|
{
|
|
//
|
|
// Delete password
|
|
//
|
|
// CODEWORK: Shouldn't need to know ID number.
|
|
// Implement m_fDelete flag in CMP template maybe?
|
|
//
|
|
FLAG_INST_DATA_FOR_DELETION(MD_ANONYMOUS_PWD);
|
|
}
|
|
else
|
|
{
|
|
STORE_INST_DATA_ON_SHEET(m_strPassword);
|
|
}
|
|
END_META_INST_WRITE(err)
|
|
EndWaitCursor();
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::OnItemChanged()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Register a change in control value on this page. Mark the page as dirty.
|
|
All change messages map to this function
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
SetModified(TRUE);
|
|
SetControlStates(m_chk_AllowAnymous.GetCheck() > 0);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::OnCheckAllowAnonymous()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Respond to 'allow anonymous' checkbox being pressed
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (m_chk_AllowAnymous.GetCheck() == 0)
|
|
{
|
|
//
|
|
// Show security warning
|
|
//
|
|
CClearTxtDlg dlg;
|
|
|
|
if (dlg.DoModal() != IDOK)
|
|
{
|
|
m_chk_AllowAnymous.SetCheck(1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
SetControlStates(m_chk_AllowAnymous.GetCheck() > 0);
|
|
OnItemChanged();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::OnCheckAllowOnlyAnonymous()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Respond to 'allow only anonymous' checkbox being pressed
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (m_chk_OnlyAnonymous.GetCheck() == 0)
|
|
{
|
|
//
|
|
// Show security warning
|
|
//
|
|
CClearTxtDlg dlg;
|
|
|
|
if (dlg.DoModal() != IDOK)
|
|
{
|
|
m_chk_OnlyAnonymous.SetCheck(1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
OnItemChanged();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::OnButtonBrowseUser()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
User browser button has been pressed. Browse for IUSR account name
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
CString str;
|
|
|
|
if (GetIUsrAccount(str))
|
|
{
|
|
//
|
|
// If the name is non-local (determined by having
|
|
// a slash in the name, password sync is disabled,
|
|
// and a password should be entered.
|
|
//
|
|
m_edit_UserName.SetWindowText(str);
|
|
|
|
if (!(m_fPasswordSync = IsLocalAccount(str)))
|
|
{
|
|
m_edit_Password.SetWindowText(_T(""));
|
|
m_edit_Password.SetFocus();
|
|
}
|
|
|
|
m_chk_PasswordSync.SetCheck(m_fPasswordSync);
|
|
OnItemChanged();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::OnButtonCheckPassword()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check password button has been pressed.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (!UpdateData(TRUE))
|
|
{
|
|
return;
|
|
}
|
|
|
|
CError err(CComAuthInfo::VerifyUserPassword(m_strUserName, m_strPassword));
|
|
|
|
if (!err.MessageBoxOnFailure())
|
|
{
|
|
::AfxMessageBox(IDS_PASSWORD_OK);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::OnButtonAdd()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
'Add' button has been pressed
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (m_list_Administrators.AddToAccessList(
|
|
this,
|
|
QueryServerName(),
|
|
m_oblSID
|
|
))
|
|
{
|
|
OnItemChanged();
|
|
}
|
|
|
|
SetAdminRemoveState();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::OnSelchangeListAdministrators()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Selection Change in admin list box handler
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
SetAdminRemoveState();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::OnButtonDelete()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete all selected items in the list box
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
int nSel = 0;
|
|
int cChanges = 0;
|
|
CAccessEntry * pAccess;
|
|
|
|
while ((pAccess = m_list_Administrators.GetNextSelectedItem(&nSel)) != NULL)
|
|
{
|
|
//
|
|
// Remove button should be disabled unless all selected
|
|
// items are deletable
|
|
//
|
|
ASSERT(pAccess->IsDeletable());
|
|
if (pAccess->IsDeletable())
|
|
{
|
|
++cChanges;
|
|
pAccess->FlagForDeletion();
|
|
m_list_Administrators.DeleteString(nSel);
|
|
|
|
//
|
|
// Don't advance counter to account for shift
|
|
//
|
|
continue;
|
|
}
|
|
|
|
++nSel;
|
|
}
|
|
|
|
if (cChanges)
|
|
{
|
|
OnItemChanged();
|
|
}
|
|
|
|
if (!SetAdminRemoveState())
|
|
{
|
|
m_button_Add.SetFocus();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::OnCheckEnablePwSynchronization()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handler for 'enable password synchronization' checkbox press
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
m_fPasswordSyncChanged = TRUE;
|
|
m_fPasswordSync = !m_fPasswordSync;
|
|
OnItemChanged();
|
|
SetControlStates(m_chk_AllowAnymous.GetCheck() > 0);
|
|
|
|
if (!m_fPasswordSync )
|
|
{
|
|
m_edit_Password.SetSel(0,-1);
|
|
m_edit_Password.SetFocus();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CFtpAccountsPage::OnChangeEditUsername()
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
Handler for 'username' edit box change messages
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
m_fUserNameChanged = TRUE;
|
|
OnItemChanged();
|
|
}
|