/*++ 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 "fscfg.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(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(); }