nt-makefile-clean-targets-20010917
[openafs.git] / src / WINNT / afsapplib / al_browse.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
13 }
14
15 #include <WINNT/afsapplib.h>
16 #include "al_dynlink.h"
17 #include <WINNT/TaAfsAdmSvrClient.h>
18
19
20 /*
21  * DEFINITIONS ________________________________________________________________
22  *
23  */
24
25 #define cxICON              19            // size of an ACL entry icon
26
27 #define cyICON              16            // size of an ACL entry icon
28
29 #define clrTRANSPARENT      RGB(0,255,0)  // background color on ACL entry icons
30
31
32 /*
33  * BROWSE DIALOG ______________________________________________________________
34  *
35  */
36
37 typedef struct BROWSEDIALOGPARAMS {
38    TCHAR szCell[ cchRESOURCE ];
39    TCHAR szNamed[ cchRESOURCE ];
40    BOOL fThisCellOnly;
41    HIMAGELIST hImages;
42
43    BROWSETYPE bt;       // for what entry type do we browse?
44
45    HWND hDlg;
46    HANDLE hThread;
47    BOOL fCanStopThreadEasily;
48    BOOL fShouldStopThread;
49    BOOL fThreadActive;
50    TCHAR szThreadCell[ cchRESOURCE ];
51
52    int idsTitle;
53    int idsPrompt;
54    int idsNone;
55
56    LPCELLLIST lpcl;
57    PVOID hCreds;
58 } BROWSEDIALOGPARAMS, *LPBROWSEDIALOGPARAMS;
59
60
61 BOOL CALLBACK DlgProc_Browse (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp);
62 void DlgProc_Browse_OnInitDialog (HWND hDlg, BROWSEDIALOGPARAMS *pbdp);
63 void DlgProc_Browse_OnNone (HWND hDlg, BROWSEDIALOGPARAMS *pbdp);
64 void DlgProc_Browse_SelectedEntry (HWND hDlg, BROWSEDIALOGPARAMS *pbdp);
65 void DlgProc_Browse_UpdateCellText (BROWSEDIALOGPARAMS *pbdp, LPTSTR pszCell);
66
67 BOOL DlgProc_Browse_StartSearch (BROWSEDIALOGPARAMS *pbdp, BOOL fCloseDlgIfFail);
68 void DlgProc_Browse_StopSearch (BROWSEDIALOGPARAMS *pbdp);
69 DWORD _stdcall DlgProc_Browse_ThreadProc (LPARAM lp);
70
71 void EnumeratePrincipalsRemotely (LPBROWSEDIALOGPARAMS pbdp, DWORD idClient);
72 void EnumeratePrincipalsLocally (LPBROWSEDIALOGPARAMS pbdp);
73
74
75 /*
76  *** ShowBrowseDialog
77  *
78  * This function presents a dialog which allows the user to select a user
79  * or group from a list.
80  *
81  */
82
83 BOOL AfsAppLib_ShowBrowseDialog (LPBROWSEDLG_PARAMS lpp)
84 {
85    BROWSEDIALOGPARAMS *pbdp;
86    BOOL rc = FALSE;
87
88    if ((pbdp = New (BROWSEDIALOGPARAMS)) != NULL)
89    {
90       memset (pbdp, 0x00, sizeof(BROWSEDIALOGPARAMS));
91       lstrcpy (pbdp->szNamed, lpp->szNamed);
92       lstrcpy (pbdp->szCell, lpp->szCell);
93       pbdp->lpcl = lpp->lpcl;
94       pbdp->bt = lpp->bt;
95       pbdp->idsTitle = lpp->idsTitle;
96       pbdp->idsPrompt = lpp->idsPrompt;
97       pbdp->idsNone = lpp->idsNone;
98       pbdp->hCreds = lpp->hCreds;
99
100       switch (pbdp->bt)
101       {
102          case btLOCAL_USER:
103          case btLOCAL_GROUP:
104             pbdp->fThisCellOnly = TRUE;
105             break;
106
107          case btANY_USER:
108          case btANY_GROUP:
109             pbdp->fThisCellOnly = FALSE;
110             break;
111       }
112
113       if (ModalDialogParam (IDD_APPLIB_BROWSE, lpp->hParent, (DLGPROC)DlgProc_Browse, (LPARAM)pbdp) == IDOK)
114       {
115          lstrcpy (lpp->szCell, pbdp->szCell);
116          lstrcpy (lpp->szNamed, pbdp->szNamed);
117          rc = TRUE;
118       }
119
120       Delete (pbdp);
121    }
122
123    return rc;
124 }
125
126
127 /*
128  *** DlgProc_Browse
129  *
130  * This is the dialog proc for the Browse Cell dialog.
131  *
132  */
133
134 #define WM_FOUNDNAME   (WM_USER +100)
135 #define WM_THREADSTART (WM_USER +101)
136 #define WM_THREADDONE  (WM_USER +102)
137
138 BOOL CALLBACK DlgProc_Browse (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
139 {
140    BROWSEDIALOGPARAMS *pbdp;
141
142    if (AfsAppLib_HandleHelp (IDD_APPLIB_BROWSE, hDlg, msg, wp, lp))
143    {
144       return FALSE;
145    }
146
147    if (msg == WM_INITDIALOG)
148    {
149       SetWindowLong (hDlg, DWL_USER, lp);
150    }
151
152    if ((pbdp = (BROWSEDIALOGPARAMS *)GetWindowLong (hDlg, DWL_USER)) != NULL)
153    {
154       switch (msg)
155       {
156          case WM_INITDIALOG:
157             DlgProc_Browse_OnInitDialog (hDlg, pbdp);
158             break;
159
160          case WM_NOTIFY:
161             switch (((LPNMHDR)lp)->code)
162             {
163                case LVN_ITEMCHANGED:
164                   if ( ((LPNM_LISTVIEW)lp)->uNewState & LVIS_SELECTED )
165                   {
166                      DlgProc_Browse_SelectedEntry (hDlg, pbdp);
167                   }
168                   break;
169
170                case NM_DBLCLK:
171                   PostMessage (hDlg, WM_COMMAND, MAKELONG(IDC_BROWSE_SELECT,BN_CLICKED), (LPARAM)GetDlgItem(hDlg,IDC_BROWSE_SELECT));
172                   break;
173             }
174             break;
175
176          case WM_DESTROY:
177             DlgProc_Browse_StopSearch (pbdp);
178
179             if (pbdp->hImages != NULL)
180             {
181                ListView_SetImageList (GetDlgItem (hDlg, IDC_BROWSE_LIST), 0, 0);
182                ImageList_Destroy (pbdp->hImages);
183             }
184             break;
185
186          case WM_FOUNDNAME:
187          {
188             LPTSTR pszName = (LPTSTR)lp;
189             if (pszName != NULL)
190             {
191                HWND hList = GetDlgItem (hDlg, IDC_BROWSE_LIST);
192                LV_AddItem (hList, 1, INDEX_SORT, 0, 0, pszName);
193                FreeString (pszName);
194             }
195             break;
196          }
197
198          case WM_THREADSTART:
199          {
200             TCHAR szText[ cchRESOURCE ];
201             GetString (szText, IDS_BROWSE_WAITING);
202             SetDlgItemText (pbdp->hDlg, IDC_BROWSE_STATUS, szText);
203             break;
204          }
205
206          case WM_THREADDONE:
207          {
208             SetDlgItemText (pbdp->hDlg, IDC_BROWSE_STATUS, TEXT(""));
209             break;
210          }
211
212          case WM_COMMAND:
213             switch (LOWORD(wp))
214             {
215                case IDCANCEL:
216                   EndDialog (hDlg, LOWORD(wp));
217                   break;
218
219                case IDC_BROWSE_SELECT:
220                   if ( (GetDlgItem (pbdp->hDlg, IDC_BROWSE_NONE) != NULL) &&
221                        (IsDlgButtonChecked (pbdp->hDlg, IDC_BROWSE_NONE)) )
222                   {
223                      pbdp->szCell[0] = TEXT('\0');
224                      pbdp->szNamed[0] = TEXT('\0');
225                   }
226                   else
227                   {
228                      GetDlgItemText (hDlg, IDC_BROWSE_CELL,  pbdp->szCell,  cchNAME);
229                      GetDlgItemText (hDlg, IDC_BROWSE_NAMED, pbdp->szNamed, cchRESOURCE);
230                   }
231                   EndDialog (hDlg, IDOK);
232                   break;
233
234                case IDC_BROWSE_CELL:
235                   if (HIWORD(wp) == CBN_SELCHANGE)
236                   {
237                      GetDlgItemText (hDlg, IDC_BROWSE_CELL, pbdp->szCell, cchNAME);
238                      DlgProc_Browse_StartSearch (pbdp, FALSE);
239                   }
240                   break;
241
242                case IDC_BROWSE_RESTART:
243                   GetDlgItemText (hDlg, IDC_BROWSE_CELL, pbdp->szCell, cchNAME);
244                   DlgProc_Browse_StartSearch (pbdp, FALSE);
245                   PostMessage (hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem (hDlg, IDC_BROWSE_NAMED), (LPARAM)TRUE);
246                   break;
247
248                case IDC_BROWSE_NAMED:
249                   if (HIWORD(wp) == EN_UPDATE)  // has the user hit Enter here?
250                   {
251                      TCHAR szTest[ cchRESOURCE ];
252
253                      GetDlgItemText (hDlg, IDC_BROWSE_NAMED, szTest, cchRESOURCE);
254
255                      if ( (lstrlen (szTest) > 0) &&
256                           (szTest[ lstrlen(szTest)-1 ] == TEXT('\n')) )
257                      {
258                         szTest[ lstrlen(szTest)-1 ] = TEXT('\0');
259
260                         if ( (lstrlen (szTest) > 0) &&
261                              (szTest[ lstrlen(szTest)-1 ] == TEXT('\r')) )
262                         {
263                            szTest[ lstrlen(szTest)-1 ] = TEXT('\0');
264                         }
265
266                         SetDlgItemText (hDlg, IDC_BROWSE_NAMED, szTest);
267                         PostMessage (hDlg, WM_COMMAND, MAKELONG(IDC_BROWSE_SELECT,BN_CLICKED), (LPARAM)GetDlgItem(hDlg,IDC_BROWSE_SELECT));
268                      }
269                   }
270                   break;
271
272                case IDC_BROWSE_NONE:
273                   DlgProc_Browse_OnNone (hDlg, pbdp);
274                   break;
275             }
276             break;
277       }
278    }
279
280    return FALSE;
281 }
282
283
284 /*
285  *** DlgProc_Browse_OnInitDialog
286  *
287  * The WM_INITDIALOG handler for the Browse dialog.  This routine fills
288  * in the dialog with any starting parameters, and kicks off a new
289  * searching thread for the given cell.
290  *
291  */
292
293 void DlgProc_Browse_OnInitDialog (HWND hDlg, BROWSEDIALOGPARAMS *pbdp)
294 {
295    TCHAR szText[ cchRESOURCE ];
296    LPTSTR psz;
297
298    pbdp->hDlg = hDlg;
299
300    // We'll need an imagelist, if we want icons in the listview.
301    // This looks difficult but it's not--tis just a matter of selecting
302    // an appropriate bitmap.
303    //
304    if ((pbdp->hImages = ImageList_Create (cxICON, cyICON, ILC_COLOR4 | ILC_MASK, 1, 1)) != 0)
305    {
306       HBITMAP bmp;
307
308       if (pbdp->bt == btLOCAL_USER)
309       {
310          bmp = LoadBitmap (APPLIB_HINST, MAKEINTRESOURCE( IDB_LOCAL_USER ));
311       }
312       else if (pbdp->bt == btANY_USER)
313       {
314          bmp = LoadBitmap (APPLIB_HINST, MAKEINTRESOURCE( IDB_FOREIGN_USER ));
315       }
316       else if (pbdp->bt == btLOCAL_GROUP)
317       {
318          bmp = LoadBitmap (APPLIB_HINST, MAKEINTRESOURCE( IDB_LOCAL_GROUP ));
319       }
320       else if (pbdp->bt == btANY_GROUP)
321       {
322          bmp = LoadBitmap (APPLIB_HINST, MAKEINTRESOURCE( IDB_FOREIGN_GROUP ));
323       }
324
325       if (bmp != NULL)
326       {
327          ImageList_AddMasked (pbdp->hImages, bmp, clrTRANSPARENT);
328          DeleteObject (bmp);
329       }
330
331       ListView_SetImageList (GetDlgItem (hDlg, IDC_BROWSE_LIST), pbdp->hImages, LVSIL_SMALL);
332    }
333
334    // There's a default pushbutton on this dialog, so that hitting
335    // RETURN when you're in the Cell combobox will restart the search
336    // (a default pushbutton always gets called when RETURN is hit,
337    // unless your control traps it).  But the user doesn't want to *see*
338    // that thing, so move it way off the dialog's client area.
339    //
340    RECT r;
341    GetWindowRect (GetDlgItem (hDlg, IDC_BROWSE_RESTART), &r);
342    SetWindowPos (GetDlgItem (hDlg, IDC_BROWSE_RESTART), NULL,
343                  0 - (r.right-r.left), 0 - (r.bottom-r.top), 0, 0,
344                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
345
346    // Fill in the choices underneath IDC_BROWSE_CELL.  Can the
347    // user enter a new cell name?
348    //
349    if (pbdp->fThisCellOnly)
350    {
351       EnableWindow (GetDlgItem (hDlg, IDC_BROWSE_CELL), FALSE);
352    }
353    else
354    {
355       CB_StartChange (GetDlgItem (hDlg, IDC_BROWSE_CELL));
356
357       if (!pbdp->lpcl)
358       {
359          TCHAR szDefCell[ cchNAME ];
360          if (AfsAppLib_GetLocalCell (szDefCell) && *szDefCell)
361          {
362             CB_AddItem (GetDlgItem (hDlg, IDC_BROWSE_CELL), szDefCell, 1);
363          }
364       }
365       else for (size_t ii = 0; ii < pbdp->lpcl->nCells; ++ii)
366       {
367          CB_AddItem (GetDlgItem (hDlg, IDC_BROWSE_CELL), pbdp->lpcl->aCells[ii], 1+ii);
368       }
369
370       CB_EndChange (GetDlgItem (hDlg, IDC_BROWSE_CELL), 1);
371    }
372
373    // Select various texts to display in the dialog
374    //
375    psz = FormatString (TEXT("%1"), TEXT("%m"), pbdp->idsTitle);
376    SetWindowText (hDlg, psz);
377    FreeString (psz);
378    GetString (szText, pbdp->idsPrompt);
379    SetDlgItemText (hDlg, IDC_BROWSE_TYPE, szText);
380
381    // If the caller wants us to display a "[X] No Group" checkbox, do so
382    // by creating a checkbox right underneath the IDC_BROWSE_NAMED edit
383    // control--note that we'll have to hide IDC_BROWSE_STATUS if that's
384    // the case.
385    //
386    if (pbdp->idsNone != 0)
387    {
388       ShowWindow (GetDlgItem (pbdp->hDlg, IDC_BROWSE_STATUS), FALSE);
389
390       RECT rr;
391       GetRectInParent (GetDlgItem (pbdp->hDlg, IDC_BROWSE_NAMED), &rr);
392
393       LONG cy;
394       cy = rr.bottom -rr.top;
395       rr.top += cy +3;
396       rr.bottom = rr.top +cy;
397
398       GetString (szText, pbdp->idsNone);
399       CreateWindow ("Button", szText, WS_CHILD | BS_AUTOCHECKBOX,
400                     rr.left, rr.top, rr.right-rr.left, rr.bottom-rr.top,
401                     pbdp->hDlg, (HMENU)IDC_BROWSE_NONE, APPLIB_HINST, 0);
402
403       HFONT hf = (HFONT)GetStockObject (DEFAULT_GUI_FONT);
404       SendMessage (GetDlgItem (pbdp->hDlg, IDC_BROWSE_NONE), WM_SETFONT, (WPARAM)hf, FALSE);
405       ShowWindow (GetDlgItem (pbdp->hDlg, IDC_BROWSE_NONE), TRUE);
406
407       if (pbdp->szNamed[0] == TEXT('\0'))
408          CheckDlgButton (pbdp->hDlg, IDC_BROWSE_NONE, TRUE);
409       else
410          CheckDlgButton (pbdp->hDlg, IDC_BROWSE_NONE, FALSE);
411
412       DlgProc_Browse_OnNone (pbdp->hDlg, pbdp);
413    }
414
415    SetDlgItemText (hDlg, IDC_BROWSE_CELL,  pbdp->szCell);
416    SetDlgItemText (hDlg, IDC_BROWSE_NAMED, pbdp->szNamed);
417
418    // Start looking for users/groups
419    //
420    DlgProc_Browse_StartSearch (pbdp, TRUE);
421 }
422
423
424 /*
425  *** DlgProc_Browse_OnNone
426  *
427  * This routine is called whenever the user checks or unchecks the
428  * "[X] None" checkbox (which we may not even be displaying)
429  *
430  */
431
432 void DlgProc_Browse_OnNone (HWND hDlg, BROWSEDIALOGPARAMS *pbdp)
433 {
434    if (GetDlgItem (pbdp->hDlg, IDC_BROWSE_NONE) != NULL)
435    {
436       BOOL fNone = IsDlgButtonChecked (pbdp->hDlg, IDC_BROWSE_NONE);
437
438       EnableWindow (GetDlgItem (hDlg, IDC_BROWSE_CELL),  !fNone && !pbdp->fThisCellOnly);
439       EnableWindow (GetDlgItem (hDlg, IDC_BROWSE_NAMED), !fNone);
440       EnableWindow (GetDlgItem (hDlg, IDC_BROWSE_LIST),  !fNone);
441
442       DlgProc_Browse_SelectedEntry (hDlg, pbdp);
443    }
444 }
445
446
447 /*
448  *** DlgProc_Browse_SelectedEntry
449  *
450  * This routine is called whenever the user selects a new entry within
451  * the Browse dialog's listview
452  *
453  */
454
455 void DlgProc_Browse_SelectedEntry (HWND hDlg, BROWSEDIALOGPARAMS *pbdp)
456 {
457    if ( (GetDlgItem (pbdp->hDlg, IDC_BROWSE_NONE) != NULL) &&
458         (IsDlgButtonChecked (pbdp->hDlg, IDC_BROWSE_NONE)) )
459    {
460       pbdp->szNamed[0] = TEXT('\0');
461    }
462    else
463    {
464       HWND hList = GetDlgItem (hDlg, IDC_BROWSE_LIST);
465       short idxSelected = LV_GetSelected (hList);
466
467       if (idxSelected == -1)
468          pbdp->szNamed[0] = TEXT('\0');
469       else
470          LV_GetItemText (hList, idxSelected, 0, pbdp->szNamed);
471
472       SetDlgItemText (hDlg, IDC_BROWSE_NAMED, pbdp->szNamed);
473    }
474 }
475
476
477 /*
478  *** DlgProc_Browse_UpdateCellText
479  *
480  * This routine places the given cell name in the browse dialog.
481  *
482  */
483
484 void DlgProc_Browse_UpdateCellText (BROWSEDIALOGPARAMS *pbdp, LPTSTR pszCell)
485 {
486    SetDlgItemText (pbdp->hDlg, IDC_BROWSE_CELL, pbdp->szCell);
487 }
488
489
490 /*
491  *** DlgProc_Browse_StartSearch
492  *
493  * This routine initiates a thread which enumerates all users/groups within
494  * the given cell, posting messages to describe what it finds to the Browse
495  * dialog's DLGPROC.
496  *
497  */
498
499 BOOL DlgProc_Browse_StartSearch (BROWSEDIALOGPARAMS *pbdp, BOOL fCloseDlgIfFail)
500 {
501    DWORD dwThreadID;
502
503    // Can't start a new search until the old search terminates.
504    //
505    DlgProc_Browse_StopSearch (pbdp);
506
507    // Then make sure that we have a valid cell to query--if not, it may
508    // be grounds to terminate the entire browse dialog.
509    //
510    lstrcpy (pbdp->szThreadCell, pbdp->szCell);
511
512    if (!pbdp->szCell[0])
513    {
514       AfsAppLib_GetLocalCell (pbdp->szCell);
515
516       lstrcpy (pbdp->szThreadCell, pbdp->szCell);
517
518       DlgProc_Browse_UpdateCellText (pbdp, pbdp->szThreadCell);
519    }
520
521    if (!pbdp->szCell[0])
522    {
523       if (fCloseDlgIfFail)
524          EndDialog (pbdp->hDlg, IDCANCEL);
525
526       MessageBeep (MB_ICONHAND);
527       Message (MB_ICONHAND, IDS_BROWSE_BADCELL_TITLE, IDS_BROWSE_BADCELL_DESC);
528
529       if (!fCloseDlgIfFail)
530          PostMessage (pbdp->hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem (pbdp->hDlg, IDC_BROWSE_CELL), (LPARAM)TRUE);
531       return FALSE;
532    }
533
534    // Great--we can do the search.  Start a thread to do so.
535    //
536    pbdp->fCanStopThreadEasily = FALSE;
537    pbdp->fShouldStopThread = FALSE;
538    pbdp->fThreadActive = FALSE;
539
540    ListView_DeleteAllItems (GetDlgItem (pbdp->hDlg, IDC_BROWSE_LIST));
541
542    pbdp->hThread = CreateThread (NULL, 0,
543                                  (LPTHREAD_START_ROUTINE)DlgProc_Browse_ThreadProc,
544                                  pbdp, 0, &dwThreadID);
545
546    return (pbdp->hThread == 0) ? FALSE : TRUE;
547 }
548
549
550 /*
551  *** DlgProc_Browse_StopSearch
552  *
553  * This routine signals the search thread to stop, and will not return
554  * until it does.
555  *
556  */
557
558 void DlgProc_Browse_StopSearch (BROWSEDIALOGPARAMS *pbdp)
559 {
560    if (pbdp->fThreadActive)
561    {
562       if (pbdp->fCanStopThreadEasily)
563       {
564          pbdp->fShouldStopThread = TRUE;
565
566          WaitForSingleObject (pbdp->hThread, INFINITE);
567       }
568       else
569       {
570          TerminateThread (pbdp->hThread, 0);
571          pbdp->fThreadActive = FALSE;
572       }
573    }
574
575    SetDlgItemText (pbdp->hDlg, IDC_BROWSE_STATUS, TEXT(""));
576 }
577
578
579 /*
580  *** DlgProc_Browse_ThreadProc
581  *
582  * The worker thread for the Browse dialog; this routine enumerates all
583  * users or groups on the given cell, posting a WM_FOUNDNAME message to
584  * the Browse dialog after every successful find.  Note that LPARAM on
585  * such messages points to a string which should be freed with FreeString()
586  * when no longer needed.
587  *
588  */
589
590 DWORD _stdcall DlgProc_Browse_ThreadProc (LPARAM lp)
591 {
592    BROWSEDIALOGPARAMS *pbdp;
593
594    if ((pbdp = (BROWSEDIALOGPARAMS *)lp) != NULL)
595    {
596       pbdp->fThreadActive = TRUE;
597
598       PostMessage (pbdp->hDlg, WM_THREADSTART, 0, 0);
599
600       DWORD idClient;
601       if ((idClient = AfsAppLib_GetAdminServerClientID()) != 0)
602       {
603          EnumeratePrincipalsRemotely (pbdp, idClient);
604       }
605       else
606       {
607          if (OpenClientLibrary())
608          {
609             if (OpenKasLibrary())
610             {
611                EnumeratePrincipalsLocally (pbdp);
612                CloseKasLibrary();
613             }
614
615             CloseClientLibrary();
616          }
617       }
618
619       pbdp->fThreadActive = FALSE;
620
621       PostMessage (pbdp->hDlg, WM_THREADDONE, 0, 0);
622    }
623
624    return 0;
625 }
626
627
628 void EnumeratePrincipalsLocally (LPBROWSEDIALOGPARAMS pbdp)
629 {
630    ULONG status;
631
632    char szCellA[ MAX_PATH ];
633    CopyStringToAnsi (szCellA, pbdp->szCell);
634
635    PVOID hCell;
636    if (afsclient_CellOpen (szCellA, pbdp->hCreds, &hCell, (afs_status_p)&status))
637    {
638       // Enumerate the principals recognized by KAS.
639       //
640       PVOID hEnum;
641       if (kas_PrincipalGetBegin (hCell, NULL, &hEnum, (afs_status_p)&status))
642       {
643          pbdp->fCanStopThreadEasily = TRUE;
644
645          while (!pbdp->fShouldStopThread)
646          {
647             kas_identity_t who;
648             if (!kas_PrincipalGetNext (hEnum, &who, (afs_status_p)&status))
649                break;
650
651             LPTSTR pszName;
652             if ((pszName = CloneAnsi ((LPSTR)who.principal)) == NULL)
653                break;
654
655             PostMessage (pbdp->hDlg, WM_FOUNDNAME, 0, (LPARAM)pszName);
656             // pszName freed by DlgProc_Browse when it receives the message
657          }
658
659          kas_PrincipalGetDone (hEnum, (afs_status_p)&status);
660       }
661
662       afsclient_CellClose (hCell, (afs_status_p)&status);
663    }
664 }
665
666
667 void EnumeratePrincipalsRemotely (LPBROWSEDIALOGPARAMS pbdp, DWORD idClient)
668 {
669    ULONG status;
670
671    // Open the relevant cell
672    //
673    ASID idCell;
674    if (asc_CellOpen (idClient, pbdp->hCreds, pbdp->szThreadCell, AFSADMSVR_SCOPE_USERS, &idCell, &status))
675    {
676       // Obtain a list of ASIDs from the admin server, each representing
677       // a principal which we want to show.
678       //
679       LPASIDLIST pAsidList;
680       if (asc_ObjectFindMultiple (idClient, idCell, TYPE_USER, NULL, NULL, &pAsidList, &status))
681       {
682          if (pAsidList)
683          {
684             // Obtain rudimentary properties (e.g., their names) for these ASIDs
685             //
686             LPASOBJPROPLIST pPropList;
687             if (asc_ObjectPropertiesGetMultiple (idClient, GET_RUDIMENTARY_DATA, idCell, pAsidList, &pPropList, &status))
688             {
689                if (pPropList)
690                {
691                   // Use the information in {pPropList} to populate the display
692                   //
693                   for (size_t iEntry = 0; iEntry < pPropList->cEntries; ++iEntry)
694                   {
695                      LPTSTR pszName;
696                      if ((pszName = CloneString (pPropList->aEntries[ iEntry ].ObjectProperties.szName)) != NULL)
697                      {
698                         PostMessage (pbdp->hDlg, WM_FOUNDNAME, 0, (LPARAM)pszName);
699                         // pszName freed by DlgProc_Browse when it receives the message
700                      }
701                   }
702
703                   asc_ObjPropListFree (&pPropList);
704                }
705             }
706
707             asc_AsidListFree (&pAsidList);
708          }
709       }
710
711       asc_CellClose (idClient, idCell, &status);
712    }
713 }
714