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