jbuehler-add-missing-extern-c-patch-20031207
[openafs.git] / src / WINNT / afsusrmgr / task.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 "TaAfsUsrMgr.h"
16 #include "messages.h"
17 #include "creds.h"
18 #include "action.h"
19 #include "usr_col.h"
20
21
22 /*
23  * DEFINITIONS ________________________________________________________________
24  *
25  */
26
27 #ifndef iswhite
28 #define iswhite(_ch) ( ((_ch) == TEXT(' ')) || ((_ch) == TEXT('\t')) )
29 #endif
30
31 /*
32  * PROTOTYPES _________________________________________________________________
33  *
34  */
35
36 void Task_OpenCell (LPTASKPACKET ptp);
37 void Task_UpdCreds (LPTASKPACKET ptp);
38 void Task_UpdUsers (LPTASKPACKET ptp);
39 void Task_UpdGroups (LPTASKPACKET ptp);
40 void Task_UpdMachines (LPTASKPACKET ptp);
41 void Task_Refresh (LPTASKPACKET ptp);
42 void Task_RefreshMult (LPTASKPACKET ptp);
43 void Task_Get_Actions (LPTASKPACKET ptp);
44 void Task_Get_Random_Key (LPTASKPACKET ptp);
45 void Task_User_Change (LPTASKPACKET ptp);
46 void Task_User_Find (LPTASKPACKET ptp);
47 void Task_User_Enum (LPTASKPACKET ptp);
48 void Task_User_GroupList_Set (LPTASKPACKET ptp);
49 BOOL Task_User_GroupList_Set_Do (LPUSER_GROUPLIST_SET_PARAMS lpp, ULONG *pStatus);
50 void Task_User_CPW (LPTASKPACKET ptp);
51 void Task_User_Unlock (LPTASKPACKET ptp);
52 void Task_User_Create (LPTASKPACKET ptp);
53 void Task_User_Delete (LPTASKPACKET ptp);
54 void Task_Group_Change (LPTASKPACKET ptp);
55 void Task_Group_Search (LPTASKPACKET ptp);
56 void Task_Group_Members_Get (LPTASKPACKET ptp);
57 void Task_Group_Members_Set (LPTASKPACKET ptp);
58 BOOL Task_Group_Members_Set_Do (LPGROUP_MEMBERS_SET_PARAMS lpp, ULONG *pStatus);
59 void Task_Group_Enum (LPTASKPACKET ptp);
60 void Task_Group_Rename (LPTASKPACKET ptp);
61 void Task_Group_Owned_Get (LPTASKPACKET ptp);
62 void Task_Group_Owned_Set (LPTASKPACKET ptp);
63 BOOL Task_Group_Owned_Set_Do (LPGROUP_OWNED_SET_PARAMS lpp, ULONG *pStatus);
64 void Task_Group_Create (LPTASKPACKET ptp);
65 void Task_Group_Delete (LPTASKPACKET ptp);
66 void Task_Cell_Change (LPTASKPACKET ptp);
67 void Task_List_Translate (LPTASKPACKET ptp);
68 void Task_Object_Listen (LPTASKPACKET ptp);
69 void Task_Object_Get (LPTASKPACKET ptp);
70 void Task_Set_Refresh (LPTASKPACKET ptp);
71 void Task_Expired_Creds (LPTASKPACKET ptp);
72
73 void WeedAsidList (LPASIDLIST *ppList, BOOL fWantMachines);
74 void TranslateRegExp (LPTSTR pszTarget, LPCTSTR pszSource);
75 BOOL PerformRefresh (LPTASKPACKET ptp, ASID idScope, ULONG *pStatus);
76
77
78 /*
79  * ROUTINES ___________________________________________________________________
80  *
81  */
82
83 LPTASKPACKET CreateTaskPacket (int idTask, HWND hReply, PVOID lpUser)
84 {
85    LPTASKPACKET ptp;
86
87    if ((ptp = New (TASKPACKET)) != NULL)
88       {
89       memset (ptp, 0x00, sizeof(TASKPACKET));
90
91       ptp->idTask = idTask;
92       ptp->hReply = hReply;
93       ptp->lpUser = lpUser;
94       ptp->rc = TRUE;
95       ptp->status = 0;
96
97       if ((ptp->pReturn = New (TASKPACKETDATA)) != NULL)
98          {
99          memset (ptp->pReturn, 0x00, sizeof(TASKPACKETDATA));
100          }
101       }
102
103    return ptp;
104 }
105
106
107 void FreeTaskPacket (LPTASKPACKET ptp)
108 {
109    if (ptp)
110       {
111       if (ptp->pReturn)
112          {
113          if (TASKDATA(ptp)->pAsidList)
114             asc_AsidListFree (&TASKDATA(ptp)->pAsidList);
115          if (TASKDATA(ptp)->pActionList)
116             asc_ActionListFree (&TASKDATA(ptp)->pActionList);
117          Delete (ptp->pReturn);
118          }
119       Delete (ptp);
120       }
121 }
122
123
124 void PerformTask (LPTASKPACKET ptp)
125 {
126    switch (ptp->idTask)
127       {
128       case taskOPENCELL:
129          Task_OpenCell (ptp);
130          break;
131
132       case taskUPD_CREDS:
133          Task_UpdCreds (ptp);
134          break;
135
136       case taskUPD_USERS:
137          Task_UpdUsers (ptp);
138          break;
139
140       case taskUPD_GROUPS:
141          Task_UpdGroups (ptp);
142          break;
143
144       case taskUPD_MACHINES:
145          Task_UpdMachines (ptp);
146          break;
147
148       case taskREFRESH:
149          Task_Refresh (ptp);
150          break;
151
152       case taskREFRESHMULT:
153          Task_RefreshMult (ptp);
154          break;
155
156       case taskGET_ACTIONS:
157          Task_Get_Actions (ptp);
158          break;
159
160       case taskGET_RANDOM_KEY:
161          Task_Get_Random_Key (ptp);
162          break;
163
164       case taskUSER_CHANGE:
165          Task_User_Change (ptp);
166          break;
167
168       case taskUSER_FIND:
169          Task_User_Find (ptp);
170          break;
171
172       case taskUSER_ENUM:
173          Task_User_Enum (ptp);
174          break;
175
176       case taskUSER_GROUPLIST_SET:
177          Task_User_GroupList_Set (ptp);
178          break;
179
180       case taskUSER_CPW:
181          Task_User_CPW (ptp);
182          break;
183
184       case taskUSER_UNLOCK:
185          Task_User_Unlock (ptp);
186          break;
187
188       case taskUSER_CREATE:
189          Task_User_Create (ptp);
190          break;
191
192       case taskUSER_DELETE:
193          Task_User_Delete (ptp);
194          break;
195
196       case taskGROUP_CHANGE:
197          Task_Group_Change (ptp);
198          break;
199
200       case taskGROUP_SEARCH:
201          Task_Group_Search (ptp);
202          break;
203
204       case taskGROUP_MEMBERS_GET:
205          Task_Group_Members_Get (ptp);
206          break;
207
208       case taskGROUP_MEMBERS_SET:
209          Task_Group_Members_Set (ptp);
210          break;
211
212       case taskGROUP_ENUM:
213          Task_Group_Enum (ptp);
214          break;
215
216       case taskGROUP_RENAME:
217          Task_Group_Rename (ptp);
218          break;
219
220       case taskGROUP_OWNED_GET:
221          Task_Group_Owned_Get (ptp);
222          break;
223
224       case taskGROUP_OWNED_SET:
225          Task_Group_Owned_Set (ptp);
226          break;
227
228       case taskGROUP_CREATE:
229          Task_Group_Create (ptp);
230          break;
231
232       case taskGROUP_DELETE:
233          Task_Group_Delete (ptp);
234          break;
235
236       case taskCELL_CHANGE:
237          Task_Cell_Change (ptp);
238          break;
239
240       case taskLIST_TRANSLATE:
241          Task_List_Translate (ptp);
242          break;
243
244       case taskOBJECT_LISTEN:
245          Task_Object_Listen (ptp);
246          break;
247
248       case taskOBJECT_GET:
249          Task_Object_Get (ptp);
250          break;
251
252       case taskSET_REFRESH:
253          Task_Set_Refresh (ptp);
254          break;
255
256       case taskEXPIRED_CREDS:
257          Task_Expired_Creds (ptp);
258          break;
259
260       default:
261          ptp->rc = FALSE;
262          ptp->status = ERROR_INVALID_FUNCTION;
263          break;
264       }
265 }
266
267
268 /*
269  * KEYS _______________________________________________________________________
270  *
271  */
272
273 HASHVALUE CALLBACK Key_Asid_HashData (LPHASHLISTKEY pKey, PVOID pData)
274 {
275    return *(ASID*)pData;
276 }
277
278 HASHVALUE CALLBACK Key_Asid_HashObject (LPHASHLISTKEY pKey, PVOID pObject)
279 {
280    return Key_Asid_HashData (pKey, (ASID*)pObject);
281 }
282
283 BOOL CALLBACK Key_Asid_Compare (LPHASHLISTKEY pKey, PVOID pObject, PVOID pData)
284 {
285    return ((*(ASID*)pObject) == (*(ASID*)pData));
286 }
287
288
289 /*
290  * TASKS ______________________________________________________________________
291  *
292  */
293
294 void Task_OpenCell (LPTASKPACKET ptp)
295 {
296    LPOPENCELL_PARAMS lpp = (LPOPENCELL_PARAMS)( ptp->lpUser );
297
298    Display_StartWorking();
299
300    // Try to open the cell for administration
301    //
302    ptp->rc = asc_CellOpen (g.idClient, lpp->hCreds, lpp->szCell, AFSADMSVR_SCOPE_USERS, &TASKDATA(ptp)->idCell, &ptp->status);
303
304    if (ptp->rc)
305       {
306       PostMessage (g.hMain, WM_SHOW_YOURSELF, 0, 1);
307       }
308    else if ((!ptp->rc) && (!IsWindow(ptp->hReply)))
309       {
310       if (lpp->fCloseAppOnFail)
311          FatalErrorDialog (ptp->status, IDS_ERROR_CANT_OPEN_CELL, TEXT("%s"), lpp->szCell);
312       else
313          ErrorDialog (ptp->status, IDS_ERROR_CANT_OPEN_CELL, TEXT("%s"), lpp->szCell);
314       }
315
316    // If we previously had another cell open, close it.
317    //
318    if (ptp->rc)
319       {
320       asc_Enter();
321
322       if (g.idCell)
323          {
324          ULONG status;
325          (void)asc_CellClose (g.idClient, g.idCell, &status);
326          }
327       g.idCell = TASKDATA(ptp)->idCell;
328
329       asc_Leave();
330       }
331
332    // Update the "Selected Cell:" text on the main window
333    //
334    TCHAR szCell[ cchNAME ];
335    if (!g.idCell)
336       GetString (szCell, IDS_CELL_NONE);
337    else if (!asc_CellNameGet_Fast (g.idClient, g.idCell, szCell))
338       GetString (szCell, IDS_CELL_NONE);
339    SetDlgItemText (g.hMain, IDC_CELL, szCell);
340    ShowCurrentCredentials();
341
342    // Oh--also, set the refresh rate for the newly-opened cell
343    //
344    ULONG dummy;
345    asc_CellRefreshRateSet (g.idClient, g.idCell, gr.cminRefreshRate, &dummy);
346
347    // Start re-populating the Users or Groups tab (whichever is showing)
348    //
349    Display_PopulateList();
350
351    Display_StopWorking();
352
353    // When we've opened a new cell, it's time to open the Actions window.
354    //
355    if (gr.fShowActions)
356       PostMessage (g.hMain, WM_SHOW_ACTIONS, 0, 0);
357
358    Delete (lpp);
359    ptp->lpUser = 0; // we freed this; don't let the caller use it again
360 }
361
362
363 void Task_UpdCreds (LPTASKPACKET ptp)
364 {
365    // Update the display to report our new credentials
366    //
367    ShowCurrentCredentials();
368
369    // Tell the admin server to use our new credentials, and refresh everything
370    //
371    if (!asc_CredentialsPush (g.idClient, g.hCreds, g.idCell, &ptp->status))
372       ptp->rc = FALSE;
373    else
374       ptp->rc = PerformRefresh (ptp, g.idCell, &ptp->status);
375 }
376
377
378 void Task_UpdUsers (LPTASKPACKET ptp)
379 {
380    // First we'll query the admin server to find a list of all users which
381    // match our search pattern.
382    //
383    lstrcpy (TASKDATA(ptp)->szPattern, g.szPatternUsers);
384
385    TCHAR szRegExp[ cchNAME ];
386    TranslateRegExp (szRegExp, TASKDATA(ptp)->szPattern);
387    if (!asc_ObjectFindMultiple (g.idClient, g.idCell, TYPE_USER, szRegExp, &gr.SearchUsers, &TASKDATA(ptp)->pAsidList, &ptp->status))
388       ptp->rc = FALSE;
389
390    // If we got a result back, weed out any entries that look like machines.
391    //
392    if (ptp->rc)
393       {
394       WeedAsidList (&TASKDATA(ptp)->pAsidList, FALSE);
395       }
396
397    // Wow, that was easy. Okay, next step: ensure that we have properties
398    // for all these guys in the local cache--to do that, we'll query their
399    // properties, then free the result.
400    //
401    if (ptp->rc)
402       {
403       LPASOBJPROPLIST pPropList = NULL;
404       if (!asc_ObjectPropertiesGetMultiple (g.idClient, GET_ALL_DATA, g.idCell, TASKDATA(ptp)->pAsidList, &pPropList, &ptp->status))
405          ptp->rc = FALSE;
406       if (pPropList)
407          asc_ObjPropListFree (&pPropList);
408       }
409 }
410
411
412 void Task_UpdGroups (LPTASKPACKET ptp)
413 {
414    // First we'll query the admin server to find a list of all groups which
415    // match our search pattern.
416    //
417    lstrcpy (TASKDATA(ptp)->szPattern, g.szPatternGroups);
418
419    TCHAR szRegExp[ cchNAME ];
420    TranslateRegExp (szRegExp, TASKDATA(ptp)->szPattern);
421    if (!asc_ObjectFindMultiple (g.idClient, g.idCell, TYPE_GROUP, szRegExp, NULL, &TASKDATA(ptp)->pAsidList, &ptp->status))
422       ptp->rc = FALSE;
423
424    // Wow, that was easy. Okay, next step: ensure that we have properties
425    // for all these guys in the local cache--to do that, we'll query their
426    // properties, then free the result.
427    //
428    if (ptp->rc)
429       {
430       LPASOBJPROPLIST pPropList = NULL;
431       if (!asc_ObjectPropertiesGetMultiple (g.idClient, GET_ALL_DATA, g.idCell, TASKDATA(ptp)->pAsidList, &pPropList, &ptp->status))
432          ptp->rc = FALSE;
433       if (pPropList)
434          asc_ObjPropListFree (&pPropList);
435       }
436 }
437
438
439 void Task_UpdMachines (LPTASKPACKET ptp)
440 {
441    // First we'll query the admin server to find a list of all users which
442    // match our search pattern.
443    //
444    TCHAR szRegExp[ cchNAME ];
445    if (g.szPatternMachines[0])
446       TranslateRegExp (szRegExp, g.szPatternMachines);
447    else
448       lstrcpy (szRegExp, TEXT("^[0-9.]*$"));
449
450    if (!asc_ObjectFindMultiple (g.idClient, g.idCell, TYPE_USER, szRegExp, NULL, &TASKDATA(ptp)->pAsidList, &ptp->status))
451       ptp->rc = FALSE;
452
453    lstrcpy (TASKDATA(ptp)->szPattern, g.szPatternMachines);
454
455    // If we got a result back, weed out any entries that don't look
456    // like machines.
457    //
458    if (ptp->rc)
459       {
460       WeedAsidList (&TASKDATA(ptp)->pAsidList, TRUE);
461       }
462
463    // Wow, that was easy. Okay, next step: ensure that we have properties
464    // for all these guys in the local cache--to do that, we'll query their
465    // properties, then free the result.
466    //
467    if (ptp->rc)
468       {
469       LPASOBJPROPLIST pPropList = NULL;
470       if (!asc_ObjectPropertiesGetMultiple (g.idClient, GET_ALL_DATA, g.idCell, TASKDATA(ptp)->pAsidList, &pPropList, &ptp->status))
471          ptp->rc = FALSE;
472       if (pPropList)
473          asc_ObjPropListFree (&pPropList);
474       }
475 }
476
477
478
479 void Task_Refresh (LPTASKPACKET ptp)
480 {
481    ASID idScope = (ASID)( ptp->lpUser );
482
483    ptp->rc = PerformRefresh (ptp, idScope, &ptp->status);
484 }
485
486
487 void Task_RefreshMult (LPTASKPACKET ptp)
488 {
489    LPASIDLIST pAsidList = (LPASIDLIST)( ptp->lpUser );
490
491    // Invalidate the admin server's cached information about the specified
492    // object. Remember that this is recursive hierarchically: if you pass
493    // in a cell's ID, for instance, information about all users, groups,
494    // servers, services, partitions and volumes anywhere in that cell will
495    // be discarded.
496    //
497    ptp->rc = asc_ObjectRefreshMultiple (g.idClient, g.idCell, pAsidList, &ptp->status);
498
499    // The Refresh call above just made us invalidate the status for one or
500    // more objects; to get the display to reflect the changes, we'll have to
501    // query the server for the latest properties for those objects. Once that's
502    // done, we'll just redraw the main window and it will pick up the changes.
503    //
504    if (ptp->rc)
505       {
506       ULONG status;
507       LPASOBJPROPLIST pPropList = NULL;
508       if (asc_ObjectPropertiesGetMultiple (g.idClient, GET_ALL_DATA, g.idCell, pAsidList, &pPropList, &status))
509          {
510          // That call returned properties for the objects; we don't need
511          // the properties here--we just wanted to get them in the cache.
512          // Now that they're in the cache, redrawing the main window will
513          // cause the latest data to be displayed.
514          //
515          if (pPropList)
516             asc_ObjPropListFree (&pPropList);
517          Display_RefreshView_Fast();
518          }
519       }
520
521    asc_AsidListFree (&pAsidList);
522    ptp->lpUser = 0; // we freed this; don't let the caller use it again
523 }
524
525
526 void Task_Get_Actions (LPTASKPACKET ptp)
527 {
528    // Query the admin server to get a current list of operations-in-progress.
529    // We'll limit our search to operations being performed on this cell.
530    //
531    ptp->rc = asc_ActionGetMultiple (g.idClient, 0, g.idCell, &TASKDATA(ptp)->pActionList, &ptp->status);
532 }
533
534
535 void Task_Get_Random_Key (LPTASKPACKET ptp)
536 {
537    ptp->rc = asc_RandomKeyGet (g.idClient, g.idCell, TASKDATA(ptp)->key, &ptp->status);
538
539    if (!ptp->rc && !IsWindow(ptp->hReply))
540       {
541       ErrorDialog (ptp->status, IDS_ERROR_CANT_GET_RANDOM_KEY);
542       }
543 }
544
545
546 void Task_User_Change (LPTASKPACKET ptp)
547 {
548    LPUSER_CHANGE_PARAMS lpp = (LPUSER_CHANGE_PARAMS)( ptp->lpUser );
549
550    if ((ptp->rc = asc_UserChange (g.idClient, g.idCell, lpp->idUser, &lpp->NewProperties, &ptp->status)) == TRUE)
551       {
552       Display_RefreshView_Fast();
553       }
554
555    if (!ptp->rc && !IsWindow (ptp->hReply))
556       {
557       TCHAR szUser[ cchNAME ];
558       User_GetDisplayName (szUser, lpp->idUser);
559       ErrorDialog (ptp->status, IDS_ERROR_CANT_CHANGE_USER, TEXT("%s"), szUser);
560       }
561
562    Delete (lpp);
563    ptp->lpUser = 0; // we freed this; don't let the caller use it again
564 }
565
566
567 void Task_User_Find (LPTASKPACKET ptp)
568 {
569    LPTSTR pszName = (LPTSTR)( ptp->lpUser );
570
571    if ((ptp->rc = asc_ObjectFind (g.idClient, g.idCell, TYPE_USER, pszName, &TASKDATA(ptp)->idObject, &ptp->status)) == TRUE)
572       {
573       ptp->rc = asc_ObjectPropertiesGet (g.idClient, GET_ALL_DATA, g.idCell, TASKDATA(ptp)->idObject, &TASKDATA(ptp)->Properties, &ptp->status);
574       }
575
576    FreeString (pszName);
577    ptp->lpUser = 0; // we freed this; don't let the caller use it again
578 }
579
580
581 void Task_User_Enum (LPTASKPACKET ptp)
582 {
583    LPCTSTR pszPattern = (LPCTSTR)( ptp->lpUser );
584
585    TCHAR szRegExp[ cchNAME ];
586    TranslateRegExp (szRegExp, pszPattern);
587    if ((ptp->rc = asc_ObjectFindMultiple (g.idClient, g.idCell, TYPE_USER, szRegExp, NULL, &TASKDATA(ptp)->pAsidList, &ptp->status)) == TRUE)
588       {
589       LPASOBJPROPLIST pPropList = NULL;
590
591       ptp->rc = asc_ObjectPropertiesGetMultiple (g.idClient, GET_RUDIMENTARY_DATA, g.idCell, TASKDATA(ptp)->pAsidList, &pPropList, &ptp->status);
592
593       if (pPropList)
594          asc_ObjPropListFree (&pPropList);
595       }
596
597    FreeString (pszPattern);
598    ptp->lpUser = 0; // we freed this; don't let the caller use it again
599 }
600
601
602 void Task_User_GroupList_Set (LPTASKPACKET ptp)
603 {
604    LPUSER_GROUPLIST_SET_PARAMS lpp = (LPUSER_GROUPLIST_SET_PARAMS)( ptp->lpUser );
605
606    ptp->rc = Task_User_GroupList_Set_Do (lpp, &ptp->status);
607
608    asc_AsidListFree (&lpp->pUsers);
609    asc_AsidListFree (&lpp->pGroups);
610    Delete (lpp);
611    ptp->lpUser = 0; // we freed this; don't let the caller use it again
612 }
613
614
615 BOOL Task_User_GroupList_Set_Do (LPUSER_GROUPLIST_SET_PARAMS lpp, ULONG *pStatus)
616 {
617    BOOL rc = TRUE;
618
619    // Maintain a structure describing any errors we encounter, so we can give
620    // a reasonable error dialog if need be.
621    //
622    LPERRORDATA ped = ED_Create (IDS_ERROR_CANT_SET_GROUPS, IDS_ERROR_CANT_SET_GROUPS_MULTIPLE);
623
624    // We'll need the supplied group-list in a hashlist, so we can quickly
625    // test it for inclusion of a particular group.
626    //
627    LPHASHLIST pGroupsAllow = New (HASHLIST);
628    for (size_t iGroup = 0; iGroup < lpp->pGroups->cEntries; ++iGroup)
629       pGroupsAllow->AddUnique ((PVOID)(lpp->pGroups->aEntries[ iGroup ].idObject));
630
631    // We'll have to do this next bit for each user in the supplied user-list
632    //
633    for (size_t iUser = 0; iUser < lpp->pUsers->cEntries; ++iUser)
634       {
635       ULONG status;
636
637       // Obtain the appropriate current list of groups for this user
638       //
639       LPASIDLIST pGroupsOld = NULL;
640       if (lpp->fMembership)
641          {
642          if (!asc_GroupMembershipGet (g.idClient, g.idCell, lpp->pUsers->aEntries[ iUser ].idObject, &pGroupsOld, &status))
643             {
644             ED_RegisterStatus (ped, lpp->pUsers->aEntries[ iUser ].idObject, FALSE, status);
645             continue;
646             }
647          }
648       else // (!lpp->fMembership)
649          {
650          if (!asc_GroupOwnershipGet (g.idClient, g.idCell, lpp->pUsers->aEntries[ iUser ].idObject, &pGroupsOld, &status))
651             {
652             ED_RegisterStatus (ped, lpp->pUsers->aEntries[ iUser ].idObject, FALSE, status);
653             continue;
654             }
655          }
656       if (!pGroupsOld)
657          continue;
658
659       // Test each group in that current list to see if it's also on our
660       // pGroupsAllow list. If not, remove it.
661       //
662       for (iGroup = 0; iGroup < pGroupsOld->cEntries; ++iGroup)
663          {
664          if (pGroupsAllow->fIsInList ((PVOID)(pGroupsOld->aEntries[iGroup].idObject)))
665             continue;
666
667          if (lpp->fMembership)
668             {
669             if (!asc_GroupMemberRemove (g.idClient, g.idCell, pGroupsOld->aEntries[iGroup].idObject, lpp->pUsers->aEntries[iUser].idObject, &status))
670                ED_RegisterStatus (ped, lpp->pUsers->aEntries[ iUser ].idObject, FALSE, status);
671             }
672          else // (!lpp->fMembership)
673             {
674             ASOBJPROP Properties;
675             if (asc_ObjectPropertiesGet (g.idClient, GET_ALL_DATA, g.idCell, pGroupsOld->aEntries[iGroup].idObject, &Properties, &status))
676                {
677                AFSADMSVR_CHANGEGROUP_PARAMS pp;
678                memset (&pp, 0x00, sizeof(pp));
679                lstrcpy (pp.szOwner, Properties.szName); // make group self-owned
680                pp.aaListStatus = Properties.u.GroupProperties.aaListStatus;
681                pp.aaListGroupsOwned = Properties.u.GroupProperties.aaListGroupsOwned;
682                pp.aaListMembers = Properties.u.GroupProperties.aaListMembers;
683                pp.aaAddMember = Properties.u.GroupProperties.aaAddMember;
684                pp.aaDeleteMember = Properties.u.GroupProperties.aaDeleteMember;
685                if (!asc_GroupChange (g.idClient, g.idCell, pGroupsOld->aEntries[iGroup].idObject, &pp, &status))
686                   ED_RegisterStatus (ped, lpp->pUsers->aEntries[ iUser ].idObject, FALSE, status);
687                }
688             }
689          }
690
691       // Now the more complex part: see if there are any groups in the
692       // supplied group-list which are marked as mandatory, but which
693       // aren't in our pGroupsOld list. We'll need to put the latter in a
694       // hashlist for this...
695       //
696       LPHASHLIST pGroupsOldList = New (HASHLIST);
697       for (iGroup = 0; iGroup < pGroupsOld->cEntries; ++iGroup)
698          pGroupsOldList->AddUnique ((PVOID)(pGroupsOld->aEntries[ iGroup ].idObject));
699
700       for (iGroup = 0; iGroup < lpp->pGroups->cEntries; ++iGroup)
701          {
702          if (!lpp->pGroups->aEntries[ iGroup ].lParam)
703             continue; // group not mandatory
704          if (pGroupsOldList->fIsInList ((PVOID)(lpp->pGroups->aEntries[ iGroup ].idObject)))
705             continue; // already a member
706
707          if (lpp->fMembership)
708             {
709             if (!asc_GroupMemberAdd (g.idClient, g.idCell, lpp->pGroups->aEntries[iGroup].idObject, lpp->pUsers->aEntries[iUser].idObject, &status))
710                ED_RegisterStatus (ped, lpp->pUsers->aEntries[ iUser ].idObject, FALSE, status);
711             }
712          else // (!lpp->fMembership)
713             {
714             ASOBJPROP Properties;
715             if (asc_ObjectPropertiesGet (g.idClient, GET_ALL_DATA, g.idCell, lpp->pGroups->aEntries[iGroup].idObject, &Properties, &status))
716                {
717                AFSADMSVR_CHANGEGROUP_PARAMS pp;
718                memset (&pp, 0x00, sizeof(pp));
719                pp.aaListStatus = Properties.u.GroupProperties.aaListStatus;
720                pp.aaListGroupsOwned = Properties.u.GroupProperties.aaListGroupsOwned;
721                pp.aaListMembers = Properties.u.GroupProperties.aaListMembers;
722                pp.aaAddMember = Properties.u.GroupProperties.aaAddMember;
723                pp.aaDeleteMember = Properties.u.GroupProperties.aaDeleteMember;
724
725                if (asc_ObjectNameGet_Fast (g.idClient, g.idCell, lpp->pUsers->aEntries[iUser].idObject, pp.szOwner, &status))
726                   {
727                   if (!asc_GroupChange (g.idClient, g.idCell, lpp->pGroups->aEntries[iGroup].idObject, &pp, &status))
728                      ED_RegisterStatus (ped, lpp->pUsers->aEntries[ iUser ].idObject, FALSE, status);
729                   }
730                }
731             }
732          }
733
734       Delete (pGroupsOldList);
735       asc_AsidListFree (&pGroupsOld);
736       }
737
738    // If there were any errors, report them.
739    //
740    if ((*pStatus = ED_GetFinalStatus(ped)) != 0)
741       {
742       rc = FALSE;
743       ED_ShowErrorDialog(ped);
744       }
745    ED_Free(ped);
746
747    // Done; clean up
748    //
749    Delete (pGroupsAllow);
750    return rc;
751 }
752
753
754 void Task_User_CPW (LPTASKPACKET ptp)
755 {
756    LPUSER_CPW_PARAMS lpp = (LPUSER_CPW_PARAMS)( ptp->lpUser );
757
758    ptp->rc = asc_UserPasswordSet (g.idClient, g.idCell, lpp->idUser, lpp->keyVersion, lpp->keyString, lpp->keyData, &ptp->status);
759
760    if ((!ptp->rc) && (!IsWindow(ptp->hReply)))
761       {
762       TCHAR szName[ cchNAME ];
763       User_GetDisplayName (szName, lpp->idUser);
764       ErrorDialog (ptp->status, IDS_ERROR_CANT_CHANGE_PASSWORD, TEXT("%s"), szName);
765       }
766
767    Delete (lpp);
768    ptp->lpUser = 0; // we freed this; don't let the caller use it again
769 }
770
771
772 void Task_User_Unlock (LPTASKPACKET ptp)
773 {
774    LPASIDLIST pUserList = (LPASIDLIST)( ptp->lpUser );
775
776    // Maintain a structure describing any errors we encounter, so we can give
777    // a reasonable error dialog if need be.
778    //
779    LPERRORDATA ped = ED_Create (IDS_ERROR_CANT_UNLOCK, IDS_ERROR_CANT_UNLOCK_MULTIPLE);
780
781    // Try to unlock the users' accounts...
782    //
783    for (size_t iUser = 0; iUser < pUserList->cEntries; ++iUser)
784       {
785       if (!asc_UserUnlock (g.idClient, g.idCell, pUserList->aEntries[ iUser ].idObject, &ptp->status))
786          ED_RegisterStatus (ped, pUserList->aEntries[ iUser ].idObject, FALSE, ptp->status);
787       }
788
789    // If there were any errors, report them.
790    //
791    if (ED_GetFinalStatus(ped) && !IsWindow(ptp->hReply))
792       ED_ShowErrorDialog(ped);
793    ED_Free(ped);
794
795    asc_AsidListFree (&pUserList);
796    ptp->lpUser = 0; // we freed this; don't let the caller use it again
797 }
798
799
800 void Task_User_Create (LPTASKPACKET ptp)
801 {
802    LPUSER_CREATE_PARAMS lpp = (LPUSER_CREATE_PARAMS)(ptp->lpUser);
803
804    // We may actually have been asked to create more than one user here;
805    // the {lpp->mszNames} parameter is a multi-string. So everything we
806    // do, we'll do for each new user-name...
807    //
808    for (LPTSTR pszName = lpp->mszNames; pszName && *pszName; pszName += 1+lstrlen(pszName))
809       {
810       // First create this new user account
811       //
812       ASID idUser;
813
814       AFSADMSVR_CREATEUSER_PARAMS pp;
815       memset (&pp, 0x00, sizeof(AFSADMSVR_CREATEUSER_PARAMS));
816       User_SplitDisplayName (pszName, pp.szName, pp.szInstance);
817       lstrcpy (pp.szPassword, lpp->szPassword);
818       pp.idUser = lpp->idUser;
819       pp.fCreateKAS = lpp->fCreateKAS;
820       pp.fCreatePTS = lpp->fCreatePTS;
821       if ((ptp->rc = asc_UserCreate (g.idClient, g.idCell, &pp, &idUser, &ptp->status)) == FALSE)
822          {
823          if (!IsWindow (ptp->hReply))
824             ErrorDialog (ptp->status, IDS_ERROR_CANT_CREATE_USER, TEXT("%s"), pszName);
825          continue;
826          }
827
828       // Then change its properties to be what we want
829       //
830       if ((ptp->rc = asc_UserChange (g.idClient, g.idCell, idUser, &lpp->Properties, &ptp->status)) == FALSE)
831          {
832          if (!IsWindow (ptp->hReply))
833             ErrorDialog (ptp->status, IDS_ERROR_CANT_CHANGE_USER, TEXT("%s"), pszName);
834          }
835       if (!ptp->rc)
836          continue;
837
838       // Finally update its lists of groups
839       //
840       if (lpp->pGroupsMember)
841          {
842          USER_GROUPLIST_SET_PARAMS pp;
843          memset (&pp, 0x00, sizeof(USER_GROUPLIST_SET_PARAMS));
844          asc_AsidListCreate (&pp.pUsers);
845          asc_AsidListAddEntry (&pp.pUsers, idUser, 0);
846          asc_AsidListCopy (&pp.pGroups, &lpp->pGroupsMember);
847          pp.fMembership = TRUE;
848          ptp->rc = Task_User_GroupList_Set_Do (&pp, &ptp->status);
849          asc_AsidListFree (&pp.pUsers);
850          asc_AsidListFree (&pp.pGroups);
851          }
852       if (lpp->pGroupsOwner)
853          {
854          USER_GROUPLIST_SET_PARAMS pp;
855          memset (&pp, 0x00, sizeof(USER_GROUPLIST_SET_PARAMS));
856          asc_AsidListCreate (&pp.pUsers);
857          asc_AsidListAddEntry (&pp.pUsers, idUser, 0);
858          asc_AsidListCopy (&pp.pGroups, &lpp->pGroupsOwner);
859          pp.fMembership = FALSE;
860          ptp->rc = Task_User_GroupList_Set_Do (&pp, &ptp->status);
861          asc_AsidListFree (&pp.pUsers);
862          asc_AsidListFree (&pp.pGroups);
863          }
864       }
865
866    // And we're done!
867    //
868    Display_PopulateList();
869
870    if (lpp->pGroupsOwner)
871       asc_AsidListFree (&lpp->pGroupsOwner);
872    if (lpp->pGroupsMember)
873       asc_AsidListFree (&lpp->pGroupsMember);
874    if (lpp->mszNames)
875       FreeString (lpp->mszNames);
876    Delete (lpp);
877    ptp->lpUser = 0; // we freed this; don't let the caller use it again
878 }
879
880
881 void Task_User_Delete (LPTASKPACKET ptp)
882 {
883    LPUSER_DELETE_PARAMS lpp = (LPUSER_DELETE_PARAMS)(ptp->lpUser);
884
885    // Maintain a structure describing any errors we encounter, so we can give
886    // a reasonable error dialog if need be.
887    //
888    LPERRORDATA ped = ED_Create (IDS_ERROR_CANT_DELETE_USER, IDS_ERROR_CANT_DELETE_USER_MULTIPLE);
889
890    // Go through and delete these users
891    //
892    for (size_t iUser = 0; iUser < lpp->pUserList->cEntries; ++iUser)
893       {
894       AFSADMSVR_DELETEUSER_PARAMS pp;
895       memset (&pp, 0x00, sizeof(pp));
896       pp.fDeleteKAS = lpp->fDeleteKAS;
897       pp.fDeletePTS = lpp->fDeletePTS;
898
899       ULONG status;
900       if (!asc_UserDelete (g.idClient, g.idCell, lpp->pUserList->aEntries[iUser].idObject, &pp, &status))
901          ED_RegisterStatus (ped, lpp->pUserList->aEntries[iUser].idObject, FALSE, status);
902       }
903
904    // If there were any errors, report them.
905    //
906    if (ED_GetFinalStatus(ped) && !IsWindow(ptp->hReply))
907       ED_ShowErrorDialog(ped);
908    ED_Free(ped);
909
910    // And we're done!
911    //
912    Display_PopulateList();
913
914    if (lpp->pUserList)
915       asc_AsidListFree (&lpp->pUserList);
916    Delete (lpp);
917    ptp->lpUser = 0; // we freed this; don't let the caller use it again
918 }
919
920
921 void Task_Group_Change (LPTASKPACKET ptp)
922 {
923    LPGROUP_CHANGE_PARAMS lpp = (LPGROUP_CHANGE_PARAMS)( ptp->lpUser );
924
925    if ((ptp->rc = asc_GroupChange (g.idClient, g.idCell, lpp->idGroup, &lpp->NewProperties, &ptp->status)) == TRUE)
926       {
927       Display_RefreshView_Fast();
928       }
929
930    if (!ptp->rc && !IsWindow (ptp->hReply))
931       {
932       TCHAR szGroup[ cchNAME ];
933       asc_ObjectNameGet_Fast (g.idClient, g.idCell, lpp->idGroup, szGroup);
934       ErrorDialog (ptp->status, IDS_ERROR_CANT_CHANGE_GROUP, TEXT("%s"), szGroup);
935       }
936
937    Delete (lpp);
938    ptp->lpUser = 0; // we freed this; don't let the caller use it again
939 }
940
941
942 void Task_Group_Search (LPTASKPACKET ptp)
943 {
944    LPGROUP_SEARCH_PARAMS lpp = (LPGROUP_SEARCH_PARAMS)( ptp->lpUser );
945
946    // Prepare an intermediate place for us to put the results of our search.
947    // We'll be doing lots of work in this intermediate list, so it'll be
948    // implemented as a hashlist with a key over the objects' ASIDs.
949    //
950    typedef struct
951       {
952       ASID idGroup;
953       size_t cUsers;
954       } GROUP_SEARCH_FOUND, *LPGROUP_SEARCH_FOUND;
955
956    LPHASHLIST pListGroups = New (HASHLIST);
957    LPHASHLISTKEY pListKeyAsid = pListGroups->CreateKey ("ASID", Key_Asid_Compare, Key_Asid_HashObject, Key_Asid_HashData);
958
959    // Search through the appropriate groups for each user in the list
960    //
961    for (size_t iUser = 0; iUser < lpp->pUserList->cEntries; ++iUser)
962       {
963       LPASIDLIST pGroups = NULL;
964       ULONG status;
965
966       if (lpp->fMembership)
967          {
968          if (!asc_GroupMembershipGet (g.idClient, g.idCell, lpp->pUserList->aEntries[ iUser ].idObject, &pGroups, &status))
969             continue;
970          }
971       else // (!lpp->fMembership)
972          {
973          if (!asc_GroupOwnershipGet (g.idClient, g.idCell, lpp->pUserList->aEntries[ iUser ].idObject, &pGroups, &status))
974             continue;
975          }
976
977       if (pGroups)
978          {
979          // For each group we found, make sure the group is in the big
980          // list we'll be returning. Use the {lParam} field of the
981          // list's entry as a counter, to remember how many users have
982          // this group
983          //
984          for (size_t iGroup = 0; iGroup < pGroups->cEntries; ++iGroup)
985             {
986             // Is it in the list already? If not, add it.
987             //
988             LPGROUP_SEARCH_FOUND pFind;
989             if ((pFind = (LPGROUP_SEARCH_FOUND)pListKeyAsid->GetFirstObject (&pGroups->aEntries[ iGroup ].idObject)) != NULL)
990                {
991                pFind->cUsers ++;
992                }
993             else
994                {
995                pFind = New (GROUP_SEARCH_FOUND);
996                pFind->idGroup = pGroups->aEntries[ iGroup ].idObject;
997                pFind->cUsers = 1;
998                pListGroups->Add (pFind);
999                }
1000             }
1001
1002          asc_AsidListFree (&pGroups);
1003          }
1004       }
1005
1006    // Now that we have a list of groups that match our search criteria,
1007    // stick it in an ASID list. The lParam field for each ASID will be set
1008    // to 1 if all users have that group, or 0 if only some have it.
1009    //
1010    if (!asc_AsidListCreate (&TASKDATA(ptp)->pAsidList))
1011       {
1012       ptp->rc = FALSE;
1013       ptp->status = ERROR_NOT_ENOUGH_MEMORY;
1014       }
1015
1016    if (ptp->rc)
1017       {
1018       for (LPENUM pEnum = pListGroups->FindFirst(); pEnum; pEnum = pEnum->FindNext())
1019          {
1020          LPGROUP_SEARCH_FOUND pFind = (LPGROUP_SEARCH_FOUND)( pEnum->GetObject() );
1021
1022          asc_AsidListAddEntry (&TASKDATA(ptp)->pAsidList, pFind->idGroup, (LPARAM)( (pFind->cUsers == lpp->pUserList->cEntries) ? 1 : 0 ));
1023
1024          pListGroups->Remove (pFind);
1025          Delete (pFind);
1026          }
1027
1028       TASKDATA(ptp)->fMembership = lpp->fMembership;
1029       }
1030
1031    // Now that we have an ASID list full of groups to return, make sure we
1032    // have rudimentary properties for all those groups.
1033    //
1034    if (ptp->rc)
1035       {
1036       LPASIDLIST pList;
1037       asc_AsidListCopy (&pList, &TASKDATA(ptp)->pAsidList);
1038
1039       LPASOBJPROPLIST pPropList = NULL;
1040       if (!asc_ObjectPropertiesGetMultiple (g.idClient, GET_RUDIMENTARY_DATA, g.idCell, pList, &pPropList, &ptp->status))
1041          ptp->rc = FALSE;
1042       if (pPropList)
1043          asc_ObjPropListFree (&pPropList);
1044
1045       asc_AsidListFree (&pList);
1046       }
1047
1048    if (pListGroups)
1049       Delete (pListGroups);
1050    asc_AsidListFree (&lpp->pUserList);
1051    Delete (lpp);
1052    ptp->lpUser = 0; // we freed this; don't let the caller use it again
1053 }
1054
1055
1056 void Task_Group_Members_Get (LPTASKPACKET ptp)
1057 {
1058    LPASIDLIST pGroups = (LPASIDLIST)( ptp->lpUser );
1059
1060    // Prepare an intermediate place for us to put the results of our search.
1061    // We'll be doing lots of work in this intermediate list, so it'll be
1062    // implemented as a hashlist with a key over the objects' ASIDs.
1063    //
1064    typedef struct
1065       {
1066       ASID idUser;
1067       size_t cGroups;
1068       } GROUP_MEMBER_FOUND, *LPGROUP_MEMBER_FOUND;
1069
1070    LPHASHLIST pListUsers = New (HASHLIST);
1071    LPHASHLISTKEY pListKeyAsid = pListUsers->CreateKey ("ASID", Key_Asid_Compare, Key_Asid_HashObject, Key_Asid_HashData);
1072
1073    // For each group in the list, find all of that group's members
1074    //
1075    for (size_t iGroup = 0; iGroup < pGroups->cEntries; ++iGroup)
1076       {
1077       LPASIDLIST pMembers = NULL;
1078       ULONG status;
1079
1080       if (!asc_GroupMembersGet (g.idClient, g.idCell, pGroups->aEntries[ iGroup ].idObject, &pMembers, &status))
1081          continue;
1082
1083       if (pMembers)
1084          {
1085          // For each member we found, make sure the member is in the big
1086          // list we'll be returning. Use the {lParam} field of the
1087          // list's entry as a counter, to remember how many groups have
1088          // this member.
1089          //
1090          for (size_t iMember = 0; iMember < pMembers->cEntries; ++iMember)
1091             {
1092             // Is it in the list already? If not, add it.
1093             //
1094             LPGROUP_MEMBER_FOUND pFind;
1095             if ((pFind = (LPGROUP_MEMBER_FOUND)pListKeyAsid->GetFirstObject (&pMembers->aEntries[ iMember ].idObject)) != NULL)
1096                {
1097                pFind->cGroups ++;
1098                }
1099             else
1100                {
1101                pFind = New (GROUP_MEMBER_FOUND);
1102                pFind->idUser = pMembers->aEntries[ iMember ].idObject;
1103                pFind->cGroups = 1;
1104                pListUsers->Add (pFind);
1105                }
1106             }
1107
1108          asc_AsidListFree (&pMembers);
1109          }
1110       }
1111
1112    // Now that we have a list of users that match our search criteria,
1113    // stick it in an ASID list. The lParam field for each ASID will be set
1114    // to 1 if all groups have that member, or 0 if only some have it.
1115    //
1116    if (!asc_AsidListCreate (&TASKDATA(ptp)->pAsidList))
1117       {
1118       ptp->rc = FALSE;
1119       ptp->status = ERROR_NOT_ENOUGH_MEMORY;
1120       }
1121
1122    if (ptp->rc)
1123       {
1124       for (LPENUM pEnum = pListUsers->FindFirst(); pEnum; pEnum = pEnum->FindNext())
1125          {
1126          LPGROUP_MEMBER_FOUND pFind = (LPGROUP_MEMBER_FOUND)( pEnum->GetObject() );
1127
1128          asc_AsidListAddEntry (&TASKDATA(ptp)->pAsidList, pFind->idUser, (LPARAM)( (pFind->cGroups == pGroups->cEntries) ? 1 : 0 ));
1129
1130          pListUsers->Remove (pFind);
1131          Delete (pFind);
1132          }
1133       }
1134
1135    // Now that we have an ASID list full of users to return, make sure we
1136    // have rudimentary properties for all those users.
1137    //
1138    if (ptp->rc)
1139       {
1140       LPASIDLIST pList;
1141       asc_AsidListCopy (&pList, &TASKDATA(ptp)->pAsidList);
1142
1143       LPASOBJPROPLIST pPropList = NULL;
1144       if (!asc_ObjectPropertiesGetMultiple (g.idClient, GET_RUDIMENTARY_DATA, g.idCell, pList, &pPropList, &ptp->status))
1145          ptp->rc = FALSE;
1146       if (pPropList)
1147          asc_ObjPropListFree (&pPropList);
1148
1149       asc_AsidListFree (&pList);
1150       }
1151
1152    if (pListUsers)
1153       Delete (pListUsers);
1154    asc_AsidListFree (&pGroups);
1155    ptp->lpUser = 0; // we freed this; don't let the caller use it again
1156 }
1157
1158
1159 void Task_Group_Members_Set (LPTASKPACKET ptp)
1160 {
1161    LPGROUP_MEMBERS_SET_PARAMS lpp = (LPGROUP_MEMBERS_SET_PARAMS)( ptp->lpUser );
1162
1163    ptp->rc = Task_Group_Members_Set_Do (lpp, &ptp->status);
1164
1165    asc_AsidListFree (&lpp->pGroups);
1166    asc_AsidListFree (&lpp->pMembers);
1167    Delete (lpp);
1168    ptp->lpUser = 0; // we freed this; don't let the caller use it again
1169 }
1170
1171
1172 BOOL Task_Group_Members_Set_Do (LPGROUP_MEMBERS_SET_PARAMS lpp, ULONG *pStatus)
1173 {
1174    BOOL rc = TRUE;
1175
1176    // Maintain a structure describing any errors we encounter, so we can give
1177    // a reasonable error dialog if need be.
1178    //
1179    LPERRORDATA ped = ED_Create (IDS_ERROR_CANT_SET_MEMBERS, IDS_ERROR_CANT_SET_MEMBERS_MULTIPLE);
1180
1181    // We'll need the supplied member-list in a hashlist, so we can quickly
1182    // test it to see if a particular member should remain in a group.
1183    //
1184    LPHASHLIST pMembersAllow = New (HASHLIST);
1185    for (size_t iMember = 0; iMember < lpp->pMembers->cEntries; ++iMember)
1186       pMembersAllow->AddUnique ((PVOID)(lpp->pMembers->aEntries[ iMember ].idObject));
1187
1188    // We'll have to do this next bit for each group in the supplied group-list
1189    //
1190    for (size_t iGroup = 0; iGroup < lpp->pGroups->cEntries; ++iGroup)
1191       {
1192       ULONG status;
1193
1194       // Obtain the current list of members for this group
1195       //
1196       LPASIDLIST pMembersOld = NULL;
1197       if (!asc_GroupMembersGet (g.idClient, g.idCell, lpp->pGroups->aEntries[ iGroup ].idObject, &pMembersOld, &status))
1198          {
1199          ED_RegisterStatus (ped, lpp->pGroups->aEntries[ iGroup ].idObject, FALSE, status);
1200          continue;
1201          }
1202       if (!pMembersOld)
1203          continue;
1204
1205       // Test each member in that current list to see if it's also on our
1206       // pMembersAllow list. If not, remove it.
1207       //
1208       for (iMember = 0; iMember < pMembersOld->cEntries; ++iMember)
1209          {
1210          if (pMembersAllow->fIsInList ((PVOID)(pMembersOld->aEntries[iMember].idObject)))
1211             continue;
1212
1213          if (!asc_GroupMemberRemove (g.idClient, g.idCell, lpp->pGroups->aEntries[iGroup].idObject, pMembersOld->aEntries[iMember].idObject, &status))
1214             ED_RegisterStatus (ped, lpp->pGroups->aEntries[ iGroup ].idObject, FALSE, status);
1215          }
1216
1217       // Now the more complex part: see if there are any members in the
1218       // supplied member-list which are marked as mandatory, but which
1219       // aren't in our pMembersOld list. We'll need to put the latter in a
1220       // hashlist for this...
1221       //
1222       LPHASHLIST pMembersOldList = New (HASHLIST);
1223       for (iMember = 0; iMember < pMembersOld->cEntries; ++iMember)
1224          pMembersOldList->AddUnique ((PVOID)(pMembersOld->aEntries[ iMember ].idObject));
1225
1226       for (iMember = 0; iMember < lpp->pMembers->cEntries; ++iMember)
1227          {
1228          if (!lpp->pMembers->aEntries[ iMember ].lParam)
1229             continue; // member not mandatory
1230          if (pMembersOldList->fIsInList ((PVOID)(lpp->pMembers->aEntries[ iMember ].idObject)))
1231             continue; // already a member
1232
1233          if (!asc_GroupMemberAdd (g.idClient, g.idCell, lpp->pGroups->aEntries[iGroup].idObject, lpp->pMembers->aEntries[iMember].idObject, &status))
1234             ED_RegisterStatus (ped, lpp->pGroups->aEntries[ iGroup ].idObject, FALSE, status);
1235          }
1236
1237       Delete (pMembersOldList);
1238
1239       asc_AsidListFree (&pMembersOld);
1240       }
1241
1242    // If there were any errors, report them.
1243    //
1244    if ((*pStatus = ED_GetFinalStatus(ped)) != 0)
1245       {
1246       rc = FALSE;
1247       ED_ShowErrorDialog(ped);
1248       }
1249    ED_Free(ped);
1250
1251    // Done; clean up
1252    //
1253    Delete (pMembersAllow);
1254    return rc;
1255 }
1256
1257
1258 void Task_Group_Enum (LPTASKPACKET ptp)
1259 {
1260    LPCTSTR pszPattern = (LPCTSTR)( ptp->lpUser );
1261
1262    TCHAR szRegExp[ cchNAME ];
1263    TranslateRegExp (szRegExp, pszPattern);
1264    if ((ptp->rc = asc_ObjectFindMultiple (g.idClient, g.idCell, TYPE_GROUP, szRegExp, NULL, &TASKDATA(ptp)->pAsidList, &ptp->status)) == TRUE)
1265       {
1266       LPASOBJPROPLIST pPropList = NULL;
1267
1268       ptp->rc = asc_ObjectPropertiesGetMultiple (g.idClient, GET_RUDIMENTARY_DATA, g.idCell, TASKDATA(ptp)->pAsidList, &pPropList, &ptp->status);
1269
1270       if (pPropList)
1271          asc_ObjPropListFree (&pPropList);
1272       }
1273
1274    FreeString (pszPattern);
1275    ptp->lpUser = 0; // we freed this; don't let the caller use it again
1276 }
1277
1278
1279 void Task_Group_Rename (LPTASKPACKET ptp)
1280 {
1281    LPGROUP_RENAME_PARAMS lpp = (LPGROUP_RENAME_PARAMS)( ptp->lpUser );
1282
1283    if ((ptp->rc = asc_GroupRename (g.idClient, g.idCell, lpp->idGroup, lpp->szNewName, &ptp->status)) != FALSE)
1284       {
1285       Display_RefreshView_Fast();
1286       }
1287
1288    if (!ptp->rc && !IsWindow (ptp->hReply))
1289       {
1290       TCHAR szOldName[ cchNAME ];
1291       asc_ObjectNameGet_Fast (g.idClient, g.idCell, lpp->idGroup, szOldName);
1292       ErrorDialog (ptp->status, IDS_ERROR_CANT_RENAME_GROUP, TEXT("%s%s"), szOldName, lpp->szNewName);
1293       }
1294
1295    Delete (lpp);
1296    ptp->lpUser = 0; // we freed this; don't let the caller use it again
1297 }
1298
1299
1300 void Task_Group_Owned_Get (LPTASKPACKET ptp)
1301 {
1302    ASID idGroup = (ASID)( ptp->lpUser );
1303
1304    ptp->rc = asc_GroupOwnershipGet (g.idClient, g.idCell, idGroup, &TASKDATA(ptp)->pAsidList, &ptp->status);
1305
1306    // Modify the ASID list to have lParams of 1. (This indicates that all
1307    // our supplied groups own this thing; silly but consistent with the
1308    // other such interfaces.)
1309    //
1310    if (TASKDATA(ptp)->pAsidList)
1311       {
1312       for (size_t ii = 0; ii < TASKDATA(ptp)->pAsidList->cEntries; ++ii)
1313          TASKDATA(ptp)->pAsidList->aEntries[ ii ].lParam = 1;
1314       }
1315
1316    // Now that we have an ASID list full of groups to return, make sure we
1317    // have rudimentary properties for all those groups.
1318    //
1319    if (ptp->rc)
1320       {
1321       LPASIDLIST pList;
1322       asc_AsidListCopy (&pList, &TASKDATA(ptp)->pAsidList);
1323
1324       LPASOBJPROPLIST pPropList = NULL;
1325       if (!asc_ObjectPropertiesGetMultiple (g.idClient, GET_RUDIMENTARY_DATA, g.idCell, pList, &pPropList, &ptp->status))
1326          ptp->rc = FALSE;
1327       if (pPropList)
1328          asc_ObjPropListFree (&pPropList);
1329
1330       asc_AsidListFree (&pList);
1331       }
1332 }
1333
1334
1335 void Task_Group_Owned_Set (LPTASKPACKET ptp)
1336 {
1337    LPGROUP_OWNED_SET_PARAMS lpp = (LPGROUP_OWNED_SET_PARAMS)( ptp->lpUser );
1338
1339    ptp->rc = Task_Group_Owned_Set_Do (lpp, &ptp->status);
1340
1341    asc_AsidListFree (&lpp->pOwnedGroups);
1342    Delete (lpp);
1343    ptp->lpUser = 0; // we freed this; don't let the caller use it again
1344 }
1345
1346
1347 BOOL Task_Group_Owned_Set_Do (LPGROUP_OWNED_SET_PARAMS lpp, ULONG *pStatus)
1348 {
1349    BOOL rc = TRUE;
1350
1351    // Maintain a structure describing any errors we encounter, so we can give
1352    // a reasonable error dialog if need be.
1353    //
1354    LPERRORDATA ped = ED_Create (IDS_ERROR_CANT_CHANGE_OWNER, IDS_ERROR_CANT_CHANGE_OWNER_MULTIPLE);
1355
1356    // We'll need the supplied groups-to-own list in a hashlist, so we can
1357    // quickly test it for inclusion of a particular group.
1358    //
1359    LPHASHLIST pGroupsAllow = New (HASHLIST);
1360    for (size_t iGroup = 0; iGroup < lpp->pOwnedGroups->cEntries; ++iGroup)
1361       pGroupsAllow->AddUnique ((PVOID)(lpp->pOwnedGroups->aEntries[ iGroup ].idObject));
1362
1363    // Obtain the current list-of-groups-owned for this group
1364    //
1365    LPASIDLIST pGroupsOld = NULL;
1366    if ((rc = asc_GroupOwnershipGet (g.idClient, g.idCell, lpp->idGroup, &pGroupsOld, pStatus)) == FALSE)
1367       pGroupsOld = NULL;
1368
1369    if (!pGroupsOld)
1370       {
1371       for (size_t ii = 0; ii < lpp->pOwnedGroups->cEntries; ++ii)
1372          ED_RegisterStatus (ped, lpp->pOwnedGroups->aEntries[ii].idObject, FALSE, *pStatus);
1373       }
1374    else
1375       {
1376       // Test each group in that current list to see if it's also on our
1377       // pGroupsAllow list. If not, remove it.
1378       //
1379       for (iGroup = 0; iGroup < pGroupsOld->cEntries; ++iGroup)
1380          {
1381          if (pGroupsAllow->fIsInList ((PVOID)(pGroupsOld->aEntries[iGroup].idObject)))
1382             continue;
1383
1384          ULONG status;
1385          ASOBJPROP Properties;
1386          if (!asc_ObjectPropertiesGet (g.idClient, GET_ALL_DATA, g.idCell, pGroupsOld->aEntries[iGroup].idObject, &Properties, &status))
1387             ED_RegisterStatus (ped, pGroupsOld->aEntries[iGroup].idObject, FALSE, status);
1388          else
1389             {
1390             AFSADMSVR_CHANGEGROUP_PARAMS pp;
1391             memset (&pp, 0x00, sizeof(pp));
1392             lstrcpy (pp.szOwner, Properties.szName); // make group self-owned
1393             pp.aaListStatus = Properties.u.GroupProperties.aaListStatus;
1394             pp.aaListGroupsOwned = Properties.u.GroupProperties.aaListGroupsOwned;
1395             pp.aaListMembers = Properties.u.GroupProperties.aaListMembers;
1396             pp.aaAddMember = Properties.u.GroupProperties.aaAddMember;
1397             pp.aaDeleteMember = Properties.u.GroupProperties.aaDeleteMember;
1398
1399             if (!asc_GroupChange (g.idClient, g.idCell, pGroupsOld->aEntries[iGroup].idObject, &pp, &status))
1400                ED_RegisterStatus (ped, pGroupsOld->aEntries[iGroup].idObject, FALSE, status);
1401             }
1402          }
1403
1404       // Now the more complex part: see if there are any groups in the
1405       // supplied group-list which are marked as mandatory, but which
1406       // aren't in our pGroupsOld list. We'll need to put the latter in a
1407       // hashlist for this...
1408       //
1409       LPHASHLIST pGroupsOldList = New (HASHLIST);
1410       for (iGroup = 0; iGroup < pGroupsOld->cEntries; ++iGroup)
1411          pGroupsOldList->AddUnique ((PVOID)(pGroupsOld->aEntries[ iGroup ].idObject));
1412
1413       for (iGroup = 0; iGroup < lpp->pOwnedGroups->cEntries; ++iGroup)
1414          {
1415          if (!lpp->pOwnedGroups->aEntries[ iGroup ].lParam)
1416             continue; // group not mandatory
1417          if (pGroupsOldList->fIsInList ((PVOID)(lpp->pOwnedGroups->aEntries[ iGroup ].idObject)))
1418             continue; // already a member
1419
1420          ULONG status;
1421          ASOBJPROP Properties;
1422          if (!asc_ObjectPropertiesGet (g.idClient, GET_ALL_DATA, g.idCell, lpp->pOwnedGroups->aEntries[iGroup].idObject, &Properties, &status))
1423             ED_RegisterStatus (ped, lpp->pOwnedGroups->aEntries[iGroup].idObject, FALSE, status);
1424          else
1425             {
1426             AFSADMSVR_CHANGEGROUP_PARAMS pp;
1427             memset (&pp, 0x00, sizeof(pp));
1428             pp.aaListStatus = Properties.u.GroupProperties.aaListStatus;
1429             pp.aaListGroupsOwned = Properties.u.GroupProperties.aaListGroupsOwned;
1430             pp.aaListMembers = Properties.u.GroupProperties.aaListMembers;
1431             pp.aaAddMember = Properties.u.GroupProperties.aaAddMember;
1432             pp.aaDeleteMember = Properties.u.GroupProperties.aaDeleteMember;
1433
1434             if (asc_ObjectNameGet_Fast (g.idClient, g.idCell, lpp->idGroup, pp.szOwner, &status))
1435                {
1436                if (!asc_GroupChange (g.idClient, g.idCell, lpp->pOwnedGroups->aEntries[iGroup].idObject, &pp, &status))
1437                   ED_RegisterStatus (ped, lpp->pOwnedGroups->aEntries[iGroup].idObject, FALSE, status);
1438                }
1439             }
1440          }
1441
1442       Delete (pGroupsOldList);
1443       asc_AsidListFree (&pGroupsOld);
1444       }
1445
1446    // If there were any errors, report them.
1447    //
1448    if ((*pStatus = ED_GetFinalStatus(ped)) != 0)
1449       {
1450       rc = FALSE;
1451       ED_ShowErrorDialog(ped);
1452       }
1453    ED_Free(ped);
1454
1455    // Done; clean up
1456    //
1457    Delete (pGroupsAllow);
1458    return rc;
1459 }
1460
1461
1462 void Task_Group_Create (LPTASKPACKET ptp)
1463 {
1464    LPGROUP_CREATE_PARAMS lpp = (LPGROUP_CREATE_PARAMS)(ptp->lpUser);
1465
1466    // If no owner was specified, use our current credentials' ID. If
1467    // we can't get that, we'll make each group self-owned.
1468    //
1469    if (!lpp->szOwner[0])
1470       {
1471       TCHAR szCell[ cchNAME ];
1472       if (!AfsAppLib_CrackCredentials (g.hCreds, szCell, lpp->szOwner))
1473          lpp->szOwner[0] = TEXT('\0');
1474       }
1475
1476    // We may actually have been asked to create more than one group here;
1477    // the {lpp->mszNames} parameter is a multi-string. So everything we
1478    // do, we'll do for each new group-name...
1479    //
1480    for (LPTSTR pszName = lpp->mszNames; pszName && *pszName; pszName += 1+lstrlen(pszName))
1481       {
1482       // First create this new group account
1483       //
1484       ASID idGroup;
1485
1486       AFSADMSVR_CREATEGROUP_PARAMS pp;
1487       memset (&pp, 0x00, sizeof(AFSADMSVR_CREATEGROUP_PARAMS));
1488       pp.idGroup = lpp->idGroup;
1489       lstrcpy (pp.szName, pszName);
1490       lstrcpy (pp.szOwner, lpp->szOwner);
1491       if (!pp.szOwner[0])
1492          lstrcpy (pp.szOwner, pszName);
1493
1494       if ((ptp->rc = asc_GroupCreate (g.idClient, g.idCell, &pp, &idGroup, &ptp->status)) == FALSE)
1495          {
1496          if (!IsWindow (ptp->hReply))
1497             ErrorDialog (ptp->status, IDS_ERROR_CANT_CREATE_GROUP, TEXT("%s"), pszName);
1498          continue;
1499          }
1500
1501       // Then change its properties to be what we want
1502       //
1503       if ((ptp->rc = asc_GroupChange (g.idClient, g.idCell, idGroup, &lpp->Properties, &ptp->status)) == FALSE)
1504          {
1505          if (!IsWindow (ptp->hReply))
1506             ErrorDialog (ptp->status, IDS_ERROR_CANT_CHANGE_GROUP, TEXT("%s"), pszName);
1507          }
1508       if (!ptp->rc)
1509          continue;
1510
1511       // Finally update its lists of groups
1512       //
1513       if (lpp->pMembers)
1514          {
1515          GROUP_MEMBERS_SET_PARAMS pp;
1516          memset (&pp, 0x00, sizeof(GROUP_MEMBERS_SET_PARAMS));
1517          asc_AsidListCreate (&pp.pGroups);
1518          asc_AsidListAddEntry (&pp.pGroups, idGroup, 0);
1519          asc_AsidListCopy (&pp.pMembers, &lpp->pMembers);
1520          ptp->rc = Task_Group_Members_Set_Do (&pp, &ptp->status);
1521          asc_AsidListFree (&pp.pGroups);
1522          asc_AsidListFree (&pp.pMembers);
1523          }
1524       if (lpp->pGroupsOwner)
1525          {
1526          GROUP_OWNED_SET_PARAMS pp;
1527          memset (&pp, 0x00, sizeof(GROUP_OWNED_SET_PARAMS));
1528          pp.idGroup = idGroup;
1529          asc_AsidListCopy (&pp.pOwnedGroups, &lpp->pGroupsOwner);
1530          ptp->rc = Task_Group_Owned_Set_Do (&pp, &ptp->status);
1531          asc_AsidListFree (&pp.pOwnedGroups);
1532          }
1533       }
1534
1535    // And we're done!
1536    //
1537    Display_PopulateList();
1538
1539    if (lpp->pGroupsOwner)
1540       asc_AsidListFree (&lpp->pGroupsOwner);
1541    if (lpp->pMembers)
1542       asc_AsidListFree (&lpp->pMembers);
1543    if (lpp->mszNames)
1544       FreeString (lpp->mszNames);
1545    Delete (lpp);
1546    ptp->lpUser = 0; // we freed this; don't let the caller use it again
1547 }
1548
1549
1550 void Task_Group_Delete (LPTASKPACKET ptp)
1551 {
1552    LPASIDLIST pGroupList = (LPASIDLIST)(ptp->lpUser);
1553
1554    // Maintain a structure describing any errors we encounter, so we can give
1555    // a reasonable error dialog if need be.
1556    //
1557    LPERRORDATA ped = ED_Create (IDS_ERROR_CANT_DELETE_GROUP, IDS_ERROR_CANT_DELETE_GROUP_MULTIPLE);
1558
1559    // Go through and delete these users
1560    //
1561    for (size_t iGroup = 0; iGroup < pGroupList->cEntries; ++iGroup)
1562       {
1563       ULONG status;
1564       if (!asc_GroupDelete (g.idClient, g.idCell, pGroupList->aEntries[iGroup].idObject, &status))
1565          ED_RegisterStatus (ped, pGroupList->aEntries[iGroup].idObject, FALSE, status);
1566       }
1567
1568    // If there were any errors, report them.
1569    //
1570    if (ED_GetFinalStatus(ped) && !IsWindow(ptp->hReply))
1571       ED_ShowErrorDialog(ped);
1572    ED_Free(ped);
1573
1574    // And we're done!
1575    //
1576    Display_PopulateList();
1577
1578    if (pGroupList)
1579       asc_AsidListFree (&pGroupList);
1580    ptp->lpUser = 0; // we freed this; don't let the caller use it again
1581 }
1582
1583
1584 void Task_Cell_Change (LPTASKPACKET ptp)
1585 {
1586    LPCELL_CHANGE_PARAMS lpp = (LPCELL_CHANGE_PARAMS)(ptp->lpUser);
1587
1588    AFSADMSVR_CHANGECELL_PARAMS Change;
1589    memset (&Change, 0x00, sizeof(Change));
1590    Change.idUserMax = (DWORD)(lpp->idUserMax);
1591    Change.idGroupMax = (DWORD)(lpp->idGroupMax);
1592    ptp->rc = asc_CellChange (g.idClient, lpp->idCell, &Change, &ptp->status);
1593
1594    if (!ptp->rc && !IsWindow (ptp->hReply))
1595       {
1596       TCHAR szCell[ cchNAME ];
1597       asc_CellNameGet_Fast (g.idClient, lpp->idCell, szCell);
1598       ErrorDialog (ptp->status, IDS_ERROR_CANT_CHANGE_CELL, TEXT("%s"), szCell);
1599       }
1600
1601    Delete (lpp);
1602    ptp->lpUser = 0; // we freed this; don't let the caller use it again
1603 }
1604
1605
1606 void Task_List_Translate (LPTASKPACKET ptp)
1607 {
1608    LPLIST_TRANSLATE_PARAMS lpp = (LPLIST_TRANSLATE_PARAMS)( ptp->lpUser );
1609    TASKDATA(ptp)->Type = lpp->Type;
1610
1611    // We'll need a hashlist into which to dump our results as we build
1612    // them (we use a hashlist so we can quickly detect and ignore duplicates).
1613    //
1614    LPHASHLIST pList = New (HASHLIST);
1615
1616    // Now split the input string up into a series of names. To do that,
1617    // we'll valid separator characters are; since names can't have whitespace,
1618    // we'll include that.
1619    //
1620    TCHAR szSeparators[ cchRESOURCE ];
1621    if (!GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SLIST, szSeparators, cchRESOURCE))
1622       szSeparators[0] = TEXT(',');
1623    GetString (&szSeparators[1], IDS_SEPARATORS);
1624
1625    if (lpp->pszNames)
1626       {
1627       LPCTSTR pszStart = lpp->pszNames;
1628       while (iswhite(*pszStart) || lstrchr (szSeparators, *pszStart))
1629          ++pszStart;
1630
1631       while (*pszStart)
1632          {
1633          // Find the first non-name character
1634          //
1635          LPCTSTR pszEnd = pszStart;
1636          while (*pszEnd && !iswhite(*pszEnd) && !lstrchr(szSeparators, *pszEnd))
1637             ++pszEnd;
1638
1639          // Copy off this particular name
1640          //
1641          TCHAR szName[ cchNAME ];
1642          lstrcpy (szName, pszStart);
1643          szName[ pszEnd - pszStart ] = TEXT('\0');
1644
1645          // Find the next valid-name character
1646          //
1647          pszStart = pszEnd;
1648          while (iswhite(*pszStart) || lstrchr(szSeparators, *pszStart))
1649             ++pszStart;
1650
1651          // Translate this particular name. We'll also handle wildcards
1652          // here: if we don't get any wildcard characters, treat it as
1653          // a direct lookup; if we do, treat it as a regexp match.
1654          //
1655          if (lstrchr (szName, TEXT('*')) || lstrchr (szName, TEXT('?')) ||
1656              lstrchr (szName, TEXT('^')) || lstrchr (szName, TEXT('!')))
1657             {
1658             TCHAR szRegExp[ cchNAME ];
1659             TranslateRegExp (szRegExp, szName);
1660
1661             LPASIDLIST pAsidList;
1662             if (asc_ObjectFindMultiple (g.idClient, g.idCell, lpp->Type, szRegExp, NULL, &pAsidList, &ptp->status))
1663                {
1664                if (pAsidList)
1665                   {
1666                   for (size_t ii = 0; ii < pAsidList->cEntries; ++ii)
1667                      pList->AddUnique ((PVOID)(pAsidList->aEntries[ii].idObject));
1668                   asc_AsidListFree (&pAsidList);
1669                   }
1670                }
1671             }
1672          else // No wildcards; just look up the name directly
1673             {
1674             ASID idObject;
1675             if (asc_ObjectFind (g.idClient, g.idCell, lpp->Type, szName, &idObject, &ptp->status))
1676                pList->AddUnique ((PVOID)idObject);
1677             }
1678          }
1679       }
1680
1681    // Finally, build an ASIDLIST from our hashlist's contents.
1682    //
1683    if (!asc_AsidListCreate (&TASKDATA(ptp)->pAsidList))
1684       {
1685       ptp->rc = FALSE;
1686       ptp->status = ERROR_NOT_ENOUGH_MEMORY;
1687       }
1688    else
1689       {
1690       for (LPENUM pEnum = pList->FindFirst(); pEnum; pEnum = pEnum->FindNext())
1691          {
1692          ASID idObject = (ASID)(pEnum->GetObject());
1693          asc_AsidListAddEntry (&TASKDATA(ptp)->pAsidList, idObject, 0);
1694          }
1695       }
1696
1697    // Done! Clean up.
1698    //
1699    Delete (pList);
1700    FreeString (lpp->pszNames);
1701    Delete (lpp);
1702    ptp->lpUser = 0; // we freed this; don't let the caller use it again
1703 }
1704
1705
1706 void Task_Object_Listen (LPTASKPACKET ptp)
1707 {
1708    LPOBJECT_LISTEN_PARAMS lpp = (LPOBJECT_LISTEN_PARAMS)( ptp->lpUser );
1709
1710    if (IsWindow(lpp->hNotify) && (lpp->pAsidList))
1711       ptp->rc = asc_ObjectListenMultiple (g.idClient, g.idCell, lpp->pAsidList, lpp->hNotify, &ptp->status);
1712    else
1713       ptp->rc = asc_ObjectListenClear (g.idClient, lpp->hNotify, &ptp->status);
1714
1715    if (lpp->pAsidList)
1716       asc_AsidListFree (&lpp->pAsidList);
1717    Delete (lpp);
1718    ptp->lpUser = 0; // we freed this; don't let the caller use it again
1719 }
1720
1721
1722 void Task_Object_Get (LPTASKPACKET ptp)
1723 {
1724    ASID idObject = (ASID)(ptp->lpUser);
1725    ptp->rc = asc_ObjectPropertiesGet (g.idClient, GET_ALL_DATA, g.idCell, idObject, &TASKDATA(ptp)->Properties, &ptp->status);
1726 }
1727
1728
1729 void Task_Set_Refresh (LPTASKPACKET ptp)
1730 {
1731    if (g.idCell)
1732       {
1733       ptp->rc = asc_CellRefreshRateSet (g.idClient, g.idCell, gr.cminRefreshRate, &ptp->status);
1734       }
1735 }
1736
1737
1738 void Task_Expired_Creds (LPTASKPACKET ptp)
1739 {
1740    if (g.idCell)
1741       {
1742       CheckForExpiredCredentials();
1743       }
1744 }
1745
1746
1747 void WeedAsidList (LPASIDLIST *ppList, BOOL fWantMachines)
1748 {
1749    ULONG status;
1750
1751    // First off, we can't do anything unless we have these guys' names.
1752    //
1753    if (ppList && (*ppList) && (*ppList)->cEntries)
1754       {
1755       LPASOBJPROPLIST pPropList = NULL;
1756       asc_ObjectPropertiesGetMultiple (g.idClient, GET_RUDIMENTARY_DATA, g.idCell, *ppList, &pPropList, &status);
1757       if (pPropList)
1758          asc_ObjPropListFree (&pPropList);
1759       }
1760
1761    for (size_t ii = 0; ppList && (*ppList) && (ii < (*ppList)->cEntries); )
1762       {
1763       TCHAR szName[ cchRESOURCE ];
1764       if (!asc_ObjectNameGet_Fast (g.idClient, g.idCell, (*ppList)->aEntries[ ii ].idObject, szName, &status))
1765          {
1766          ++ii;
1767          continue;
1768          }
1769
1770       if (fIsMachineAccount(szName) == fWantMachines)
1771          ++ii;
1772       else
1773          asc_AsidListRemoveEntryByIndex (ppList, ii);
1774       }
1775 }
1776
1777
1778 void TranslateRegExp (LPTSTR pszTarget, LPCTSTR pszSource)
1779 {
1780    if (pszSource)
1781       {
1782       if (!gr.fWindowsRegexp)
1783          {
1784          lstrcpy (pszTarget, pszSource);
1785          }
1786       else
1787          {
1788          for ( ; *pszSource; pszSource++)
1789             {
1790             switch (*pszSource)
1791                {
1792                case TEXT('['):
1793                case TEXT(']'):
1794                case TEXT('.'):
1795                   *pszTarget++ = TEXT('\\');
1796                   *pszTarget++ = *pszSource;
1797                   break;
1798
1799                case TEXT('?'):
1800                   *pszTarget++ = TEXT('.');
1801                   break;
1802
1803                case TEXT('*'):
1804                   *pszTarget++ = TEXT('.');
1805                   *pszTarget++ = TEXT('*');
1806                   break;
1807
1808                default:
1809                   *pszTarget++ = *pszSource;
1810                   break;
1811                }
1812             }
1813          }
1814       }
1815
1816    *pszTarget++ = TEXT('\0');
1817 }
1818
1819
1820 BOOL PerformRefresh (LPTASKPACKET ptp, ASID idScope, ULONG *pStatus)
1821 {
1822    // Invalidate the admin server's cached information about the specified
1823    // object. Remember that this is recursive hierarchically: if you pass
1824    // in a cell's ID, for instance, information about all users, groups,
1825    // servers, services, partitions and volumes anywhere in that cell will
1826    // be discarded.
1827    //
1828    if (!idScope)
1829       idScope = g.idCell;
1830
1831    if (!asc_ObjectRefresh (g.idClient, g.idCell, idScope, pStatus))
1832       return FALSE;
1833
1834    // The Refresh call above is a misnomer; it's really an Invalidate request,
1835    // in that it only causes the admin server to dump its cached information
1836    // over the specified scope. At this point we need to do something to
1837    // trigger the server to re-query that information, so that it will send
1838    // an ACTION_REFRESH notification (indicating it's doing that requery),
1839    // which we'll pick up on and use as a trigger to refresh our display.
1840    // A convenient way to get the server to do that re-query is to ask it
1841    // to perform some simple search among the users in the cell--we'll ask
1842    // it to find, oh, say, "JoeBobUser", and in order to do that, it will
1843    // have to re-fill its cache.
1844    //
1845    LPASIDLIST pListDummy;
1846    ULONG statusDummy;
1847    (void)asc_ObjectFindMultiple (g.idClient, g.idCell, TYPE_USER, TEXT("JoeBobUser"), NULL, &pListDummy, &statusDummy);
1848    if (pListDummy != NULL)
1849       asc_AsidListFree (&pListDummy);
1850
1851    return TRUE;
1852 }
1853