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