xref: /reactos/dll/cpl/usrmgr/userprops.c (revision ccef43f3)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS User Manager Control Panel
4  * FILE:            dll/cpl/usrmgr/userprops.c
5  * PURPOSE:         User property sheet
6  *
7  * PROGRAMMERS:     Eric Kohl
8  */
9 
10 #include "usrmgr.h"
11 
12 typedef struct _GENERAL_USER_DATA
13 {
14     DWORD dwFlags;
15     DWORD dwPasswordExpired;
16     TCHAR szUserName[1];
17 } GENERAL_USER_DATA, *PGENERAL_USER_DATA;
18 
19 #define VALID_GENERAL_FLAGS (UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD | UF_ACCOUNTDISABLE | UF_LOCKOUT)
20 
21 typedef struct _PROFILE_USER_DATA
22 {
23     TCHAR szUserName[1];
24 } PROFILE_USER_DATA, *PPROFILE_USER_DATA;
25 
26 typedef struct _MEMBERSHIP_USER_DATA
27 {
28     PLOCALGROUP_USERS_INFO_0 pGroupData;
29     DWORD dwGroupCount;
30     TCHAR szUserName[1];
31 } MEMBERSHIP_USER_DATA, *PMEMBERSHIP_USER_DATA;
32 
33 
34 static VOID
35 GetUserProfileData(HWND hwndDlg,
36                    PPROFILE_USER_DATA pUserData)
37 {
38     PUSER_INFO_3 userInfo = NULL;
39     NET_API_STATUS status;
40     BOOL bLocal;
41     TCHAR szDrive[8];
42     INT i;
43     INT nSel;
44 
45     status = NetUserGetInfo(NULL, pUserData->szUserName, 3, (LPBYTE*)&userInfo);
46     if (status != NERR_Success)
47         return;
48 
49     SetDlgItemText(hwndDlg, IDC_USER_PROFILE_PATH, userInfo->usri3_profile);
50     SetDlgItemText(hwndDlg, IDC_USER_PROFILE_SCRIPT, userInfo->usri3_script_path);
51 
52 
53     bLocal = (userInfo->usri3_home_dir_drive == NULL) ||
54               (_tcslen(userInfo->usri3_home_dir_drive) == 0);
55     CheckRadioButton(hwndDlg, IDC_USER_PROFILE_LOCAL, IDC_USER_PROFILE_REMOTE,
56                      bLocal ? IDC_USER_PROFILE_LOCAL : IDC_USER_PROFILE_REMOTE);
57 
58     for (i = 0; i < 26; i++)
59     {
60         wsprintf(szDrive, _T("%c:"), (TCHAR)('A' + i));
61         nSel = SendMessage(GetDlgItem(hwndDlg, IDC_USER_PROFILE_DRIVE),
62                            CB_INSERTSTRING, -1, (LPARAM)szDrive);
63     }
64 
65     if (bLocal)
66     {
67         SetDlgItemText(hwndDlg, IDC_USER_PROFILE_LOCAL_PATH, userInfo->usri3_home_dir);
68         EnableWindow(GetDlgItem(hwndDlg, IDC_USER_PROFILE_DRIVE), FALSE);
69         EnableWindow(GetDlgItem(hwndDlg, IDC_USER_PROFILE_REMOTE_PATH), FALSE);
70     }
71     else
72     {
73         SetDlgItemText(hwndDlg, IDC_USER_PROFILE_REMOTE_PATH, userInfo->usri3_home_dir);
74         nSel = SendMessage(GetDlgItem(hwndDlg, IDC_USER_PROFILE_DRIVE),
75                            CB_FINDSTRINGEXACT, -1, (LPARAM)userInfo->usri3_home_dir_drive);
76     }
77 
78     SendMessage(GetDlgItem(hwndDlg, IDC_USER_PROFILE_DRIVE),
79                 CB_SETCURSEL, nSel, 0);
80 
81     NetApiBufferFree(userInfo);
82 }
83 
84 
85 static BOOL
86 SetUserProfileData(HWND hwndDlg,
87                    PPROFILE_USER_DATA pUserData)
88 {
89     PUSER_INFO_3 pUserInfo = NULL;
90     LPTSTR pszProfilePath = NULL;
91     LPTSTR pszScriptPath = NULL;
92     LPTSTR pszHomeDir = NULL;
93     LPTSTR pszHomeDrive = NULL;
94     NET_API_STATUS status;
95     DWORD dwIndex;
96     INT nLength;
97     INT nIndex;
98 
99     NetUserGetInfo(NULL, pUserData->szUserName, 3, (LPBYTE*)&pUserInfo);
100 
101     /* Get the profile path */
102     nLength = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_USER_PROFILE_PATH));
103     if (nLength == 0)
104     {
105         pUserInfo->usri3_profile = NULL;
106     }
107     else
108     {
109         pszProfilePath = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(TCHAR));
110         GetDlgItemText(hwndDlg, IDC_USER_PROFILE_PATH, pszProfilePath, nLength + 1);
111         pUserInfo->usri3_profile = pszProfilePath;
112     }
113 
114     /* Get the script path */
115     nLength = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_USER_PROFILE_SCRIPT));
116     if (nLength == 0)
117     {
118         pUserInfo->usri3_script_path = NULL;
119     }
120     else
121     {
122         pszScriptPath = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(TCHAR));
123         GetDlgItemText(hwndDlg, IDC_USER_PROFILE_SCRIPT, pszScriptPath, nLength + 1);
124         pUserInfo->usri3_script_path = pszScriptPath;
125     }
126 
127     if (IsDlgButtonChecked(hwndDlg, IDC_USER_PROFILE_LOCAL) == BST_CHECKED)
128     {
129         /* Local home directory */
130         nLength = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_USER_PROFILE_LOCAL_PATH));
131         if (nLength == 0)
132         {
133             pUserInfo->usri3_home_dir = NULL;
134         }
135         else
136         {
137             pszHomeDir = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(TCHAR));
138             GetDlgItemText(hwndDlg, IDC_USER_PROFILE_LOCAL_PATH, pszHomeDir, nLength + 1);
139             pUserInfo->usri3_home_dir = pszHomeDir;
140         }
141     }
142     else
143     {
144         /* Remote home directory */
145         nLength = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_USER_PROFILE_REMOTE_PATH));
146         if (nLength == 0)
147         {
148             pUserInfo->usri3_home_dir = NULL;
149         }
150         else
151         {
152             pszHomeDir = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(TCHAR));
153             GetDlgItemText(hwndDlg, IDC_USER_PROFILE_REMOTE_PATH, pszHomeDir, nLength + 1);
154             pUserInfo->usri3_home_dir = pszHomeDir;
155         }
156 
157         nIndex = SendMessage(GetDlgItem(hwndDlg, IDC_USER_PROFILE_DRIVE), CB_GETCURSEL, 0, 0);
158         if (nIndex != CB_ERR)
159         {
160             nLength = SendMessage(GetDlgItem(hwndDlg, IDC_USER_PROFILE_DRIVE), CB_GETLBTEXTLEN, nIndex, 0);
161             pszHomeDrive = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(TCHAR));
162             SendMessage(GetDlgItem(hwndDlg, IDC_USER_PROFILE_DRIVE), CB_GETLBTEXT, nIndex, (LPARAM)pszHomeDrive);
163             pUserInfo->usri3_home_dir_drive = pszHomeDrive;
164         }
165     }
166 
167     status = NetUserSetInfo(NULL, pUserData->szUserName, 3, (LPBYTE)pUserInfo, &dwIndex);
168     if (status != NERR_Success)
169     {
170         ERR("NetUserSetInfo failed. Status: %lu  Index: %lu", status, dwIndex);
171     }
172 
173     if (pszProfilePath)
174         HeapFree(GetProcessHeap(), 0, pszProfilePath);
175 
176     if (pszScriptPath)
177         HeapFree(GetProcessHeap(), 0, pszScriptPath);
178 
179     if (pszHomeDir)
180         HeapFree(GetProcessHeap(), 0, pszHomeDir);
181 
182     if (pszHomeDrive)
183         HeapFree(GetProcessHeap(), 0, pszHomeDrive);
184 
185     NetApiBufferFree(pUserInfo);
186 
187     return (status == NERR_Success);
188 }
189 
190 
191 INT_PTR CALLBACK
192 UserProfilePageProc(HWND hwndDlg,
193                     UINT uMsg,
194                     WPARAM wParam,
195                     LPARAM lParam)
196 {
197     PPROFILE_USER_DATA pUserData;
198 
199     UNREFERENCED_PARAMETER(lParam);
200     UNREFERENCED_PARAMETER(wParam);
201     UNREFERENCED_PARAMETER(hwndDlg);
202 
203     pUserData= (PPROFILE_USER_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
204 
205     switch (uMsg)
206     {
207         case WM_INITDIALOG:
208             pUserData = (PPROFILE_USER_DATA)HeapAlloc(GetProcessHeap(),
209                                                       HEAP_ZERO_MEMORY,
210                                                       sizeof(PROFILE_USER_DATA) +
211                                                       lstrlen((LPTSTR)((PROPSHEETPAGE *)lParam)->lParam) * sizeof(TCHAR));
212             lstrcpy(pUserData->szUserName, (LPTSTR)((PROPSHEETPAGE *)lParam)->lParam);
213 
214             SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pUserData);
215 
216             GetUserProfileData(hwndDlg,
217                                pUserData);
218             break;
219 
220         case WM_COMMAND:
221             switch (LOWORD(wParam))
222             {
223                 case IDC_USER_PROFILE_PATH:
224                 case IDC_USER_PROFILE_SCRIPT:
225                     if (HIWORD(wParam) == EN_CHANGE)
226                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
227                     break;
228 
229                 case IDC_USER_PROFILE_LOCAL:
230                     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_PROFILE_LOCAL_PATH), TRUE);
231                     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_PROFILE_DRIVE), FALSE);
232                     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_PROFILE_REMOTE_PATH), FALSE);
233                     break;
234 
235                 case IDC_USER_PROFILE_REMOTE:
236                     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_PROFILE_LOCAL_PATH), FALSE);
237                     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_PROFILE_DRIVE), TRUE);
238                     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_PROFILE_REMOTE_PATH), TRUE);
239                     break;
240             }
241             break;
242 
243         case WM_DESTROY:
244             HeapFree(GetProcessHeap(), 0, pUserData);
245             break;
246 
247         case WM_NOTIFY:
248             if (((LPPSHNOTIFY)lParam)->hdr.code == PSN_APPLY)
249             {
250                 SetUserProfileData(hwndDlg, pUserData);
251                 return TRUE;
252             }
253             break;
254     }
255 
256     return FALSE;
257 }
258 
259 
260 static VOID
261 GetUserMembershipData(HWND hwndDlg, PMEMBERSHIP_USER_DATA pUserData)
262 {
263     NET_API_STATUS status;
264     DWORD dwTotal;
265     DWORD i;
266     HIMAGELIST hImgList;
267     HICON hIcon;
268     LV_ITEM lvi;
269     HWND hwndLV;
270     LV_COLUMN column;
271     RECT rect;
272 
273 
274     hwndLV = GetDlgItem(hwndDlg, IDC_USER_MEMBERSHIP_LIST);
275 
276     /* Create the image list */
277     hImgList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 5, 5);
278     hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_GROUP), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
279     ImageList_AddIcon(hImgList, hIcon);
280     DestroyIcon(hIcon);
281     (void)ListView_SetImageList(hwndLV, hImgList, LVSIL_SMALL);
282 
283     /* Set the list column */
284     GetClientRect(hwndLV, &rect);
285 
286     memset(&column, 0x00, sizeof(column));
287     column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM;
288     column.fmt = LVCFMT_LEFT;
289     column.cx = (INT)(rect.right - rect.left);
290     column.iSubItem = 0;
291     (void)ListView_InsertColumn(hwndLV, 0, &column);
292 
293 
294     status = NetUserGetLocalGroups(NULL, pUserData->szUserName, 0, 0,
295                                    (LPBYTE*)&pUserData->pGroupData,
296                                    MAX_PREFERRED_LENGTH,
297                                    &pUserData->dwGroupCount,
298                                    &dwTotal);
299     if (status != NERR_Success)
300         return;
301 
302     for (i = 0; i < pUserData->dwGroupCount; i++)
303     {
304         ZeroMemory(&lvi, sizeof(lvi));
305         lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
306         lvi.pszText = pUserData->pGroupData[i].lgrui0_name;
307         lvi.state = 0;
308         lvi.iImage = 0;
309 
310         (void)ListView_InsertItem(hwndLV, &lvi);
311     }
312 }
313 
314 
315 static VOID
316 RemoveGroupFromUser(HWND hwndDlg,
317                     PMEMBERSHIP_USER_DATA pUserData)
318 {
319     TCHAR szGroupName[UNLEN + 1];
320     TCHAR szText[256];
321     LOCALGROUP_MEMBERS_INFO_3 memberInfo;
322     HWND hwndLV;
323     INT nItem;
324     NET_API_STATUS status;
325 
326     hwndLV = GetDlgItem(hwndDlg, IDC_USER_MEMBERSHIP_LIST);
327     nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
328     if (nItem == -1)
329         return;
330 
331     /* Get the new user name */
332     ListView_GetItemText(hwndLV,
333                          nItem, 0,
334                          szGroupName,
335                          UNLEN + 1);
336 
337     /* Display a warning message because the remove operation cannot be reverted */
338     wsprintf(szText, TEXT("Do you really want to remove the user \"%s\" from the group \"%s\"?"),
339              pUserData->szUserName, szGroupName);
340     if (MessageBox(NULL, szText, TEXT("User Accounts"), MB_ICONWARNING | MB_YESNO) == IDNO)
341         return;
342 
343     memberInfo.lgrmi3_domainandname = pUserData->szUserName;
344 
345     status = NetLocalGroupDelMembers(NULL, szGroupName,
346                                      3, (LPBYTE)&memberInfo, 1);
347     if (status != NERR_Success)
348     {
349         TCHAR szText[256];
350         wsprintf(szText, TEXT("Error: %u"), status);
351         MessageBox(NULL, szText, TEXT("NetLocalGroupDelMembers"), MB_ICONERROR | MB_OK);
352         return;
353     }
354 
355     (void)ListView_DeleteItem(hwndLV, nItem);
356 
357     if (ListView_GetItemCount(hwndLV) == 0)
358         EnableWindow(GetDlgItem(hwndDlg, IDC_USER_MEMBERSHIP_REMOVE), FALSE);
359 }
360 
361 
362 static VOID
363 InitUserGroupsList(HWND hwndDlg)
364 {
365     HWND hwndLV;
366     LV_COLUMN column;
367     RECT rect;
368     TCHAR szStr[32];
369 
370     NET_API_STATUS netStatus;
371     PLOCALGROUP_INFO_1 pBuffer;
372     DWORD entriesread;
373     DWORD totalentries;
374     DWORD_PTR resume_handle = 0;
375     DWORD i;
376     LV_ITEM lvi;
377     INT iItem;
378 
379     HIMAGELIST hImgList;
380     HICON hIcon;
381 
382     hwndLV = GetDlgItem(hwndDlg, IDC_USER_ADD_MEMBERSHIP_LIST);
383     GetClientRect(hwndLV, &rect);
384 
385     hImgList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 5, 5);
386     hIcon = LoadImage(hApplet, MAKEINTRESOURCE(IDI_GROUP), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
387     ImageList_AddIcon(hImgList, hIcon);
388     DestroyIcon(hIcon);
389 
390     (void)ListView_SetImageList(hwndLV, hImgList, LVSIL_SMALL);
391     (void)ListView_SetExtendedListViewStyle(hwndLV, LVS_EX_FULLROWSELECT);
392 
393     memset(&column, 0x00, sizeof(column));
394     column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM | LVCF_TEXT;
395     column.fmt = LVCFMT_LEFT;
396     column.cx = (INT)((rect.right - rect.left) * 0.40);
397     column.iSubItem = 0;
398     LoadString(hApplet, IDS_NAME, szStr, sizeof(szStr) / sizeof(szStr[0]));
399     column.pszText = szStr;
400     (void)ListView_InsertColumn(hwndLV, 0, &column);
401 
402     column.cx = (INT)((rect.right - rect.left) * 0.60);
403     column.iSubItem = 1;
404     LoadString(hApplet, IDS_DESCRIPTION, szStr, sizeof(szStr) / sizeof(szStr[0]));
405     column.pszText = szStr;
406     (void)ListView_InsertColumn(hwndLV, 1, &column);
407 
408     for (;;)
409     {
410         netStatus = NetLocalGroupEnum(NULL, 1, (LPBYTE*)&pBuffer,
411                                       1024, &entriesread,
412                                       &totalentries, &resume_handle);
413         if (netStatus != NERR_Success && netStatus != ERROR_MORE_DATA)
414             break;
415 
416         for (i = 0; i < entriesread; i++)
417         {
418            memset(&lvi, 0x00, sizeof(lvi));
419            lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
420            lvi.pszText = pBuffer[i].lgrpi1_name;
421            lvi.state = 0;
422            lvi.iImage = 0;
423            iItem = ListView_InsertItem(hwndLV, &lvi);
424 
425            ListView_SetItemText(hwndLV, iItem, 1,
426                                 pBuffer[i].lgrpi1_comment);
427         }
428 
429         NetApiBufferFree(pBuffer);
430 
431         /* No more data left */
432         if (netStatus != ERROR_MORE_DATA)
433             break;
434     }
435 }
436 
437 
438 static BOOL
439 AddSelectedGroupsToUser(HWND hwndDlg,
440                         PMEMBERSHIP_USER_DATA pUserData)
441 {
442     HWND hwndLV;
443     INT nItem;
444     TCHAR szGroupName[UNLEN + 1];
445     BOOL bResult = FALSE;
446     BOOL bFound;
447     DWORD i;
448     LOCALGROUP_MEMBERS_INFO_3 memberInfo;
449     NET_API_STATUS status;
450 
451     hwndLV = GetDlgItem(hwndDlg, IDC_USER_ADD_MEMBERSHIP_LIST);
452 
453     if (ListView_GetSelectedCount(hwndLV) > 0)
454     {
455         nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
456         while (nItem != -1)
457         {
458             /* Get the new user name */
459             ListView_GetItemText(hwndLV,
460                                  nItem, 0,
461                                  szGroupName,
462                                  UNLEN + 1);
463 
464             bFound = FALSE;
465             for (i = 0; i < pUserData->dwGroupCount; i++)
466             {
467                 if (_tcscmp(pUserData->pGroupData[i].lgrui0_name, szGroupName) == 0)
468                     bFound = TRUE;
469             }
470 
471             if (!bFound)
472             {
473                 memberInfo.lgrmi3_domainandname = pUserData->szUserName;
474 
475                 status = NetLocalGroupAddMembers(NULL, szGroupName, 3,
476                                                  (LPBYTE)&memberInfo, 1);
477                 if (status == NERR_Success)
478                 {
479                     TRACE("Selected group: %s", dbgstrx(szGroupName));
480                     bResult = TRUE;
481                 }
482                 else
483                 {
484                     TCHAR szText[256];
485                     wsprintf(szText, TEXT("Error: %u"), status);
486                     MessageBox(NULL, szText, TEXT("NetLocalGroupAddMembers"), MB_ICONERROR | MB_OK);
487                 }
488             }
489 
490             nItem = ListView_GetNextItem(hwndLV, nItem, LVNI_SELECTED);
491         }
492     }
493 
494     return bResult;
495 }
496 
497 
498 INT_PTR CALLBACK
499 AddGroupToUserDlgProc(HWND hwndDlg,
500                       UINT uMsg,
501                       WPARAM wParam,
502                       LPARAM lParam)
503 {
504     PMEMBERSHIP_USER_DATA pUserData;
505 
506     UNREFERENCED_PARAMETER(wParam);
507 
508     pUserData= (PMEMBERSHIP_USER_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
509 
510     switch (uMsg)
511     {
512         case WM_INITDIALOG:
513             pUserData= (PMEMBERSHIP_USER_DATA)lParam;
514             SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pUserData);
515             InitUserGroupsList(hwndDlg);
516             break;
517 
518         case WM_COMMAND:
519             switch (LOWORD(wParam))
520             {
521                 case IDOK:
522                     if (AddSelectedGroupsToUser(hwndDlg, pUserData))
523                         EndDialog(hwndDlg, IDOK);
524                     else
525                         EndDialog(hwndDlg, IDCANCEL);
526                     break;
527 
528                 case IDCANCEL:
529                     EndDialog(hwndDlg, IDCANCEL);
530                     break;
531             }
532             break;
533 
534         default:
535             return FALSE;
536     }
537 
538     return TRUE;
539 }
540 
541 
542 static VOID
543 AddGroupToUser(HWND hwndDlg,
544                PMEMBERSHIP_USER_DATA pUserData)
545 {
546     HWND hwndLV;
547     NET_API_STATUS status;
548     DWORD i;
549     DWORD dwTotal;
550     LV_ITEM lvi;
551 
552     if (DialogBoxParam(hApplet,
553                        MAKEINTRESOURCE(IDD_USER_ADD_MEMBERSHIP),
554                        hwndDlg,
555                        AddGroupToUserDlgProc,
556                        (LPARAM)pUserData) == IDOK)
557     {
558         // TODO: Update Membership list!
559         hwndLV = GetDlgItem(hwndDlg, IDC_USER_MEMBERSHIP_LIST);
560 
561         if (pUserData->pGroupData)
562             NetApiBufferFree(pUserData->pGroupData);
563 
564         (void)ListView_DeleteAllItems(hwndLV);
565 
566         status = NetUserGetLocalGroups(NULL, pUserData->szUserName, 0, 0,
567                                        (LPBYTE*)&pUserData->pGroupData,
568                                        MAX_PREFERRED_LENGTH,
569                                        &pUserData->dwGroupCount,
570                                        &dwTotal);
571         if (status != NERR_Success)
572             return;
573 
574         for (i = 0; i < pUserData->dwGroupCount; i++)
575         {
576             ZeroMemory(&lvi, sizeof(lvi));
577             lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
578             lvi.pszText = pUserData->pGroupData[i].lgrui0_name;
579             lvi.state = 0;
580             lvi.iImage = 0;
581 
582             (void)ListView_InsertItem(hwndLV, &lvi);
583         }
584     }
585 }
586 
587 
588 static BOOL
589 OnUserPropSheetNotify(HWND hwndDlg,
590                       PMEMBERSHIP_USER_DATA pUserData,
591                       LPARAM lParam)
592 {
593     LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam;
594 
595     switch (((LPNMHDR)lParam)->idFrom)
596     {
597         case IDC_USER_MEMBERSHIP_LIST:
598             switch (((LPNMHDR)lParam)->code)
599             {
600                 case NM_CLICK:
601                     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_MEMBERSHIP_REMOVE), (lpnmlv->iItem != -1));
602                     break;
603 
604                 case LVN_KEYDOWN:
605                     if (((LPNMLVKEYDOWN)lParam)->wVKey == VK_DELETE)
606                     {
607                         RemoveGroupFromUser(hwndDlg, pUserData);
608                     }
609                     break;
610 
611             }
612             break;
613     }
614 
615     return FALSE;
616 }
617 
618 
619 INT_PTR CALLBACK
620 UserMembershipPageProc(HWND hwndDlg,
621                        UINT uMsg,
622                        WPARAM wParam,
623                        LPARAM lParam)
624 {
625     PMEMBERSHIP_USER_DATA pUserData;
626 
627     UNREFERENCED_PARAMETER(lParam);
628     UNREFERENCED_PARAMETER(wParam);
629     UNREFERENCED_PARAMETER(hwndDlg);
630 
631     pUserData= (PMEMBERSHIP_USER_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
632 
633     switch (uMsg)
634     {
635         case WM_INITDIALOG:
636             pUserData = (PMEMBERSHIP_USER_DATA)HeapAlloc(GetProcessHeap(),
637                                                          HEAP_ZERO_MEMORY,
638                                                          sizeof(MEMBERSHIP_USER_DATA) +
639                                                          lstrlen((LPTSTR)((PROPSHEETPAGE *)lParam)->lParam) * sizeof(TCHAR));
640             lstrcpy(pUserData->szUserName, (LPTSTR)((PROPSHEETPAGE *)lParam)->lParam);
641 
642             SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pUserData);
643 
644             GetUserMembershipData(hwndDlg, pUserData);
645             break;
646 
647         case WM_COMMAND:
648             switch (LOWORD(wParam))
649             {
650                 case IDC_USER_MEMBERSHIP_ADD:
651                     AddGroupToUser(hwndDlg, pUserData);
652                     break;
653 
654                 case IDC_USER_MEMBERSHIP_REMOVE:
655                     RemoveGroupFromUser(hwndDlg, pUserData);
656                     break;
657             }
658             break;
659 
660         case WM_NOTIFY:
661             if (((LPPSHNOTIFY)lParam)->hdr.code == PSN_APPLY)
662             {
663                 return TRUE;
664             }
665             else
666             {
667                 return OnUserPropSheetNotify(hwndDlg, pUserData, lParam);
668             }
669             break;
670 
671 
672         case WM_DESTROY:
673             if (pUserData->pGroupData)
674                 NetApiBufferFree(pUserData->pGroupData);
675 
676             HeapFree(GetProcessHeap(), 0, pUserData);
677             break;
678     }
679 
680     return FALSE;
681 }
682 
683 
684 static VOID
685 UpdateUserOptions(HWND hwndDlg,
686                   PGENERAL_USER_DATA pUserData,
687                   BOOL bInit)
688 {
689     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_GENERAL_CANNOT_CHANGE),
690                  !pUserData->dwPasswordExpired);
691     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_GENERAL_NEVER_EXPIRES),
692                  !pUserData->dwPasswordExpired);
693     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_GENERAL_FORCE_CHANGE),
694                  (pUserData->dwFlags & (UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD)) == 0);
695 
696     EnableWindow(GetDlgItem(hwndDlg, IDC_USER_GENERAL_LOCKED),
697                  (pUserData->dwFlags & UF_LOCKOUT) != 0);
698 
699     if (bInit)
700     {
701         CheckDlgButton(hwndDlg, IDC_USER_GENERAL_FORCE_CHANGE,
702                        pUserData->dwPasswordExpired ? BST_CHECKED : BST_UNCHECKED);
703 
704         CheckDlgButton(hwndDlg, IDC_USER_GENERAL_CANNOT_CHANGE,
705                        (pUserData->dwFlags & UF_PASSWD_CANT_CHANGE) ? BST_CHECKED : BST_UNCHECKED);
706 
707         CheckDlgButton(hwndDlg, IDC_USER_GENERAL_NEVER_EXPIRES,
708                        (pUserData->dwFlags & UF_DONT_EXPIRE_PASSWD) ? BST_CHECKED : BST_UNCHECKED);
709 
710         CheckDlgButton(hwndDlg, IDC_USER_GENERAL_DISABLED,
711                        (pUserData->dwFlags & UF_ACCOUNTDISABLE) ? BST_CHECKED : BST_UNCHECKED);
712 
713         CheckDlgButton(hwndDlg, IDC_USER_GENERAL_LOCKED,
714                        (pUserData->dwFlags & UF_LOCKOUT) ? BST_CHECKED : BST_UNCHECKED);
715     }
716 }
717 
718 
719 static VOID
720 GetUserGeneralData(HWND hwndDlg,
721                    PGENERAL_USER_DATA pUserData)
722 {
723     PUSER_INFO_3 pUserInfo = NULL;
724 
725     SetDlgItemText(hwndDlg, IDC_USER_GENERAL_NAME, pUserData->szUserName);
726 
727     NetUserGetInfo(NULL, pUserData->szUserName, 3, (LPBYTE*)&pUserInfo);
728 
729     SetDlgItemText(hwndDlg, IDC_USER_GENERAL_FULL_NAME, pUserInfo->usri3_full_name);
730     SetDlgItemText(hwndDlg, IDC_USER_GENERAL_DESCRIPTION, pUserInfo->usri3_comment);
731 
732     pUserData->dwFlags = pUserInfo->usri3_flags;
733     pUserData->dwPasswordExpired = pUserInfo->usri3_password_expired;
734 
735     NetApiBufferFree(pUserInfo);
736 
737     UpdateUserOptions(hwndDlg, pUserData, TRUE);
738 }
739 
740 
741 static BOOL
742 SetUserGeneralData(HWND hwndDlg,
743                    PGENERAL_USER_DATA pUserData)
744 {
745     PUSER_INFO_3 pUserInfo = NULL;
746     LPTSTR pszFullName = NULL;
747     LPTSTR pszComment = NULL;
748     NET_API_STATUS status;
749     DWORD dwIndex;
750     INT nLength;
751 
752     NetUserGetInfo(NULL, pUserData->szUserName, 3, (LPBYTE*)&pUserInfo);
753 
754     pUserInfo->usri3_flags =
755         (pUserData->dwFlags & VALID_GENERAL_FLAGS) |
756         (pUserInfo->usri3_flags & ~VALID_GENERAL_FLAGS);
757 
758     pUserInfo->usri3_password_expired = pUserData->dwPasswordExpired;
759 
760     nLength = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_USER_GENERAL_FULL_NAME));
761     if (nLength == 0)
762     {
763         pUserInfo->usri3_full_name = NULL;
764     }
765     else
766     {
767         pszFullName = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(TCHAR));
768         GetDlgItemText(hwndDlg, IDC_USER_GENERAL_FULL_NAME, pszFullName, nLength + 1);
769         pUserInfo->usri3_full_name = pszFullName;
770     }
771 
772     nLength = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_USER_GENERAL_DESCRIPTION));
773     if (nLength == 0)
774     {
775         pUserInfo->usri3_full_name = NULL;
776     }
777     else
778     {
779         pszComment = HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(TCHAR));
780         GetDlgItemText(hwndDlg, IDC_USER_GENERAL_DESCRIPTION, pszComment, nLength + 1);
781         pUserInfo->usri3_comment = pszComment;
782     }
783 
784     status = NetUserSetInfo(NULL, pUserData->szUserName, 3, (LPBYTE)pUserInfo, &dwIndex);
785     if (status != NERR_Success)
786     {
787         ERR("NetUserSetInfo failed. Status: %lu  Index: %lu", status, dwIndex);
788     }
789 
790     if (pszFullName)
791         HeapFree(GetProcessHeap(), 0, pszFullName);
792 
793     if (pszComment)
794         HeapFree(GetProcessHeap(), 0, pszComment);
795 
796     NetApiBufferFree(pUserInfo);
797 
798     return (status == NERR_Success);
799 }
800 
801 
802 INT_PTR CALLBACK
803 UserGeneralPageProc(HWND hwndDlg,
804                     UINT uMsg,
805                     WPARAM wParam,
806                     LPARAM lParam)
807 {
808     PGENERAL_USER_DATA pUserData;
809 
810     UNREFERENCED_PARAMETER(lParam);
811     UNREFERENCED_PARAMETER(wParam);
812     UNREFERENCED_PARAMETER(hwndDlg);
813 
814     pUserData= (PGENERAL_USER_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
815 
816     switch (uMsg)
817     {
818         case WM_INITDIALOG:
819             pUserData = (PGENERAL_USER_DATA)HeapAlloc(GetProcessHeap(),
820                                                       HEAP_ZERO_MEMORY,
821                                                       sizeof(GENERAL_USER_DATA) +
822                                                       lstrlen((LPTSTR)((PROPSHEETPAGE *)lParam)->lParam) * sizeof(TCHAR));
823             lstrcpy(pUserData->szUserName, (LPTSTR)((PROPSHEETPAGE *)lParam)->lParam);
824 
825             SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pUserData);
826 
827             GetUserGeneralData(hwndDlg,
828                                pUserData);
829             break;
830 
831         case WM_COMMAND:
832             switch (LOWORD(wParam))
833             {
834                 case IDC_USER_GENERAL_FULL_NAME:
835                 case IDC_USER_GENERAL_DESCRIPTION:
836                     if (HIWORD(wParam) == EN_CHANGE)
837                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
838                     break;
839 
840                 case IDC_USER_GENERAL_FORCE_CHANGE:
841                     pUserData->dwPasswordExpired = !pUserData->dwPasswordExpired;
842                     UpdateUserOptions(hwndDlg, pUserData, FALSE);
843                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
844                     break;
845 
846                 case IDC_USER_GENERAL_CANNOT_CHANGE:
847                     pUserData->dwFlags ^= UF_PASSWD_CANT_CHANGE;
848                     UpdateUserOptions(hwndDlg, pUserData, FALSE);
849                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
850                     break;
851 
852                 case IDC_USER_GENERAL_NEVER_EXPIRES:
853                     pUserData->dwFlags ^= UF_DONT_EXPIRE_PASSWD;
854                     UpdateUserOptions(hwndDlg, pUserData, FALSE);
855                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
856                     break;
857 
858                 case IDC_USER_GENERAL_DISABLED:
859                     pUserData->dwFlags ^= UF_ACCOUNTDISABLE;
860                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
861                     break;
862 
863                 case IDC_USER_GENERAL_LOCKED:
864                     pUserData->dwFlags ^= UF_LOCKOUT;
865                     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
866                     break;
867             }
868             break;
869 
870         case WM_NOTIFY:
871             if (((LPPSHNOTIFY)lParam)->hdr.code == PSN_APPLY)
872             {
873                 SetUserGeneralData(hwndDlg, pUserData);
874                 return TRUE;
875             }
876             break;
877 
878         case WM_DESTROY:
879             HeapFree(GetProcessHeap(), 0, pUserData);
880             break;
881     }
882 
883     return FALSE;
884 }
885 
886 
887 static VOID
888 InitUserPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DLGPROC DlgProc, LPTSTR pszUser)
889 {
890     ZeroMemory(psp, sizeof(PROPSHEETPAGE));
891     psp->dwSize = sizeof(PROPSHEETPAGE);
892     psp->dwFlags = PSP_DEFAULT;
893     psp->hInstance = hApplet;
894     psp->pszTemplate = MAKEINTRESOURCE(idDlg);
895     psp->pfnDlgProc = DlgProc;
896     psp->lParam = (LPARAM)pszUser;
897 }
898 
899 
900 BOOL
901 UserProperties(HWND hwndDlg)
902 {
903     PROPSHEETPAGE psp[3];
904     PROPSHEETHEADER psh;
905     TCHAR szUserName[UNLEN + 1];
906     INT nItem;
907     HWND hwndLV;
908 
909     hwndLV = GetDlgItem(hwndDlg, IDC_USERS_LIST);
910     nItem = ListView_GetNextItem(hwndLV, -1, LVNI_SELECTED);
911     if (nItem == -1)
912         return FALSE;
913 
914     /* Get the new user name */
915     ListView_GetItemText(hwndLV,
916                          nItem, 0,
917                          szUserName,
918                          UNLEN + 1);
919 
920     ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
921     psh.dwSize = sizeof(PROPSHEETHEADER);
922     psh.dwFlags =  PSH_PROPSHEETPAGE | PSH_PROPTITLE;
923     psh.hwndParent = hwndDlg;
924     psh.hInstance = hApplet;
925     psh.hIcon = NULL;
926     psh.pszCaption = szUserName;
927     psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
928     psh.nStartPage = 0;
929     psh.ppsp = psp;
930 
931     InitUserPropSheetPage(&psp[0], IDD_USER_GENERAL, UserGeneralPageProc, szUserName);
932     InitUserPropSheetPage(&psp[1], IDD_USER_MEMBERSHIP, UserMembershipPageProc, szUserName);
933     InitUserPropSheetPage(&psp[2], IDD_USER_PROFILE, UserProfilePageProc, szUserName);
934 
935     return (PropertySheet(&psh) == IDOK);
936 }
937