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