void AfsAdmSvr_EndOperation (size_t iOp)
{
   AfsAdmSvr_Enter();

   if ((iOp != (size_t)-1) && (iOp < l.cOperationsAllocated) && (l.aOperations[ iOp ].fInUse))
      {
      if (l.aOperations[ iOp ].pAction)
         {
         Print (dlOPERATION, TEXT("Ending action 0x%08lX"), l.aOperations[ iOp ].pAction->idAction);
         AfsAdmSvr_PostCallback (cbtACTION, TRUE, l.aOperations[ iOp ].pAction);
         Delete (l.aOperations[ iOp ].pAction);
         }
      memset (&l.aOperations[ iOp ], 0x00, sizeof(l.aOperations[ iOp ]));
      l.cOperations --;
      }

   AfsAdmSvr_TestShutdown();
   AfsAdmSvr_Leave();
}
void AfsAdmSvr_PostCallback (CALLBACKTYPE Type, BOOL fFinished, LPASACTION pAction)
{
   AfsAdmSvr_PostCallback (Type, fFinished, pAction, 0);
}
size_t AfsAdmSvr_BeginOperation (UINT_PTR idClient, LPASACTION pAction)
{
   AfsAdmSvr_Enter();

   ++l.cOperations;

   size_t iOp;
   for (iOp = 0; iOp < l.cOperationsAllocated; ++iOp)
      {
      if (!l.aOperations[ iOp ].fInUse)
         break;
      }
   if (!REALLOC (l.aOperations, l.cOperationsAllocated, 1+iOp, cREALLOC_OPERATIONS))
      {
      AfsAdmSvr_Leave();
      return (size_t)(-1);
      }

   l.aOperations[ iOp ].idClient = idClient;
   l.aOperations[ iOp ].pAction = NULL;
   l.aOperations[ iOp ].fInUse = TRUE;

   if (pAction)
      {
      l.aOperations[ iOp ].pAction = New (ASACTION);
      memcpy (l.aOperations[ iOp ].pAction, pAction, sizeof(ASACTION));
      l.aOperations[ iOp ].pAction->idAction = ++l.idActionLast;
      l.aOperations[ iOp ].pAction->idClient = idClient;
      l.aOperations[ iOp ].pAction->csecActive = 0;

      TCHAR szDesc[256];
      switch (l.aOperations[ iOp ].pAction->Action)
         {
         case ACTION_REFRESH:
            wsprintf (szDesc, TEXT("Refresh (scope=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Refresh.idScope);
            break;
         case ACTION_SCOUT:
            wsprintf (szDesc, TEXT("Scout (scope=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Refresh.idScope);
            break;
         case ACTION_USER_CHANGE:
            wsprintf (szDesc, TEXT("ChangeUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Change.idUser);
            break;
         case ACTION_USER_PW_CHANGE:
            wsprintf (szDesc, TEXT("SetUserPassword (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Pw_Change.idUser);
            break;
         case ACTION_USER_UNLOCK:
            wsprintf (szDesc, TEXT("UnlockUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Unlock.idUser);
            break;
         case ACTION_USER_CREATE:
            wsprintf (szDesc, TEXT("CreateUser (user=%s)"), l.aOperations[ iOp ].pAction->u.User_Create.szUser);
            break;
         case ACTION_USER_DELETE:
            wsprintf (szDesc, TEXT("CreateUser (user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.User_Delete.idUser);
            break;
         case ACTION_GROUP_CHANGE:
            wsprintf (szDesc, TEXT("ChangeGroup (group=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Change.idGroup);
            break;
         case ACTION_GROUP_MEMBER_ADD:
            wsprintf (szDesc, TEXT("AddGroupMember (group=0x%08lX, user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Member_Add.idGroup, l.aOperations[ iOp ].pAction->u.Group_Member_Add.idUser);
            break;
         case ACTION_GROUP_MEMBER_REMOVE:
            wsprintf (szDesc, TEXT("RemoveGroupMember (group=0x%08lX, user=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Member_Remove.idGroup, l.aOperations[ iOp ].pAction->u.Group_Member_Remove.idUser);
            break;
         case ACTION_GROUP_RENAME:
            wsprintf (szDesc, TEXT("RenameGroup (group=0x%08lX, new name=%s)"), l.aOperations[ iOp ].pAction->u.Group_Rename.idGroup, l.aOperations[ iOp ].pAction->u.Group_Rename.szNewName);
            break;
         case ACTION_GROUP_DELETE:
            wsprintf (szDesc, TEXT("CreateGroup (group=0x%08lX)"), l.aOperations[ iOp ].pAction->u.Group_Delete.idGroup);
            break;
         case ACTION_CELL_CHANGE:
            wsprintf (szDesc, TEXT("ChangeCell (cell=0x%08lX)"), l.aOperations[ iOp ].pAction->idCell);
            break;
         default:
            wsprintf (szDesc, TEXT("Unknown Action (#%lu)"), l.aOperations[ iOp ].pAction->Action);
            break;
         }
      Print (dlOPERATION, TEXT("Starting action 0x%08lX: %s"), l.aOperations[ iOp ].pAction->idAction, szDesc);

      AfsAdmSvr_PostCallback (cbtACTION, FALSE, l.aOperations[ iOp ].pAction);
      }

   l.aOperations[ iOp ].dwTickStart = GetTickCount();
   AfsAdmSvr_Leave();
   return iOp;
}