BOOL SERVER::SetMonitor (BOOL fShouldMonitor, ULONG *pStatus) { BOOL rc = TRUE; ULONG status = 0; if (m_fMonitor != fShouldMonitor) { LPCELL lpCell; if ((lpCell = m_lpiCell->OpenCell (&status)) == NULL) rc = FALSE; else { NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusBegin, GetIdentifier()); if ((m_fMonitor = fShouldMonitor) == FALSE) { FreeAll(); (lpCell->m_nServersUnmonitored)++; } else // (fMonitor == TRUE) { (lpCell->m_nServersUnmonitored)--; Invalidate(); rc = RefreshAll (&status); } NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusEnd, GetIdentifier(), m_lastStatus); lpCell->Close(); } } if (!rc && pStatus) *pStatus = status; return rc; }
PVOID SERVER::OpenVosObject (PVOID *phCell, ULONG *pStatus) { if (!m_hCellVOS) { LPCELL lpCell; if ((lpCell = m_lpiCell->OpenCell (pStatus)) != NULL) { m_hCellVOS = lpCell->GetCellObject (pStatus); lpCell->Close(); } } if (m_hCellVOS && !m_hVOS) { TCHAR szCell[ cchNAME ]; m_lpiCell->GetCellName (szCell); WORKERPACKET wp; wp.wpVosServerOpen.hCell = m_hCellVOS; wp.wpVosServerOpen.pszServer = m_szName; if (Worker_DoTask (wtaskVosServerOpen, &wp, pStatus)) m_hVOS = wp.wpVosServerOpen.hServer; } if (m_hVOS) { if (phCell) *phCell = m_hCellVOS; ++m_cReqVOS; } return m_hVOS; }
DWORD WINAPI AfsAdmSvr_AutoOpen_ThreadProc (PVOID lp) { DWORD dwScope = PtrToUlong(lp); ULONG status; if (!l.fOperational) return 0; // First we'll have to find out which cell to open // TCHAR szCell[ cchNAME ]; if (!CELL::GetDefaultCell (szCell, &status)) { Print (dlERROR, TEXT("CELL::GetDefaultCell failed; error 0x%08lX"), status); } else { // Then try to actually open the cell // Print (dlSTANDARD, TEXT("Auto-opening cell %s; scope=%s"), szCell, (dwScope == (AFSADMSVR_SCOPE_VOLUMES | AFSADMSVR_SCOPE_USERS)) ? TEXT("full") : (dwScope == AFSADMSVR_SCOPE_VOLUMES) ? TEXT("volumes") : TEXT("users")); LPIDENT lpiCell; if ((lpiCell = CELL::OpenCell ((LPTSTR)szCell, &status)) == NULL) { Print (dlERROR, TEXT("Auto-open of cell %s failed; error 0x%08lX"), szCell, status); } else { LPCELL lpCell; if ((lpCell = lpiCell->OpenCell (&status)) == NULL) { Print (dlERROR, TEXT("Auto-open: OpenCell failed; error 0x%08lX"), status); } else { AfsAdmSvr_AddToMinScope (dwScope); if (!lpCell->RefreshAll (&status)) Print (dlERROR, TEXT("Auto-open: RefreshCell failed; error 0x%08lX"), status); else Print (dlSTANDARD, TEXT("Auto-open of cell %s successful"), szCell); lpCell->Close(); // We intentionally do not call CELL::CloseCell() here--as would // ordinarily be necessary to balance our CELL::OpenCell() call // above--because we never want to close our cache for this cell. // The point of calling AutoOpen() up front is to keep an admin // server alive and ready for use on a particular cell--calling // CELL::CloseCell() here negates that purpose. } } } return 0; }
BOOL SERVER::RefreshStatus (BOOL fNotify, ULONG *pStatus) { BOOL rc = TRUE; DWORD status = 0; if (m_fStatusOutOfDate) { m_fStatusOutOfDate = FALSE; if (fNotify) NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusBegin, GetIdentifier()); LPCELL lpCell; if ((lpCell = OpenCell (&status)) == NULL) rc = FALSE; else { PVOID hCell; if ((hCell = lpCell->GetCellObject (&status)) == NULL) rc = FALSE; else { WORKERPACKET wp; wp.wpClientAFSServerGet.hCell = hCell; wp.wpClientAFSServerGet.pszServer = m_szName; if (!Worker_DoTask (wtaskClientAFSServerGet, &wp, &status)) rc = FALSE; else { m_ss.nAddresses = 0; for (size_t iAddr = 0; iAddr < AFS_MAX_SERVER_ADDRESS; ++iAddr) { if (wp.wpClientAFSServerGet.Entry.serverAddress[ iAddr ] == 0) continue; AfsClass_IntToAddress (&m_ss.aAddresses[ m_ss.nAddresses++ ], wp.wpClientAFSServerGet.Entry.serverAddress[ iAddr ]); } lpCell->m_lServers->Update (this); // That update affected a hashlistkey } } lpCell->Close(); } if (fNotify) NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusEnd, GetIdentifier(), ((rc) ? 0 : status)); } if (pStatus && !rc) *pStatus = status; return TRUE; }
SERVER::~SERVER (void) { if (!m_fMonitor) { LPCELL lpCell; if ((lpCell = m_lpiCell->OpenCell()) != NULL) { (lpCell->m_nServersUnmonitored)--; lpCell->Close(); } } if (m_lpiThis) m_lpiThis->m_cRef --; FreeAll(); Delete (m_lAggregates); Delete (m_lServices); }
USER::USER (LPCELL lpCellParent, LPTSTR pszPrincipal, LPTSTR pszInstance) { m_lpiCell = lpCellParent->GetIdentifier(); lstrcpy (m_szPrincipal, pszPrincipal); lstrcpy (m_szInstance, (pszInstance) ? pszInstance : TEXT("")); m_lpiThis = NULL; m_fStatusOutOfDate = TRUE; m_mszOwnerOf = NULL; m_mszMemberOf = NULL; memset(&m_us, 0, sizeof(m_us)); }
// AfsAdmSvr_PushCredentials // ...requests that the specified AFS credentials be used hereafter // when manipulating the specified cell. You should follow this // call with a Refresh request if necessary. // extern "C" int AfsAdmSvr_PushCredentials (UINT_PTR idClient, UINT_PTR hCreds, ASID idCell, ULONG *pStatus) { ULONG status; size_t iOp = AfsAdmSvr_BeginOperation (idClient); Print (dlDETAIL, TEXT("Client 0x%08lX: PushCredentials (hCreds=0x%08lX, idCell=0x%08lX)"), idClient, hCreds, idCell); if (!AfsAdmSvr_fIsValidClient (idClient)) return FALSE_(ERROR_INVALID_PARAMETER,pStatus,iOp); if (GetAsidType (idCell) != itCELL) return FALSE_(ERROR_INVALID_PARAMETER,pStatus,iOp); LPCELL lpCell; if ((lpCell = ((LPIDENT)idCell)->OpenCell (&status)) == NULL) return FALSE_(ERROR_INVALID_PARAMETER,pStatus,iOp); lpCell->SetCurrentCredentials ((PVOID)hCreds); lpCell->Close(); AfsAdmSvr_EndOperation (iOp); return TRUE; }
SERVER::SERVER (LPCELL lpCellParent, LPTSTR pszName) { m_lpiCell = lpCellParent->GetIdentifier(); lstrcpy (m_szName, pszName); m_lpCellBOS = NULL; m_hCellBOS = NULL; m_hBOS = NULL; m_cReqBOS = 0; m_hCellVOS = NULL; m_hVOS = NULL; m_cReqVOS = 0; m_fCanGetAggregates = TRUE; m_fAggregatesOutOfDate = TRUE; m_lAggregates = New (HASHLIST); m_lAggregates->SetCriticalSection (AfsClass_GetCriticalSection()); m_lkAggregateName = m_lAggregates->CreateKey ("Aggregate Name", SERVER::KeyAggregateName_Compare, SERVER::KeyAggregateName_HashObject, SERVER::KeyAggregateName_HashData, cKEYAGGREGATENAME_TABLESIZE); m_lkAggregateID = m_lAggregates->CreateKey ("Aggregate ID", SERVER::KeyAggregateID_Compare, SERVER::KeyAggregateID_HashObject, SERVER::KeyAggregateID_HashData, cKEYAGGREGATEID_TABLESIZE); m_fCanGetServices = TRUE; m_fServicesOutOfDate = TRUE; m_lServices = New (HASHLIST); m_lServices->SetCriticalSection (AfsClass_GetCriticalSection()); m_lkServiceName = m_lServices->CreateKey ("Service Name", SERVER::KeyServiceName_Compare, SERVER::KeyServiceName_HashObject, SERVER::KeyServiceName_HashData, cKEYSERVICENAME_TABLESIZE); m_wGhost = 0; m_lpiThis = NULL; m_fMonitor = TRUE; m_fDelete = FALSE; m_lastStatus = 0; m_fVLDBOutOfDate = FALSE; /* FIXME: added because it was missing */ m_fStatusOutOfDate = TRUE; memset (&m_ss, 0x00, sizeof(SERVERSTATUS)); }
DWORD WINAPI Alert_ScoutProc (LPVOID lp) { // We'll keep working forever... // for (;;) { AfsClass_Enter(); LPCELL lpCell = (g.lpiCell == NULL) ? NULL : g.lpiCell->OpenCell(); if (lpCell != NULL) { // See if our credentials have expired // CheckForExpiredCredentials(); // See if any new servers have arrived, or old servers disappeared. // lpCell->RefreshServerList(); // Check all the out-of-date servers we can find. // HENUM hEnum; for (LPSERVER lpServer = lpCell->ServerFindFirst (&hEnum); lpServer; lpServer = lpCell->ServerFindNext (&hEnum)) { LPIDENT lpiServer = lpServer->GetIdentifier(); LPOBJECTALERTS lpoa; if ( ((lpoa = Alert_GetObjectAlerts (lpiServer)) != NULL) && (lpoa->dwTickNextTest <= GetTickCount()) ) { // Okay! We've found a server that needs to be tested for // alert conditions. Do that now, and when we're done, set // its next query-time to some distance in the future. // if (lpoa->dwTickNextRefresh == 0) { if (lpoa->cTickRefresh != 0) lpoa->dwTickNextRefresh = lpoa->cTickRefresh + GetTickCount(); } else if (lpoa->dwTickNextRefresh <= GetTickCount()) { (void)lpServer->Invalidate(); (void)lpServer->RefreshAll(); lpoa->dwTickNextRefresh = lpoa->cTickRefresh + GetTickCount(); } (void)Alert_Scout_CheckServer (lpServer); } lpServer->Close(); } lpCell->Close(); } AfsClass_Leave(); // Now that we have completed a pass over the servers in this cell, // and now that we're not holding any critical sections on which // other threads would otherwise block, go to sleep for a while. // WaitForSingleObjectEx (heScoutWakeup, 45L * cmsec1SECOND, FALSE); } return 0; }
BOOL SERVER::CanTalkToServer (ULONG *pStatus) { // Ensure the server exists in the cell at all-- // this call just updates the server's IP addresses // etc (information it gets from the database servers) // and doesn't require talking to the server itself. // if (!RefreshStatus (FALSE, pStatus)) return FALSE; // Find a new refsec array element to use... // AfsClass_InitRefreshSections(); EnterCriticalSection (pcsRefSec); int idSection; for (idSection = 0; idSection < (int)cRefSec; ++idSection) { if (!aRefSec[ idSection ].fInUse) break; } if (idSection == (int)cRefSec) { if (!REALLOC (aRefSec, cRefSec, 1+idSection, 4)) { if (pStatus) *pStatus = GetLastError(); LeaveCriticalSection (pcsRefSec); return FALSE; } } aRefSec[ idSection ].fInUse = TRUE; aRefSec[ idSection ].fCanceled = FALSE; aRefSec[ idSection ].lpServer = this; aRefSec[ idSection ].hCell = NULL; LPCELL lpCell; if ((lpCell = OpenCell()) != NULL) { aRefSec[ idSection ].hCell = lpCell->GetCellObject(); lpCell->Close(); } LeaveCriticalSection (pcsRefSec); // Until we find out differently, assume that we won't be // able to query VOS or BOS on this server. // m_fCanGetAggregates = FALSE; m_fCanGetServices = FALSE; m_lastStatus = 0; // Fork a separate thread, on which to quickly try to talk // to the server. // DWORD dwThreadID; HANDLE hThread; if ((hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)CanTalkToServer_ThreadProc, IntToPtr(idSection), 0, &dwThreadID)) == NULL) { EnterCriticalSection (pcsRefSec); aRefSec[ idSection ].fInUse = FALSE; LeaveCriticalSection (pcsRefSec); if (pStatus) *pStatus = GetLastError(); return FALSE; } SetThreadPriority (hThread, THREAD_PRIORITY_BELOW_NORMAL); // Wait for that thread to terminate, or for our // newly-allocated RefSec entry to be marked Canceled. // DWORD dw; for (dw = STILL_ACTIVE; dw == STILL_ACTIVE; ) { EnterCriticalSection (pcsRefSec); GetExitCodeThread (hThread, &dw); if (dw == STILL_ACTIVE) { if ( (aRefSec[ idSection ].fInUse) && (aRefSec[ idSection ].lpServer == this) && (aRefSec[ idSection ].fCanceled) ) { if (m_lastStatus == 0) m_lastStatus = ERROR_CANCELLED; dw = 0; } } LeaveCriticalSection (pcsRefSec); if (dw == STILL_ACTIVE) Sleep(100); // wait another brief instant } // dw == 0 : user canceled operation (thread is still running!) // dw == 1 : thread completed successfully, and set fCanTalkTo* flags. // // Note that the thread will clear aRefSec[idSection].fInUse when it // terminates (so, if dw!=-1, it has already done so). // if (pStatus) *pStatus = m_lastStatus; return (dw == 0) ? FALSE : TRUE; }
BOOL SERVER::RefreshAll (ULONG *pStatus, double dInit, double dFactor) { BOOL rc = TRUE; ULONG status = 0; if (m_fAggregatesOutOfDate || m_fServicesOutOfDate) { if ((++cRefreshAllReq) == 1) { NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllBegin, GetIdentifier(), 0); } double perAGGREGATES = 65.0; // % of time spent finding aggs & sets double perSERVICES = 25.0; // % of time spent finding services double perVLDB = 10.0; // % of time spent finding VLDB info if (cRefreshAllReq >= 2) // being called as part of a cell-wide op? { perAGGREGATES = 80.0; // % of time spent finding aggs & sets perSERVICES = 20.0; // % of time spent finding services perVLDB = 0.0; // we won't query VLDB stuff ourself. } NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusBegin, GetIdentifier()); if (!CanTalkToServer (&status)) // Determines fCanGetAggregates, fCanGetServices { if (m_fMonitor) SetMonitor (FALSE); rc = FALSE; } else { if (!m_fCanGetAggregates) { FreeAggregates(); m_fAggregatesOutOfDate = FALSE; } else { size_t nAggregates = 0; size_t iAggregate = 0; HENUM hEnum; LPAGGREGATE lpAggregate; for (lpAggregate = AggregateFindFirst (&hEnum); lpAggregate; lpAggregate = AggregateFindNext (&hEnum)) { ++nAggregates; lpAggregate->Close(); } if (nAggregates) { for (lpAggregate = AggregateFindFirst (&hEnum); lpAggregate; lpAggregate = AggregateFindNext (&hEnum)) { ULONG perComplete = (ULONG)( ((double)perAGGREGATES / 100.0) * ((double)iAggregate * 100.0 / nAggregates) ); NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllUpdate, lpAggregate->GetIdentifier(), NULL, NULL, NULL, (ULONG)( 100.0 * dInit + dFactor * (double)perComplete ), 0); lpAggregate->RefreshFilesets (TRUE); lpAggregate->Close(); ++iAggregate; } } } if (!m_fCanGetServices) { FreeServices(); m_fServicesOutOfDate = FALSE; } else { size_t nServices = 0; size_t iService = 0; HENUM hEnum; LPSERVICE lpService; for (lpService = ServiceFindFirst (&hEnum); lpService; lpService = ServiceFindNext (&hEnum)) { ++nServices; lpService->Close(); } if (nServices) { for (lpService = ServiceFindFirst (&hEnum); lpService; lpService = ServiceFindNext (&hEnum)) { ULONG perComplete = (ULONG)( (double)perAGGREGATES + ((double)perSERVICES / 100.0) * ((double)iService * 100.0 / nServices) ); NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllUpdate, lpService->GetIdentifier(), NULL, NULL, NULL, (ULONG)( 100.0 * dInit + dFactor * (double)perComplete ), 0); lpService->RefreshStatus (TRUE); lpService->Close(); ++iService; } } } if (cRefreshAllReq == 1) // not being called as part of a cell-wide op? { LPCELL lpCell; if ((lpCell = OpenCell()) != NULL) { lpCell->RefreshVLDB (GetIdentifier(), TRUE, NULL); lpCell->Close(); } } } NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusEnd, GetIdentifier(), m_lastStatus); if ((--cRefreshAllReq) == 0) { NOTIFYCALLBACK::SendNotificationToAll (evtRefreshAllEnd, GetIdentifier(), NULL, NULL, NULL, 100, m_lastStatus); } } if (rc && m_lastStatus) rc = FALSE; if (!rc && pStatus) *pStatus = status; return rc; }
BOOL USER::RefreshStatus (BOOL fNotify, ULONG *pStatus) { BOOL rc = TRUE; DWORD status = 0; DWORD kasStatus = 0; DWORD ptsStatus = 0; if (m_fStatusOutOfDate) { m_fStatusOutOfDate = FALSE; if (fNotify) NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusBegin, GetIdentifier()); memset (&m_us, 0x00, sizeof(m_us)); FreeString (m_mszOwnerOf); m_mszOwnerOf = NULL; FreeString (m_mszMemberOf); m_mszMemberOf = NULL; TCHAR szFullName[ cchNAME ]; AfsClass_GenFullUserName (szFullName, m_szPrincipal, m_szInstance); LPCELL lpCell; if ((lpCell = OpenCell (&status)) == NULL) rc = FALSE; else { PVOID hCell; if ((hCell = lpCell->GetCellObject (&status)) == NULL) rc = FALSE; else { // Try to get KAS information. // WORKERPACKET wpGetKas; wpGetKas.wpKasPrincipalGet.hCell = hCell; wpGetKas.wpKasPrincipalGet.hServer = lpCell->GetKasObject (&kasStatus); wpGetKas.wpKasPrincipalGet.pszPrincipal = m_szPrincipal; wpGetKas.wpKasPrincipalGet.pszInstance = m_szInstance; if (Worker_DoTask (wtaskKasPrincipalGet, &wpGetKas, &kasStatus)) { m_us.fHaveKasInfo = TRUE; TCHAR szLastModPrincipal[ cchNAME ]; TCHAR szLastModInstance[ cchNAME ]; CopyAnsiToString (szLastModPrincipal, wpGetKas.wpKasPrincipalGet.Data.lastModPrincipal.principal); CopyAnsiToString (szLastModInstance, wpGetKas.wpKasPrincipalGet.Data.lastModPrincipal.instance); m_us.KASINFO.fIsAdmin = (wpGetKas.wpKasPrincipalGet.Data.adminSetting == KAS_ADMIN) ? TRUE : FALSE; m_us.KASINFO.fCanGetTickets = (wpGetKas.wpKasPrincipalGet.Data.tgsSetting == TGS) ? TRUE : FALSE; m_us.KASINFO.fEncrypt = (wpGetKas.wpKasPrincipalGet.Data.encSetting == ENCRYPT) ? TRUE : FALSE; m_us.KASINFO.fCanChangePassword = (wpGetKas.wpKasPrincipalGet.Data.cpwSetting == CHANGE_PASSWORD) ? TRUE : FALSE; m_us.KASINFO.fCanReusePasswords = (wpGetKas.wpKasPrincipalGet.Data.rpwSetting == REUSE_PASSWORD) ? TRUE : FALSE; AfsClass_UnixTimeToSystemTime (&m_us.KASINFO.timeExpires, wpGetKas.wpKasPrincipalGet.Data.userExpiration); AfsClass_UnixTimeToSystemTime (&m_us.KASINFO.timeLastPwChange, wpGetKas.wpKasPrincipalGet.Data.lastChangePasswordTime); AfsClass_UnixTimeToSystemTime (&m_us.KASINFO.timeLastMod, wpGetKas.wpKasPrincipalGet.Data.lastModTime); m_us.KASINFO.lpiLastMod = IDENT::FindUser (m_lpiCell, szLastModPrincipal, szLastModInstance); m_us.KASINFO.csecTicketLifetime = wpGetKas.wpKasPrincipalGet.Data.maxTicketLifetime; m_us.KASINFO.keyVersion = wpGetKas.wpKasPrincipalGet.Data.keyVersion; memcpy (&m_us.KASINFO.key.key, &wpGetKas.wpKasPrincipalGet.Data.key.key, ENCRYPTIONKEY_LEN); m_us.KASINFO.dwKeyChecksum = wpGetKas.wpKasPrincipalGet.Data.keyCheckSum; m_us.KASINFO.cdayPwExpire = wpGetKas.wpKasPrincipalGet.Data.daysToPasswordExpire; m_us.KASINFO.cFailLogin = wpGetKas.wpKasPrincipalGet.Data.failLoginCount; m_us.KASINFO.csecFailLoginLock = wpGetKas.wpKasPrincipalGet.Data.lockTime; } // Try to get PTS information. // WORKERPACKET wpGetPts; wpGetPts.wpPtsUserGet.hCell = hCell; wpGetPts.wpPtsUserGet.pszUser = szFullName; if (Worker_DoTask (wtaskPtsUserGet, &wpGetPts, &ptsStatus)) { m_us.fHavePtsInfo = TRUE; m_us.PTSINFO.cgroupCreationQuota = wpGetPts.wpPtsUserGet.Entry.groupCreationQuota; m_us.PTSINFO.cgroupMember = wpGetPts.wpPtsUserGet.Entry.groupMembershipCount; m_us.PTSINFO.uidName = wpGetPts.wpPtsUserGet.Entry.nameUid; m_us.PTSINFO.uidOwner = wpGetPts.wpPtsUserGet.Entry.ownerUid; m_us.PTSINFO.uidCreator = wpGetPts.wpPtsUserGet.Entry.creatorUid; CopyAnsiToString (m_us.PTSINFO.szOwner, wpGetPts.wpPtsUserGet.Entry.owner); CopyAnsiToString (m_us.PTSINFO.szCreator, wpGetPts.wpPtsUserGet.Entry.creator); m_us.PTSINFO.aaListStatus = USERACCESS_TO_ACCOUNTACCESS (wpGetPts.wpPtsUserGet.Entry.listStatus); m_us.PTSINFO.aaGroupsOwned = USERACCESS_TO_ACCOUNTACCESS (wpGetPts.wpPtsUserGet.Entry.listGroupsOwned); m_us.PTSINFO.aaMembership = USERACCESS_TO_ACCOUNTACCESS (wpGetPts.wpPtsUserGet.Entry.listMembership); } // Grab the list of groups to which this user belongs // WORKERPACKET wpBegin; wpBegin.wpPtsUserMemberListBegin.hCell = hCell; wpBegin.wpPtsUserMemberListBegin.pszUser = szFullName; if (Worker_DoTask (wtaskPtsUserMemberListBegin, &wpBegin, &status)) { for (;;) { TCHAR szGroup[ cchNAME ]; WORKERPACKET wpNext; wpNext.wpPtsUserMemberListNext.hEnum = wpBegin.wpPtsUserMemberListBegin.hEnum; wpNext.wpPtsUserMemberListNext.pszGroup = szGroup; if (!Worker_DoTask (wtaskPtsUserMemberListNext, &wpNext)) break; FormatMultiString (&m_mszMemberOf, FALSE, TEXT("%1"), TEXT("%s"), szGroup); } WORKERPACKET wpDone; wpDone.wpPtsUserMemberListDone.hEnum = wpBegin.wpPtsUserMemberListBegin.hEnum; Worker_DoTask (wtaskPtsUserMemberListDone, &wpDone); } // Grab the list of groups which this user owns // wpBegin.wpPtsOwnedGroupListBegin.hCell = hCell; wpBegin.wpPtsOwnedGroupListBegin.pszOwner = szFullName; if (Worker_DoTask (wtaskPtsOwnedGroupListBegin, &wpBegin, &status)) { for (;;) { TCHAR szGroup[ cchNAME ]; WORKERPACKET wpNext; wpNext.wpPtsOwnedGroupListNext.hEnum = wpBegin.wpPtsOwnedGroupListBegin.hEnum; wpNext.wpPtsOwnedGroupListNext.pszGroup = szGroup; if (!Worker_DoTask (wtaskPtsOwnedGroupListNext, &wpNext)) break; FormatMultiString (&m_mszOwnerOf, FALSE, TEXT("%1"), TEXT("%s"), szGroup); } WORKERPACKET wpDone; wpDone.wpPtsOwnedGroupListDone.hEnum = wpBegin.wpPtsOwnedGroupListBegin.hEnum; Worker_DoTask (wtaskPtsOwnedGroupListDone, &wpDone); } } lpCell->Close(); } if (fNotify) NOTIFYCALLBACK::SendNotificationToAll (evtRefreshStatusEnd, GetIdentifier(), ((rc) ? 0 : status)); } if (rc && (!m_us.fHaveKasInfo) && (!status) && kasStatus) { status = kasStatus; rc = FALSE; } if (rc && (!m_us.fHavePtsInfo) && (!status) && ptsStatus) { status = ptsStatus; // not fatal; rc remains TRUE } if (pStatus && !rc) *pStatus = status; return TRUE; }