From 7517895b6f5c7c478954b246b55ca0b013562a09 Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@alchemyviewer.org>
Date: Wed, 15 Nov 2023 22:29:32 -0500
Subject: [PATCH] Fix various crashes and bugs in group code

---
 indra/newview/llgroupmgr.cpp        | 30 ++++++++++++++-----------
 indra/newview/llgroupmgr.h          | 34 ++++++++++++++++++++++++++---
 indra/newview/llpanelgrouproles.cpp | 17 +++++++++++++--
 3 files changed, 63 insertions(+), 18 deletions(-)

diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index 1792af64f97..ca9f210f677 100644
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -250,8 +250,12 @@ BOOL LLGroupMgrGroupData::getRoleData(const LLUUID& role_id, LLRoleData& role_da
 	role_list_t::const_iterator rit = mRoles.find(role_id);
 	if (rit != mRoles.end())
 	{
-		role_data = (*rit).second->getRoleData();
-		return TRUE;
+		auto& role_datap = rit->second;
+		if (role_datap)
+		{
+			role_data = role_datap->getRoleData();
+			return TRUE;
+		}
 	}
 
 	// This role must not exist.
@@ -1451,11 +1455,11 @@ LLGroupMgrGroupData* LLGroupMgr::createGroupData(const LLUUID& id)
 {
 	LLGroupMgrGroupData* group_datap = NULL;
 
-	group_map_t::iterator existing_group = LLGroupMgr::getInstance()->mGroups.find(id);
-	if (existing_group == LLGroupMgr::getInstance()->mGroups.end())
+	group_map_t::iterator existing_group = mGroups.find(id);
+	if (existing_group == mGroups.end())
 	{
 		group_datap = new LLGroupMgrGroupData(id);
-		LLGroupMgr::getInstance()->addGroup(group_datap);
+		addGroup(group_datap);
 	}
 	else
 	{
@@ -1472,8 +1476,8 @@ LLGroupMgrGroupData* LLGroupMgr::createGroupData(const LLUUID& id)
 
 bool LLGroupMgr::hasPendingPropertyRequest(const LLUUID & id)
 {
-    properties_request_map_t::iterator existing_req = LLGroupMgr::getInstance()->mPropRequests.find(id);
-    if (existing_req != LLGroupMgr::getInstance()->mPropRequests.end())
+    properties_request_map_t::iterator existing_req = mPropRequests.find(id);
+    if (existing_req != mPropRequests.end())
     {
         if (gFrameTime - existing_req->second < MIN_GROUP_PROPERTY_REQUEST_FREQ)
         {
@@ -1481,7 +1485,7 @@ bool LLGroupMgr::hasPendingPropertyRequest(const LLUUID & id)
         }
         else
         {
-            LLGroupMgr::getInstance()->mPropRequests.erase(existing_req);
+            mPropRequests.erase(existing_req);
         }
     }
     return false;
@@ -1489,7 +1493,7 @@ bool LLGroupMgr::hasPendingPropertyRequest(const LLUUID & id)
 
 void LLGroupMgr::addPendingPropertyRequest(const LLUUID& id)
 {
-    LLGroupMgr::getInstance()->mPropRequests.insert_or_assign(id, gFrameTime);
+    mPropRequests.insert_or_assign(id, gFrameTime);
 }
 
 void LLGroupMgr::notifyObservers(LLGroupChange gc)
@@ -1579,12 +1583,12 @@ void LLGroupMgr::sendGroupPropertiesRequest(const LLUUID& group_id)
 	// This will happen when we get the reply
 	//LLGroupMgrGroupData* group_datap = createGroupData(group_id);
 	
-    if (LLGroupMgr::getInstance()->hasPendingPropertyRequest(group_id))
+    if (hasPendingPropertyRequest(group_id))
     {
         LL_DEBUGS("GrpMgr") << "LLGroupMgr::sendGroupPropertiesRequest suppressed repeat for " << group_id << LL_ENDL;
         return;
     }
-    LLGroupMgr::getInstance()->addPendingPropertyRequest(group_id);
+    addPendingPropertyRequest(group_id);
 
 	LLMessageSystem* msg = gMessageSystem;
 	msg->newMessageFast(_PREHASH_GroupProfileRequest);
@@ -1926,7 +1930,7 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id,
 				for (LLGroupMemberData::role_list_t::iterator rit = member_data->roleBegin();
 					rit != member_data->roleEnd(); ++rit)
 				{
-					if ((*rit).first.notNull() && (*rit).second != 0)
+					if ((*rit).first.notNull() && (*rit).second != nullptr)
 					{
 						(*rit).second->removeMember(ejected_member_id);
 					}
@@ -2213,7 +2217,7 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content)
 		// Set mMemberDataComplete for correct handling of empty responses. See MAINT-5237
 		group_datap->mMemberDataComplete = true;
 		group_datap->mChanged = TRUE;
-		LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA);
+		notifyObservers(GC_MEMBER_DATA);
 		return;
 	}
 	
diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h
index 2fac45ece7d..4fc56a9b4da 100644
--- a/indra/newview/llgroupmgr.h
+++ b/indra/newview/llgroupmgr.h
@@ -77,7 +77,7 @@ class LLGroupMemberData
 friend class LLGroupMgrGroupData;
 
 public:
-	typedef boost::unordered_flat_map<LLUUID, LLGroupRoleData*> role_list_t;
+	typedef boost::unordered_map<LLUUID,LLGroupRoleData*> role_list_t;
 	
 	LLGroupMemberData(const LLUUID& id, 
 						S32 contribution,
@@ -102,8 +102,6 @@ friend class LLGroupMgrGroupData;
 
 	BOOL isInRole(const LLUUID& role_id) { return (mRolesList.find(role_id) != mRolesList.end()); }
 
-	const role_list_t& getRoles() { return mRolesList; }
-
 	LLUUID	mID;
 	S32		mContribution;
 	U64		mAgentPowers;
@@ -117,6 +115,36 @@ struct LLRoleData
 {
 	LLRoleData() : mRolePowers(0), mChangeType(RC_UPDATE_NONE) { }
 
+	LLRoleData(const LLRoleData& rd) 
+	{
+		*this = rd;
+	}
+
+	LLRoleData(LLRoleData&& rd) 
+	{
+		*this = std::move(rd);
+	}
+
+	LLRoleData& operator=(const LLRoleData& rd)
+	{
+		mRoleName = rd.mRoleName;
+		mRoleTitle = rd.mRoleTitle;
+		mRoleDescription = rd.mRoleDescription;
+		mRolePowers = rd.mRolePowers;
+		mChangeType = rd.mChangeType;
+		return *this;
+	};
+
+	LLRoleData& operator=(LLRoleData&& rd) noexcept
+	{
+		mRoleName = std::move(rd.mRoleName);
+		mRoleTitle = std::move(rd.mRoleTitle);
+		mRoleDescription = std::move(rd.mRoleDescription);
+		mRolePowers = rd.mRolePowers;
+		mChangeType = rd.mChangeType;
+		return *this;
+	};
+
 	std::string mRoleName;
 	std::string mRoleTitle;
 	std::string mRoleDescription;
diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp
index 3cef4c00102..c3721ddfa0c 100644
--- a/indra/newview/llpanelgrouproles.cpp
+++ b/indra/newview/llpanelgrouproles.cpp
@@ -423,6 +423,10 @@ void LLPanelGroupRoles::setGroupID(const LLUUID& id)
 	if ( button )
 		button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE));
 
+	button = getChild<LLButton>("export_list");
+	if (button)
+		button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_VISIBLE_IN_DIR));
+
 	if(mSubTabContainer)
 		mSubTabContainer->selectTab(1);
 	group_roles_tab->mFirstOpen = TRUE;
@@ -1089,7 +1093,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect()
 		else
 		{
 			// This could happen if changes are not synced right on sub-panel change.
-			LL_WARNS() << "No group role data for " << iter->second->getID() << LL_ENDL;
+			LL_WARNS() << "No group role data for " << iter->first << LL_ENDL;
 		}
 	}
 	mAssignedRolesList->setEnabled(TRUE);
@@ -1815,6 +1819,15 @@ void LLPanelGroupMembersSubTab::updateMembers()
 		mMembersList->deleteAllItems();
 	}
 
+	for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it)
+	{
+		if (it->second.connected())
+		{
+			it->second.disconnect();
+		}
+	}
+	mAvatarNameCacheConnections.clear();
+
 	LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end();
 
 	LLTimer update_time;
@@ -2403,7 +2416,7 @@ void LLPanelGroupRolesSubTab::handleRoleSelect()
 	mSelectedRole = item->getUUID();
 	buildMembersList();
 
-	mCopyRoleButton->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_ROLE_CREATE));
+	mCopyRoleButton->setEnabled((gdatap->mRoles.size() < (U32)MAX_ROLES) && gAgent.hasPowerInGroup(mGroupID, GP_ROLE_CREATE));
 	can_delete = can_delete && gAgent.hasPowerInGroup(mGroupID,
 													  GP_ROLE_DELETE);
 	mDeleteRoleButton->setEnabled(can_delete);
-- 
GitLab