From fda5eb9cccdef09e99edc2d280295f17149560b3 Mon Sep 17 00:00:00 2001
From: Kitty Barnett <develop@catznip.com>
Date: Sat, 9 Jul 2016 22:08:23 +0200
Subject: [PATCH] Code cleanup: better handling of group joins when @setgroup
 restricted   -> bundle all permission checks in a predictable single function
 (see RlvActions::canChangeActiveGroup)   -> properly handle the case where a
 user is ejected from a group   -> provide feedback to the user after we force
 the previous group back when joining a new group

--HG--
branch : RLVa
---
 indra/newview/llgroupactions.cpp              |  8 ++--
 indra/newview/llgrouplist.cpp                 | 14 +++---
 indra/newview/rlvactions.cpp                  |  7 +++
 indra/newview/rlvactions.h                    |  5 ++
 indra/newview/rlvdefines.h                    |  1 +
 indra/newview/rlvhandler.cpp                  | 48 ++++++++++++++-----
 .../skins/default/xui/en/rlva_strings.xml     |  5 ++
 7 files changed, 64 insertions(+), 24 deletions(-)

diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index aaa5952ef7..73bb8543ee 100755
--- a/indra/newview/llgroupactions.cpp
+++ b/indra/newview/llgroupactions.cpp
@@ -294,8 +294,8 @@ bool LLGroupActions::onJoinGroup(const LLSD& notification, const LLSD& response)
 void LLGroupActions::leave(const LLUUID& group_id)
 {
 //	if (group_id.isNull())
-// [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.4.1a) | Added: RLVa-1.3.0f
-	if ( (group_id.isNull()) || ((gAgent.getGroupID() == group_id) && (gRlvHandler.hasBehaviour(RLV_BHVR_SETGROUP))) )
+// [RLVa:KB] - Checked: RLVa-1.3.0
+	if ( (group_id.isNull()) || ((gAgent.getGroupID() == group_id) && (!RlvActions::canChangeActiveGroup())) )
 // [/RLVa:KB]
 	{
 		return;
@@ -348,8 +348,8 @@ void LLGroupActions::processLeaveGroupDataResponse(const LLUUID group_id)
 // static
 void LLGroupActions::activate(const LLUUID& group_id)
 {
-// [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.4.1a) | Added: RLVa-1.3.0f
-	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SETGROUP)) && (gRlvHandler.getAgentGroup() != group_id) )
+// [RLVa:KB] - Checked: RLVa-1.3.0
+	if ( (!RlvActions::canChangeActiveGroup()) && (gRlvHandler.getAgentGroup() != group_id) )
 	{
 		return;
 	}
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index 062154f03c..339414e5cb 100755
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -43,8 +43,8 @@
 #include "llviewercontrol.h"	// for gSavedSettings
 #include "llviewermenu.h"		// for gMenuHolder
 #include "llvoiceclient.h"
-// [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.3.0f) | Added: RLVa-1.3.0f
-#include "rlvhandler.h"
+// [RLVa:KB] - Checked: RLVa-2.0.3
+#include "rlvactions.h"
 // [/RLVa:KB]
 
 static LLDefaultChildRegistry::Register<LLGroupList> r("group_list");
@@ -284,14 +284,14 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata)
 	bool real_group_selected = selected_group_id.notNull(); // a "real" (not "none") group is selected
 
 	// each group including "none" can be activated
-//	if (userdata.asString() == "activate")
-//		return gAgent.getGroupID() != selected_group_id;
-// [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.4.1a) | Added: RLVa-1.3.0f
+// [RLVa:KB] - Checked: RLVa-1.3.0
 	if (userdata.asString() == "activate")
-		return (gAgent.getGroupID() != selected_group_id) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SETGROUP));
+		return (gAgent.getGroupID() != selected_group_id) && (RlvActions::canChangeActiveGroup());
 	else if (userdata.asString() == "leave")
-		return (real_group_selected) && ((gAgent.getGroupID() != selected_group_id) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SETGROUP)));
+		return (real_group_selected) && ((gAgent.getGroupID() != selected_group_id) || (RlvActions::canChangeActiveGroup()));
 // [/RLVa:KB]
+//	if (userdata.asString() == "activate")
+//		return gAgent.getGroupID() != selected_group_id;
 
 	if (userdata.asString() == "call")
 	  return real_group_selected && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp
index 1def8205fb..b98de3cbf2 100644
--- a/indra/newview/rlvactions.cpp
+++ b/indra/newview/rlvactions.cpp
@@ -121,6 +121,13 @@ bool RlvActions::getCameraFOVLimits(F32& nFOVMin, F32& nFOVMax)
 
 bool RlvActions::s_BlockNamesContexts[SNC_COUNT] = { 0 };
 
+bool RlvActions::canChangeActiveGroup(const LLUUID& idRlvObject)
+{
+	// User can change their active group if:
+	//   - not specifically restricted (by another object that the one specified) from changing their active group
+	return (idRlvObject.isNull()) ? !gRlvHandler.hasBehaviour(RLV_BHVR_SETGROUP) : !gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETGROUP, idRlvObject);
+}
+
 // Little helper function to check the IM exclusion range for @recvim, @sendim and @startim (returns: min_dist <= (pos user - pos target) <= max_dist)
 static bool rlvCheckAvatarIMDistance(const LLUUID& idAvatar, ERlvBehaviourModifier eModDistMin, ERlvBehaviourModifier eModDistMax)
 {
diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h
index e11066e25a..14f0c3b85b 100644
--- a/indra/newview/rlvactions.h
+++ b/indra/newview/rlvactions.h
@@ -74,6 +74,11 @@ public:
 	// Communication/Avatar interaction
 	// ================================
 public:
+	/*
+	 * Returns true if the user is allowed to change their currently active group
+	 */
+	static bool canChangeActiveGroup(const LLUUID& idRlvObject = LLUUID::null);
+
 	/*
 	 * Returns true if the user is allowed to receive IMs from the specified sender (can be an avatar or a group)
 	 */
diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h
index 84a921b3fb..3011a41325 100644
--- a/indra/newview/rlvdefines.h
+++ b/indra/newview/rlvdefines.h
@@ -370,6 +370,7 @@ enum ERlvAttachGroupType
 
 #define RLV_STRING_BLOCKED_AUTOPILOT		"blocked_autopilot"
 #define RLV_STRING_BLOCKED_GENERIC			"blocked_generic"
+#define RLV_STRING_BLOCKED_GROUPCHANGE		"blocked_groupchange"
 #define RLV_STRING_BLOCKED_PERMATTACH		"blocked_permattach"
 #define RLV_STRING_BLOCKED_PERMTELEPORT		"blocked_permteleport"
 #define RLV_STRING_BLOCKED_RECVIM			"blocked_recvim"
diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp
index f4033a2380..6ad9e4c848 100644
--- a/indra/newview/rlvhandler.cpp
+++ b/indra/newview/rlvhandler.cpp
@@ -472,21 +472,43 @@ ERlvCmdRet RlvHandler::processClearCommand(const RlvCommand& rlvCmd)
 // Externally invoked event handlers
 //
 
-// Checked: 2011-05-22 (RLVa-1.4.1a) | Added: RLVa-1.3.1b
 bool RlvHandler::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& sdUserdata)
 {
+	// NOTE: we'll fire once for every group the user belongs to so we need to manually keep track of pending changes
+	static LLUUID s_idLastAgentGroup = LLUUID::null;
+	static bool s_fGroupChanging = false;
+
+	if (s_idLastAgentGroup != gAgent.getGroupID())
+	{
+		s_idLastAgentGroup = gAgent.getGroupID();
+		s_fGroupChanging = false;
+	}
+
 	// If the user managed to change their active group (= newly joined or created group) we need to reactivate the previous one
-	if ( (hasBehaviour(RLV_BHVR_SETGROUP)) && ("new group" == event->desc()) && (m_idAgentGroup != gAgent.getGroupID()) )
-	{
-		// [Copy/paste from LLGroupActions::activate()]
-		LLMessageSystem* msg = gMessageSystem;
-		msg->newMessageFast(_PREHASH_ActivateGroup);
-		msg->nextBlockFast(_PREHASH_AgentData);
-		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-		msg->addUUIDFast(_PREHASH_GroupID, m_idAgentGroup);
-		gAgent.sendReliableMessage();
-		return true;
+	if ( (!RlvActions::canChangeActiveGroup()) && ("new group" == event->desc()) && (m_idAgentGroup != gAgent.getGroupID()) )
+	{
+		// Make sure they still belong to the group
+		if ( (m_idAgentGroup.notNull()) && (!gAgent.isInGroup(m_idAgentGroup)) )
+		{
+			m_idAgentGroup.setNull();
+			s_fGroupChanging = false;
+		}
+
+		if (!s_fGroupChanging)
+		{
+			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_GROUPCHANGE, LLSD().with("GROUP_SLURL", (m_idAgentGroup.notNull()) ? llformat("secondlife:///app/group/%s/about", m_idAgentGroup.asString()) : "(none)"));
+
+			// [Copy/paste from LLGroupActions::activate()]
+			LLMessageSystem* msg = gMessageSystem;
+			msg->newMessageFast(_PREHASH_ActivateGroup);
+			msg->nextBlockFast(_PREHASH_AgentData);
+			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+			msg->addUUIDFast(_PREHASH_GroupID, m_idAgentGroup);
+			gAgent.sendReliableMessage();
+			s_fGroupChanging = true;
+			return true;
+		}
 	}
 	else
 	{
@@ -2384,7 +2406,7 @@ void RlvHandler::onForceWearCallback(const uuid_vec_t& idItems, U32 nFlags) cons
 template<> template<>
 ERlvCmdRet RlvForceHandler<RLV_BHVR_SETGROUP>::onCommand(const RlvCommand& rlvCmd)
 {
-	if (gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETGROUP, rlvCmd.getObjectID()))
+	if (!RlvActions::canChangeActiveGroup(rlvCmd.getObjectID()))
 	{
 		return RLV_RET_FAILED_LOCK;
 	}
diff --git a/indra/newview/skins/default/xui/en/rlva_strings.xml b/indra/newview/skins/default/xui/en/rlva_strings.xml
index 6861f9c465..62651c9a09 100644
--- a/indra/newview/skins/default/xui/en/rlva_strings.xml
+++ b/indra/newview/skins/default/xui/en/rlva_strings.xml
@@ -56,6 +56,11 @@
 			<key>value</key>
 			<string>Unable to perform action due to RLV restrictions</string>
 		</map>
+		<key>blocked_groupchange</key>
+		<map>
+			<key>value</key>
+			<string>Unable to change your active group due to an RLV restriction; switching back to [GROUP_SLURL]</string>
+		</map>
 		<key>blocked_permattach</key>
 		<map>
 			<key>value</key>
-- 
GitLab