// Copyright (C) 1997 Microsoft Corporation // // UserMemberPage class // // 9-11-97 sburns #include "headers.hxx" #include "UserMemberPage.hpp" #include "resource.h" #include "lsm.h" #include "adsi.hpp" #include "MemberVisitor.hpp" #include "dlgcomm.hpp" static const DWORD HELP_MAP[] = { IDC_GROUPS, idh_memberof_list, IDC_ADD, idh_memberof_add, IDC_REMOVE, idh_memberof_remove, 0, 0 }; UserMemberPage::UserMemberPage( MMCPropertyPage::NotificationState* state, const String& userADSIPath) : ADSIPage( IDD_USER_MEMBER, HELP_MAP, state, userADSIPath) { LOG_CTOR2(UserMemberPage, userADSIPath); } UserMemberPage::~UserMemberPage() { LOG_DTOR2(UserMemberPage, GetADSIPath()); } void UserMemberPage::OnInit() { LOG_FUNCTION(UserMemberPage::OnInit); // Setup the controls listview = new MembershipListView( Win::GetDlgItem(hwnd, IDC_GROUPS), GetMachineName(), MembershipListView::USER_MEMBERSHIP); // load the group properties into the dialog. HRESULT hr = S_OK; do { SmartInterface user(0); hr = ADSI::GetUser(GetADSIPath(), user); BREAK_ON_FAILED_HRESULT(hr); // populate the list with group membership MemberVisitor visitor(original_groups, hwnd, GetObjectName(), GetMachineName()); hr = ADSI::VisitGroups(user, visitor); BREAK_ON_FAILED_HRESULT(hr); listview->SetContents(original_groups); } while (0); if (FAILED(hr)) { popup.Error( hwnd, hr, String::format(IDS_ERROR_READING_USER, GetObjectName().c_str())); Win::PostMessage(Win::GetParent(hwnd), WM_CLOSE, 0, 0); } ClearChanges(); enable(); } void UserMemberPage::enable() { // LOG_FUNCTION(UserMemberPage::enable); bool selected = Win::ListView_GetSelectedCount( Win::GetDlgItem(hwnd, IDC_GROUPS)) > 0; HWND removeButton = Win::GetDlgItem(hwnd, IDC_REMOVE); if (!selected) { // If we're about to disable the remove button, check to see if it // has focus first. If it does, we need to move focus to another // control. Similarly for default pushbutton style. // NTRAID#NTBUG9-435045-2001/07/13-sburns if (removeButton == ::GetFocus()) { HWND addButton = Win::GetDlgItem(hwnd, IDC_ADD); Win::SetFocus(addButton); Win::Button_SetStyle(addButton, BS_DEFPUSHBUTTON, true); Win::Button_SetStyle(removeButton, BS_PUSHBUTTON, true); } } Win::EnableWindow(removeButton, selected); } bool UserMemberPage::OnNotify( HWND /* windowFrom */ , UINT_PTR controlIDFrom, UINT code, LPARAM lparam) { LOG_FUNCTION(UserMemberPage::OnNotify); switch (controlIDFrom) { case IDC_GROUPS: { switch (code) { case LVN_ITEMCHANGED: { ASSERT(lparam); if (lparam) { NMLISTVIEW* lv = reinterpret_cast(lparam); if (lv->uChanged & LVIF_STATE) { // a list item changed state enable(); } } break; } case LVN_KEYDOWN: { ASSERT(lparam); if (lparam) { NMLVKEYDOWN* kd = reinterpret_cast(lparam); if (kd->wVKey == VK_INSERT) { listview->OnAddButton(); } else if (kd->wVKey == VK_DELETE) { listview->OnRemoveButton(); } } break; } case LVN_INSERTITEM: case LVN_DELETEITEM: { SetChanged(controlIDFrom); Win::PropSheet_Changed(Win::GetParent(hwnd), hwnd); break; } default: { break; } } break; } default: { } } return true; } void UserMemberPage::OnDestroy() { LOG_FUNCTION(UserMemberPage::OnDestroy); delete listview; listview = 0; } bool UserMemberPage::OnCommand( HWND /* windowFrom */ , unsigned controlIDFrom, unsigned code) { // LOG_FUNCTION(UserMemberPage::OnCommand); switch (controlIDFrom) { case IDC_ADD: { if (code == BN_CLICKED) { listview->OnAddButton(); } break; } case IDC_REMOVE: { if (code == BN_CLICKED) { listview->OnRemoveButton(); } break; } default: { break; } } return true; } bool UserMemberPage::OnApply(bool isClosing) { LOG_FUNCTION(UserMemberPage::OnApply); if (WasChanged(IDC_GROUPS)) { // save the changes thru ADSI HRESULT hr = S_OK; do { SmartInterface user(0); hr = ADSI::GetUser(GetADSIPath(), user); BREAK_ON_FAILED_HRESULT(hr); SmartInterface iads(0); hr = iads.AcquireViaQueryInterface(user); BREAK_ON_FAILED_HRESULT(hr); String sidPath; hr = ADSI::GetSidPath(iads, sidPath); BREAK_ON_FAILED_HRESULT(hr); MemberList new_groups; listview->GetContents(new_groups); hr = ReconcileMembershipChanges( sidPath, original_groups, new_groups); BREAK_ON_FAILED_HRESULT(hr); if (!isClosing) { // refresh the listview original_groups.clear(); MemberVisitor visitor( original_groups, hwnd, GetObjectName(), GetMachineName()); hr = ADSI::VisitGroups(user, visitor); BREAK_ON_FAILED_HRESULT(hr); listview->SetContents(original_groups); } SetChangesApplied(); ClearChanges(); } while (0); if (FAILED(hr)) { popup.Error( hwnd, hr, String::format( IDS_ERROR_SETTING_USER_PROPERTIES, GetObjectName().c_str(), GetMachineName().c_str())); } } return true; } HRESULT UserMemberPage::ReconcileMembershipChanges( const String& userADSIPath, MemberList originalGroups, // a copy const MemberList& newGroups) { LOG_FUNCTION2(UserMemberPage::ReconcileMembershipChanges, userADSIPath); ASSERT(!userADSIPath.empty()); bool successful = true; // be optimistic! HRESULT hr = S_OK; for ( MemberList::iterator i = newGroups.begin(); i != newGroups.end(); i++) { MemberInfo& info = *i; MemberList::iterator f = std::find(originalGroups.begin(), originalGroups.end(), info); if (f != originalGroups.end()) { // found. remove the matching node in the original list originalGroups.erase(f); } else { // not found. Add the user as a member of the group SmartInterface group(0); hr = ADSI::GetGroup(info.path, group); if (SUCCEEDED(hr)) { hr = group->Add(AutoBstr(userADSIPath)); if (hr == Win32ToHresult(ERROR_MEMBER_IN_ALIAS)) { // already a member: pop up a warning but don't consider this // a real error. 6791 hr = S_OK; String name = GetObjectName(); BSTR groupName; HRESULT anotherHr = group->get_Name(&groupName); if (SUCCEEDED(anotherHr)) { popup.Info( hwnd, String::format( IDS_ALREADY_MEMBER, name.c_str(), groupName)); ::SysFreeString(groupName); } } } if (FAILED(hr)) { LOG_HRESULT(hr); successful = false; } } } // at this point, the original list contains only those nodes which are // not in the new list. Remove these from the group membership for ( i = originalGroups.begin(); i != originalGroups.end(); i++) { SmartInterface group(0); hr = ADSI::GetGroup(i->path, group); if (SUCCEEDED(hr)) { hr = group->Remove(AutoBstr(userADSIPath)); // CODEWORK: what if the member is not part of the group? } if (FAILED(hr)) { LOG_HRESULT(hr); successful = false; } } if (!successful) { popup.Error( hwnd, 0, String::format( IDS_ERROR_CHANGING_MEMBERSHIP, GetObjectName().c_str())); } return hr; }