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

425 lines
9.0 KiB

  1. // Copyright (C) 1997 Microsoft Corporation
  2. //
  3. // UserMemberPage class
  4. //
  5. // 9-11-97 sburns
  6. #include "headers.hxx"
  7. #include "UserMemberPage.hpp"
  8. #include "resource.h"
  9. #include "lsm.h"
  10. #include "adsi.hpp"
  11. #include "MemberVisitor.hpp"
  12. #include "dlgcomm.hpp"
  13. static const DWORD HELP_MAP[] =
  14. {
  15. IDC_GROUPS, idh_memberof_list,
  16. IDC_ADD, idh_memberof_add,
  17. IDC_REMOVE, idh_memberof_remove,
  18. 0, 0
  19. };
  20. UserMemberPage::UserMemberPage(
  21. MMCPropertyPage::NotificationState* state,
  22. const String& userADSIPath)
  23. :
  24. ADSIPage(
  25. IDD_USER_MEMBER,
  26. HELP_MAP,
  27. state,
  28. userADSIPath)
  29. {
  30. LOG_CTOR2(UserMemberPage, userADSIPath);
  31. }
  32. UserMemberPage::~UserMemberPage()
  33. {
  34. LOG_DTOR2(UserMemberPage, GetADSIPath());
  35. }
  36. void
  37. UserMemberPage::OnInit()
  38. {
  39. LOG_FUNCTION(UserMemberPage::OnInit);
  40. // Setup the controls
  41. listview =
  42. new MembershipListView(
  43. Win::GetDlgItem(hwnd, IDC_GROUPS),
  44. GetMachineName(),
  45. MembershipListView::USER_MEMBERSHIP);
  46. // load the group properties into the dialog.
  47. HRESULT hr = S_OK;
  48. do
  49. {
  50. SmartInterface<IADsUser> user(0);
  51. hr = ADSI::GetUser(GetADSIPath(), user);
  52. BREAK_ON_FAILED_HRESULT(hr);
  53. // populate the list with group membership
  54. MemberVisitor
  55. visitor(original_groups, hwnd, GetObjectName(), GetMachineName());
  56. hr = ADSI::VisitGroups(user, visitor);
  57. BREAK_ON_FAILED_HRESULT(hr);
  58. listview->SetContents(original_groups);
  59. }
  60. while (0);
  61. if (FAILED(hr))
  62. {
  63. popup.Error(
  64. hwnd,
  65. hr,
  66. String::format(IDS_ERROR_READING_USER, GetObjectName().c_str()));
  67. Win::PostMessage(Win::GetParent(hwnd), WM_CLOSE, 0, 0);
  68. }
  69. ClearChanges();
  70. enable();
  71. }
  72. void
  73. UserMemberPage::enable()
  74. {
  75. // LOG_FUNCTION(UserMemberPage::enable);
  76. bool selected =
  77. Win::ListView_GetSelectedCount(
  78. Win::GetDlgItem(hwnd, IDC_GROUPS)) > 0;
  79. HWND removeButton = Win::GetDlgItem(hwnd, IDC_REMOVE);
  80. if (!selected)
  81. {
  82. // If we're about to disable the remove button, check to see if it
  83. // has focus first. If it does, we need to move focus to another
  84. // control. Similarly for default pushbutton style.
  85. // NTRAID#NTBUG9-435045-2001/07/13-sburns
  86. if (removeButton == ::GetFocus())
  87. {
  88. HWND addButton = Win::GetDlgItem(hwnd, IDC_ADD);
  89. Win::SetFocus(addButton);
  90. Win::Button_SetStyle(addButton, BS_DEFPUSHBUTTON, true);
  91. Win::Button_SetStyle(removeButton, BS_PUSHBUTTON, true);
  92. }
  93. }
  94. Win::EnableWindow(removeButton, selected);
  95. }
  96. bool
  97. UserMemberPage::OnNotify(
  98. HWND /* windowFrom */ ,
  99. UINT_PTR controlIDFrom,
  100. UINT code,
  101. LPARAM lparam)
  102. {
  103. LOG_FUNCTION(UserMemberPage::OnNotify);
  104. switch (controlIDFrom)
  105. {
  106. case IDC_GROUPS:
  107. {
  108. switch (code)
  109. {
  110. case LVN_ITEMCHANGED:
  111. {
  112. ASSERT(lparam);
  113. if (lparam)
  114. {
  115. NMLISTVIEW* lv = reinterpret_cast<NMLISTVIEW*>(lparam);
  116. if (lv->uChanged & LVIF_STATE)
  117. {
  118. // a list item changed state
  119. enable();
  120. }
  121. }
  122. break;
  123. }
  124. case LVN_KEYDOWN:
  125. {
  126. ASSERT(lparam);
  127. if (lparam)
  128. {
  129. NMLVKEYDOWN* kd = reinterpret_cast<NMLVKEYDOWN*>(lparam);
  130. if (kd->wVKey == VK_INSERT)
  131. {
  132. listview->OnAddButton();
  133. }
  134. else if (kd->wVKey == VK_DELETE)
  135. {
  136. listview->OnRemoveButton();
  137. }
  138. }
  139. break;
  140. }
  141. case LVN_INSERTITEM:
  142. case LVN_DELETEITEM:
  143. {
  144. SetChanged(controlIDFrom);
  145. Win::PropSheet_Changed(Win::GetParent(hwnd), hwnd);
  146. break;
  147. }
  148. default:
  149. {
  150. break;
  151. }
  152. }
  153. break;
  154. }
  155. default:
  156. {
  157. }
  158. }
  159. return true;
  160. }
  161. void
  162. UserMemberPage::OnDestroy()
  163. {
  164. LOG_FUNCTION(UserMemberPage::OnDestroy);
  165. delete listview;
  166. listview = 0;
  167. }
  168. bool
  169. UserMemberPage::OnCommand(
  170. HWND /* windowFrom */ ,
  171. unsigned controlIDFrom,
  172. unsigned code)
  173. {
  174. // LOG_FUNCTION(UserMemberPage::OnCommand);
  175. switch (controlIDFrom)
  176. {
  177. case IDC_ADD:
  178. {
  179. if (code == BN_CLICKED)
  180. {
  181. listview->OnAddButton();
  182. }
  183. break;
  184. }
  185. case IDC_REMOVE:
  186. {
  187. if (code == BN_CLICKED)
  188. {
  189. listview->OnRemoveButton();
  190. }
  191. break;
  192. }
  193. default:
  194. {
  195. break;
  196. }
  197. }
  198. return true;
  199. }
  200. bool
  201. UserMemberPage::OnApply(bool isClosing)
  202. {
  203. LOG_FUNCTION(UserMemberPage::OnApply);
  204. if (WasChanged(IDC_GROUPS))
  205. {
  206. // save the changes thru ADSI
  207. HRESULT hr = S_OK;
  208. do
  209. {
  210. SmartInterface<IADsUser> user(0);
  211. hr = ADSI::GetUser(GetADSIPath(), user);
  212. BREAK_ON_FAILED_HRESULT(hr);
  213. SmartInterface<IADs> iads(0);
  214. hr = iads.AcquireViaQueryInterface(user);
  215. BREAK_ON_FAILED_HRESULT(hr);
  216. String sidPath;
  217. hr = ADSI::GetSidPath(iads, sidPath);
  218. BREAK_ON_FAILED_HRESULT(hr);
  219. MemberList new_groups;
  220. listview->GetContents(new_groups);
  221. hr =
  222. ReconcileMembershipChanges(
  223. sidPath,
  224. original_groups,
  225. new_groups);
  226. BREAK_ON_FAILED_HRESULT(hr);
  227. if (!isClosing)
  228. {
  229. // refresh the listview
  230. original_groups.clear();
  231. MemberVisitor
  232. visitor(
  233. original_groups,
  234. hwnd,
  235. GetObjectName(),
  236. GetMachineName());
  237. hr = ADSI::VisitGroups(user, visitor);
  238. BREAK_ON_FAILED_HRESULT(hr);
  239. listview->SetContents(original_groups);
  240. }
  241. SetChangesApplied();
  242. ClearChanges();
  243. }
  244. while (0);
  245. if (FAILED(hr))
  246. {
  247. popup.Error(
  248. hwnd,
  249. hr,
  250. String::format(
  251. IDS_ERROR_SETTING_USER_PROPERTIES,
  252. GetObjectName().c_str(),
  253. GetMachineName().c_str()));
  254. }
  255. }
  256. return true;
  257. }
  258. HRESULT
  259. UserMemberPage::ReconcileMembershipChanges(
  260. const String& userADSIPath,
  261. MemberList originalGroups, // a copy
  262. const MemberList& newGroups)
  263. {
  264. LOG_FUNCTION2(UserMemberPage::ReconcileMembershipChanges, userADSIPath);
  265. ASSERT(!userADSIPath.empty());
  266. bool successful = true; // be optimistic!
  267. HRESULT hr = S_OK;
  268. for (
  269. MemberList::iterator i = newGroups.begin();
  270. i != newGroups.end();
  271. i++)
  272. {
  273. MemberInfo& info = *i;
  274. MemberList::iterator f =
  275. std::find(originalGroups.begin(), originalGroups.end(), info);
  276. if (f != originalGroups.end())
  277. {
  278. // found. remove the matching node in the original list
  279. originalGroups.erase(f);
  280. }
  281. else
  282. {
  283. // not found. Add the user as a member of the group
  284. SmartInterface<IADsGroup> group(0);
  285. hr = ADSI::GetGroup(info.path, group);
  286. if (SUCCEEDED(hr))
  287. {
  288. hr = group->Add(AutoBstr(userADSIPath));
  289. if (hr == Win32ToHresult(ERROR_MEMBER_IN_ALIAS))
  290. {
  291. // already a member: pop up a warning but don't consider this
  292. // a real error. 6791
  293. hr = S_OK;
  294. String name = GetObjectName();
  295. BSTR groupName;
  296. HRESULT anotherHr = group->get_Name(&groupName);
  297. if (SUCCEEDED(anotherHr))
  298. {
  299. popup.Info(
  300. hwnd,
  301. String::format(
  302. IDS_ALREADY_MEMBER,
  303. name.c_str(),
  304. groupName));
  305. ::SysFreeString(groupName);
  306. }
  307. }
  308. }
  309. if (FAILED(hr))
  310. {
  311. LOG_HRESULT(hr);
  312. successful = false;
  313. }
  314. }
  315. }
  316. // at this point, the original list contains only those nodes which are
  317. // not in the new list. Remove these from the group membership
  318. for (
  319. i = originalGroups.begin();
  320. i != originalGroups.end();
  321. i++)
  322. {
  323. SmartInterface<IADsGroup> group(0);
  324. hr = ADSI::GetGroup(i->path, group);
  325. if (SUCCEEDED(hr))
  326. {
  327. hr = group->Remove(AutoBstr(userADSIPath));
  328. // CODEWORK: what if the member is not part of the group?
  329. }
  330. if (FAILED(hr))
  331. {
  332. LOG_HRESULT(hr);
  333. successful = false;
  334. }
  335. }
  336. if (!successful)
  337. {
  338. popup.Error(
  339. hwnd,
  340. 0,
  341. String::format(
  342. IDS_ERROR_CHANGING_MEMBERSHIP,
  343. GetObjectName().c_str()));
  344. }
  345. return hr;
  346. }