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