d10e7feab9380b69257f065b6bb1b142e2f69a9e
[reactos.git] / reactos / dll / cpl / usrmgr / users.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS User Manager Control Panel
4 * FILE: dll/cpl/usrmgr/users.c
5 * PURPOSE: Users property page
6 *
7 * PROGRAMMERS: Eric Kohl
8 */
9
10 /*
11 * TODO:
12 * - Add new user to the users group.
13 * - Remove a user from all groups.
14 * - Implement user property pages.
15 * - Use localized messages.
16 */
17
18 #include "usrmgr.h"
19
20
21 typedef struct _USER_DATA
22 {
23 HMENU hPopupMenu;
24
25 INT iCurrentItem;
26
27 } USER_DATA, *PUSER_DATA;
28
29
30
31 static BOOL
32 CheckPasswords(HWND hwndDlg,
33 INT nIdDlgItem1,
34 INT nIdDlgItem2)
35 {
36 TCHAR szPassword1[256];
37 TCHAR szPassword2[256];
38 UINT uLen1;
39 UINT uLen2;
40
41 uLen1 = GetDlgItemText(hwndDlg, nIdDlgItem1, szPassword1, 256);
42 uLen2 = GetDlgItemText(hwndDlg, nIdDlgItem2, szPassword2, 256);
43
44 /* Check the passwords */
45 if (uLen1 != uLen2 || _tcscmp(szPassword1, szPassword2) != 0)
46 {
47 MessageBox(hwndDlg,
48 TEXT("The passwords you entered are not the same!"),
49 TEXT("ERROR"),
50 MB_OK | MB_ICONERROR);
51 return FALSE;
52 }
53
54
55 return TRUE;
56 }
57
58
59 INT_PTR CALLBACK
60 ChangePasswordDlgProc(HWND hwndDlg,
61 UINT uMsg,
62 WPARAM wParam,
63 LPARAM lParam)
64 {
65 UNREFERENCED_PARAMETER(wParam);
66
67 switch (uMsg)
68 {
69 case WM_INITDIALOG:
70 break;
71
72 case WM_COMMAND:
73 switch (LOWORD(wParam))
74 {
75 case IDOK:
76 if (CheckPasswords(hwndDlg, IDC_EDIT_PASSWORD1, IDC_EDIT_PASSWORD2))
77 EndDialog(hwndDlg, 0);
78 break;
79
80 case IDCANCEL:
81 EndDialog(hwndDlg, 0);
82 break;
83 }
84 break;
85
86 default:
87 return FALSE;
88 }
89
90 return TRUE;
91 }
92
93
94 static VOID
95 UpdateUserOptions(HWND hwndDlg,
96 PUSER_INFO_3 userInfo,
97 BOOL bInit)
98 {
99 EnableWindow(GetDlgItem(hwndDlg, IDC_USER_NEW_CANNOT_CHANGE),
100 !userInfo->usri3_password_expired);
101 EnableWindow(GetDlgItem(hwndDlg, IDC_USER_NEW_NEVER_EXPIRES),
102 !userInfo->usri3_password_expired);
103
104 EnableWindow(GetDlgItem(hwndDlg, IDC_USER_NEW_FORCE_CHANGE),
105 (userInfo->usri3_flags & (UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD)) == 0);
106
107 if (bInit)
108 {
109 CheckDlgButton(hwndDlg, IDC_USER_NEW_FORCE_CHANGE,
110 userInfo->usri3_password_expired ? BST_CHECKED : BST_UNCHECKED);
111
112 CheckDlgButton(hwndDlg, IDC_USER_NEW_CANNOT_CHANGE,
113 (userInfo->usri3_flags & UF_PASSWD_CANT_CHANGE) ? BST_CHECKED : BST_UNCHECKED);
114
115 CheckDlgButton(hwndDlg, IDC_USER_NEW_NEVER_EXPIRES,
116 (userInfo->usri3_flags & UF_DONT_EXPIRE_PASSWD) ? BST_CHECKED : BST_UNCHECKED);
117
118 CheckDlgButton(hwndDlg, IDC_USER_NEW_DISABLED,
119 (userInfo->usri3_flags & UF_ACCOUNTDISABLE) ? BST_CHECKED : BST_UNCHECKED);
120 }
121 }
122
123
124 INT_PTR CALLBACK
125 NewUserDlgProc(HWND hwndDlg,
126 UINT uMsg,
127 WPARAM wParam,
128 LPARAM lParam)
129 {
130 PUSER_INFO_3 userInfo;
131 INT nLength;
132
133 UNREFERENCED_PARAMETER(wParam);
134
135 userInfo = (PUSER_INFO_3)GetWindowLongPtr(hwndDlg, DWLP_USER);
136
137 switch (uMsg)
138 {
139 case WM_INITDIALOG:
140 userInfo = (PUSER_INFO_3)lParam;
141 SetWindowLongPtr(hwndDlg, DWLP_USER, lParam);
142 SendDlgItemMessage(hwndDlg, IDC_USER_NEW_NAME, EM_SETLIMITTEXT, 20, 0);
143 UpdateUserOptions(hwndDlg, userInfo, TRUE);
144 break;
145
146 case WM_COMMAND:
147 switch (LOWORD(wParam))
148 {
149 case IDC_USER_NEW_NAME:
150 if (HIWORD(wParam) == EN_CHANGE)
151 {
152 nLength = SendDlgItemMessage(hwndDlg, IDC_USER_NEW_NAME, WM_GETTEXTLENGTH, 0, 0);
153 EnableWindow(GetDlgItem(hwndDlg, IDOK), (nLength > 0));
154 }
155 break;
156
157 case IDC_USER_NEW_FORCE_CHANGE:
158 userInfo->usri3_password_expired = !userInfo->usri3_password_expired;
159 UpdateUserOptions(hwndDlg, userInfo, FALSE);
160 break;
161
162 case IDC_USER_NEW_CANNOT_CHANGE:
163 userInfo->usri3_flags ^= UF_PASSWD_CANT_CHANGE;
164 UpdateUserOptions(hwndDlg, userInfo, FALSE);
165 break;
166
167 case IDC_USER_NEW_NEVER_EXPIRES:
168 userInfo->usri3_flags ^= UF_DONT_EXPIRE_PASSWD;
169 UpdateUserOptions(hwndDlg, userInfo, FALSE);
170 break;
171
172 case IDC_USER_NEW_DISABLED:
173 userInfo->usri3_flags ^= UF_ACCOUNTDISABLE;
174 break;
175
176 case IDOK:
177 if (!CheckAccountName(hwndDlg, IDC_USER_NEW_NAME, NULL))
178 {
179 SetFocus(GetDlgItem(hwndDlg, IDC_USER_NEW_NAME));
180 SendDlgItemMessage(hwndDlg, IDC_USER_NEW_NAME, EM_SETSEL, 0, -1);
181 break;
182 }
183
184 if (!CheckPasswords(hwndDlg, IDC_USER_NEW_PASSWORD1, IDC_USER_NEW_PASSWORD2))
185 {
186 SetDlgItemText(hwndDlg, IDC_USER_NEW_PASSWORD1, TEXT(""));
187 SetDlgItemText(hwndDlg, IDC_USER_NEW_PASSWORD2, TEXT(""));
188 break;
189 }
190
191 /* Store the user name */
192 nLength = SendDlgItemMessage(hwndDlg, IDC_USER_NEW_NAME, WM_GETTEXTLENGTH, 0, 0);
193 if (nLength > 0)
194 {
195 userInfo->usri3_name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nLength + 1) * sizeof(WCHAR));
196 GetDlgItemText(hwndDlg, IDC_USER_NEW_NAME, userInfo->usri3_name, nLength + 1);
197 }
198
199 /* Store the full user name */
200 nLength = SendDlgItemMessage(hwndDlg, IDC_USER_NEW_FULL_NAME, WM_GETTEXTLENGTH, 0, 0);
201 if (nLength > 0)
202 {
203 userInfo->usri3_full_name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nLength + 1) * sizeof(WCHAR));
204 GetDlgItemText(hwndDlg, IDC_USER_NEW_FULL_NAME, userInfo->usri3_full_name, nLength + 1);
205 }
206
207 /* Store the description */
208 nLength = SendDlgItemMessage(hwndDlg, IDC_USER_NEW_DESCRIPTION, WM_GETTEXTLENGTH, 0, 0);
209 if (nLength > 0)
210 {
211 userInfo->usri3_comment = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nLength + 1) * sizeof(WCHAR));
212 GetDlgItemText(hwndDlg, IDC_USER_NEW_DESCRIPTION, userInfo->usri3_comment, nLength + 1);
213 }
214
215 /* Store the password */
216 nLength = SendDlgItemMessage(hwndDlg, IDC_USER_NEW_PASSWORD1, WM_GETTEXTLENGTH, 0, 0);
217 if (nLength > 0)
218 {
219 userInfo->usri3_password = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nLength + 1) * sizeof(WCHAR));
220 GetDlgItemText(hwndDlg, IDC_USER_NEW_PASSWORD1, userInfo->usri3_password, nLength + 1);
221 }
222
223 EndDialog(hwndDlg, IDOK);
224 break;
225
226 case IDCANCEL:
227 EndDialog(hwndDlg, IDCANCEL);
228 break;
229 }
230 break;
231
232 default:
233 return FALSE;
234 }
235
236 return TRUE;
237 }
238
239
240 static VOID
241 UserNew(HWND hwndDlg)
242 {
243 USER_INFO_3 user;
244 NET_API_STATUS status;
245 LV_ITEM lvi;
246 INT iItem;
247 HWND hwndLV;
248
249 ZeroMemory(&user, sizeof(USER_INFO_3));
250
251 user.usri3_priv = USER_PRIV_USER;
252 user.usri3_flags = UF_SCRIPT;
253 user.usri3_acct_expires = TIMEQ_FOREVER;
254 user.usri3_max_storage = USER_MAXSTORAGE_UNLIMITED;
255 user.usri3_primary_group_id = DOMAIN_GROUP_RID_USERS;
256
257 user.usri3_password_expired = TRUE;
258
259 if (DialogBoxParam(hApplet,
260 MAKEINTRESOURCE(IDD_USER_NEW),
261 hwndDlg,
262 NewUserDlgProc,
263 (LPARAM)&user) == IDOK)
264 {
265 #if 0
266 status = NetUserAdd(NULL,
267 3,
268 (LPBYTE)&user,
269 NULL);
270 #else
271 status = NERR_Success;
272 #endif
273 if (status != NERR_Success)
274 {
275 TCHAR szText[256];
276 wsprintf(szText, TEXT("Error: %u"), status);
277 MessageBox(NULL, szText, TEXT("NetUserAdd"), MB_ICONERROR | MB_OK);
278 return;
279 }
280
281 hwndLV = GetDlgItem(hwndDlg, IDC_USERS_LIST);
282
283 ZeroMemory(&lvi, sizeof(lvi));
284 lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
285 lvi.pszText = user.usri3_name;
286 lvi.state = 0;
287 lvi.iImage = (user.usri3_flags & UF_ACCOUNTDISABLE) ? 1 : 0;
288 iItem = ListView_InsertItem(hwndLV, &lvi);
289
290 ListView_SetItemText(hwndLV, iItem, 1,
291 user.usri3_full_name);
292
293 ListView_SetItemText(hwndLV, iItem, 2,
294 user.usri3_comment);
295 }
296
297 if (user.usri3_name)
298 HeapFree(GetProcessHeap, 0, user.usri3_name);
299
300 if (user.usri3_full_name)
301 HeapFree(GetProcessHeap, 0, user.usri3_full_name);
302
303 if (user.usri3_comment)
304 HeapFree(GetProcessHeap, 0, user.usri3_comment);
305
306 if (user.usri3_password)
307 HeapFree(GetProcessHeap, 0, user.usri3_password);
308 }
309
310
311 static VOID
312 UserRename(HWND hwndDlg)
313 {
314 HWND hwndLV;
315 INT nItem;
316
317 hwndLV = GetDlgItem(hwndDlg, IDC_USERS_LIST);
318 if (hwndLV == NULL)
319 return;
320
321 nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
322 if (nItem != -1)
323 {
324 (void)ListView_EditLabel(hwndLV, nItem);
325 }
326 }
327
328
329 static BOOL
330 UserDelete(HWND hwndDlg)
331 {
332 TCHAR szUserName[UNLEN];
333 TCHAR szText[256];
334 INT nItem;
335 HWND hwndLV;
336 NET_API_STATUS status;
337
338 hwndLV = GetDlgItem(hwndDlg, IDC_USERS_LIST);
339 nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
340 if (nItem == -1)
341 return FALSE;
342
343 /* Get the new user name */
344 ListView_GetItemText(hwndLV,
345 nItem, 0,
346 szUserName,
347 UNLEN);
348
349 /* Display a warning message because the delete operation cannot be reverted */
350 wsprintf(szText, TEXT("Dou you really want to delete the user \"%s\"?"), szUserName);
351 if (MessageBox(NULL, szText, TEXT("User Accounts"), MB_ICONWARNING | MB_YESNO) == IDNO)
352 return FALSE;
353
354 /* Delete the user */
355 #if 0
356 status = NetUserDel(NULL, szUserName);
357 #else
358 status = NERR_Success;
359 #endif
360 if (status != NERR_Success)
361 {
362 TCHAR szText[256];
363 wsprintf(szText, TEXT("Error: %u"), status);
364 MessageBox(NULL, szText, TEXT("NetUserDel"), MB_ICONERROR | MB_OK);
365 return FALSE;
366 }
367
368 /* Delete the user from the list */
369 (void)ListView_DeleteItem(hwndLV, nItem);
370
371 return TRUE;
372 }
373
374
375 static VOID
376 SetUsersListColumns(HWND hwndListView)
377 {
378 LV_COLUMN column;
379 RECT rect;
380 TCHAR szStr[32];
381
382 GetClientRect(hwndListView, &rect);
383
384 memset(&column, 0x00, sizeof(column));
385 column.mask=LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT;
386 column.fmt=LVCFMT_LEFT;
387 column.cx = (INT)((rect.right - rect.left) * 0.25);
388 column.iSubItem = 0;
389 LoadString(hApplet, IDS_NAME, szStr, sizeof(szStr) / sizeof(szStr[0]));
390 column.pszText = szStr;
391 (void)ListView_InsertColumn(hwndListView, 0, &column);
392
393 column.cx = (INT)((rect.right - rect.left) * 0.50);
394 column.iSubItem = 1;
395 LoadString(hApplet, IDS_FULLNAME, szStr, sizeof(szStr) / sizeof(szStr[0]));
396 column.pszText = szStr;
397 (void)ListView_InsertColumn(hwndListView, 1, &column);
398
399 column.cx = (INT)((rect.right - rect.left) * 0.25);
400 column.iSubItem = 2;
401 LoadString(hApplet, IDS_DESCRIPTION, szStr, sizeof(szStr) / sizeof(szStr[0]));
402 column.pszText = szStr;
403 (void)ListView_InsertColumn(hwndListView, 2, &column);
404 }
405
406
407 static VOID
408 UpdateUsersList(HWND hwndListView)
409 {
410 NET_API_STATUS netStatus;
411 PUSER_INFO_20 pBuffer;
412 DWORD entriesread;
413 DWORD totalentries;
414 DWORD resume_handle = 0;
415 DWORD i;
416 LV_ITEM lvi;
417 INT iItem;
418
419
420 for (;;)
421 {
422 netStatus = NetUserEnum(NULL, 20, FILTER_NORMAL_ACCOUNT,
423 (LPBYTE*)&pBuffer,
424 1024, &entriesread,
425 &totalentries, &resume_handle);
426 if (netStatus != NERR_Success && netStatus != ERROR_MORE_DATA)
427 break;
428
429 for (i = 0; i < entriesread; i++)
430 {
431 memset(&lvi, 0x00, sizeof(lvi));
432 lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
433 lvi.pszText = pBuffer[i].usri20_name;
434 lvi.state = 0;
435 lvi.iImage = (pBuffer[i].usri20_flags & UF_ACCOUNTDISABLE) ? 1 : 0;
436 iItem = ListView_InsertItem(hwndListView, &lvi);
437
438 ListView_SetItemText(hwndListView, iItem, 1,
439 pBuffer[i].usri20_full_name);
440
441 ListView_SetItemText(hwndListView, iItem, 2,
442 pBuffer[i].usri20_comment);
443 }
444
445 NetApiBufferFree(&pBuffer);
446
447 /* No more data left */
448 if (netStatus != ERROR_MORE_DATA)
449 break;
450 }
451
452 }
453
454
455 static VOID
456 OnInitDialog(HWND hwndDlg)
457 {
458 HWND hwndListView;
459 HIMAGELIST hImgList;
460 HICON hIcon;
461
462 /* Create the image list */
463 hImgList = ImageList_Create(16, 16, ILC_COLOR8 | ILC_MASK, 5, 5);
464 hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_USER), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
465 ImageList_AddIcon(hImgList, hIcon);
466 hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_LOCKED_USER), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
467 ImageList_AddIcon(hImgList, hIcon);
468 DestroyIcon(hIcon);
469
470 hwndListView = GetDlgItem(hwndDlg, IDC_USERS_LIST);
471
472 (VOID)ListView_SetImageList(hwndListView, hImgList, LVSIL_SMALL);
473
474 (void)ListView_SetExtendedListViewStyle(hwndListView, LVS_EX_FULLROWSELECT);
475
476 SetUsersListColumns(hwndListView);
477
478 UpdateUsersList(hwndListView);
479 }
480
481
482 static BOOL
483 OnBeginLabelEdit(LPNMLVDISPINFO pnmv)
484 {
485 HWND hwndEdit;
486
487 hwndEdit = ListView_GetEditControl(pnmv->hdr.hwndFrom);
488 if (hwndEdit == NULL)
489 return TRUE;
490
491 SendMessage(hwndEdit, EM_SETLIMITTEXT, 20, 0);
492
493 return FALSE;
494 }
495
496
497 static BOOL
498 OnEndLabelEdit(LPNMLVDISPINFO pnmv)
499 {
500 TCHAR szOldUserName[UNLEN];
501 TCHAR szNewUserName[UNLEN];
502 USER_INFO_0 useri0;
503 NET_API_STATUS status;
504
505 /* Leave, if there is no valid listview item */
506 if (pnmv->item.iItem == -1)
507 return FALSE;
508
509 /* Get the new user name */
510 ListView_GetItemText(pnmv->hdr.hwndFrom,
511 pnmv->item.iItem, 0,
512 szOldUserName,
513 UNLEN);
514
515 /* Leave, if the user canceled the edit action */
516 if (pnmv->item.pszText == NULL)
517 return FALSE;
518
519 /* Get the new user name */
520 lstrcpy(szNewUserName, pnmv->item.pszText);
521
522 /* Leave, if the user name was not changed */
523 if (lstrcmp(szOldUserName, szNewUserName) == 0)
524 return FALSE;
525
526 /* Check the user name for illegal characters */
527 if (!CheckAccountName(NULL, 0, szNewUserName))
528 return FALSE;
529
530 /* Change the user name */
531 useri0.usri0_name = szNewUserName;
532
533 #if 0
534 status = NetUserSetInfo(NULL, szOldUserName, 0, (LPBYTE)&useri0, NULL);
535 #else
536 status = NERR_Success;
537 #endif
538 if (status != NERR_Success)
539 {
540 TCHAR szText[256];
541 wsprintf(szText, TEXT("Error: %u"), status);
542 MessageBox(NULL, szText, TEXT("NetUserSetInfo"), MB_ICONERROR | MB_OK);
543 return FALSE;
544 }
545
546 /* Update the listview item */
547 ListView_SetItemText(pnmv->hdr.hwndFrom,
548 pnmv->item.iItem, 0,
549 szNewUserName);
550
551 return TRUE;
552 }
553
554
555 static BOOL
556 OnNotify(HWND hwndDlg, PUSER_DATA pUserData, NMHDR *phdr)
557 {
558 LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)phdr;
559
560 switch (phdr->idFrom)
561 {
562 case IDC_USERS_LIST:
563 switch(phdr->code)
564 {
565 case NM_CLICK:
566 pUserData->iCurrentItem = lpnmlv->iItem;
567 if (lpnmlv->iItem == -1)
568 {
569 }
570 else
571 {
572 }
573 break;
574
575 case NM_DBLCLK:
576 break;
577
578 case NM_RCLICK:
579 ClientToScreen(GetDlgItem(hwndDlg, IDC_USERS_LIST), &lpnmlv->ptAction);
580 TrackPopupMenu(GetSubMenu(pUserData->hPopupMenu, (lpnmlv->iItem == -1) ? 0 : 1),
581 TPM_LEFTALIGN, lpnmlv->ptAction.x, lpnmlv->ptAction.y, 0, hwndDlg, NULL);
582 break;
583
584 case LVN_BEGINLABELEDIT:
585 return OnBeginLabelEdit((LPNMLVDISPINFO)phdr);
586
587 case LVN_ENDLABELEDIT:
588 return OnEndLabelEdit((LPNMLVDISPINFO)phdr);
589 }
590 break;
591 }
592
593 return FALSE;
594 }
595
596
597 INT_PTR CALLBACK
598 UsersPageProc(HWND hwndDlg,
599 UINT uMsg,
600 WPARAM wParam,
601 LPARAM lParam)
602 {
603 PUSER_DATA pUserData;
604
605 UNREFERENCED_PARAMETER(wParam);
606
607 pUserData = (PUSER_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
608
609 switch (uMsg)
610 {
611 case WM_INITDIALOG:
612 pUserData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USER_DATA));
613 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pUserData);
614
615 pUserData->hPopupMenu = LoadMenu(hApplet, MAKEINTRESOURCE(IDM_POPUP_USER));
616
617 OnInitDialog(hwndDlg);
618 break;
619
620 case WM_COMMAND:
621 switch (LOWORD(wParam))
622 {
623 case IDM_USER_CHANGE_PASSWORD:
624 DialogBoxParam(hApplet,
625 MAKEINTRESOURCE(IDD_CHANGE_PASSWORD),
626 hwndDlg,
627 ChangePasswordDlgProc,
628 (LPARAM)NULL);
629 break;
630
631 case IDM_USER_RENAME:
632 UserRename(hwndDlg);
633 break;
634
635 case IDM_USER_NEW:
636 UserNew(hwndDlg);
637 break;
638
639 case IDM_USER_DELETE:
640 UserDelete(hwndDlg);
641 break;
642
643 case IDM_USER_PROPERTIES:
644 MessageBeep(-1);
645 break;
646 }
647 break;
648
649 case WM_NOTIFY:
650 return OnNotify(hwndDlg, pUserData, (NMHDR *)lParam);
651
652 case WM_DESTROY:
653 DestroyMenu(pUserData->hPopupMenu);
654 HeapFree(GetProcessHeap(), 0, pUserData);
655 break;
656 }
657
658 return FALSE;
659 }