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