diff --git a/.hgpatchinfo/RLVa.dep b/.hgpatchinfo/RLVa.dep
new file mode 100644
index 0000000000000000000000000000000000000000..09b266c2d8d5ba9d7240f692265e30dd5463f58b
--- /dev/null
+++ b/.hgpatchinfo/RLVa.dep
@@ -0,0 +1 @@
+dd7f770961c9455fbd6b7c74c82b7048f9ebef4d
\ No newline at end of file
diff --git a/.hgtags b/.hgtags
index 9139aae9a4ac2ec79d98a995cd93944c6d0d954a..bad12f4d7fbb5c2d7a36bbce76adcd358927b7de 100644
--- a/.hgtags
+++ b/.hgtags
@@ -27,6 +27,7 @@ d2382d374139850efa5bb6adfb229e3e656cfc40 howard-demo
 d40ac9dd949cba6dab1cc386da6a2027690c2519 alpha-5
 d6781e22543acd7e21b967209f3c6e7003d380e3 fork to viewer-2-0
 c6e6324f5be1401f077ad18a4a0f6b46451c2f7b last_sprint
+425f96b1e81e01644bf5e951961e7d1023bffb89 RLVa-1.2.0
 0000000000000000000000000000000000000000 v2start
 0000000000000000000000000000000000000000 2-1rn1
 0000000000000000000000000000000000000000 2-1-beta-2
diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h
index 52b85c7bba132691d43b7022a1e73b44cdd106ab..c64d9a13b3f62565c63b3e4b40488f2f695f3abc 100644
--- a/indra/llcommon/llchat.h
+++ b/indra/llcommon/llchat.h
@@ -81,6 +81,10 @@ public:
 		mChatType(CHAT_TYPE_NORMAL),
 		mAudible(CHAT_AUDIBLE_FULLY),
 		mMuted(FALSE),
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.0.0a
+		mRlvLocFiltered(FALSE),
+		mRlvNamesFiltered(FALSE),
+// [/RLVa:KB]
 		mTime(0.0),
 		mTimeStr(),
 		mPosAgent(),
@@ -98,6 +102,10 @@ public:
 	EChatType		mChatType;
 	EChatAudible	mAudible;
 	BOOL			mMuted;		// pass muted chat to maintain list of chatters
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.0.0a
+	BOOL			mRlvLocFiltered;
+	BOOL			mRlvNamesFiltered;
+// [/RLVa:KB]
 	F64				mTime;		// viewer only, seconds from viewer start
 	std::string		mTimeStr;
 	LLVector3		mPosAgent;
diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp
index ccffe98c9653c3bf3874f712b4a7ac7d3d4044e7..1936bbefe6cbb849cac294392e852d21953b19f4 100644
--- a/indra/llui/llfloaterreg.cpp
+++ b/indra/llui/llfloaterreg.cpp
@@ -45,6 +45,10 @@ std::set<std::string> LLFloaterReg::sAlwaysShowableList;
 
 static LLFloaterRegListener sFloaterRegListener;
 
+// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+LLFloaterReg::validate_signal_t LLFloaterReg::mValidateSignal;
+// [/RLVa:KB]
+
 //*******************************************************
 
 //static
@@ -214,9 +218,12 @@ LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::str
 //static
 LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus) 
 {
-	if( sBlockShowFloaters
-			// see EXT-7090
-			&& sAlwaysShowableList.find(name) == sAlwaysShowableList.end())
+//	if( sBlockShowFloaters
+//			// see EXT-7090
+//			&& sAlwaysShowableList.find(name) == sAlwaysShowableList.end())
+// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+	if ( (sBlockShowFloaters && sAlwaysShowableList.find(name) == sAlwaysShowableList.end()) || (!mValidateSignal(name, key)) )
+// [/RLVa:KB]
 		return 0;//
 	LLFloater* instance = getInstance(name, key); 
 	if (instance) 
diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h
index 94387fb41a5b18e2b065eaf36eddc04c9b0b4a2d..c2c82de70cea11385079e3606132b8e6e40a9827 100644
--- a/indra/llui/llfloaterreg.h
+++ b/indra/llui/llfloaterreg.h
@@ -75,6 +75,15 @@ private:
 	 */
 	static std::set<std::string> sAlwaysShowableList;
 	
+// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+	// Used to determine whether a floater can be shown
+public:
+	typedef boost::signals2::signal<bool(const std::string&, const LLSD&), boost_boolean_combiner> validate_signal_t;
+	static boost::signals2::connection setValidateCallback(const validate_signal_t::slot_type& cb) { return mValidateSignal.connect(cb); }
+private:
+	static validate_signal_t mValidateSignal;
+// [/RLVa:KB]
+
 public:
 	// Registration
 	
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index ac710dea48c36e80accaaa18ccf8785f198b1930..e07b2cc9fa61c4d25d97c2762b400a68ae523be2 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -564,6 +564,14 @@ set(viewer_SOURCE_FILES
     llxmlrpctransaction.cpp
     noise.cpp
     pipeline.cpp
+    rlvhandler.cpp
+    rlvhelper.cpp
+    rlvcommon.cpp
+    rlvlocks.cpp
+    rlvinventory.cpp
+    rlvextensions.cpp
+    rlvfloaters.cpp
+    rlvui.cpp
     )
 
 set(VIEWER_BINARY_NAME "secondlife-bin" CACHE STRING
@@ -1087,6 +1095,15 @@ set(viewer_HEADER_FILES
     macmain.h
     noise.h
     pipeline.h
+    rlvdefines.h
+    rlvhandler.h
+    rlvhelper.h
+    rlvcommon.h
+    rlvlocks.h
+    rlvinventory.h
+    rlvextensions.h
+    rlvfloaters.h
+    rlvui.h
     VertexCache.h
     VorbisFramework.h
     )
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 91d5e6e724ee9605c07c46c9fa8ad74e3fd7bd46..2821d30c97a7bf49bef5da59fab20d3b7a4ee4a9 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1,6 +1,149 @@
 <?xml version="1.0" ?>
 <llsd>
 <map>
+    <key>RestrainedLove</key>
+    <map>
+      <key>Comment</key>
+      <string>Toggles the RestrainedLove features (BDSM lockable toys support). Needs a restart of the viewer.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+    <key>RestrainedLoveDebug</key>
+    <map>
+      <key>Comment</key>
+      <string>Toggles the RestrainedLove debug mode (displays the commands when in debug mode).</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>RestrainedLoveNoSetEnv</key>
+    <map>
+      <key>Comment</key>
+      <string>When TRUE, forbids to set the environment (time of day and Windlight settings) via RestrainedLove. Needs a restart of the viewer.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>RestrainedLoveForbidGiveToRLV</key>
+    <map>
+      <key>Comment</key>
+      <string>When FALSE, allows to give sub-folders to the #RLV RestrainedLove folder.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+    <key>RLVaDebugHideUnsetDuplicate</key>
+    <map>
+      <key>Comment</key>
+      <string>Suppresses reporting "unset" or "duplicate" command restrictions when RestrainedLoveDebug is TRUE</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>RLVaEnableCompositeFolders</key>
+    <map>
+      <key>Comment</key>
+      <string>Enables composite folders for shared inventory</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>RLVaEnableLegacyNaming</key>
+    <map>
+      <key>Comment</key>
+      <string>Enables legacy naming convention for folders</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+    <key>RLVaEnableSharedWear</key>
+    <map>
+      <key>Comment</key>
+      <string>Attachments in the shared #RLV folder can be force-attached without needing to specify an attachment point</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>RLVaHideLockedLayers</key>
+    <map>
+      <key>Comment</key>
+      <string>Hides "remove outfit" restricted worn clothing layers from @getoufit</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>RLVaHideLockedAttachments</key>
+    <map>
+      <key>Comment</key>
+      <string>Hides non-detachable worn attachments from @getattach</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>RLVaSharedInvAutoRename</key>
+    <map>
+      <key>Comment</key>
+      <string>Automatically renames shared inventory items when worn</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+    <key>RLVaShowNameTags</key>
+    <map>
+      <key>Comment</key>
+      <string>Display of names above avatars is subject to the general "Show Names" setting when @shownames=n restricted</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>WarnFirstRLVGiveToRLV</key>
+    <map>
+      <key>Comment</key>
+      <string>Enables FirstRLVGiveToRLV warning dialog</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
 	<key>CrashHostUrl</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index dc76a4e5183ad137b5917aaa933d311b46c7369f..0b18994aff2831d448518adf13f14d3661496f9d 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -1,6 +1,17 @@
 <llsd>
     <map>
-    <key>BusyResponseChanged</key>
+      <key>RLVaLoginLastLocation</key>
+      <map>
+        <key>Comment</key>
+        <string>Determines whether the next login will be forced to the last logoff location (set by the viewer)</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>Boolean</string>
+        <key>Value</key>
+        <integer>1</integer>
+      </map>
+      <key>BusyResponseChanged</key>
         <map>
         <key>Comment</key>
             <string>Does user's busy mode message differ from default?</string>
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index fe7e883d8382a8e525e6ac31fd7bab9f6bcc41f6..42a3da88735604fbcdf566c94f4e3c0ebcd4cd02 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -75,6 +75,9 @@
 #include "llwindow.h"
 #include "llworld.h"
 #include "llworldmap.h"
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 using namespace LLVOAvatarDefines;
 
@@ -451,6 +454,9 @@ void LLAgent::movePitch(F32 mag)
 // Does this parcel allow you to fly?
 BOOL LLAgent::canFly()
 {
+// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0d) | Modified: RLVa-1.0.0c
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_FLY)) return FALSE;
+// [/RLVa:KB]
 	if (isGodlike()) return TRUE;
 
 	LLViewerRegion* regionp = getRegion();
@@ -499,6 +505,13 @@ void LLAgent::setFlying(BOOL fly)
 
 	if (fly)
 	{
+// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0d) | Modified: RLVa-1.0.0c
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_FLY))
+		{
+			return;
+		}
+// [/RLVa:KB]
+
 		BOOL was_flying = getFlying();
 		if (!canFly() && !was_flying)
 		{
@@ -553,7 +566,14 @@ bool LLAgent::enableFlying()
 
 void LLAgent::standUp()
 {
-	setControlFlags(AGENT_CONTROL_STAND_UP);
+//	setControlFlags(AGENT_CONTROL_STAND_UP);
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+	// RELEASE-RLVa: [SL-2.0.0] Check this function's callers since usually they require explicit blocking
+	if ( (!rlv_handler_t::isEnabled()) || (gRlvHandler.canStand()) )
+	{
+		setControlFlags(AGENT_CONTROL_STAND_UP);
+	}
+// [/RLVa:KB]
 }
 
 
@@ -829,7 +849,14 @@ LLVector3d LLAgent::getPosGlobalFromAgent(const LLVector3 &pos_agent) const
 
 void LLAgent::sitDown()
 {
-	setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
+//	setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
+// [RLVa:KB] - Checked: 2010-08-28 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	// RELEASE-RLVa: [SL-2.0.0] Check this function's callers since usually they require explicit blocking
+	if ( (!rlv_handler_t::isEnabled()) || ((gRlvHandler.canStand()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) )
+	{
+		setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
+	}
+// [/RLVa:KB]
 }
 
 
@@ -2076,7 +2103,15 @@ void LLAgent::onAnimStop(const LLUUID& id)
 	}
 	else if (id == ANIM_AGENT_AWAY)
 	{
+//		clearAFK();
+// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Added: RLVa-1.1.0g
+#ifdef RLV_EXTENSION_CMD_ALLOWIDLE
+		if (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE))
+			clearAFK();
+#else
 		clearAFK();
+#endif // RLV_EXTENSION_CMD_ALLOWIDLE
+// [/RLVa:KB]
 	}
 	else if (id == ANIM_AGENT_STANDUP)
 	{
@@ -3292,6 +3327,17 @@ void LLAgent::teleportRequest(
 // Landmark ID = LLUUID::null means teleport home
 void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
 {
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a
+	// NOTE: we'll allow teleporting home unless both @tplm=n *and* @tploc=n restricted
+	if ( (rlv_handler_t::isEnabled()) &&
+		 ( ( (landmark_asset_id.notNull()) ? gRlvHandler.hasBehaviour(RLV_BHVR_TPLM)
+		                                   : gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC) ) ||
+		   ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && (gAgentAvatarp->isSitting())) ))
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	LLViewerRegion *regionp = getRegion();
 	if(regionp && teleportCore())
 	{
@@ -3356,6 +3402,24 @@ void LLAgent::teleportCancel()
 
 void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
 {
+// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+	if ( (rlv_handler_t::isEnabled()) && (!RlvUtil::isForceTp()) )
+	{
+		// If we're getting teleported due to @tpto we should disregard any @tploc=n or @unsit=n restrictions from the same object
+		if ( (gRlvHandler.hasBehaviourExcept(RLV_BHVR_TPLOC, gRlvHandler.getCurrentObject())) ||
+		     ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && 
+			   (gRlvHandler.hasBehaviourExcept(RLV_BHVR_UNSIT, gRlvHandler.getCurrentObject()))) )
+		{
+			return;
+		}
+
+		if ( (gRlvHandler.getCurrentCommand()) && (RLV_BHVR_TPTO == gRlvHandler.getCurrentCommand()->getBehaviourType()) )
+		{
+			gRlvHandler.setCanCancelTp(false);
+		}
+	}
+// [/RLVa:KB]
+
 	LLViewerRegion* regionp = getRegion();
 	U64 handle = to_region_handle(pos_global);
 	LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle);
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 68e408d3e4aa9264e31cc8f6f465cba1e4e8c8cc..1f87f53191b68ba313c312755a56a7c81a63c2ce 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -48,6 +48,9 @@
 #include "llvoavatarself.h"
 #include "llwindow.h"
 #include "llworld.h"
+// [RLVa:KB] - Checked: 2010-05-10 (RLVa-1.2.0g)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 using namespace LLVOAvatarDefines;
 
@@ -2253,6 +2256,13 @@ void LLAgentCamera::changeCameraToCustomizeAvatar()
 		return;
 	}
 
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g
+	if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStand()) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	gAgent.standUp(); // force stand up
 	gViewerWindow->getWindow()->resetBusyCount();
 
diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp
index d520debc31f9f37e70b53f552b815f2c75661b09..66f3853e792d4f5dc36fc85526f1e13ca0ca3f2a 100644
--- a/indra/newview/llagentlistener.cpp
+++ b/indra/newview/llagentlistener.cpp
@@ -37,6 +37,9 @@
 #include "llviewerobject.h"
 #include "llviewerobjectlist.h"
 #include "llviewerregion.h"
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 LLAgentListener::LLAgentListener(LLAgent &agent)
   : LLEventAPI("LLAgent",
@@ -85,8 +88,28 @@ void LLAgentListener::requestSit(LLSD const & event_data) const
 	// *TODO - find a permanent place to share this code properly.
 	LLViewerObject *object = gObjectList.findObject(event_data["obj_uuid"]);
 
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.1.0j
+	// TODO-RLVa: [RLVa-1.2.1] Figure out how to call this?
+	if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canSit(object)) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	if (object && object->getPCode() == LL_PCODE_VOLUME)
 	{
+// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) )
+		{
+			if (gAgentAvatarp->isSitting())
+			{
+				gAgent.standUp();
+				return;
+			}
+			gRlvHandler.setSitSource(gAgent.getPositionGlobal());
+		}
+// [/RLVa:KB]
+
 		gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
 		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
 		gMessageSystem->addUUIDFast(_PREHASH_AgentID, mAgent.getID());
@@ -101,6 +124,14 @@ void LLAgentListener::requestSit(LLSD const & event_data) const
 
 void LLAgentListener::requestStand(LLSD const & event_data) const
 {
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+	// TODO-RLVa: [RLVa-1.2.1] Figure out how to call this?
+	if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStand()) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	mAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
 }
 
diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp
index f52f1361181f948a011312c35832d2a8f8f8dfd1..c2c23f30fa31bcd3d89600ed90f70b4af4a1998f 100644
--- a/indra/newview/llagentui.cpp
+++ b/indra/newview/llagentui.cpp
@@ -38,6 +38,9 @@
 #include "llviewerparcelmgr.h"
 #include "llvoavatarself.h"
 #include "llslurl.h"
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //static
 void LLAgentUI::buildName(std::string& name)
@@ -122,6 +125,18 @@ BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const
 	// create a default name and description for the landmark
 	std::string parcel_name = LLViewerParcelMgr::getInstance()->getAgentParcelName();
 	std::string region_name = region->getName();
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+	// RELEASE-RLVa: [SL-2.0.0] Check ELocationFormat to make sure our switch still makes sense
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+	{
+		parcel_name = RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL);
+		region_name = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+		if (LOCATION_FORMAT_NO_MATURITY == fmt)
+			fmt = LOCATION_FORMAT_LANDMARK;
+		else if (LOCATION_FORMAT_FULL == fmt)
+			fmt = LOCATION_FORMAT_NO_COORDS;
+	}
+// [/RLVa:KB]
 	std::string sim_access_string = region->getSimAccessString();
 	std::string buffer;
 	if( parcel_name.empty() )
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index d7d2cadfe6a6e79c910a35a519d846be12a72570..b79e70c768b3b034ea49b56e71787b146bd58770 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -49,6 +49,9 @@
 #include "llvoavatarself.h"
 #include "llwearable.h"
 #include "llwearablelist.h"
+// [RLVa:KB] - Checked: RLVa-1.2.0a (2010-03-04)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #include <boost/scoped_ptr.hpp>
 
@@ -763,12 +766,28 @@ U32 LLAgentWearables::pushWearable(const LLWearableType::EType type, LLWearable
 		llwarns << "Null wearable sent for type " << type << llendl;
 		return MAX_CLOTHING_PER_TYPE;
 	}
-	if (type < LLWearableType::WT_COUNT || mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE)
-	{
-		mWearableDatas[type].push_back(wearable);
+//	if (type < LLWearableType::WT_COUNT || mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE)
+//	{
+//		mWearableDatas[type].push_back(wearable);
+//		wearableUpdated(wearable);
+//		checkWearableAgainstInventory(wearable);
+//		return mWearableDatas[type].size()-1;
+//	}
+// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+	if ( (type < LLWearableType::WT_COUNT) && (mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE) )
+	{
+		// Don't add the same wearable twice
+		U32 idxWearable = getWearableIndex(wearable);
+		RLV_ASSERT(MAX_CLOTHING_PER_TYPE == idxWearable); // pushWearable() on an already added wearable is a bug *somewhere*
+		if (MAX_CLOTHING_PER_TYPE == idxWearable)
+		{
+			mWearableDatas[type].push_back(wearable);
+			idxWearable = mWearableDatas[type].size() - 1;
+		}
 		wearableUpdated(wearable);
 		checkWearableAgainstInventory(wearable);
-		return mWearableDatas[type].size()-1;
+		return idxWearable;
+// [/RLVa:KB]
 	}
 	return MAX_CLOTHING_PER_TYPE;
 }
@@ -1302,7 +1321,11 @@ void LLAgentWearables::removeWearable(const LLWearableType::EType type, bool do_
 	{
 		LLWearable* old_wearable = getWearable(type,index);
 		
-		if (old_wearable)
+//		if (old_wearable)
+// [RLVa:KB] - Checked: 2010-05-11 (RLVa-1.2.0c) | Modified: RLVa-1.2.0g
+		// NOTE: we block actual removal in removeWearableFinal(); all we really want here is to avoid showing the save notice
+		if ( (old_wearable) && ((!rlv_handler_t::isEnabled()) || (!gRlvWearableLocks.isLockedWearable(old_wearable))) )
+// [/RLVa:KB]
 		{
 			if (old_wearable->isDirty())
 			{
@@ -1360,20 +1383,30 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo
 		{
 			LLWearable* old_wearable = getWearable(type,i);
 			//queryWearableCache(); // moved below
-			if (old_wearable)
+//			if (old_wearable)
+// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+			if ( (old_wearable) && ((!rlv_handler_t::isEnabled()) || (!gRlvWearableLocks.isLockedWearable(old_wearable))) )
+// [/RLVa:KB]
 			{
 				popWearable(old_wearable);
 				old_wearable->removeFromAvatar(TRUE);
 			}
 		}
-		mWearableDatas[type].clear();
+//		mWearableDatas[type].clear();
+// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+		// The line above shouldn't be needed and would cause issues if we block removing one of the wearables
+		RLV_VERIFY( ((!rlv_handler_t::isEnabled()) || (!gRlvWearableLocks.hasLockedWearable(type))) ? mWearableDatas[type].empty() : true );
+// [/RLVa:KB]
 	}
 	else
 	{
 		LLWearable* old_wearable = getWearable(type, index);
 		//queryWearableCache(); // moved below
 
-		if (old_wearable)
+//		if (old_wearable)
+// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+		if ( (old_wearable) && ((!rlv_handler_t::isEnabled()) || (!gRlvWearableLocks.isLockedWearable(old_wearable))) )
+// [/RLVa:KB]
 		{
 			popWearable(old_wearable);
 			old_wearable->removeFromAvatar(TRUE);
@@ -1411,6 +1444,12 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
 	S32 count = wearables.count();
 	llassert(items.count() == count);
 
+// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+	// If the user is @add/remoutfit restricted in any way then this function won't just work as-is, so instead of removing and re-adding
+	// we're stuck with any wearable type potentially having left-over (remove locked) clothing that we'll need to reorder in-place
+	S32 idxCurPerType[LLWearableType::WT_COUNT] = { 0 };
+// [/RLVa:KB]
+
 	S32 i;
 	for (i = 0; i < count; i++)
 	{
@@ -1430,10 +1469,51 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
 				// exactly one wearable per body part
 				setWearable(type,0,new_wearable);
 			}
-			else
+//			else
+//			{
+//				pushWearable(type,new_wearable);
+//			}
+// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+			else if ( (!rlv_handler_t::isEnabled()) || (!gRlvWearableLocks.hasLockedWearable(type)) || (!remove) )
 			{
+				// Sanity check: there shouldn't be any worn wearables for this type the first time we encounter it
+				RLV_ASSERT( (!remove) || (0 != idxCurPerType[type]) || (0 == getWearableCount(type)) );
 				pushWearable(type,new_wearable);
 			}
+			else
+			{
+				// Get the current index of the wearable (or add it if doesn't exist yet)
+				S32 idxCur = getWearableIndex(new_wearable);
+				if (MAX_CLOTHING_PER_TYPE == idxCur)
+				{
+					// Skip adding if @addoutfit=n restricted *unless* the wearable made it into COF [see LLAppMgr::updateAgentWearables()]
+					if ( (RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(type)) && 
+						 (!gInventory.isObjectDescendentOf(new_item->getUUID(), LLAppearanceMgr::instance().getCOF())) )
+					{
+						continue;
+					}
+					idxCur = pushWearable(type,new_wearable);
+				}
+
+				// Since we're moving up from index 0 we just swap the two wearables and things will work out in the end (hopefully)
+				if (idxCurPerType[type] != idxCur)
+				{
+					wearableentry_map_t::iterator itWearable = mWearableDatas.find(type);
+					RLV_ASSERT(itWearable != mWearableDatas.end());
+					if (itWearable == mWearableDatas.end()) continue;
+					wearableentry_vec_t& typeWearable = itWearable->second;
+					RLV_ASSERT(typeWearable.size() >= 2);
+					if (typeWearable.size() < 2) continue;
+
+					typeWearable[idxCur] = typeWearable[idxCurPerType[type]];
+					typeWearable[idxCurPerType[type]] = new_wearable;
+					//wearableUpdated(new_wearable);
+					//checkWearableAgainstInventory(new_wearable);
+				}
+			}
+			idxCurPerType[type]++;
+// [/RLVa:KB]
+
 			wearableUpdated(new_wearable);
 			checkWearableAgainstInventory(new_wearable);
 		}
@@ -1473,6 +1553,16 @@ void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* ne
 	
 	const LLWearableType::EType type = new_wearable->getType();
 
+// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0g
+	// TODO-RLVa: [RLVa-1.2.1] This looks like dead code in SL-2.0.2 so we can't really check to see if it works :|
+	if (rlv_handler_t::isEnabled())
+	{
+		ERlvWearMask eWear = gRlvWearableLocks.canWear(type);
+		if ( (RLV_WEAR_LOCKED == eWear) || ((!do_append) && (!(eWear & RLV_WEAR_REPLACE))) )
+			return;
+	}
+// [/RLVa:KB]
+
 	if (!do_append)
 	{
 		// Remove old wearable, if any
@@ -1800,6 +1890,34 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo
 {
 	if (!isAgentAvatarValid()) return;
 
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+	// RELEASE-RLVa: [SL-2.0.0] Check our callers and verify that erasing elements from the passed vector won't break random things
+	if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
+	{
+		llvo_vec_t::iterator itObj = objects_to_remove.begin();
+		while (itObj != objects_to_remove.end())
+		{
+			const LLViewerObject* pAttachObj = *itObj;
+			if (gRlvAttachmentLocks.isLockedAttachment(pAttachObj))
+			{
+				itObj = objects_to_remove.erase(itObj);
+
+				// Fall-back code: re-add the attachment if it got removed from COF somehow (compensates for possible bugs elsewhere)
+				LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+				LLLinkedItemIDMatches f(pAttachObj->getAttachmentItemID());
+				gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), folders, items, LLInventoryModel::EXCLUDE_TRASH, f);
+				RLV_ASSERT( 0 != items.count() );
+				if (0 == items.count())
+					LLAppearanceMgr::instance().registerAttachment(pAttachObj->getAttachmentItemID());
+			}
+			else
+			{
+				++itObj;
+			}
+		}
+	}
+// [/RLVa:KB]
+
 	if (objects_to_remove.empty())
 		return;
 
@@ -1846,6 +1964,23 @@ void LLAgentWearables::userRemoveAllAttachments()
 
 void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array)
 {
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+	// RELEASE-RLVa: [SL-2.0.0] Check our callers and verify that erasing elements from the passed vector won't break random things
+	if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) )
+	{
+		// Fall-back code: everything should really already have been pruned before we get this far
+		for (S32 idxItem = obj_item_array.count() - 1; idxItem >= 0; idxItem--)
+		{
+			const LLInventoryItem* pItem = obj_item_array.get(idxItem).get();
+			if (!gRlvAttachmentLocks.canAttach(pItem))
+			{
+				obj_item_array.remove(idxItem);
+				RLV_ASSERT(false);
+			}
+		}
+	}
+// [/RLVa:KB]
+
 	// Build a compound message to send all the objects that need to be rezzed.
 	S32 obj_count = obj_item_array.count();
 
@@ -1882,7 +2017,18 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
 		msg->nextBlockFast(_PREHASH_ObjectData );
 		msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
 		msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
-		msg->addU8Fast(_PREHASH_AttachmentPt, 0 );	// Wear at the previous or default attachment point
+
+//		msg->addU8Fast(_PREHASH_AttachmentPt, 0 );	// Wear at the previous or default attachment point
+// [RLVa:KB] - Checked: 2010-07-28 (RLVa-1.2.0i) | Added: RLVa-1.2.0i
+		bool fWearAdd = false;
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) )
+		{
+			fWearAdd = true;
+			RlvAttachmentLockWatchdog::instance().onWearAttachment(item, (fWearAdd) ? RLV_WEAR_ADD : RLV_WEAR_REPLACE);
+		}
+		msg->addU8Fast(_PREHASH_AttachmentPt, (fWearAdd) ? 0 | ATTACHMENT_ADD : 0);
+// [/RLVa:KB]
+
 		pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
 		msg->addStringFast(_PREHASH_Name, item->getName());
 		msg->addStringFast(_PREHASH_Description, item->getDescription());
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index f846e9e32e7931c8ee05d49350db1bbe41c11a95..88fee221adf904493f0ae27cd67ef7fdf4c8b617 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -48,6 +48,9 @@
 #include "llvoavatarself.h"
 #include "llviewerregion.h"
 #include "llwearablelist.h"
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // RAII thingy to guarantee that a variable gets reset when the Setter
 // goes out of scope.  More general utility would be handy - TODO:
@@ -1006,6 +1009,34 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up
 		return false;
 	}
 
+// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+	if ( (rlv_handler_t::isEnabled()) && 
+		 ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY))) )
+	{
+		switch (item_to_wear->getType())
+		{
+			case LLAssetType::AT_BODYPART:
+			case LLAssetType::AT_CLOTHING:
+				{
+					ERlvWearMask eWear = gRlvWearableLocks.canWear(item_to_wear);
+					if (RLV_WEAR_LOCKED == eWear)
+						return false;
+					replace &= ((RLV_WEAR_REPLACE & eWear) == RLV_WEAR_REPLACE);
+				}
+				break;
+			case LLAssetType::AT_OBJECT:
+				{
+					// TODO-RLVa: [SL-2.1.0] Rewrite for MULTI_ATTACHMENTS
+					if (!gRlvAttachmentLocks.canAttach(item_to_wear))
+						return false;
+				}
+				break;
+			default:
+				return false;
+		}
+	}
+// [/RLVa:KB]
+
 	switch (item_to_wear->getType())
 	{
 	case LLAssetType::AT_CLOTHING:
@@ -1367,6 +1398,45 @@ void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_lin
 	}
 }
 
+// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+void LLAppearanceMgr::syncCOF(const LLInventoryModel::item_array_t& items, LLAssetType::EType type, LLPointer<LLInventoryCallback> cb)
+{
+	const LLUUID idCOF = getCOF();
+	LLInventoryModel::item_array_t cur_cof_items, new_cof_items = items;
+
+	// Grab the current COF contents
+	LLIsType f(type);
+	LLInventoryModel::cat_array_t cats; 
+	gInventory.collectDescendentsIf(getCOF(), cats, cur_cof_items, LLInventoryModel::EXCLUDE_TRASH, f);
+
+	// Purge everything in cur_cof_items that isn't part of new_cof_items
+	for (S32 idxCurItem = 0, cntCurItem = cur_cof_items.count(); idxCurItem < cntCurItem; idxCurItem++)
+	{
+		const LLViewerInventoryItem* pItem = cur_cof_items.get(idxCurItem);
+		if (std::find_if(new_cof_items.begin(), new_cof_items.end(), RlvPredIsEqualOrLinkedItem(pItem)) == new_cof_items.end())
+		{
+			// Item doesn't exist in new_cof_items => purge (if it's a link)
+			if (pItem->getIsLinkType())
+				gInventory.purgeObject(pItem->getUUID());
+		}
+		else
+		{
+			// Item exists in new_cof_items => remove *all* occurances in new_cof_items (removes duplicate COF links to this item as well)
+			new_cof_items.erase(
+				std::remove_if(new_cof_items.begin(), new_cof_items.end(), RlvPredIsEqualOrLinkedItem(pItem)), new_cof_items.end());
+		}
+	}
+
+	// Link to whatever remains in new_cof_items
+	for (S32 idxNewItem = 0, cntNewItem = new_cof_items.count(); idxNewItem < cntNewItem; idxNewItem++)
+	{
+		const LLInventoryItem* pItem = new_cof_items.get(idxNewItem);
+		link_inventory_item(
+			gAgent.getID(), pItem->getLinkedUUID(), idCOF, pItem->getName(), pItem->getDescription(), LLAssetType::AT_LINK, cb);
+	}
+}
+// [/SL:KB]
+
 // Keep the last N wearables of each type.  For viewer 2.0, N is 1 for
 // both body parts and clothing items.
 void LLAppearanceMgr::filterWearableItems(
@@ -1419,10 +1489,31 @@ void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid,
 	}
 }
 
+//void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0b) | Added: RLVa-1.2.0b
 void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 {
-	LLViewerInventoryCategory *pcat = gInventory.getCategory(category);
-	llinfos << "starting, cat " << (pcat ? pcat->getName() : "[UNKNOWN]") << llendl;
+	LLInventoryModel::item_array_t body_items_new, wear_items_new, obj_items_new, gest_items_new;
+	getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART, false);
+	getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING, false);
+	getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT, false);
+	getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE, false);
+	updateCOF(body_items_new, wear_items_new, obj_items_new, gest_items_new, append, category);
+}
+
+void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, 
+								LLInventoryModel::item_array_t& wear_items_new, 
+								LLInventoryModel::item_array_t& obj_items_new,
+								LLInventoryModel::item_array_t& gest_items_new,
+								bool append /*=false*/, const LLUUID& idOutfit /*=LLUUID::null*/)
+// [/RLVa:KB]
+{
+//	LLViewerInventoryCategory *pcat = gInventory.getCategory(category);
+//	llinfos << "starting, cat " << (pcat ? pcat->getName() : "[UNKNOWN]") << llendl;
+// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Added: RLVa-1.2.0b
+	// RELEASE-RLVa: [SL-2.0.0] If pcat ever gets used for anything further down the beta we'll know about it
+	llinfos << "starting" << llendl;
+// [/RLVa:KB]
 
 	const LLUUID cof = getCOF();
 
@@ -1443,75 +1534,142 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)
 	
 	// Collect and filter descendents to determine new COF contents.
 
-	// - Body parts: always include COF contents as a fallback in case any
-	// required parts are missing.
+	//
+	// - Body parts: always include COF contents as a fallback in case any required parts are missing.
+	//
 	// Preserve body parts from COF if appending.
 	LLInventoryModel::item_array_t body_items;
 	getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false);
-	getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false);
+//	getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false);
+// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b
+	// Filter out any new body parts that can't be worn before adding them
+	if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) )
+		body_items_new.erase(std::remove_if(body_items_new.begin(), body_items_new.end(), rlvPredIsNotWearableItem), body_items_new.end());
+	body_items.insert(body_items.end(), body_items_new.begin(), body_items_new.end());
+// [/RLVa:KB]
 	if (append)
 		reverse(body_items.begin(), body_items.end());
 	// Reduce body items to max of one per type.
 	removeDuplicateItems(body_items);
 	filterWearableItems(body_items, 1);
 
+	//
 	// - Wearables: include COF contents only if appending.
+	//
 	LLInventoryModel::item_array_t wear_items;
 	if (append)
 		getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false);
-	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false);
+// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b
+	else if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) )
+	{
+		// Make sure that all currently locked clothing layers remain in COF when replacing
+		getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false);
+		wear_items.erase(std::remove_if(wear_items.begin(), wear_items.end(), rlvPredIsRemovableItem), wear_items.end());
+	}
+// [/RLVa:KB]
+//	getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false);
+// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b
+	// Filter out any new wearables that can't be worn before adding them
+	if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) )
+		wear_items_new.erase(std::remove_if(wear_items_new.begin(), wear_items_new.end(), rlvPredIsNotWearableItem), wear_items_new.end());
+	wear_items.insert(wear_items.end(), wear_items_new.begin(), wear_items_new.end());
+// [/RLVa:KB]
 	// Reduce wearables to max of one per type.
 	removeDuplicateItems(wear_items);
 	filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE);
 
+	//
 	// - Attachments: include COF contents only if appending.
+	//
 	LLInventoryModel::item_array_t obj_items;
 	if (append)
 		getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false);
-	getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false);
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b
+	else if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) )
+	{
+		// Make sure that all currently locked attachments remain in COF when replacing
+		getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false);
+		obj_items.erase(std::remove_if(obj_items.begin(), obj_items.end(), rlvPredIsRemovableItem), obj_items.end());
+	}
+// [/RLVa:KB]
+//	getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false);
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b
+	// Filter out any new attachments that can't be worn before adding them
+	if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) )
+		obj_items_new.erase(std::remove_if(obj_items_new.begin(), obj_items_new.end(), rlvPredIsNotWearableItem), obj_items_new.end());
+	obj_items.insert(obj_items.end(), obj_items_new.begin(), obj_items_new.end());
+// [/RLVa:KB]
 	removeDuplicateItems(obj_items);
 
+	//
 	// - Gestures: include COF contents only if appending.
+	//
 	LLInventoryModel::item_array_t gest_items;
 	if (append)
 		getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false);
-	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false);
+//	getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false);
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Added: RLVa-1.2.0b
+	gest_items.insert(gest_items.end(), gest_items_new.begin(), gest_items_new.end());
+// [/RLVa:KB]
 	removeDuplicateItems(gest_items);
 	
-	// Remove current COF contents.
-	bool keep_outfit_links = append;
-	purgeCategory(cof, keep_outfit_links);
-	gInventory.notifyObservers();
-
 	// Create links to new COF contents.
 	llinfos << "creating LLUpdateAppearanceOnDestroy" << llendl;
 	LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy(!append);
 
-#ifndef LL_RELEASE_FOR_DOWNLOAD
-	llinfos << "Linking body items" << llendl;
-#endif
-	linkAll(cof, body_items, link_waiter);
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
-	llinfos << "Linking wear items" << llendl;
-#endif
-	linkAll(cof, wear_items, link_waiter);
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
-	llinfos << "Linking obj items" << llendl;
-#endif
-	linkAll(cof, obj_items, link_waiter);
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
-	llinfos << "Linking gesture items" << llendl;
-#endif
-	linkAll(cof, gest_items, link_waiter);
+// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	if (!append)
+	{
+// [/SL:KB]
+		// Remove current COF contents.
+		bool keep_outfit_links = append;
+		purgeCategory(cof, keep_outfit_links);
+		gInventory.notifyObservers();
+		#ifndef LL_RELEASE_FOR_DOWNLOAD
+			llinfos << "Linking body items" << llendl;
+		#endif
+		linkAll(cof, body_items, link_waiter);
+
+		#ifndef LL_RELEASE_FOR_DOWNLOAD
+			llinfos << "Linking wear items" << llendl;
+		#endif
+		linkAll(cof, wear_items, link_waiter);
+
+		#ifndef LL_RELEASE_FOR_DOWNLOAD
+			llinfos << "Linking obj items" << llendl;
+		#endif
+		linkAll(cof, obj_items, link_waiter);
+
+		#ifndef LL_RELEASE_FOR_DOWNLOAD
+			llinfos << "Linking gesture items" << llendl;
+		#endif
+		linkAll(cof, gest_items, link_waiter);
+// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	}
+	else
+	{
+		// Synchronize COF
+		//  -> it's possible that we don't link to any new items in which case 'link_waiter' fires when it goes out of scope below
+		syncCOF(body_items, LLAssetType::AT_BODYPART, link_waiter);
+		syncCOF(wear_items, LLAssetType::AT_CLOTHING, link_waiter);
+		syncCOF(obj_items, LLAssetType::AT_OBJECT, link_waiter);
+		syncCOF(gest_items, LLAssetType::AT_GESTURE, link_waiter);
+		gInventory.notifyObservers();
+	}
+// [/SL:KB]
 
 	// Add link to outfit if category is an outfit. 
-	if (!append)
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Added: RLVa-1.2.0b
+	if ( (!append) && (idOutfit.notNull()) )
 	{
-		createBaseOutfitLink(category, link_waiter);
+		createBaseOutfitLink(idOutfit, link_waiter);
 	}
+// [/RLVa:KB]
+//	if (!append)
+//	{
+//		createBaseOutfitLink(category, link_waiter);
+//	}
+
 	llinfos << "waiting for LLUpdateAppearanceOnDestroy" << llendl;
 }
 
@@ -1562,6 +1720,25 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo
 				LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID);
 				if( item && (item->getAssetUUID() == wearable->getAssetID()) )
 				{
+// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+					// TODO-RLVa: [RLVa-1.2.1] This is fall-back code so if we don't ever trigger this code it can just be removed
+					//   -> one way to trigger the assertion:
+					//			1) "Replace Outfit" on a folder with clothing and an attachment that goes @addoutfit=n
+					//			2) updateCOF will add/link the items into COF => no @addoutfit=n present yet => allowed
+					//			3) llOwnerSay("@addoutfit=n") executes
+					//			4) code below runs => @addoutfit=n conflicts with adding new wearables
+					//     => if it's left as-is then the wearables won't get worn (but remain in COF which causes issues of its own)
+					//     => if it's changed to debug-only then we make tge assumption that anything that makes it into COF is always OK
+#ifdef RLV_DEBUG
+					// NOTE: make sure we don't accidentally block setting the initial wearables
+					if ( (rlv_handler_t::isEnabled()) && (RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(wearable->getType())) &&
+						 (!gAgentWearables.getWearableFromItemID(item->getUUID())) && (gAgentWearables.areWearablesLoaded()) )
+					{
+						RLV_VERIFY(RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(wearable->getType()));
+						continue;
+					}
+#endif // RLV_DEBUG
+// [/RLVa:KB]
 					items.put(item);
 					wearables.put(wearable);
 				}
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 64e161e1dec687e34bab39de1ecfc1fbdf2e69fa..b4796dd3db02db4bf5768939235489ac742ede7b 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -56,6 +56,11 @@ public:
 // [/SL:KB]
 	bool needToSaveCOF();
 	void updateCOF(const LLUUID& category, bool append = false);
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	void updateCOF(LLInventoryModel::item_array_t& body_items_new, LLInventoryModel::item_array_t& wear_items_new,
+				   LLInventoryModel::item_array_t& obj_items_new, LLInventoryModel::item_array_t& gest_items_new,
+				   bool append = false, const LLUUID& idOutfit = LLUUID::null);
+// [/RLVa:KB]
 	void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append);
 	void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append);
 	void wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append);
@@ -208,6 +213,10 @@ private:
 
 	void setOutfitLocked(bool locked);
 
+// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	void syncCOF(const LLInventoryModel::item_array_t& items, LLAssetType::EType type, LLPointer<LLInventoryCallback> cb);
+// [/SL:KB]
+
 	bool mAttachmentInvLinkEnabled;
 	bool mOutfitIsDirty;
 	bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls.
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index bfe3e52657019fbb34f4f832005bf51a5706d821..a295d02dde7136851ef740229e1dedd1200218b9 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -80,6 +80,10 @@
 #include "llurlmatch.h"
 #include "lltextutil.h"
 
+// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g)
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 #include "llweb.h"
 #include "llsecondlifeurls.h"
 
@@ -334,7 +338,16 @@ LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
 void idle_afk_check()
 {
 	// check idle timers
+//	if (gSavedSettings.getS32("AFKTimeout") && (gAwayTriggerTimer.getElapsedTimeF32() > gSavedSettings.getS32("AFKTimeout")))
+// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+#ifdef RLV_EXTENSION_CMD_ALLOWIDLE
+	// Enforce an idle time of 30 minutes if @allowidle=n restricted
+	S32 nAFKTimeout = (gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) ? gSavedSettings.getS32("AFKTimeout") : 60 * 30;
+	if ( (nAFKTimeout) && (gAwayTriggerTimer.getElapsedTimeF32() > nAFKTimeout) )
+#else
 	if (gSavedSettings.getS32("AFKTimeout") && (gAwayTriggerTimer.getElapsedTimeF32() > gSavedSettings.getS32("AFKTimeout")))
+#endif // RLV_EXTENSION_CMD_ALLOWIDLE
+// [/RLVa:KB]
 	{
 		gAgent.setAFK();
 	}
diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp
index 1cd705c2f9d8b555f56a83cbb388e029083a00a2..ddc8eec79bb774407f468cf1709a9a273b259c19 100644
--- a/indra/newview/llavatarlist.cpp
+++ b/indra/newview/llavatarlist.cpp
@@ -45,6 +45,9 @@
 #include "lluuid.h"
 #include "llvoiceclient.h"
 #include "llviewercontrol.h"	// for gSavedSettings
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list");
 
@@ -121,6 +124,9 @@ LLAvatarList::LLAvatarList(const Params& p)
 , mShowInfoBtn(p.show_info_btn)
 , mShowProfileBtn(p.show_profile_btn)
 , mShowSpeakingIndicator(p.show_speaking_indicator)
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+, mRlvCheckShowNames(false)
+// [/RLVa:KB]
 {
 	setCommitOnSelectionChange(true);
 
@@ -368,6 +374,9 @@ S32 LLAvatarList::notifyParent(const LLSD& info)
 void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_online, EAddPosition pos)
 {
 	LLAvatarListItem* item = new LLAvatarListItem();
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	item->setRlvCheckShowNames(mRlvCheckShowNames);
+// [/RLVa:KB]
 	item->setName(name);
 	item->setAvatarId(id, mSessionID, mIgnoreOnlineStatus);
 	item->setOnline(mIgnoreOnlineStatus ? true : is_online);
@@ -387,7 +396,10 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is
 BOOL LLAvatarList::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
 	BOOL handled = LLUICtrl::handleRightMouseDown(x, y, mask);
-	if ( mContextMenu )
+//	if ( mContextMenu )
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+	if ( (mContextMenu) && ((!mRlvCheckShowNames) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))) )
+// [/RLVa:KB]
 	{
 		uuid_vec_t selected_uuids;
 		getSelectedUUIDs(selected_uuids);
@@ -443,9 +455,32 @@ void LLAvatarList::updateLastInteractionTimes()
 
 void LLAvatarList::onItemDoubleClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
 {
-	mItemDoubleClickSignal(ctrl, x, y, mask);
+//	mItemDoubleClickSignal(ctrl, x, y, mask);
+// [RLVa:KB] - Checked: 2010-06-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	if ( (!mRlvCheckShowNames) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
+		mItemDoubleClickSignal(ctrl, x, y, mask);
+// [/RLVa:KB]
 }
 
+// [RLVa:KB] - Checked: 2010-06-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+void LLAvatarList::refreshNames()
+{
+	std::vector<LLPanel*> items;
+	getItems(items);
+
+	std::string strFullName;
+	for (std::vector<LLPanel*>::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem)
+	{
+		LLAvatarListItem* pItem = static_cast<LLAvatarListItem*>(*itItem);
+		if (gCacheName->getFullName(pItem->getAvatarId(), strFullName))
+			pItem->setName(strFullName);
+	}
+
+	if (&NAME_COMPARATOR == mItemComparator)
+		sort();
+}
+// [/RLVa:KB]
+
 bool LLAvatarItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const
 {
 	const LLAvatarListItem* avatar_item1 = dynamic_cast<const LLAvatarListItem*>(item1);
diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h
index 83faa53c281a6f309899ca8902cfb3130160f1ce..f02bc4bd07245c746ac58b65cbc0dba2bebc0932 100644
--- a/indra/newview/llavatarlist.h
+++ b/indra/newview/llavatarlist.h
@@ -87,6 +87,11 @@ public:
 	// Return true if filter has at least one match.
 	bool filterHasMatches();
 
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	void setRlvCheckShowNames(bool fRlvCheckShowNames) { mRlvCheckShowNames = fRlvCheckShowNames; }
+	void refreshNames();
+// [/RLVa:KB]
+
 	boost::signals2::connection setRefreshCompleteCallback(const commit_signal_t::slot_type& cb);
 
 	boost::signals2::connection setItemDoubleClickCallback(const mouse_signal_t::slot_type& cb);
@@ -115,6 +120,9 @@ private:
 	bool mShowInfoBtn;
 	bool mShowProfileBtn;
 	bool mShowSpeakingIndicator;
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	bool mRlvCheckShowNames;
+// [/RLVa:KB]
 
 	LLTimer*				mLITUpdateTimer; // last interaction time update timer
 	std::string				mIconParamName;
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index 341913edf7b80723677976545d18e01a94c7d011..11e852bd561dafadb2c3f0750fd6ae03610912a9 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -37,6 +37,9 @@
 #include "llagent.h"
 #include "llavatariconctrl.h"
 #include "lloutputmonitorctrl.h"
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 bool LLAvatarListItem::sStaticInitialized = false;
 S32 LLAvatarListItem::sLeftPadding = 0;
@@ -65,7 +68,11 @@ LLAvatarListItem::LLAvatarListItem(bool not_from_ui_factory/* = true*/)
 	mProfileBtn(NULL),
 	mOnlineStatus(E_UNKNOWN),
 	mShowInfoBtn(true),
-	mShowProfileBtn(true)
+//	mShowProfileBtn(true)
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	mShowProfileBtn(true),
+	mRlvCheckShowNames(false)
+// [/RLVa:KB]
 {
 	if (not_from_ui_factory)
 	{
@@ -122,8 +129,12 @@ S32 LLAvatarListItem::notifyParent(const LLSD& info)
 void LLAvatarListItem::onMouseEnter(S32 x, S32 y, MASK mask)
 {
 	getChildView("hovered_icon")->setVisible( true);
-	mInfoBtn->setVisible(mShowInfoBtn);
-	mProfileBtn->setVisible(mShowProfileBtn);
+//	mInfoBtn->setVisible(mShowInfoBtn);
+//	mProfileBtn->setVisible(mShowProfileBtn);
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	mInfoBtn->setVisible( (mShowInfoBtn) && ((!mRlvCheckShowNames) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))) );
+	mProfileBtn->setVisible( (mShowProfileBtn) && ((!mRlvCheckShowNames) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))) );
+// [/RLVa:KB]
 
 	LLPanel::onMouseEnter(x, y, mask);
 
@@ -163,7 +174,11 @@ void LLAvatarListItem::setOnline(bool online)
 
 void LLAvatarListItem::setName(const std::string& name)
 {
-	setNameInternal(name, mHighlihtSubstring);
+//	setNameInternal(name, mHighlihtSubstring);
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	bool fRlvFilter = (mRlvCheckShowNames) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES));
+	setNameInternal( (!fRlvFilter) ? name : RlvStrings::getAnonym(name), mHighlihtSubstring);
+// [/RLVa:KB]
 }
 
 void LLAvatarListItem::setHighlight(const std::string& highlight)
diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h
index e252e69ea9b614852d87c55aed039281808e6d2d..79f29546586770ee8baeb0d05976589333ec80f3 100644
--- a/indra/newview/llavatarlistitem.h
+++ b/indra/newview/llavatarlistitem.h
@@ -96,6 +96,9 @@ public:
 	void showSpeakingIndicator(bool show);
 	void showLastInteractionTime(bool show);
 	void setAvatarIconVisible(bool visible);
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	void setRlvCheckShowNames(bool fRlvCheckShowNames) { mRlvCheckShowNames = fRlvCheckShowNames; }
+// [/RLVa:KB]
 	
 	const LLUUID& getAvatarId() const;
 	const std::string getAvatarName() const;
@@ -180,6 +183,9 @@ private:
 	//Speaker indicator and avatar name coords are translated accordingly
 	bool mShowInfoBtn;
 	bool mShowProfileBtn;
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	bool mRlvCheckShowNames;
+// [/RLVa:KB]
 
 	static bool	sStaticInitialized; // this variable is introduced to improve code readability
 	static S32  sLeftPadding; // padding to first left visible child (icon or name)
diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp
index c78f73c3b88d1e41ab9a19201a7383a17ca27667..7b0b53735524fddf64e11dd7df5cb340ca039a6b 100644
--- a/indra/newview/llcallfloater.cpp
+++ b/indra/newview/llcallfloater.cpp
@@ -307,6 +307,10 @@ void LLCallFloater::updateSession()
 			setVisible(true);
 		}
 	}
+
+// [RLVa:KB] - Checked: 2010-06-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	mAvatarList->setRlvCheckShowNames(is_local_chat);
+// [/RLVa:KB]
 }
 
 void LLCallFloater::refreshParticipantList()
diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h
index 881f777b4826152be0c4a626ea1f50b953f83bcf..28d8310242c9289f43444022880ec9dbc16adbe2 100644
--- a/indra/newview/llcallfloater.h
+++ b/indra/newview/llcallfloater.h
@@ -73,6 +73,10 @@ public:
 
 	static void sOnCurrentChannelChanged(const LLUUID& session_id);
 
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	LLAvatarList* getAvatarCallerList() { return mAvatarList; }
+// [/RLVa:KB]
+
 private:
 	typedef enum e_voice_controls_type
 	{
diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp
index 967db212447f87493714e757056ccc7dbef083cc..8dcb7efbce9ae23cb3667f7aa0b070b16c562bf3 100644
--- a/indra/newview/llchatbar.cpp
+++ b/indra/newview/llchatbar.cpp
@@ -61,6 +61,9 @@
 #include "llviewermenu.h"
 #include "lluictrlfactory.h"
 #include "llbottomtray.h"
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //
 // Globals
@@ -80,7 +83,10 @@ private:
 };
 
 
-extern void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel);
+//extern void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel);
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-0.2.2a
+extern void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel);
+// [/RLVa:KB]
 
 //
 // Functions
@@ -473,7 +479,11 @@ void LLChatBar::onInputEditorKeystroke( LLLineEditor* caller, void* userdata )
 
 	S32 length = raw_text.length();
 
-	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
+//	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
+// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d
+	// RELEASE-RLVa: [SL-2.0.0] This entire class appears to be dead/non-functional?
+	if ( (length > 0) && (raw_text[0] != '/') && (!gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT)) )
+// [/RLVa:KB]
 	{
 		gAgent.startTyping();
 	}
@@ -577,6 +587,22 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL
 		utf8_text = utf8str_truncate(utf8_text, MAX_STRING - 1);
 	}
 
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
+	// RELEASE-RLVa: [SL-2.0.0] This entire class appears to be dead/non-functional?
+	if ( (0 == channel) && (rlv_handler_t::isEnabled()) )
+	{
+		// Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation)
+		if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) )
+			type = CHAT_TYPE_WHISPER;
+		else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) )
+			type = CHAT_TYPE_NORMAL;
+		else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) )
+			type = CHAT_TYPE_NORMAL;
+
+		animate &= !gRlvHandler.hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE );
+	}
+// [/RLVa:KB]
+
 	// Don't animate for chats people can't hear (chat to scripts)
 	if (animate && (channel == 0))
 	{
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 1f67a659bd2a101bceef36f5c60729e31a86ab0e..90ce43d8b3f1328f55ce9c018facda9f488ecad2 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -52,7 +52,9 @@
 #include "llviewertexteditor.h"
 #include "llworld.h"
 #include "lluiconstants.h"
-
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f)
+#include "rlvcommon.h"
+// [/RLVa:KB]
 
 #include "llsidetray.h"//for blocked objects panel
 
@@ -86,6 +88,10 @@ public:
 		LLSD payload;
 		payload["object_id"] = object_id;
 		payload["owner_id"] = query_map["owner"];
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+		if (query_map.has("owner_name"))
+			payload["owner_name"] = query_map["owner_name"];
+// [/RLVa:KB]
 		payload["name"] = query_map["name"];
 		payload["slurl"] = LLWeb::escapeURL(query_map["slurl"]);
 		payload["group_owned"] = query_map["groupowned"];
@@ -97,6 +103,10 @@ LLObjectIMHandler gObjectIMHandler;
 
 class LLChatHistoryHeader: public LLPanel
 {
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	LLChatHistoryHeader() : mShowContextMenu(true), mShowInfoCtrl(true) {}
+// [/RLVa:KB]
+
 public:
 	static LLChatHistoryHeader* createInstance(const std::string& file_name)
 	{
@@ -209,7 +219,11 @@ public:
 
 	void showInspector()
 	{
-		if (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) return;
+//		if (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) return;
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+		// Don't double-click show the inspector if we're not showing the info control
+		if ( (!mShowInfoCtrl) || (mAvatarID.isNull() && CHAT_SOURCE_SYSTEM != mSourceType) ) return;
+// [/RLVa:KB]
 		
 		if (mSourceType == CHAT_SOURCE_OBJECT)
 		{
@@ -271,6 +285,15 @@ public:
 		if(mSourceType != CHAT_SOURCE_AGENT)
 			icon->setDrawTooltip(false);
 
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+		// Don't show the context menu, info control or avatar icon tooltip if this chat was subject to @shownames=n
+		if ( (chat.mRlvNamesFiltered) && ((CHAT_SOURCE_AGENT == mSourceType) || (CHAT_SOURCE_OBJECT == mSourceType))  )
+		{
+			mShowInfoCtrl = mShowContextMenu = false;
+			icon->setDrawTooltip(false);
+		}
+// [/RLVa:KB]
+
 		switch (mSourceType)
 		{
 			case CHAT_SOURCE_AGENT:
@@ -328,6 +351,10 @@ protected:
 
 	void showContextMenu(S32 x,S32 y)
 	{
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+		if (!mShowContextMenu)
+			return;
+// [/RLVa:KB]
 		if(mSourceType == CHAT_SOURCE_SYSTEM)
 			showSystemContextMenu(x,y);
 		if(mAvatarID.notNull() && mSourceType == CHAT_SOURCE_AGENT)
@@ -378,7 +405,10 @@ protected:
 
 	void showInfoCtrl()
 	{
-		if (mAvatarID.isNull() || mFrom.empty() || SYSTEM_FROM == mFrom) return;
+//		if (mAvatarID.isNull() || mFrom.empty() || SYSTEM_FROM == mFrom) return;
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+		if ( (!mShowInfoCtrl) || (mAvatarID.isNull() || mFrom.empty() || SYSTEM_FROM == mFrom) ) return;
+// [/RLVa:KB]
 				
 		if (!sInfoCtrl)
 		{
@@ -447,6 +477,10 @@ protected:
 	EChatSourceType		mSourceType;
 	std::string			mFrom;
 	LLUUID				mSessionID;
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	bool                mShowContextMenu;
+	bool                mShowInfoCtrl;
+// [/RLVa:KB]
 
 	S32					mMinUserNameWidth;
 };
@@ -664,22 +698,32 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
 			// Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text.
 			if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull())
 			{
-				// for object IMs, create a secondlife:///app/objectim SLapp
-				std::string url = LLSLURL("objectim", chat.mFromID, "").getSLURLString();
-				url += "?name=" + chat.mFromName;
-				url += "&owner=" + chat.mOwnerID.asString();
-
-				std::string slurl = args["slurl"].asString();
-				if (slurl.empty())
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+				// NOTE-RLVa: we don't need to do any @shownames or @showloc filtering here because we'll already have an existing URL
+				std::string url = chat.mURL;
+				RLV_ASSERT( (url.empty()) || (std::string::npos != url.find("objectim")) );
+				if ( (url.empty()) || (std::string::npos == url.find("objectim")) )
 				{
-				    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
-				    if(region)
-				      {
-					LLSLURL region_slurl(region->getName(), chat.mPosAgent);
-					slurl = region_slurl.getLocationString();
-				      }
+// [/RLVa:KB]
+					// for object IMs, create a secondlife:///app/objectim SLapp
+					/*std::string*/ url = LLSLURL("objectim", chat.mFromID, "").getSLURLString();
+					url += "?name=" + chat.mFromName;
+					url += "&owner=" + chat.mOwnerID.asString();
+
+					std::string slurl = args["slurl"].asString();
+					if (slurl.empty())
+					{
+						LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
+						if(region)
+						{
+							LLSLURL region_slurl(region->getName(), chat.mPosAgent);
+							slurl = region_slurl.getLocationString();
+						}
+					}
+					url += "&slurl=" + LLURI::escape(slurl);
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
 				}
-				url += "&slurl=" + LLURI::escape(slurl);
+// [/RLVa:KB]
 
 				// set the link for the object name to be the objectim SLapp
 				// (don't let object names with hyperlinks override our objectim Url)
@@ -689,7 +733,10 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
 				mEditor->appendText("<nolink>" + chat.mFromName + "</nolink>"  + delimiter,
 									false, link_params);
 			}
-			else if ( chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log)
+//			else if (chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log)
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+			else if (chat.mFromName != SYSTEM_FROM && chat.mFromID.notNull() && !message_from_log && !chat.mRlvNamesFiltered)
+// [/RLVa:KB]
 			{
 				LLStyle::Params link_params(style_params);
 				link_params.overwriteFrom(LLStyleMap::instance().lookupAgent(chat.mFromID));
diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp
index 67b7ac53838147914e018c4f27cce0fb941668bf..f2451d5c440b15f3602648563cbce97f99fd56aa 100644
--- a/indra/newview/llchatitemscontainerctrl.cpp
+++ b/indra/newview/llchatitemscontainerctrl.cpp
@@ -40,6 +40,10 @@
 
 #include "llslurl.h"
 
+// [RLVa:KB] - Checked: 2010-04-21 (RLVa-1.2.0f)
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 static const S32 msg_left_offset = 10;
 static const S32 msg_right_offset = 10;
 static const S32 msg_height_pad = 5;
@@ -141,7 +145,11 @@ void LLNearbyChatToastPanel::init(LLSD& notification)
 	std::string		fromName = notification["from"].asString();	// agent or object name
 	mFromID = notification["from_id"].asUUID();		// agent id or object id
 	mFromName = fromName;
-	
+
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	mShowIconTooltip = notification.has("show_icon_tooltip") ? notification["show_icon_tooltip"].asBoolean() : true;
+// [/RLVa:KB]
+
 	int sType = notification["source"].asInteger();
     mSourceType = (EChatSourceType)sType;
 	
@@ -186,7 +194,11 @@ void LLNearbyChatToastPanel::init(LLSD& notification)
 			style_params_name.font.name(font_name);
 			style_params_name.font.size(font_style_size);
 
-			style_params_name.link_href = LLSLURL("agent",mFromID,"about").getSLURLString();
+//			style_params_name.link_href = LLSLURL("agent",mFromID,"about").getSLURLString();
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+			if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+				style_params_name.link_href = LLSLURL("agent",mFromID,"about").getSLURLString();
+// [/RLVa:KB]
 
 			msg_text->appendText(str_sender, FALSE, style_params_name);
 
@@ -319,7 +331,10 @@ void LLNearbyChatToastPanel::draw()
 		LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon", false);
 		if(icon)
 		{
-			icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT);
+//			icon->setDrawTooltip(mSourceType == CHAT_SOURCE_AGENT);
+// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+			icon->setDrawTooltip( (mShowIconTooltip) && (mSourceType == CHAT_SOURCE_AGENT) );
+// [/RLVa:KB]
 			if(mSourceType == CHAT_SOURCE_OBJECT)
 				icon->setValue(LLSD("OBJECT_Icon"));
 			else if(mSourceType == CHAT_SOURCE_SYSTEM)
diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h
index 1d700dcedefd0abbfd52c421852e6b2e9f9d1485..f1ae1fe283d8e4c30cf381a9d4be8afbd36a77c2 100644
--- a/indra/newview/llchatitemscontainerctrl.h
+++ b/indra/newview/llchatitemscontainerctrl.h
@@ -46,6 +46,9 @@ protected:
         LLNearbyChatToastPanel()
 		: 
 	mIsDirty(false),
+// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	mShowIconTooltip(true),
+// [/RLVa:KB]
 	mSourceType(CHAT_SOURCE_OBJECT)
 	{};
 public:
@@ -89,6 +92,9 @@ private:
 
 
 	bool mIsDirty;
+// [RLVa:KB] - Checked: 2010-04-200 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	bool mShowIconTooltip;
+// [/RLVa:KB]
 };
 
 
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index 5ac006302e2efcb5288d66fc5789af9a7024a3e3..883269e55a4751ff008eabff42f36ebda2ec98fe 100644
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -41,6 +41,9 @@
 #include "llviewerregion.h"
 #include "llversioninfo.h"
 #include "llweb.h"
+// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // Linden library includes
 #include "llaudioengine.h"
@@ -255,6 +258,12 @@ LLSD LLFloaterAbout::getInfo()
     }
 #endif
 
+// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+	if (rlv_handler_t::isEnabled())
+		info["RLV_VERSION"] = RlvStrings::getVersionAbout();
+	else
+		info["RLV_VERSION"] = "(disabled)";
+// [/RLVa:KB]
 	info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION));
 	info["LIBCURL_VERSION"] = LLCurl::getVersionString();
 	info["J2C_VERSION"] = LLImageJ2C::getEngineInfo();
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 9391c761b72381ce727ca67a8e650637437a231c..22b4e1fec6c9877ac4fa74ba802e5560dac7fb51 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -36,6 +36,9 @@
 #include "lltooldraganddrop.h"	// for LLToolDragAndDrop
 #include "llviewercontrol.h"
 #include "llworld.h"
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // Linden libraries
 #include "llbutton.h"
@@ -234,6 +237,21 @@ void LLFloaterAvatarPicker::onRangeAdjust()
 void LLFloaterAvatarPicker::onList()
 {
 	getChildView("ok_btn")->setEnabled(isSelectBtnEnabled());
+
+// [RLVa:KB] - Checked: 2010-06-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+	if (rlv_handler_t::isEnabled())
+	{
+		LLTabContainer* pTabs = getChild<LLTabContainer>("ResidentChooserTabs");
+		LLPanel* pNearMePanel = getChild<LLPanel>("NearMePanel");
+		if ( (pTabs) && (pNearMePanel) )
+		{
+			bool fRlvEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES);
+			pTabs->enableTabButton(pTabs->getIndexForPanel(pNearMePanel), fRlvEnable);
+			if ( (!fRlvEnable) && (pTabs->getCurrentPanel() == pNearMePanel) )
+				pTabs->selectTabByName("SearchPanel");
+		}
+	}
+// [/RLVa:KB]
 }
 
 void LLFloaterAvatarPicker::populateNearMe()
diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp
index 8e7f7e083ce8249c62c7c8d12491792ed0e04e2f..41d63c368e04354e6826e58d37651929f4008e52 100644
--- a/indra/newview/llfloaterinspect.cpp
+++ b/indra/newview/llfloaterinspect.cpp
@@ -40,6 +40,9 @@
 #include "llviewercontrol.h"
 #include "llviewerobject.h"
 #include "lluictrlfactory.h"
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //LLFloaterInspect* LLFloaterInspect::sInstance = NULL;
 
@@ -113,7 +116,16 @@ void LLFloaterInspect::onClickCreatorProfile()
 		LLSelectNode* node = mObjectSelection->getFirstNode(&func);
 		if(node)
 		{
-			LLAvatarActions::showProfile(node->mPermissions->getCreator());
+//			LLAvatarActions::showProfile(node->mPermissions->getCreator());
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e
+			const LLUUID& idCreator = node->mPermissions->getCreator();
+			if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && 
+				 ((node->mPermissions->getOwner() == idCreator) || (RlvUtil::isNearbyAgent(idCreator))) )
+			{
+				return;
+			}
+			LLAvatarActions::showProfile(idCreator);
+// [/RLVa:KB]
 		}
 	}
 }
@@ -139,6 +151,10 @@ void LLFloaterInspect::onClickOwnerProfile()
 		if(node)
 		{
 			const LLUUID& owner_id = node->mPermissions->getOwner();
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+				return;
+// [/RLVa:KB]
 			LLAvatarActions::showProfile(owner_id);
 		}
 	}
@@ -148,8 +164,13 @@ void LLFloaterInspect::onSelectObject()
 {
 	if(LLFloaterInspect::getSelectedUUID() != LLUUID::null)
 	{
-		getChildView("button owner")->setEnabled(true);
+//		getChildView("button owner")->setEnabled(true);
+//		getChildView("button creator")->setEnabled(true);
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e
+		getChildView("button owner")->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES));
+		// TODO-RLVa: [RLVa-1.2.2] Is it worth checking the selected node just to selectively disable this button?
 		getChildView("button creator")->setEnabled(true);
+// [/RLVa:KB]
 	}
 }
 
@@ -208,6 +229,19 @@ void LLFloaterInspect::refresh()
 
 		gCacheName->getFullName(obj->mPermissions->getOwner(), owner_name);
 		gCacheName->getFullName(obj->mPermissions->getCreator(), creator_name);
+
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.2.1b
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+		{
+			if (!obj->mPermissions->isGroupOwned())
+				owner_name = RlvStrings::getAnonym(owner_name);
+
+			const LLUUID& idCreator = obj->mPermissions->getCreator();
+			if ( (obj->mPermissions->getOwner() == idCreator) || (RlvUtil::isNearbyAgent(idCreator)) )
+				creator_name = RlvStrings::getAnonym(creator_name);
+		}
+// [/RLVa:KB]
+
 		row["id"] = obj->getObject()->getID();
 		row["columns"][0]["column"] = "object_name";
 		row["columns"][0]["type"] = "text";
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 3804a1b85840db0d9959b06eb1f4786ca830e5d3..6dae540aa3189543aae6ebfec61ec3521a8f5149 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -101,6 +101,9 @@
 #include "llviewermedia.h"
 #include "llpluginclassmedia.h"
 #include "llteleporthistorystorage.h"
+// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #include "lllogininstance.h"        // to check if logged in yet
 
@@ -841,6 +844,11 @@ void LLFloaterPreference::refreshEnabledState()
 	LLComboBox* ctrl_reflections = getChild<LLComboBox>("Reflections");
 	LLRadioGroup* radio_reflection_detail = getChild<LLRadioGroup>("ReflectionDetailRadio");
 	
+// [RLVa:KB] - Checked: 2010-04-09 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+	if (rlv_handler_t::isEnabled())
+		childSetEnabled("busy_response", !gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM));
+// [/RLVa:KB]
+
 	// Reflections
 	BOOL reflections = gSavedSettings.getBOOL("VertexShaderEnable") 
 		&& gGLManager.mHasCubeMap
@@ -878,8 +886,14 @@ void LLFloaterPreference::refreshEnabledState()
 	// radio set for terrain detail mode
 	LLRadioGroup*   mRadioTerrainDetail = getChild<LLRadioGroup>("TerrainDetailRadio");   // can be linked with control var
 
-	ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"));
-	
+//	ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"));
+// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-0.2.0a
+	// "Basic Shaders" can't be disabled - but can be enabled - under @setenv=n
+	bool fCtrlShaderEnable = LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable");
+	ctrl_shader_enable->setEnabled(
+		fCtrlShaderEnable && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) || (!gSavedSettings.getBOOL("VertexShaderEnable"))) );
+// [/RLVa:KB]
+
 	BOOL shaders = ctrl_shader_enable->get();
 	if (shaders)
 	{
@@ -896,7 +910,13 @@ void LLFloaterPreference::refreshEnabledState()
 	
 	// *HACK just checks to see if we can use shaders... 
 	// maybe some cards that use shaders, but don't support windlight
-	ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders);
+//	ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders);
+// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-0.2.0a
+	// "Atmospheric Shaders" can't be disabled - but can be enabled - under @setenv=n
+	bool fCtrlWindLightEnable = fCtrlShaderEnable && shaders;
+	ctrl_wind_light->setEnabled(
+		fCtrlWindLightEnable && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) || (!gSavedSettings.getBOOL("WindLightUseAtmosShaders"))) );
+// [/RLVa:KB]
 
 	//Deferred/SSAO/Shadows
 	LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders");
diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp
index e4e4713dbca833d2e43103066acec9b3e5880580..34cb273c5b9e7c5429960336e02149d55838d85b 100644
--- a/indra/newview/llfloaterproperties.cpp
+++ b/indra/newview/llfloaterproperties.cpp
@@ -58,6 +58,9 @@
 
 #include "lluictrlfactory.h"
 
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLPropertiesObserver
@@ -280,6 +283,16 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
 		getChildView("BtnCreator")->setEnabled(TRUE);
 		getChildView("LabelCreatorTitle")->setEnabled(TRUE);
 		getChildView("LabelCreatorName")->setEnabled(TRUE);
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e
+		// If the object creator matches the object owner we need to anonimize the creator field as well
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && 
+			( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == item->getCreatorUUID()) ) ||
+			  (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) )
+		{
+			childSetEnabled("BtnCreator", FALSE);
+			name = RlvStrings::getAnonym(name);
+		}
+// [/RLVa:KB]
 		getChild<LLUICtrl>("LabelCreatorName")->setValue(name);
 	}
 	else
@@ -303,8 +316,15 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
 		else
 		{
 			gCacheName->getFullName(perm.getOwner(), name);
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+				name = RlvStrings::getAnonym(name);
+// [/RLVa:KB]
 		}
-		getChildView("BtnOwner")->setEnabled(TRUE);
+//		getChildView("BtnOwner")->setEnabled(TRUE);
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.0.0e
+		getChildView("BtnOwner")->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES));
+// [/RLVa:KB]
 		getChildView("LabelOwnerTitle")->setEnabled(TRUE);
 		getChildView("LabelOwnerName")->setEnabled(TRUE);
 		getChild<LLUICtrl>("LabelOwnerName")->setValue(name);
@@ -541,6 +561,17 @@ void LLFloaterProperties::onClickCreator()
 	if(!item) return;
 	if(!item->getCreatorUUID().isNull())
 	{
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+		{
+			const LLPermissions& perm = item->getPermissions();
+			if ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == item->getCreatorUUID()) ) ||
+			     (RlvUtil::isNearbyAgent(item->getCreatorUUID())) )
+			{
+				return;
+			}
+		}
+// [/RLVa:KB]
 		LLAvatarActions::showProfile(item->getCreatorUUID());
 	}
 }
@@ -556,6 +587,10 @@ void LLFloaterProperties::onClickOwner()
 	}
 	else
 	{
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+			return;
+// [/RLVa:KB]
 		LLAvatarActions::showProfile(item->getPermissions().getOwner());
 	}
 }
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index 97f192a70830089b93d2bb25d20e8e642af51696..bbd4a24664c12444f4c74fa3737a424a5b4c8b2e 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -254,6 +254,14 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)
 			if (regionp)
 			{
 				getChild<LLUICtrl>("sim_field")->setValue(regionp->getName());
+// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
+/*
+				if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) )
+				{
+					childSetText("sim_field", RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
+				}
+*/
+// [/RLVa:KB]
 				LLVector3d global_pos;
 				global_pos.setVec(objectp->getPositionRegion());
 				setPosBox(global_pos);
diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp
index 41a05055feff21da841317f9af9c4da87448ce61..f1131144a73557ee6dfa55dce67d24509aaba6c2 100644
--- a/indra/newview/llfloatersettingsdebug.cpp
+++ b/indra/newview/llfloatersettingsdebug.cpp
@@ -34,6 +34,10 @@
 #include "llcolorswatch.h"
 #include "llviewercontrol.h"
 #include "lltexteditor.h"
+// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+#include "rlvextensions.h"
+// [/RLVa:KB]
 
 
 LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) 
@@ -210,6 +214,33 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp)
 
 	if (controlp)
 	{
+// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0e) | Modified: RLVa-0.2.1d
+		// TODO-RLVa: [RLVa-1.2.1] Look into rewriting the whole debug setting blocking code
+		if (rlv_handler_t::isEnabled())
+		{
+			// Don't allow changing DBG_WRITE debug settings under @setdebug=n
+			bool fEnable = !( (gRlvHandler.hasBehaviour(RLV_BHVR_SETDEBUG)) && 
+				(RlvExtGetSet::getDebugSettingFlags(controlp->getName()) & RlvExtGetSet::DBG_WRITE) );
+			// Don't allow toggling "Basic Shaders" and/or "Atmopsheric Shaders" through the debug settings under @setenv=n
+			fEnable &= !((gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) && 
+				(("VertexShaderEnable" == controlp->getName()) || ("WindLightUseAtmosShaders" == controlp->getName())));
+#ifdef RLV_EXTENSION_STARTLOCATION
+			// Don't allow toggling RestrainedLoveLoginLastLocation
+			fEnable &= !(RLV_SETTING_LOGINLASTLOCATION == controlp->getName());
+#endif // RLV_EXTENSION_STARTLOCATION
+
+			// NOTE: this runs per-frame so there's no need to explictly handle onCommitSettings() or onClickDefault()
+			spinner1->setEnabled(fEnable);
+			spinner2->setEnabled(fEnable);
+			spinner3->setEnabled(fEnable);
+			spinner4->setEnabled(fEnable);
+			color_swatch->setEnabled(fEnable);
+			childSetEnabled("val_text", fEnable);
+			childSetEnabled("boolean_combo", fEnable);
+			childSetEnabled("default_btn", fEnable);
+		}
+// [/RLVa:KB]
+
 		eControlType type = controlp->type();
 
 		//hide combo box only for non booleans, otherwise this will result in the combo box closing every frame
diff --git a/indra/newview/llfloaterwindlight.cpp b/indra/newview/llfloaterwindlight.cpp
index 7131cb5de3b704ce36d6b8761798c9faa72fcd5b..6c58efd9ab8d2bc651e15f07e46e6c8fcea1868e 100644
--- a/indra/newview/llfloaterwindlight.cpp
+++ b/indra/newview/llfloaterwindlight.cpp
@@ -270,6 +270,17 @@ void LLFloaterWindLight::syncMenu()
 	LLWLParamSet& currentParams = param_mgr->mCurParams;
 	//std::map<std::string, LLVector4> & currentParams = param_mgr->mCurParams.mParamValues;
 
+// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g)
+/*
+	// Fixes LL "bug" (preset name isn't kept synchronized)
+	LLComboBox* comboBox = getChild<LLComboBox>("WLPresetsCombo");
+	if (comboBox->getSelectedItemLabel() != currentParams.mName)
+	{
+		comboBox->setSimple(currentParams.mName);
+	}
+*/
+// [/RLVa:KB]
+
 	// blue horizon
 	param_mgr->mBlueHorizon = currentParams.getVector(param_mgr->mBlueHorizon.mName, err);
 	getChild<LLUICtrl>("WLBlueHorizonR")->setValue(param_mgr->mBlueHorizon.r / 2.0);
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 3afa31b873c0ecea0c744f689b9d61a1e1a48f25..a375f452eca8912e507a16303d7afedc28a0c7c1 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -75,6 +75,10 @@
 
 #include "llwindow.h"			// copyTextToClipboard()
 
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 //---------------------------------------------------------------------------
 // Constants
 //---------------------------------------------------------------------------
@@ -434,6 +438,10 @@ void LLFloaterWorldMap::draw()
 //	getChildView("Clear")->setEnabled((BOOL)tracking_status);
 	getChildView("Show Destination")->setEnabled((BOOL)tracking_status || LLWorldMap::getInstance()->isTracking());
 	getChildView("copy_slurl")->setEnabled((mSLURL.isValid()) );
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	childSetEnabled("Go Home", 
+		(!rlv_handler_t::isEnabled()) || !(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)));
+// [/RLVa:KB]
 
 	setMouseOpaque(TRUE);
 	getDragHandle()->setMouseOpaque(TRUE);
@@ -716,6 +724,16 @@ void LLFloaterWorldMap::updateLocation()
 		{	// Empty SLURL will disable the "Copy SLURL to clipboard" button
 			mSLURL = LLSLURL();
 		}
+
+// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
+/*
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		{
+			childSetValue("location", RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
+			mSLURL.clear();
+		}
+*/
+// [/RLVa:KB]
 	}
 }
 
diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp
index 260e15c714c735aacb67251689a707653e7774a5..fe650bc3447d85a6d265cbf4e078170c4d7ed1c6 100644
--- a/indra/newview/llgiveinventory.cpp
+++ b/indra/newview/llgiveinventory.cpp
@@ -46,6 +46,10 @@
 #include "llrecentpeople.h"
 #include "llviewerobjectlist.h"
 #include "llvoavatarself.h"
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+#include "rlvui.h"
+// [/RLVa:KB]
 
 // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES
 // or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a
@@ -300,6 +304,20 @@ void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im
 	{
 		gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args);
 	}
+// [RLVa:KB] - Checked: 2010-05-26 (RLVa-1.2.0h) | Modified: RLVa-1.2.0h
+	else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(to_agent)) &&
+		      (!RlvUIEnabler::hasOpenProfile(to_agent)) )
+	{
+		// Log to chat history if the user didn't drop on an IM session or a profile to avoid revealing the name of the recipient
+		std::string strName, strMsgName = "inventory_item_offered-im"; LLSD args;
+		if (gCacheName->getFullName(to_agent, strName))
+		{
+			args["NAME"] = RlvStrings::getAnonym(strName);
+			strMsgName = "inventory_item_offered_rlv";
+		}
+		gIMMgr->addSystemMessage(LLUUID::null, strMsgName, args);
+	}
+// [/RLVa:KB]
 	// If this item was given by drag-and-drop on avatar while IM panel was open, log this action in the IM panel chat.
 	else if (LLIMModel::getInstance()->findIMSession(session_id))
 	{
@@ -397,7 +415,15 @@ void LLGiveInventory::commitGiveInventoryItem(const LLUUID& to_agent,
 	logInventoryOffer(to_agent, im_session_id);
 
 	// add buddy to recent people list
-	LLRecentPeople::instance().add(to_agent);
+//	LLRecentPeople::instance().add(to_agent);
+// [RLVa:KB] - Checked: 2010-04-21 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	// Block the recent activity update if this was an in-world drop on an avatar (as opposed to a drop on an IM session or on a profile)
+	if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (im_session_id.notNull()) || (!RlvUtil::isNearbyAgent(to_agent)) ||
+		 (RlvUIEnabler::hasOpenProfile(to_agent)) )
+	{
+		LLRecentPeople::instance().add(to_agent);
+	}
+// [/RLVa:KB]
 }
 
 // static
@@ -452,7 +478,15 @@ void LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent,
 		<< cat->getUUID() << llendl;
 
 	// add buddy to recent people list
-	LLRecentPeople::instance().add(to_agent);
+//	LLRecentPeople::instance().add(to_agent);
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	// Block the recent activity update if this was an in-world drop on an avatar (as opposed to a drop on an IM session or on a profile)
+	if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (im_session_id.notNull()) || (!RlvUtil::isNearbyAgent(to_agent)) ||
+		 (RlvUIEnabler::hasOpenProfile(to_agent)) )
+	{
+		LLRecentPeople::instance().add(to_agent);
+	}
+// [/RLVa:KB]
 
 	// Test out how many items are being given.
 	LLViewerInventoryCategory::cat_array_t cats;
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 83846f5b619d294de6b340150cf88d58d17e40a6..6a567578664241a1f2d9d680e842ad0daa1164cf 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -61,6 +61,9 @@
 #include "llresmgr.h"
 #include "pipeline.h"
 #include "llspatialpartition.h"
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // Height of the yellow selection highlight posts for land
 const F32 PARCEL_POST_HEIGHT = 0.666f;
@@ -68,6 +71,13 @@ const F32 PARCEL_POST_HEIGHT = 0.666f;
 // Returns true if you got at least one object
 void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask)
 {
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	LLVector3 av_pos = gAgent.getPositionAgent();
 	F32 select_dist_squared = gSavedSettings.getF32("MaxSelectDistance");
 	select_dist_squared = select_dist_squared * select_dist_squared;
@@ -132,6 +142,27 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask)
 		LLViewerCamera::getInstance()->setFar(new_far);
 		LLViewerCamera::getInstance()->setNear(new_near);
 	}
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0g
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH))
+	{
+		// We'll allow drag selection under fartouch, but only within the fartouch range
+		// (just copy/paste the code above us to make that work, thank you Lindens!)
+		LLVector3 relative_av_pos = av_pos;
+		relative_av_pos -= LLViewerCamera::getInstance()->getOrigin();
+
+		F32 new_far = relative_av_pos * LLViewerCamera::getInstance()->getAtAxis() + 1.5f;
+		F32 new_near = relative_av_pos * LLViewerCamera::getInstance()->getAtAxis() - 1.5f;
+
+		new_near = llmax(new_near, 0.1f);
+
+		LLViewerCamera::getInstance()->setFar(new_far);
+		LLViewerCamera::getInstance()->setNear(new_near);
+
+		// Usurp these two
+		limit_select_distance = TRUE;
+		select_dist_squared = 1.5f * 1.5f;
+	}
+// [/RLVa:KB]
 	LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, 
 							center_x-width/2, center_y-height/2, width, height, 
 							limit_select_distance);
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 96638018c4b0921bf667c6cbbf45d1d015e937e4..6b0801f6db2d725e9724d2ae4794289d29453287 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -47,9 +47,11 @@
 #include "llstatusbar.h"
 #include "llmenugl.h"
 #include "pipeline.h"
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 #include <boost/tokenizer.hpp>
 
-
 const F32 SPRING_STRENGTH = 0.7f;
 const F32 RESTORATION_SPRING_TIME_CONSTANT = 0.1f;
 const F32 HORIZONTAL_PADDING = 15.f;
@@ -558,6 +560,30 @@ void LLHUDText::renderText(BOOL for_select)
 
 void LLHUDText::setStringUTF8(const std::string &wtext)
 {
+// [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0a) | Modified: RLVa-1.0.0f
+	// NOTE: setString() is only called for debug beacons and the floating name tags (which we don't want to censor
+	//       because you'd see "(Region hidden) LastName" if you happen to go to a sim who's name is your first name :p
+	if (rlv_handler_t::isEnabled())
+	{
+		std::string text(wtext);
+
+		if (gRlvHandler.canShowHoverText(mSourceObject))
+		{
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+				RlvUtil::filterLocation(text);
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+				RlvUtil::filterNames(text);
+		}
+		else
+		{
+			text = "";
+		}
+
+		setString(utf8str_to_wstring(text));
+		return;
+	}
+// [/RLVa:KB]
+
 	setString(utf8str_to_wstring(wtext));
 }
 
@@ -1133,3 +1159,18 @@ F32 LLHUDText::LLHUDTextSegment::getWidth(const LLFontGL* font)
 		return width;
 	}
 }
+
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.0f
+void LLHUDText::refreshAllObjectText()
+{
+	for (TextObjectIterator itText = sTextObjects.begin(); itText != sTextObjects.end(); itText++)
+	{
+		LLHUDText* pText = *itText;
+		if ( (pText) && (!pText->mObjText.empty() && ("" != pText->mObjText) ) && 
+			 (pText->mSourceObject) && (LL_PCODE_VOLUME == pText->mSourceObject->getPCode()) )
+		{
+			pText->setStringUTF8(pText->mObjText);
+		}
+	}
+}
+// [/RLVa:KB]
diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h
index 4f4ee55a614a8cb503d711122ce415b5bb135cef..64b8dbf369fcace6572a04b238682f35b41fc659 100644
--- a/indra/newview/llhudtext.h
+++ b/indra/newview/llhudtext.h
@@ -125,6 +125,11 @@ public:
 	static void addPickable(std::set<LLViewerObject*> &pick_list);
 	static void reshape();
 	static void setDisplayText(BOOL flag) { sDisplayText = flag ; }
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.0f
+	const std::string& getObjectText() const						{ return mObjText; }
+	void               setObjectText(const std::string &utf8string)	{ mObjText = utf8string; }
+	static void        refreshAllObjectText();
+// [/RLVa:KB]
 protected:
 	LLHUDText(const U8 type);
 
@@ -170,6 +175,9 @@ private:
 	EVertAlignment	mVertAlignment;
 	S32				mLOD;
 	BOOL			mHidden;
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.0f
+	std::string     mObjText;
+// [/RLVa:KB]
 
 	static BOOL    sDisplayText ;
 	static std::set<LLPointer<LLHUDText> > sTextObjects;
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index 658e9403d874a85666980fe8c7d204e83f992910..c828b1d29e71319de8a5d0ea37bb42fbcf5bf4e5 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -56,6 +56,9 @@
 #include "llspeakers.h"
 #include "llsidetray.h"
 
+// [RLVa:KB] - Checked: 2010-04-09 (RLVa-1.2.0e)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 static const S32 RECT_PADDING_NOT_INIT = -1;
 static const S32 RECT_PADDING_NEED_RECALC = -2;
@@ -210,6 +213,56 @@ void LLIMFloater::sendMsg()
 			std::string utf8_text = wstring_to_utf8str(text);
 			utf8_text = utf8str_truncate(utf8_text, MAX_MSG_BUF_SIZE - 1);
 			
+// [RLVa:KB] - Checked: 2010-04-09 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM))
+			{
+				LLIMModel::LLIMSession* pIMSession = LLIMModel::instance().findIMSession(mSessionID);
+				RLV_ASSERT(pIMSession);
+
+				bool fRlvFilter = !pIMSession;
+				if (pIMSession)
+				{
+					switch (pIMSession->mSessionType)
+					{
+						case LLIMModel::LLIMSession::P2P_SESSION:	// One-on-one IM: allow if recipient is a sendim exception
+							fRlvFilter = !gRlvHandler.isException(RLV_BHVR_SENDIM, mOtherParticipantUUID);
+							break;
+						case LLIMModel::LLIMSession::GROUP_SESSION:	// Group chat: allow if group is a sendim exception
+							fRlvFilter = !gRlvHandler.isException(RLV_BHVR_SENDIM, mSessionID);
+							break;
+						case LLIMModel::LLIMSession::ADHOC_SESSION:	// Conference chat: allow if all participants are sendim exceptions
+							{
+								if (!pIMSession->mSpeakers)
+								{
+									fRlvFilter = true;
+									break;
+								}
+
+								LLSpeakerMgr::speaker_list_t speakers;
+								pIMSession->mSpeakers->getSpeakerList(&speakers, TRUE);
+								for (LLSpeakerMgr::speaker_list_t::const_iterator itSpeaker = speakers.begin(); 
+										itSpeaker != speakers.end(); ++itSpeaker)
+								{
+									const LLSpeaker* pSpeaker = *itSpeaker;
+									if ( (gAgent.getID() != pSpeaker->mID) && (!gRlvHandler.isException(RLV_BHVR_SENDIM, pSpeaker->mID)) )
+									{
+										fRlvFilter = true;
+										break;
+									}
+								}
+							}
+							break;
+						default:
+							fRlvFilter = true;
+							break;
+					}
+				}
+
+				if (fRlvFilter)
+					utf8_text = RlvStrings::getString(RLV_STRING_BLOCKED_SENDIM);
+			}
+// [/RLVa:KB]
+
 			if (mSessionInitialized)
 			{
 				LLIMModel::sendMessage(utf8_text, mSessionID,
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 129c9aec142de34d4d4392368a8aa9068b4d0a3b..3403521246a2fdb0801eb99ec92f5d08f71d4d60 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -62,7 +62,9 @@
 #include "lltextbox.h"
 #include "llviewercontrol.h"
 #include "llviewerparcelmgr.h"
-
+// [RLVa:KB] - Checked: 2010-04-09 (RLVa-1.2.0e)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 const static std::string IM_TIME("time");
 const static std::string IM_TEXT("message");
@@ -3072,6 +3074,20 @@ public:
 			{
 				return;
 			}
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM))
+			{
+				if (gAgent.isInGroup(session_id))							// Group chat: don't accept the invite if not an exception
+				{
+					if (!gRlvHandler.isException(RLV_BHVR_RECVIM, session_id))
+						return;
+				}
+				else if (!gRlvHandler.isException(RLV_BHVR_RECVIM, from_id))// Conference chat: don't block; censor if not an exception
+				{
+					message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM);
+				}
+			}
+// [/RLVa:KB]
 
 			// standard message, not from system
 			std::string saved;
diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp
index 532ffca4be5357a55d175725b844cf62a7490091..6d0d9b9ab264ad686c1f314e9573ad8c70ae0195 100644
--- a/indra/newview/llinspectobject.cpp
+++ b/indra/newview/llinspectobject.cpp
@@ -37,6 +37,10 @@
 #include "llviewermedia.h"
 #include "llviewermediafocus.h"
 #include "llviewerobjectlist.h"	// to select the requested object
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0c)
+#include "rlvhandler.h"
+#include "lltoolpie.h"
+// [/RLVa:KB]
 
 // Linden libraries
 #include "llbutton.h"			// setLabel(), not virtual!
@@ -377,6 +381,15 @@ void LLInspectObject::updateSitLabel(LLSelectNode* nodep)
 	{
 		sit_btn->setLabel( getString("Sit") );
 	}
+
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+	// RELEASE-RLVa: [SL-2.0.0] Make sure we're examining the same object that handle_sit_or_stand() will request a sit for
+	if (rlv_handler_t::isEnabled())
+	{
+		const LLPickInfo& pick = LLToolPie::getInstance()->getPick();
+		sit_btn->setEnabled( (pick.mObjectID.notNull()) && (gRlvHandler.canSit(pick.getObject(), pick.mObjectOffset)) );
+	}
+// [/RLVa:KB]
 }
 
 void LLInspectObject::updateTouchLabel(LLSelectNode* nodep)
@@ -472,10 +485,26 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep)
 		// a clickable link		
 		// Objects cannot be created by a group, so use agent URL format
 		LLUUID creator_id = nodep->mPermissions->getCreator();
-		std::string creator_url =
-			LLSLURL("agent", creator_id, "about").getSLURLString();
-		args["[CREATOR]"] = creator_url;
-				
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+		// Only anonimize the creator if they're also the owner or if they're a nearby avie
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) &&
+			 ((nodep->mPermissions->getOwner() == creator_id) || (RlvUtil::isNearbyAgent(creator_id))) )
+		{
+			// TODO-RLVa: [RLVa-1.2.2] We need to put a callback here in case the name hasn't previously resolved
+			std::string strFullName;
+			args["[CREATOR]"] = (gCacheName->getFullName(creator_id, strFullName)) ? RlvStrings::getAnonym(strFullName) 
+			                                                                       : LLTrans::getString("Unknown");
+		}
+		else
+		{
+// [/RLVa:KB]
+			std::string creator_url = 
+				LLSLURL("agent", creator_id, "about").getSLURLString();
+			args["[CREATOR]"] = creator_url;
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+		}
+// [/RLVa:KB]
+
 		// created by one user but owned by another
 		std::string owner_url;
 		LLUUID owner_id;
@@ -488,7 +517,21 @@ void LLInspectObject::updateCreator(LLSelectNode* nodep)
 		else
 		{
 			owner_id = nodep->mPermissions->getOwner();
-			owner_url =	LLSLURL("agent", owner_id, "about").getSLURLString();
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+			{
+				// TODO-RLVa: [RLVa-1.2.2] We need to put a callback here in case the name hasn't previously resolved
+				std::string strFullName;
+				owner_url = (gCacheName->getFullName(owner_id, strFullName)) ? RlvStrings::getAnonym(strFullName)
+				                                                             : LLTrans::getString("Unknown");
+			}
+			else
+			{
+// [/RLVa:KB]
+				owner_url = LLSLURL("agent", owner_id, "about").getSLURLString();
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+			}
+// [/RLVa:KB]
 		}
 		args["[OWNER]"] = owner_url;
 		
diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp
index e956b3b8dec81bf600bef7a8358e23588f457c70..807b764adb5327e3c1fc8fc04b47c728d6a53c54 100644
--- a/indra/newview/llinspectremoteobject.cpp
+++ b/indra/newview/llinspectremoteobject.cpp
@@ -35,6 +35,9 @@
 #include "llui.h"
 #include "lluictrl.h"
 #include "llurlaction.h"
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //////////////////////////////////////////////////////////////////////////////
 // LLInspectRemoteObject
@@ -112,8 +115,12 @@ void LLInspectRemoteObject::onOpen(const LLSD& data)
 	mSLurl      = data["slurl"].asString();
 
 	// work out the owner's name
-	mOwner = "";
-	if (gCacheName)
+//	mOwner = "";
+//	if (gCacheName)
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	mOwner = (data.has("owner_name")) ? data["owner_name"].asString() : "";
+	if ( (gCacheName) && (mOwnerID.notNull()) )
+// [/RLVa:KB]
 	{
 		gCacheName->get(mOwnerID, mGroupOwned, nameCallback, this);
 	}
@@ -186,7 +193,10 @@ void LLInspectRemoteObject::update()
 			owner = LLSLURL("agent", mOwnerID, "about").getSLURLString();
 		}
 	}
-	else
+//	else
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	else if (mOwner.empty()) // If "objectim" was subject to @shownames then we passed an anonimized owner name so use that if available
+// [/RLVa:KB]
 	{
 		owner = LLTrans::getString("Unknown");
 	}
@@ -205,6 +215,14 @@ void LLInspectRemoteObject::update()
 
 	// disable the Block button if we don't have the owner ID
 	getChild<LLUICtrl>("block_btn")->setEnabled(! mOwnerID.isNull());
+
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	if ( (rlv_handler_t::isEnabled()) && (RlvStrings::getString(RLV_STRING_HIDDEN_REGION) == mSLurl) )
+	{
+		getChild<LLUICtrl>("object_slurl")->setValue(mSLurl);
+		getChild<LLUICtrl>("map_btn")->setEnabled(false);
+	}
+// [/RLVa:KB]
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 81174730c702c7a89ca93933734ec9e3846c3573..3683b7eaacdc4472a7cdfd525bdddb08e28ebf1b 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -66,6 +66,9 @@
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llwearablelist.h"
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 typedef std::pair<LLUUID, LLUUID> two_uuids_t;
 typedef std::list<two_uuids_t> two_uuids_list_t;
@@ -618,6 +621,20 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 		addOpenRightClickMenuOption(items);
 		items.push_back(std::string("Properties"));
 
+// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a
+		if (rlv_handler_t::isEnabled())
+		{
+			const LLInventoryObject* pItem = getInventoryObject();
+			if ( (pItem) &&
+				 ( ((LLAssetType::AT_NOTECARD == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE))) ||
+				   ((LLAssetType::AT_LSL_TEXT == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT))) ||
+				   ((LLAssetType::AT_TEXTURE == pItem->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE))) ) )
+			{
+				disabled_items.push_back(std::string("Open"));
+			}
+		}
+// [/RLVa:KB]
+
 		getClipboardEntries(true, items, disabled_items, flags);
 	}
 	hide_context_entries(menu, items, disabled_items);
@@ -2897,6 +2914,15 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 		{
 			is_movable = FALSE;
 		}
+		
+// [RLVa:KB] - Checked: 2010-05-27 (RLVa-1.2.0h) | Added: RLVa-1.2.0h
+		if ( (rlv_handler_t::isEnabled()) && (move_is_into_current_outfit) )
+		{
+			const LLViewerInventoryItem* pItem = dynamic_cast<const LLViewerInventoryItem*>(inv_item);
+			is_movable = rlvPredIsWearableItem(pItem);
+		}
+// [/RLVa:KB]
+
 		if (move_is_into_trash)
 		{
 			is_movable &= inv_item->getIsLinkType() || !get_is_item_worn(inv_item->getUUID());
@@ -3959,7 +3985,10 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action)
 	else if (isRemoveAction(action))
 	{
 		LLInventoryItem* item = gInventory.getItem(mUUID);
-		if(item)
+//		if(item)
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+		if ( (item) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(item))) )
+// [/RLVa:KB]
 		{
 			LLVOAvatarSelf::detachAttachmentIntoInventory(item->getLinkedUUID());
 		}
@@ -3998,6 +4027,14 @@ std::string LLObjectBridge::getLabelSuffix() const
 
 void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace)
 {
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	// If no attachment point was specified, try looking it up from the item name
+	if ( (rlv_handler_t::isEnabled()) && (!attachment) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) )
+	{
+		attachment = RlvAttachPtLookup::getAttachPoint(item);
+	}
+// [/RLVa:KB]
+
 	const LLUUID& item_id = item->getLinkedUUID();
 
 	// Check for duplicate request.
@@ -4036,10 +4073,20 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach
 	if (replace &&
 		(attachment && attachment->getNumObjects() > 0))
 	{
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a
+		// Block if we can't "replace wear" what's currently there
+		if ( (rlv_handler_t::isEnabled()) && ((gRlvAttachmentLocks.canAttach(attachment) & RLV_WEAR_REPLACE) == 0)  )
+			return;
+// [/RLVa:KB]
 		LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_replace_attachment_rez);
 	}
 	else
 	{
+// [RLVa:KB] - Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+		// Block wearing anything on a non-attachable attachment point
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachmentPoint(attach_pt, RLV_LOCK_ADD)) )
+			return;
+// [/RLVa:KB]
 		LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/);
 	}
 }
@@ -4063,7 +4110,17 @@ bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& respon
 		if (itemp)
 		{
 			U8 attachment_pt = notification["payload"]["attachment_point"].asInteger();
-			
+// [RLVa:KB] - Checked: 2010-08-06 (RLVa-1.2.0i) | Added: RLVa-1.2.0i
+			// NOTE: we're letting our callers decide whether or not to use ATTACHMENT_ADD
+			if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) &&
+				 ((!notification["payload"].has("rlv_force")) || (!notification["payload"]["rlv_force"].asBoolean())) )
+			{
+				ERlvWearMask eWearAction = (attachment_pt & ATTACHMENT_ADD) ? RLV_WEAR_ADD : RLV_WEAR_REPLACE;
+				RlvAttachmentLockWatchdog::instance().onWearAttachment(itemp, eWearAction);;
+
+				attachment_pt |= ATTACHMENT_ADD;
+			}
+// [/RLVa:KB]
 
 			LLMessageSystem* msg = gMessageSystem;
 			msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv);
@@ -4115,6 +4172,11 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 			{
 				items.push_back(std::string("Wearable And Object Separator"));
 				items.push_back(std::string("Detach From Yourself"));
+
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+				if ( (rlv_handler_t::isEnabled()) && (!gRlvAttachmentLocks.canDetach(item)) )
+					disabled_items.push_back(std::string("Detach From Yourself"));
+// [/RLVa:KB]
 			}
 			else if (!isItemInTrash() && !isLinkedObjectInTrash() && !isLinkedObjectMissing() && !isCOFFolder())
 			{
@@ -4133,6 +4195,13 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 					disabled_items.push_back(std::string("Attach To"));
 					disabled_items.push_back(std::string("Attach To HUD"));
 				}
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+				else if ( (rlv_handler_t::isEnabled()) && (!gRlvAttachmentLocks.canAttach(item)) )
+				{
+					disabled_items.push_back(std::string("Object Wear"));
+				}
+// [/RLVa:KB]
+
 				LLMenuGL* attach_menu = menu.findChildMenuByName("Attach To", TRUE);
 				LLMenuGL* attach_hud_menu = menu.findChildMenuByName("Attach To HUD", TRUE);
 				if (attach_menu
@@ -4317,6 +4386,10 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_
 				if (get_is_item_worn(item->getUUID()))
 				{
 /*
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0c) | Modified: RLVa-0.2.2a
+					if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) )
+						continue;
+// [/RLVa:KB]
 					LLWearableList::instance().getAsset(item->getAssetUUID(),
 														item->getName(),
 														item->getType(),
@@ -4335,7 +4408,10 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_
 			for(i = 0; i  < obj_count; ++i)
 			{
 				LLViewerInventoryItem *obj_item = obj_item_array.get(i);
-				if (get_is_item_worn(obj_item->getUUID()))
+//				if (get_is_item_worn(obj_item->getUUID()))
+// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Modified: RLVa-1.0.5a
+				if ((get_is_item_worn(obj_item->getUUID())) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(obj_item))))
+// [/RVLa:KB]
 				{
 					LLVOAvatarSelf::detachAttachmentIntoInventory(obj_item->getLinkedUUID());
 				}
@@ -4493,6 +4569,12 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 					{
 						disabled_items.push_back(std::string("Wearable And Object Wear"));
 						disabled_items.push_back(std::string("Wearable Add"));
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0c) | Added: RLVa-1.2.0c
+						if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) )
+						{
+							disabled_items.push_back(std::string("Take Off"));
+						}
+// [/RLVa:KB]
 					}
 					else
 					{
@@ -4500,6 +4582,17 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 						items.push_back(std::string("Wearable Add"));
 						disabled_items.push_back(std::string("Take Off"));
 						disabled_items.push_back(std::string("Wearable Edit"));
+
+// [RLVa:KB] - Checked: 2010-06-09 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+						if (rlv_handler_t::isEnabled())
+						{
+							ERlvWearMask eWearMask = gRlvWearableLocks.canWear(item);
+							if ((eWearMask & RLV_WEAR_REPLACE) == 0)
+								disabled_items.push_back(std::string("Wearable Wear"));
+							if ((eWearMask & RLV_WEAR_ADD) == 0)
+								disabled_items.push_back(std::string("Wearable Add"));
+						}
+// [/RLVa:KB]
 					}
 					break;
 				default:
@@ -4675,6 +4768,15 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable,
 {
 	OnRemoveStruct *on_remove_struct = (OnRemoveStruct*) userdata;
 	const LLUUID &item_id = gInventory.getLinkedItemID(on_remove_struct->mUUID);
+
+// [RLVa:KB] - Checked: 2010-03-20 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+	if ( (rlv_handler_t::isEnabled()) && ((!wearable) || (!gRlvWearableLocks.canRemove(gInventory.getItem(item_id)))) )
+	{
+		delete on_remove_struct;
+		return;
+	}
+// [/RLVa:KB]
+
 	if(wearable)
 	{
 		if( get_is_item_worn( item_id ) )
@@ -4718,6 +4820,11 @@ void LLWearableBridge::removeAllClothesFromAvatar()
 			const LLWearable *wearable = gAgentWearables.getWearableFromItemID(item_id);
 			if (!wearable)
 				continue;
+
+// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+			if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) )
+				continue;
+// [/RLVa:KB]
 	
 			// Find and remove this item from the COF.
 			LLAppearanceMgr::instance().removeCOFItemLinks(item_id,false);
@@ -4726,7 +4833,10 @@ void LLWearableBridge::removeAllClothesFromAvatar()
 	gInventory.notifyObservers();
 
 	// Remove wearables from gAgentWearables
-	LLAgentWearables::userRemoveAllClothes();
+//	LLAgentWearables::userRemoveAllClothes();
+// [RLVa:KB] - Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+	LLAppearanceMgr::instance().updateAppearanceFromCOF();
+// [/RLVa:KB]
 }
 
 // static
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 53835f0166ebed6a4cb51644243d84661d3f8527..04f9ba731cb8db9cb52ea0cbf8f27a13062ceff6 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -46,6 +46,9 @@
 #include "llviewerregion.h"
 #include "llcallbacklist.h"
 #include "llvoavatarself.h"
+// [RLVa:KB] - Checked: RLVa-1.2.0a (2010-03-05)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //#define DIFF_INVENTORY_FILES
 #ifdef DIFF_INVENTORY_FILES
@@ -2442,6 +2445,14 @@ void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg,
 		llinfos << "LLInventoryModel::processSaveAssetIntoInventory item"
 			" not found: " << item_id << llendl;
 	}
+
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-0.2.0e
+	if (rlv_handler_t::isEnabled())
+	{
+		RlvAttachmentLockWatchdog::instance().onSavedAssetIntoInventory(item_id);
+	}
+// [/RLVa:KB]
+
 	if(gViewerWindow)
 	{
 		gViewerWindow->getWindow()->decBusyCount();
@@ -2492,6 +2503,20 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
 			{
 				if(tfolder->getParentUUID() == folderp->getParentUUID())
 				{
+// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+					// NOTE-RLVa: not sure if this is a hack or a bug-fix :o
+					//		-> if we rename the folder on the first BulkUpdateInventory message subsequent messages will still contain
+					//         the old folder name and gInventory.updateCategory() below will "undo" the folder name change but on the
+					//         viewer-side *only* so the folder name actually becomes out of sync with what's on the inventory server
+					//      -> so instead we keep the name of the existing folder and only do it for #RLV/~ in case this causes issues
+					//		-> a better solution would be to only do the rename *after* the transaction completes but there doesn't seem
+					//		   to be any way to accomplish that either *sighs*
+					if ( (rlv_handler_t::isEnabled()) && (!folderp->getName().empty()) && (tfolder->getName() != folderp->getName()) &&
+						 ((tfolder->getName().find(RLV_PUTINV_PREFIX) == 0)) )
+					{
+						tfolder->rename(folderp->getName());
+					}
+// [/RLVa:KB]
 					update[tfolder->getParentUUID()];
 				}
 				else
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index d714cae872de955a119a0c14f163170dd7204bc8..7126bcf28ab69ecb8a582867cc0bbd1e8964c0a0 100644
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -59,6 +59,9 @@
 #include "llviewermenu.h"
 #include "llurllineeditorctrl.h"
 #include "llagentui.h"
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //============================================================================
 /*
@@ -589,16 +592,31 @@ void LLLocationInputCtrl::reshape(S32 width, S32 height, BOOL called_from_parent
 
 void LLLocationInputCtrl::onInfoButtonClicked()
 {
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		return;
+// [/RLVa:KB]
+
 	LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "agent"));
 }
 
 void LLLocationInputCtrl::onForSaleButtonClicked()
 {
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		return;
+// [/RLVa:KB]
+
 	handle_buy_land();
 }
 
 void LLLocationInputCtrl::onAddLandmarkButtonClicked()
 {
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		return;
+// [/RLVa:KB]
+
 	LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
 	// Landmark exists, open it for preview and edit
 	if(landmark && landmark->getUUID().notNull())
@@ -715,6 +733,10 @@ void LLLocationInputCtrl::onTextEditorRightClicked(S32 x, S32 y, MASK mask)
 
 void LLLocationInputCtrl::refresh()
 {
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	mInfoBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+// [/RLVa:KB]
+
 	refreshLocation();			// update location string
 	refreshParcelIcons();
 	updateAddLandmarkButton();	// indicate whether current parcel has been landmarked 
@@ -986,6 +1008,9 @@ void LLLocationInputCtrl::enableAddLandmarkButton(bool val)
 // depending on whether current parcel has been landmarked.
 void LLLocationInputCtrl::updateAddLandmarkButton()
 {
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	mAddLandmarkBtn->setVisible(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+// [/RLVa:KB]
 	enableAddLandmarkButton(LLLandmarkActions::hasParcelLandmark());
 }
 void LLLocationInputCtrl::updateAddLandmarkTooltip()
@@ -1015,6 +1040,9 @@ void LLLocationInputCtrl::updateContextMenu(){
 		{
 			landmarkItem->setLabel(LLTrans::getString("EditLandmarkNavBarMenu"));
 		}
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+		landmarkItem->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
+// [/RLVa:KB]
 	}
 }
 void LLLocationInputCtrl::updateWidgetlayout()
@@ -1070,17 +1098,24 @@ void LLLocationInputCtrl::onLocationContextMenuItemClicked(const LLSD& userdata)
 	}
 	else if (item == "landmark")
 	{
-		LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
-		
-		if(!landmark)
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+		if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
 		{
-			LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark"));
-		}
-		else
-		{
-			LLSideTray::getInstance()->showPanel("panel_places", 
-					LLSD().with("type", "landmark").with("id",landmark->getUUID()));
+// [/RLVa:KB]
+			LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
+			
+			if(!landmark)
+			{
+				LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark"));
+			}
+			else
+			{
+				LLSideTray::getInstance()->showPanel("panel_places", 
+						LLSD().with("type", "landmark").with("id",landmark->getUUID()));
+			}
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
 		}
+// [/RLVa:KB]
 	}
 	else if (item == "cut")
 	{
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 5eb3b789f2656991e8bd7a92fd66b7970bb06f98..4dd90f07940d3a5b23c2478feb513cd35422dcbf 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -60,6 +60,9 @@
 #include "llworld.h"
 #include "llui.h"
 #include "pipeline.h"
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 const S32 NUM_AXES = 3;
 const S32 MOUSE_DRAG_SLOP = 2;       // pixels
diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp
index 3d0f4cc1ed40528d8d96987522f24b2ba9dcee42..e52ac79d3905280fca5ef2e128dad5b708124427 100644
--- a/indra/newview/llmoveview.cpp
+++ b/indra/newview/llmoveview.cpp
@@ -48,6 +48,9 @@
 #include "llviewerparcelmgr.h"
 #include "llviewerregion.h"
 #include "lltooltip.h"
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //
 // Constants
@@ -701,8 +704,15 @@ LLPanelStandStopFlying* LLPanelStandStopFlying::getStandStopFlyingPanel()
 
 void LLPanelStandStopFlying::onStandButtonClick()
 {
-	LLSelectMgr::getInstance()->deselectAllForStandingUp();
-	gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+	if ( (!rlv_handler_t::isEnabled()) || (gRlvHandler.canStand()) )
+	{
+		LLSelectMgr::getInstance()->deselectAllForStandingUp();
+		gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
+	}
+// [/RLVa:KB]
+//	LLSelectMgr::getInstance()->deselectAllForStandingUp();
+//	gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
 
 	setFocus(FALSE); // EXT-482
 	mStandButton->setVisible(FALSE); // force visibility changing to avoid seeing Stand & Move buttons at once.
diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp
index 4f9845d704297aeef8599bb2ffdbb91fe31d77a3..d343d9049be234fd02d3b846fa8ea8371cd2e509 100644
--- a/indra/newview/llnearbychatbar.cpp
+++ b/indra/newview/llnearbychatbar.cpp
@@ -46,11 +46,17 @@
 #include "llwindow.h"
 #include "llviewerwindow.h"
 #include "llrootview.h"
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 S32 LLNearbyChatBar::sLastSpecialChatChannel = 0;
 
 // legacy callback glue
-void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel);
+//void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel);
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-0.2.2a
+void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel);
+// [/RLVa:KB]
 
 static LLDefaultChildRegistry::Register<LLGestureComboList> r("gesture_combo_list");
 
@@ -495,7 +501,10 @@ void LLNearbyChatBar::onChatBoxKeystroke(LLLineEditor* caller, void* userdata)
 
 	S32 length = raw_text.length();
 
-	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
+//	if( (length > 0) && (raw_text[0] != '/') )  // forward slash is used for escape (eg. emote) sequences
+// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d
+	if ( (length > 0) && (raw_text[0] != '/') && (!gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT)) )
+// [/RLVa:KB]
 	{
 		gAgent.startTyping();
 	}
@@ -708,6 +717,21 @@ void LLNearbyChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type,
 		utf8_text = utf8str_truncate(utf8_text, MAX_STRING - 1);
 	}
 
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
+	if ( (0 == channel) && (rlv_handler_t::isEnabled()) )
+	{
+		// Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation)
+		if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) )
+			type = CHAT_TYPE_WHISPER;
+		else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) )
+			type = CHAT_TYPE_NORMAL;
+		else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) )
+			type = CHAT_TYPE_NORMAL;
+
+		animate &= !gRlvHandler.hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE );
+	}
+// [/RLVa:KB]
+
 	// Don't animate for chats people can't hear (chat to scripts)
 	if (animate && (channel == 0))
 	{
@@ -838,8 +862,57 @@ LLWString LLNearbyChatBar::stripChannelNumber(const LLWString &mesg, S32* channe
 	}
 }
 
-void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel)
+//void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel)
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-0.2.2a
+void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel)
+// [/RLVa:KB]
 {
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0a
+	// Only process chat messages (ie not CHAT_TYPE_START, CHAT_TYPE_STOP, etc)
+	if ( (rlv_handler_t::isEnabled()) && ( (CHAT_TYPE_WHISPER == type) || (CHAT_TYPE_NORMAL == type) || (CHAT_TYPE_SHOUT == type) ) )
+	{
+		if (0 == channel)
+		{
+			// (We already did this before, but LLChatHandler::handle() calls this directly)
+			if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) )
+				type = CHAT_TYPE_WHISPER;
+			else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) )
+				type = CHAT_TYPE_NORMAL;
+			else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) )
+				type = CHAT_TYPE_NORMAL;
+
+			// Redirect chat if needed
+			if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT) || (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE)) ) && 
+				 (gRlvHandler.redirectChatOrEmote(utf8_out_text)) ) )
+			{
+				return;
+			}
+
+			// Filter public chat if sendchat restricted
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHAT))
+				gRlvHandler.filterChat(utf8_out_text, true);
+		}
+		else
+		{
+			// Don't allow chat on a non-public channel if sendchannel restricted (unless the channel is an exception)
+			if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNEL)) && (!gRlvHandler.isException(RLV_BHVR_SENDCHANNEL, channel)) )
+				return;
+
+			// Don't allow chat on debug channel if @sendchat, @redirchat or @rediremote restricted (shows as public chat on viewers)
+			if (CHAT_CHANNEL_DEBUG == channel)
+			{
+				bool fIsEmote = RlvUtil::isEmote(utf8_out_text);
+				if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHAT)) || 
+					 ((!fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT))) || 
+					 ((fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE))) )
+				{
+					return;
+				}
+			}
+		}
+	}
+// [/RLVa:KB]
+
 	LLMessageSystem* msg = gMessageSystem;
 	msg->newMessageFast(_PREHASH_ChatFromViewer);
 	msg->nextBlockFast(_PREHASH_AgentData);
diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index a747c228a6683ea35bb23d8c78d89236ae598710..284b27d22d1d8781138bdde1560730e7e54a599e 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -40,6 +40,10 @@
 #include "llfloaterreg.h"//for LLFloaterReg::getTypedInstance
 #include "llviewerwindow.h"//for screen channel position
 
+// [RLVa:KB] - Checked: 2010-04-21 (RLVa-1.2.0f)
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 //add LLNearbyChatHandler to LLNotificationsUI namespace
 using namespace LLNotificationsUI;
 
@@ -340,7 +344,10 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
 {
 	if(chat_msg.mMuted == TRUE)
 		return;
-	if(chat_msg.mSourceType == CHAT_SOURCE_AGENT && chat_msg.mFromID.notNull())
+//	if(chat_msg.mSourceType == CHAT_SOURCE_AGENT && chat_msg.mFromID.notNull())
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	if ( (chat_msg.mSourceType == CHAT_SOURCE_AGENT && chat_msg.mFromID.notNull()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
+// [/RLVa:KB]
          LLRecentPeople::instance().add(chat_msg.mFromID);
 
 	if(chat_msg.mText.empty())
@@ -348,6 +355,23 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
 
 	LLChat& tmp_chat = const_cast<LLChat&>(chat_msg);
 
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+	if (rlv_handler_t::isEnabled())
+	{
+		// NOTE-RLVa: we can only filter the *message* here since most everything else will already be part of "args" as well
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (!tmp_chat.mRlvLocFiltered) && (CHAT_SOURCE_AGENT != tmp_chat.mSourceType) )
+		{
+			RlvUtil::filterLocation(tmp_chat.mText);
+			tmp_chat.mRlvLocFiltered = TRUE;
+		}
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!tmp_chat.mRlvNamesFiltered) && (CHAT_SOURCE_AGENT != tmp_chat.mSourceType) )
+		{
+			RlvUtil::filterNames(tmp_chat.mText);
+			tmp_chat.mRlvNamesFiltered = TRUE;
+		}
+	}
+// [/RLVa:KB]
+
 	LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
 	{
 		//sometimes its usefull to have no name at all...
@@ -434,6 +458,10 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
 		notification["source"] = (S32)chat_msg.mSourceType;
 		notification["chat_type"] = (S32)chat_msg.mChatType;
 		notification["chat_style"] = (S32)chat_msg.mChatStyle;
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+		if (rlv_handler_t::isEnabled())
+			notification["show_icon_tooltip"] = !chat_msg.mRlvNamesFiltered;
+// [/RLVa:KB]
 		
 		std::string r_color_name = "White";
 		F32 r_color_alpha = 1.0f; 
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 6db8001d57a1d8130d3c414ebbebc8aabeace7e9..36b7e2c07639d0b8841d4e2f3bf12f842b9e438d 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -58,6 +58,9 @@
 #include "llviewerwindow.h"
 #include "llworld.h"
 #include "llworldmapview.h"		// shared draw code
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 static LLDefaultChildRegistry::Register<LLNetMap> r1("net_map");
 
@@ -354,7 +357,11 @@ void LLNetMap::draw()
 				BOOL show_as_friend = FALSE;
 				if( i < regionp->mMapAvatarIDs.count())
 				{
-					show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL);
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+					show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL) &&
+						(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES));
+// [/RLVa:KB]
+//					show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL);
 				}
 				LLWorldMapView::drawAvatar(
 					pos_map.mV[VX], pos_map.mV[VY], 
@@ -568,35 +575,57 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )
 		return FALSE;
 	}
 
+	LLStringUtil::format_map_t args;
 	std::string avatar_name;
 	if(mClosestAgentToCursor.notNull() && gCacheName->getFullName(mClosestAgentToCursor, avatar_name))
 	{
-		// only show tooltip if same inspector not already open
-		LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar");
-		if (!existing_inspector 
-			|| !existing_inspector->getVisible()
-			|| existing_inspector->getKey()["avatar_id"].asUUID() != mClosestAgentToCursor)
+// [RLVa:KB] - Checked: 2010-08-08 (RLVa-1.2.0h) | Added: RLVa-1.2.0h | RLVa-1.2.0-final
+		if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
 		{
-			LLInspector::Params p;
-			p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
-			p.message(avatar_name);
-			p.image.name("Inspector_I");
-			p.click_callback(boost::bind(showAvatarInspector, mClosestAgentToCursor));
-			p.visible_time_near(6.f);
-			p.visible_time_far(3.f);
-			p.delay_time(0.35f);
-			p.wrap(false);
-
-			LLToolTipMgr::instance().show(p);
+// [/RLVa:KB]
+			// only show tooltip if same inspector not already open
+			LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar");
+			if (!existing_inspector 
+				|| !existing_inspector->getVisible()
+				|| existing_inspector->getKey()["avatar_id"].asUUID() != mClosestAgentToCursor)
+			{
+				LLInspector::Params p;
+				p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
+				p.message(avatar_name);
+				p.image.name("Inspector_I");
+				p.click_callback(boost::bind(showAvatarInspector, mClosestAgentToCursor));
+				p.visible_time_near(6.f);
+				p.visible_time_far(3.f);
+				p.delay_time(0.35f);
+				p.wrap(false);
+
+				LLToolTipMgr::instance().show(p);
+			}
+			return TRUE;
+// [RLVa:KB] - Checked: 2010-08-08 (RLVa-1.2.0h) | Added: RLVa-1.2.0h | RLVa-1.2.0-final
 		}
-		return TRUE;
+		else
+		{
+			args["[AGENT]"] = RlvStrings::getAnonym(avatar_name) + "\n";
+		}
+// [/RLVa:KB]
+ 	}
+// [RLVa:KB] - Checked: 2010-08-08 (RLVa-1.2.0h) | Added: RLVa-1.2.0h | RLVa-1.2.0-final
+	else
+	{
+		args["[AGENT]"] = "";
 	}
+// [/RLVa:KB]
 
-	LLStringUtil::format_map_t args;
+//	LLStringUtil::format_map_t args;
 	LLViewerRegion*	region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) );
 	if( region )
 	{
-		args["[REGION]"] = region->getName() + "\n";
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+		args["[REGION]"] = 
+			((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? region->getName() : RlvStrings::getString(RLV_STRING_HIDDEN_REGION)) + "\n";
+// [/RLVa:KB]
+//		args["[REGION]"] = region->getName() + "\n";
 	}
 	else
 	{
diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp
index 85f95bd0c718ef0a2f395e6df1ca24d4e9210bed..be9ff2813224dd68b1e653895048e3e3e65c5116 100644
--- a/indra/newview/llnotificationofferhandler.cpp
+++ b/indra/newview/llnotificationofferhandler.cpp
@@ -100,7 +100,13 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
 			notification->setReusable(LLHandlerUtil::isNotificationReusable(notification));
 
 			LLUUID session_id;
-			if (LLHandlerUtil::canSpawnIMSession(notification))
+//			if (LLHandlerUtil::canSpawnIMSession(notification))
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+			// Don't spawn a new IM session for inventory offers if this notification was subject to @shownames=n
+			// RELEASE-RLVa: [SL-2.0.1] Test on every new release to make sure the notification gets routed the way we want it to be
+			bool fSpawnIM = (LLHandlerUtil::canSpawnIMSession(notification)) && (!notification->getPayload().has("rlv_shownames"));
+			if (fSpawnIM)
+// [/RLVa:KB]
 			{
 				const std::string name = LLHandlerUtil::getSubstitutionName(notification);
 
@@ -110,7 +116,12 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
 			}
 
 			bool show_toast = LLHandlerUtil::canSpawnToast(notification);
-			bool add_notid_to_im = LLHandlerUtil::canAddNotifPanelToIM(notification);
+//			bool add_notid_to_im = LLHandlerUtil::canAddNotifPanelToIM(notification);
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+			// NOTE: add_notid_to_im needs to be FALSE if we suppressed spawning an IM because in that case the notification needs to
+			//       be routed to the "syswell" or the inventory offer floater will dissapear and the user won't be able to accept it
+			bool add_notid_to_im = (fSpawnIM) && (LLHandlerUtil::canAddNotifPanelToIM(notification));
+// [/RLVa:KB]
 			if (add_notid_to_im)
 			{
 				LLHandlerUtil::addNotifPanelToIM(notification);
@@ -149,7 +160,15 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
 			if (LLHandlerUtil::canLogToIM(notification))
 			{
 				// log only to file if notif panel can be embedded to IM and IM is opened
-				if (add_notid_to_im && LLHandlerUtil::isIMFloaterOpened(notification))
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+				if (notification->getPayload().has("rlv_shownames"))
+				{
+					// Log to chat history if this notification was subject to @shownames=n
+					LLHandlerUtil::logToNearbyChat(notification, CHAT_SOURCE_SYSTEM);
+				}
+				else if (add_notid_to_im && LLHandlerUtil::isIMFloaterOpened(notification))
+// [/RLVa:KB]
+//				if (add_notid_to_im && LLHandlerUtil::isIMFloaterOpened(notification))
 				{
 					LLHandlerUtil::logToIMP2P(notification, true);
 				}
@@ -170,8 +189,25 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
 		}
 		else
 		{
-			if (LLHandlerUtil::canAddNotifPanelToIM(notification)
-					&& !LLHandlerUtil::isIMFloaterOpened(notification))
+//			if (LLHandlerUtil::canAddNotifPanelToIM(notification)
+//					&& !LLHandlerUtil::isIMFloaterOpened(notification))
+// [SL:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+			// Repro:
+			//   1) have someone drop you 2 inventory items (new IM session will be spawned)
+			//   2) accept/decline the inventory offers as they come in
+			//		-> unread IM counter shows 0
+			//   3) toggle "Enable plain text chat history" while the IM session with the inventory offers isn't the active session
+			//		-> unread IM counter shows -2
+			//		-> LLHandlerUtil::decIMMesageCounter() really should be fixed to check for "0" before decreasing the count but
+			//         there are enough bugfixes in RLVa as it is already :(
+			// Fix:
+			//   - the one and only time we need to decrease the unread IM count is when we've clicked any of the buttons on the *toast*
+			//   - since LLIMFloater::updateMessages() hides the toast when we open the IM (which resets the unread count to 0) we should 
+			//     *only* decrease the unread IM count if there's a visible toast since the unread count will be at 0 otherwise anyway
+			LLScreenChannel* pChannel = dynamic_cast<LLScreenChannel*>(mChannel);
+			LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification->getID()) : NULL;
+			if ( (pToast) && (!pToast->getCanBeStored()) )
+// [/SL:KB]
 			{
 				LLHandlerUtil::decIMMesageCounter(notification);
 			}
@@ -186,7 +222,11 @@ bool LLOfferHandler::processNotification(const LLSD& notify)
 
 void LLOfferHandler::onDeleteToast(LLToast* toast)
 {
-	if (!LLHandlerUtil::canAddNotifPanelToIM(toast->getNotification()))
+//	if (!LLHandlerUtil::canAddNotifPanelToIM(toast->getNotification()))
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	// BUGFIX: LLHandlerUtil::canAddNotifPanelToIM() won't necessarily tell us whether the notification went into an IM or to the syswell
+	if (toast->getCanBeStored())
+// [/RLVa:KB]
 	{
 		// send a signal to the counter manager
 		mDelNotificationSignal();
diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp
index c2bbec04700ed77ec65745199c7d76c6cb9033d9..f79ec6432d1920d51cd92640133f0d0c50cdf359 100644
--- a/indra/newview/lloverlaybar.cpp
+++ b/indra/newview/lloverlaybar.cpp
@@ -297,6 +297,13 @@ void LLOverlayBar::onClickMouselook(void*)
 //static
 void LLOverlayBar::onClickStandUp(void*)
 {
+// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g)
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (gAgent.getAvatarObject()) && (gAgent.getAvatarObject()->mIsSitting) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	LLSelectMgr::getInstance()->deselectAllForStandingUp();
 	gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
 }
diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp
index bf3bf38863e8f95c7ec80fcc18235999101baac0..31f60bee9cd376649a3d2b6aca9093b5383dd7fe 100644
--- a/indra/newview/llpanelcontents.cpp
+++ b/indra/newview/llpanelcontents.cpp
@@ -59,6 +59,9 @@
 #include "llviewerregion.h"
 #include "llviewerwindow.h"
 #include "llworld.h"
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //
 // Imported globals
@@ -120,6 +123,25 @@ void LLPanelContents::getState(LLViewerObject *objectp )
 					       && ( objectp->permYouOwner() || ( !group_id.isNull() && gAgent.isInGroup(group_id) )));  // solves SL-23488
 	BOOL all_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME );
 
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a
+	if ( (rlv_handler_t::isEnabled()) && (editable) )
+	{
+		// Don't allow creation of new scripts if it's non-detachable
+		if (objectp->isAttachment())
+			editable = !gRlvAttachmentLocks.isLockedAttachment(objectp->getRootEdit());
+
+		// Don't allow creation of new scripts if we're @unsit=n or @sittp=n restricted and we're sitting on the selection
+		if ( (editable) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) )
+		{
+			// Only check the first (non-)root object because nothing else would result in enabling the button (see below)
+			LLViewerObject* pObj = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(TRUE);
+
+			editable = (pObj) && (isAgentAvatarValid()) && 
+				((!gAgentAvatarp->isSitting()) || (gAgentAvatarp->getRoot() != pObj->getRootEdit()));
+		}
+	}
+// [/RLVa:KB]
+
 	// Edit script button - ok if object is editable and there's an unambiguous destination for the object.
 	getChildView("button new script")->setEnabled(
 		editable &&
@@ -154,6 +176,22 @@ void LLPanelContents::onClickNewScript(void *userdata)
 	LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(children_ok);
 	if(object)
 	{
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a
+		if (rlv_handler_t::isEnabled())	// Fallback code [see LLPanelContents::getState()]
+		{
+			const LLViewerObject* pObjRoot = object->getRootEdit();
+			if (gRlvAttachmentLocks.isLockedAttachment(pObjRoot))
+			{
+				return;					// Disallow creating new scripts in a locked attachment
+			}
+			else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) )
+			{
+				if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == pObjRoot) )
+					return;				// .. or in a linkset the avie is sitting on under @unsit=n/@sittp=n
+			}
+		}
+// [/RLVa:KB]
+
 		LLPermissions perm;
 		perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
 		perm.initMasks(
diff --git a/indra/newview/llpanelland.cpp b/indra/newview/llpanelland.cpp
index 04c1a86f69fd73fee2dfc166aba0e7ea25ab45b2..70ea2905000b05eb99a1a0db6ba7d6592222bcbb 100644
--- a/indra/newview/llpanelland.cpp
+++ b/indra/newview/llpanelland.cpp
@@ -44,6 +44,10 @@
 
 #include "lluictrlfactory.h"
 
+// [RLVa:KB]
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 LLPanelLandSelectObserver* LLPanelLandInfo::sObserver = NULL;
 LLPanelLandInfo* LLPanelLandInfo::sInstance = NULL;
 
@@ -224,6 +228,14 @@ void LLPanelLandInfo::refresh()
 //static
 void LLPanelLandInfo::onClickClaim()
 {
+// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
+/*
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+	{
+		return;
+	}
+*/
+// [/RLVa:KB]
 	LLViewerParcelMgr::getInstance()->startBuyLand();
 }
 
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index d756a1b931abd4f508728ee86b7055b36d2bb4cb..5d80f9fcc87eaff2853c9a98ffa52d2a0f000165 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -68,6 +68,9 @@
 #include "llviewercontrol.h"
 #include "lluictrlfactory.h"
 //#include "llfirstuse.h"
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #include "lldrawpool.h"
 
@@ -383,6 +386,14 @@ void LLPanelObject::getState( )
 		enable_rotate = FALSE;
 	}
 
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g
+	if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) )
+	{
+		if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == objectp->getRootEdit()) )
+			enable_move = enable_scale = enable_rotate = FALSE;
+	}
+// [/RLVa:KB]
+
 	LLVector3 vec;
 	if (enable_move)
 	{
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index 211b9cf4b1a281fa23089b9386b1825daba8a6b1..c801ac5cfbf23608b23ab510b4a750cca1eda26a 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -63,7 +63,10 @@
 #include "llviewerregion.h"
 #include "llviewerobjectlist.h"
 #include "llviewermessage.h"
-
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b)
+#include "rlvhandler.h"
+#include "rlvui.h"
+// [/RLVa:KB]
 
 ///----------------------------------------------------------------------------
 /// Class LLTaskInvFVBridge
@@ -398,12 +401,45 @@ BOOL LLTaskInvFVBridge::isItemMovable() const
 	//	return TRUE;
 	//}
 	//return FALSE;
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a
+	if (rlv_handler_t::isEnabled())
+	{
+		const LLViewerObject* pObj = gObjectList.findObject(mPanel->getTaskUUID());
+		if (pObj)
+		{
+			if (gRlvAttachmentLocks.isLockedAttachment(pObj))
+			{
+				return FALSE;
+			}
+			else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) )
+			{
+				if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == pObj->getRootEdit()) )
+					return FALSE;
+			}
+		}
+	}
+// [/RLVa:KB]
 	return TRUE;
 }
 
 BOOL LLTaskInvFVBridge::isItemRemovable() const
 {
 	const LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID());
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.5a
+	if ( (object) && (rlv_handler_t::isEnabled()) )
+	{
+		if (gRlvAttachmentLocks.isLockedAttachment(object))
+		{
+			return FALSE;
+		}
+		else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) )
+		{
+			if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit()) )
+				return FALSE;
+		}
+	}
+// [/RLVa:KB]
+
 	if(object
 	   && (object->permModify() || object->permYouOwner()))
 	{
@@ -669,6 +705,19 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 		{
 			disabled_items.push_back(std::string("Task Open"));
 		}
+// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a
+		else if (rlv_handler_t::isEnabled())
+		{
+			LLViewerObject* pAttachObj = gObjectList.findObject(mPanel->getTaskUUID());
+			bool fLocked = (pAttachObj) ? gRlvAttachmentLocks.isLockedAttachment(pAttachObj->getRootEdit()) : false;
+			if ( ((LLAssetType::AT_NOTECARD == item->getType()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) || (fLocked))) || 
+				 ((LLAssetType::AT_LSL_TEXT == item->getType()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) || (fLocked))) ||
+				 ((LLAssetType::AT_TEXTURE == item->getType()) && (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE))) )
+			{
+				disabled_items.push_back(std::string("Task Open"));
+			}
+		}
+// [/RLVa:KB]
 	}
 	items.push_back(std::string("Task Properties"));
 	if(isItemRenameable())
@@ -1070,6 +1119,15 @@ void LLTaskLSLBridge::openItem()
 	{
 		return;
 	}
+
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a
+	if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) )
+	{
+		RlvUIEnabler::notifyBlockedViewXXX(LLAssetType::AT_SCRIPT);
+		return;
+	}
+// [/RLVa:KB]
+
 	if (object->permModify() || gAgent.isGodlike())
 	{
 		LLLiveLSLEditor* preview = LLFloaterReg::showTypedInstance<LLLiveLSLEditor>("preview_scriptedit", LLSD(mUUID), TAKE_FOCUS_YES);
@@ -1128,6 +1186,13 @@ void LLTaskNotecardBridge::openItem()
 	{
 		return;
 	}
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
+	if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) )
+	{
+		RlvUIEnabler::notifyBlockedViewXXX(LLAssetType::AT_NOTECARD);
+		return;
+	}
+// [/RLVa:KB]
 	if(object->permModify() || gAgent.isGodlike())
 	{
 		LLPreviewNotecard* preview = LLFloaterReg::showTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(mUUID), TAKE_FOCUS_YES);
diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h
index f1ca1dbfeb20b48787dfcda47a96b82fd331ecc6..a6443c4dca75d0665e974ee0fd4cdf3801012cfd 100644
--- a/indra/newview/llpaneloutfitsinventory.h
+++ b/indra/newview/llpaneloutfitsinventory.h
@@ -56,6 +56,12 @@ public:
 
 	static LLSidepanelAppearance* getAppearanceSP();
 
+// [RLVa:KB] - Checked: 2010-08-24 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	LLTabContainer* getAppearanceTabs()		{ return mAppearanceTabs; }
+	LLOutfitsList*  getMyOutfitsPanel()		{ return mMyOutfitsPanel; }
+	LLPanelWearing* getCurrentOutfitPanel()	{ return mCurrentOutfitPanel; }
+// [/RLVa:KB]
+
 	static LLPanelOutfitsInventory* findInstance();
 
 protected:
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 06ba08b51c9ca4b90a8cca81a50aa767552e2ba7..c813ec8bc8f3db64776c3feb4ff2af8520201e50 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -60,6 +60,9 @@
 #include "llvoiceclient.h"
 #include "llworld.h"
 #include "llspeakers.h"
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #define FRIEND_LIST_UPDATE_TIMEOUT	0.5
 #define NEARBY_LIST_UPDATE_INTERVAL 1
@@ -532,6 +535,9 @@ BOOL LLPanelPeople::postBuild()
 	mNearbyList->setNoItemsMsg(getString("no_one_near"));
 	mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near"));
 	mNearbyList->setShowIcons("NearbyListShowIcons");
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	mNearbyList->setRlvCheckShowNames(true);
+// [/RLVa:KB]
 
 	mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
 	mRecentList->setNoItemsCommentText(getString("no_recent_people"));
@@ -827,7 +833,11 @@ void LLPanelPeople::updateButtons()
 		LLPanel* cur_panel = mTabContainer->getCurrentPanel();
 		if (cur_panel)
 		{
-			cur_panel->getChildView("add_friend_btn")->setEnabled(!is_friend);
+//			cur_panel->getChildView("add_friend_btn")->setEnabled(!is_friend);
+// [RLVa:KB] - Checked: 2010-07-20 (RLVa-1.2.0h) | Added: RLVa-1.2.0h
+			cur_panel->getChildView("add_friend_btn")->setEnabled(
+				!is_friend && ((!nearby_tab_active) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))));
+// [/RLBa:KB]
 			if (friends_tab_active)
 			{
 				cur_panel->getChildView("del_btn")->setEnabled(multiple_selected);
@@ -837,6 +847,13 @@ void LLPanelPeople::updateButtons()
 
 	bool enable_calls = LLVoiceClient::getInstance()->isVoiceWorking() && LLVoiceClient::getInstance()->voiceEnabled();
 
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+	if ( (nearby_tab_active) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
+	{
+		item_selected = multiple_selected = false;
+	}
+// [/RLBa:KB]
+
 	buttonSetEnabled("view_profile_btn",item_selected);
 	buttonSetEnabled("share_btn",		item_selected);
 	buttonSetEnabled("im_btn",			multiple_selected); // allow starting the friends conference for multiple selection
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index d0913ee756c7740bfc0b5a8a39951534791462d5..794909f8fb79783d4362011fcdaf2c33ddcba656 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -53,6 +53,10 @@ public:
 	// when voice is available
 	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
 
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+	LLAvatarList* getNearbyList() { return mNearbyList; }
+// [/RLVa:KB]
+
 	// internals
 	class Updater;
 
diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp
index e35574be6cadf6dbe9ef8537822fe53d2e1d8519..839bd3044521666f8d74649b5b946152c4123292 100644
--- a/indra/newview/llpanelpermissions.cpp
+++ b/indra/newview/llpanelpermissions.cpp
@@ -62,7 +62,9 @@
 #include "llspinctrl.h"
 #include "roles_constants.h"
 #include "llgroupactions.h"
-
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 U8 string_value_to_click_action(std::string p_value);
 std::string click_action_to_string_value( U8 action);
@@ -329,8 +331,9 @@ void LLPanelPermissions::refresh()
 	creators_identical = LLSelectMgr::getInstance()->selectGetCreator(mCreatorID,
 																	  creator_name);
 
-	getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
-	getChildView("Creator Name")->setEnabled(TRUE);
+//	getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
+//	getChildView("Creator Name")->setEnabled(TRUE);
+// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row
 
 	// Update owner text field
 	getChildView("Owner:")->setEnabled(TRUE);
@@ -358,8 +361,28 @@ void LLPanelPermissions::refresh()
 			}
 		}
 	}
+//	getChild<LLUICtrl>("Owner Name")->setValue(owner_name);
+//	getChildView("Owner Name")->setEnabled(TRUE);
+// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row
+
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.2.1b
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+	{
+		// Only anonimize the creator if all of the selection was created by the same avie who's also the owner or they're a nearby avie
+		if ( (creators_identical) && ((mCreatorID == mOwnerID) || (RlvUtil::isNearbyAgent(mCreatorID))) )
+			creator_name = RlvStrings::getAnonym(creator_name);
+
+		// Only anonimize the owner name if all of the selection is owned by the same avie and isn't group owned
+		if ( (owners_identical) && (!LLSelectMgr::getInstance()->selectIsGroupOwned()) )
+			owner_name = RlvStrings::getAnonym(owner_name);
+	}
+
+	getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
+	getChildView("Creator Name")->setEnabled(TRUE);
+
 	getChild<LLUICtrl>("Owner Name")->setValue(owner_name);
 	getChildView("Owner Name")->setEnabled(TRUE);
+// [/RLVa:KB]
 
 	// update group text field
 	getChildView("Group:")->setEnabled(TRUE);
diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h
index 0546c1858337300983bf31ad65aa86e3a7530ccf..f7a005be6a2daef480424c5e0c4f88a168f7fcc0 100644
--- a/indra/newview/llpanelprofile.h
+++ b/indra/newview/llpanelprofile.h
@@ -53,6 +53,10 @@ public:
 
 	S32 notifyParent(const LLSD& info);
 
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RVLa-1.2.0f
+	const LLUUID& getAvatarId() const { return mAvatarId; }
+// [/RLVa:KB]
+
 protected:
 
 	LLPanelProfile();
@@ -63,7 +67,7 @@ protected:
 
 	LLTabContainer* getTabCtrl() { return mTabCtrl; }
 
-	const LLUUID& getAvatarId() { return mAvatarId; }
+//	const LLUUID& getAvatarId() { return mAvatarId; }
 
 	void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; }
 
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index d280cf162541e59728bef11446f246dae24f68a0..e36f151d18633824127415737f13ed0dcfd8759b 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -2116,6 +2116,16 @@ void LLLiveLSLEditor::onLoad(void* userdata)
 void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)
 {
 	LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
+
+// [RLVa:KB] - Checked: 2009-10-10 (RLVa-1.0.5a) | Modified: RLVa-1.0.5a
+/*
+	if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.isLockedAttachment(gObjectList.findObject(self->mObjectID), RLV_LOCK_REMOVE)) )
+	{
+		return;
+	}
+*/
+// [/RLVa:KB]
+
 	self->mCloseAfterSave = close_after_save;
 	self->saveIfNeeded();
 }
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index 5c923a040950a02199f674e8ec36f914d9d62800..f18db49d0336fba66f52772c233f68c6d697dd90 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -882,8 +882,18 @@ LLToast* LLScreenChannel::getToastByNotificationID(LLUUID id)
 	std::vector<ToastElem>::iterator it = find(mStoredToastList.begin(),
 			mStoredToastList.end(), id);
 
+//	if (it == mStoredToastList.end())
+//		return NULL;
+// [SL:KB] - Checked: 2010-04-21 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+	// BUGFIX-SL: we need to get the visible toast in LLOfferHandler::processNotification() whether it's "stored" or not 
 	if (it == mStoredToastList.end())
-		return NULL;
+	{
+		// If we can't find it among the stored toasts then widen it to "all visible toasts"
+		it = find(mToastList.begin(), mToastList.end(), id);
+		if (it == mToastList.end())
+			return NULL;
+	}
+// [/SL:KB]
 
 	return it->toast;
 }
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index c9b60bf7f5e213920884db082ffe355ed93393ee..1ed93c7ca2f5bf832e1d1f8a4ae65bf5bb4bad48 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -87,6 +87,9 @@
 #include "llvoavatarself.h"
 #include "llvovolume.h"
 #include "pipeline.h"
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #include "llglheaders.h"
 
@@ -2736,6 +2739,16 @@ BOOL LLSelectMgr::selectGetPermissions(LLPermissions& result_perm)
 
 void LLSelectMgr::selectDelete()
 {
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Added: RLVa-1.2.0a
+	if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) )
+	{
+		make_ui_sound("UISndInvalidOp");
+		if (!gFloaterTools->getVisible())
+			deselectAll();
+		return;
+	}
+// [/RLVa:KB]
+
 	S32 deleteable_count = 0;
 
 	BOOL locked_but_deleteable_object = FALSE;
@@ -3048,7 +3061,10 @@ struct LLDuplicateData
 
 void LLSelectMgr::selectDuplicate(const LLVector3& offset, BOOL select_copy)
 {
-	if (mSelectedObjects->isAttachment())
+//	if (mSelectedObjects->isAttachment())
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Added: RLVa-1.2.0a
+	if ( (mSelectedObjects->isAttachment()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) )
+// [/RLVa:KB]
 	{
 		//RN: do not duplicate attachments
 		make_ui_sound("UISndInvalidOp");
@@ -3502,11 +3518,38 @@ void LLSelectMgr::convertTransient()
 
 void LLSelectMgr::deselectAllIfTooFar()
 {
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!mSelectedObjects->isEmpty()) )
+	{
+		struct NotTransientOrFocusedMedia : public LLSelectedNodeFunctor
+		{
+			bool apply(LLSelectNode* node)
+			{
+				return (node) && (node->getObject()) && 
+					( (!node->isTransient()) && (node->getObject()->getID() != LLViewerMediaFocus::getInstance()->getFocusedObjectID()) );
+			}
+		} f;
+		if (mSelectedObjects->getFirstRootNode(&f, TRUE))
+			deselectAll();
+	}
+// [/RLVa:KB]
+
 	if (mSelectedObjects->isEmpty() || mSelectedObjects->mSelectType == SELECT_TYPE_HUD)
 	{
 		return;
 	}
 
+// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Modified: RLVa-1.1.0l
+#ifdef RLV_EXTENSION_CMD_INTERACT
+	// [Fall-back code] Don't allow an active selection (except for HUD attachments - see above) when @interact=n restricted
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))
+	{
+		deselectAll();
+		return;
+	}
+#endif // RLV_EXTENSION_CMD_INTERACT
+// [/RLVa:KB]
+
 	// HACK: Don't deselect when we're navigating to rate an object's
 	// owner or creator.  JC
 	if (gMenuObject->getVisible())
@@ -3515,13 +3558,20 @@ void LLSelectMgr::deselectAllIfTooFar()
 	}
 
 	LLVector3d selectionCenter = getSelectionCenterGlobal();
-	if (gSavedSettings.getBOOL("LimitSelectDistance")
+//	if (gSavedSettings.getBOOL("LimitSelectDistance")
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f
+	BOOL fRlvFartouch = gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH) && gFloaterTools->getVisible();
+	if ( (gSavedSettings.getBOOL("LimitSelectDistance") || (fRlvFartouch) )
+// [/RLVa:KB]
 		&& (!mSelectedObjects->getPrimaryObject() || !mSelectedObjects->getPrimaryObject()->isAvatar())
 		&& (mSelectedObjects->getPrimaryObject() != LLViewerMediaFocus::getInstance()->getFocusedObject())
 		&& !mSelectedObjects->isAttachment()
 		&& !selectionCenter.isExactlyZero())
 	{
-		F32 deselect_dist = gSavedSettings.getF32("MaxSelectDistance");
+//		F32 deselect_dist = gSavedSettings.getF32("MaxSelectDistance");
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f
+		F32 deselect_dist = (!fRlvFartouch) ? gSavedSettings.getF32("MaxSelectDistance") : 1.5f;
+// [/RLVa:KB]
 		F32 deselect_dist_sq = deselect_dist * deselect_dist;
 
 		LLVector3d select_delta = gAgent.getPositionGlobal() - selectionCenter;
@@ -5798,7 +5848,10 @@ BOOL LLSelectMgr::canDoDelete() const
 			can_delete = true;
 		}
 	}
-	
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Added: RLVa-1.2.0a
+	can_delete &= (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn());
+// [/RLVa:KB]
+
 	return can_delete;
 }
 
@@ -5830,7 +5883,12 @@ void LLSelectMgr::deselect()
 //-----------------------------------------------------------------------------
 BOOL LLSelectMgr::canDuplicate() const
 {
-	return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL; // HACK: casting away constness - MG
+//	return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL; // HACK: casting away constness - MG
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Added: RLVa-1.2.0a
+	return 
+		(const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL) &&
+		( (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn()) );
+// [/RLVa:KB]
 }
 //-----------------------------------------------------------------------------
 // duplicate()
diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index 731079fb5d6fc6a45c2e503e706903111f273ce9..33d61216322ac5b51f4a276639dcc343e4122757 100644
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -42,7 +42,9 @@
 #include "llviewercontrol.h"
 #include "llviewerinventory.h"
 #include "llviewerobjectlist.h"
-
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLItemPropertiesObserver
@@ -280,6 +282,16 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 		getChildView("BtnCreator")->setEnabled(TRUE);
 		getChildView("LabelCreatorTitle")->setEnabled(TRUE);
 		getChildView("LabelCreatorName")->setEnabled(TRUE);
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e
+		// If the object creator matches the object owner we need to anonimize the creator field as well
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && 
+			( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == item->getCreatorUUID()) ) ||
+			  (RlvUtil::isNearbyAgent(item->getCreatorUUID())) ) )
+		{
+			childSetEnabled("BtnCreator", FALSE);
+			name = RlvStrings::getAnonym(name);
+		}
+// [/RLVa:KB]
 		getChild<LLUICtrl>("LabelCreatorName")->setValue(name);
 	}
 	else
@@ -303,8 +315,15 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 		else
 		{
 			gCacheName->getFullName(perm.getOwner(), name);
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+				name = RlvStrings::getAnonym(name);
+// [/RLVa:KB]
 		}
-		getChildView("BtnOwner")->setEnabled(TRUE);
+//		getChildView("BtnOwner")->setEnabled(TRUE);
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.0.0e
+		getChildView("BtnOwner")->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES));
+// [/RLVa:KB]
 		getChildView("LabelOwnerTitle")->setEnabled(TRUE);
 		getChildView("LabelOwnerName")->setEnabled(TRUE);
 		getChild<LLUICtrl>("LabelOwnerName")->setValue(name);
@@ -606,6 +625,17 @@ void LLSidepanelItemInfo::onClickCreator()
 	if(!item) return;
 	if(!item->getCreatorUUID().isNull())
 	{
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+		{
+			const LLPermissions& perm = item->getPermissions();
+			if ( ((perm.isOwned()) && (!perm.isGroupOwned()) && (perm.getOwner() == item->getCreatorUUID()) ) ||
+			     (RlvUtil::isNearbyAgent(item->getCreatorUUID())) )
+			{
+				return;
+			}
+		}
+// [/RLVa:KB]
 		LLAvatarActions::showProfile(item->getCreatorUUID());
 	}
 }
@@ -621,6 +651,10 @@ void LLSidepanelItemInfo::onClickOwner()
 	}
 	else
 	{
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Modified: RLVa-1.0.0e
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+			return;
+// [/RLVa:KB]
 		LLAvatarActions::showProfile(item->getPermissions().getOwner());
 	}
 }
diff --git a/indra/newview/llsidepaneltaskinfo.cpp b/indra/newview/llsidepaneltaskinfo.cpp
index 4552088cadfee9a602d180898175bb7c8f0f705a..2b46c0fbef3030876e053291a000f8789638d575 100644
--- a/indra/newview/llsidepaneltaskinfo.cpp
+++ b/indra/newview/llsidepaneltaskinfo.cpp
@@ -61,6 +61,9 @@
 #include "llspinctrl.h"
 #include "roles_constants.h"
 #include "llgroupactions.h"
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 ///----------------------------------------------------------------------------
 /// Class llsidepaneltaskinfo
@@ -295,8 +298,9 @@ void LLSidepanelTaskInfo::refresh()
 	creators_identical = LLSelectMgr::getInstance()->selectGetCreator(mCreatorID,
 																	  creator_name);
 
-	getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
-	getChildView("Creator Name")->setEnabled(TRUE);
+//	getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
+//	getChildView("Creator Name")->setEnabled(TRUE);
+// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row
 
 	// Update owner text field
 	getChildView("Owner:")->setEnabled(TRUE);
@@ -324,8 +328,28 @@ void LLSidepanelTaskInfo::refresh()
 			}
 		}
 	}
+//	getChild<LLUICtrl>("Owner Name")->setValue(owner_name);
+//	getChildView("Owner Name")->setEnabled(TRUE);
+// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row
+
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+	{
+		// Only anonimize the creator if all of the selection was created by the same avie who's also the owner or they're a nearby avie
+		if ( (creators_identical) && ((mCreatorID == mOwnerID) || (RlvUtil::isNearbyAgent(mCreatorID))) )
+			creator_name = RlvStrings::getAnonym(creator_name);
+
+		// Only anonimize the owner name if all of the selection is owned by the same avie and isn't group owned
+		if ( (owners_identical) && (!LLSelectMgr::getInstance()->selectIsGroupOwned()) )
+			owner_name = RlvStrings::getAnonym(owner_name);
+	}
+
+	getChild<LLUICtrl>("Creator Name")->setValue(creator_name);
+	getChildView("Creator Name")->setEnabled(TRUE);
+
 	getChild<LLUICtrl>("Owner Name")->setValue(owner_name);
 	getChildView("Owner Name")->setEnabled(TRUE);
+// [/RLVa:KB]
 
 	// update group text field
 	getChildView("Group:")->setEnabled(TRUE);
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index 85b6e0dec45d378a27fc17a53ee745a9097eba12..9fe006ae29ac173cdb9b280f719c0f3d8b7f559e 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -502,6 +502,11 @@ bool LLSideTray::selectTabByName	(const std::string& name)
 	if (new_tab == mActiveTab)
 		return false;
 
+// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+	if ( (mValidateSignal) && (!(*mValidateSignal)(new_tab, LLSD(name))) )
+		return false;
+// [/RLVa:KB]
+
 	//deselect old tab
 	if (mActiveTab)
 	{
@@ -926,7 +931,15 @@ LLPanel*	LLSideTray::showPanel		(const std::string& panel_name, const LLSD& para
 		LLView* view = (*child_it)->findChildView(panel_name,true);
 		if(view)
 		{
-			selectTabByName	((*child_it)->getName());
+// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+			// NOTE: - selectTabByName() returns false if the tab is currently active so we can't use its return value to make a decision
+			//       - "panel_name" is a name of a panel *inside* of the tab, not the name of the tab that's being switched to
+			const std::string& tab_name = (*child_it)->getName();
+			if ( (mValidateSignal) && (!(*mValidateSignal)(getTab(tab_name), LLSD(tab_name))) )
+				continue;
+			selectTabByName(tab_name);
+// [/RLVa:KB]
+//			selectTabByName	((*child_it)->getName());
 			if(mCollapsed)
 				expandSideBar();
 
@@ -1037,3 +1050,9 @@ void	LLSideTray::updateSidetrayVisibility()
 	}
 }
 
+// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+const LLPanel* LLSideTray::getActiveTab() const
+{
+	return mActiveTab;
+}
+// [/RLVa:KB]
diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h
index f0cc2c11469a25b3f85408b9cdd8865eefa314b7..358ff89b959da981ebd8fe347f75626174f18cb1 100644
--- a/indra/newview/llsidetray.h
+++ b/indra/newview/llsidetray.h
@@ -109,7 +109,11 @@ public:
 	/*
 	 * get currently active tab
 	 */
-    const LLSideTrayTab*	getActiveTab() const { return mActiveTab; }
+//    const LLSideTrayTab*	getActiveTab() const { return mActiveTab; }
+// [RLVa:KB] - Checked: 2010-03-01 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	// *sighs* LLSideTrayTab is defined in llsidetray.cpp... we can make do with an LLPanel* though 
+    const LLPanel*	getActiveTab() const;
+// [/RLVa:KB]
 
 	/*
      * collapse SideBar, hiding visible tab and moving tab buttons
@@ -134,6 +138,13 @@ public:
 	}
 
 	LLPanel*	getButtonsPanel() { return mButtonsPanel; }
+// [RLVa:KB] - Checked: 2010-02-28 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	LLButton*	getButtonFromName(const std::string& strName)
+	{ 
+		std::map<std::string, LLButton*>::const_iterator itBtn = mTabButtons.find(strName);
+		return (mTabButtons.end() != itBtn) ? itBtn->second : NULL;
+	}
+// [/RLVa:KB]
 
 	bool		getCollapsed() { return mCollapsed; }
 
diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp
index 4cf1df165555ce3098f91a3c64902d5e3ce3e479..4ac2e7ef6ea2068c2d95ca3c2d08e8735c4204ab 100644
--- a/indra/newview/llslurl.cpp
+++ b/indra/newview/llslurl.cpp
@@ -34,6 +34,9 @@
 #include "llviewernetwork.h"
 #include "llfiltersd2xmlrpc.h"
 #include "curl/curl.h"
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 const char* LLSLURL::SLURL_HTTP_SCHEME		 = "http";
 const char* LLSLURL::SLURL_HTTPS_SCHEME		 = "https";
 const char* LLSLURL::SLURL_SECONDLIFE_SCHEME	 = "secondlife";
@@ -381,8 +384,13 @@ std::string LLSLURL::getSLURLString() const
 				S32 x = llround( (F32)mPosition[VX] );
 				S32 y = llround( (F32)mPosition[VY] );
 				S32 z = llround( (F32)mPosition[VZ] );	
-				return LLGridManager::getInstance()->getSLURLBase(mGrid) + 
-				LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z); 
+//				return LLGridManager::getInstance()->getSLURLBase(mGrid) + 
+//				LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z); 
+// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+				return LLGridManager::getInstance()->getSLURLBase(mGrid) +
+					( ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) || (!RlvUtil::isNearbyRegion(mRegion)))
+						? (LLURI::escape(mRegion) + llformat("/%d/%d/%d",x,y,z)) : RlvStrings::getString(RLV_STRING_HIDDEN_REGION) );
+// [/RLVa:KB]
 			}
 		case APP:
 		{
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 975d1f9f32cf77eebfca8057baf5fde16890fdff..58d65905df9b7542f3d01c4f33e9ad12314f74a3 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -186,6 +186,10 @@
 #include "llavatariconctrl.h"
 #include "llvoicechannel.h"
 
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 #include "lllogin.h"
 #include "llevents.h"
 #include "llstartuplistener.h"
@@ -367,6 +371,13 @@ bool idle_startup()
 		// Initialize stuff that doesn't need data from simulators
 		//
 
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-0.2.1d
+		if ( (gSavedSettings.controlExists(RLV_SETTING_MAIN)) && (gSavedSettings.getBOOL(RLV_SETTING_MAIN)) )
+		{
+			rlv_handler_t::setEnabled(TRUE);
+		}
+// [/RLVa:KB]
+
 		if (LLFeatureManager::getInstance()->isSafe())
 		{
 			LLNotificationsUtil::add("DisplaySetToSafe");
@@ -906,6 +917,18 @@ bool idle_startup()
 		// their last location, or some URL "-url //sim/x/y[/z]"
 		// All accounts have both a home and a last location, and we don't support
 		// more locations than that.  Choose the appropriate one.  JC
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.1d
+#ifndef RLV_EXTENSION_STARTLOCATION
+		if (rlv_handler_t::isEnabled())
+#else
+		if ( (rlv_handler_t::isEnabled()) && (RlvSettings::getLoginLastLocation()) )
+#endif // RLV_EXTENSION_STARTLOCATION
+		{
+			// Force login at the last location
+			LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST));
+		}
+// [/RLVa:KB]
+
 		switch (LLStartUp::getStartSLURL().getType())
 		  {
 		  case LLSLURL::LOCATION:
@@ -1664,6 +1687,14 @@ bool idle_startup()
 		llinfos << "Creating Inventory Views" << llendl;
 		LLFloaterReg::getInstance("inventory");
 
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.1.0f
+		if (rlv_handler_t::isEnabled())
+		{
+			// Regularly process a select subset of retained commands during logon
+			gIdleCallbacks.addFunction(RlvHandler::onIdleStartup, new LLTimer());
+		}
+// [/RLVa:KB]
+
 		LLStartUp::setStartupState( STATE_MISC );
 		return FALSE;
 	}
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index b622e9897126979517a9da81c10e96d9ecde42f7..112b058183601a7f1b7780ca0564eb3d3aa7b98f 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -84,7 +84,6 @@
 // system includes
 #include <iomanip>
 
-
 //
 // Globals
 //
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 54484a1dbb523821d12699e07a1fc2d47a5b1ad8..62d67a794efcbecec46edb5933267136cdb5178e 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -58,6 +58,9 @@
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llworld.h"
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // syntactic sugar
 #define callMemberFunction(object,ptrToMember)  ((object).*(ptrToMember))
@@ -1135,6 +1138,15 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
 		return;
 	}
 
+
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a
+	// Fallback in case there's a new code path that leads here (see behaviour notes)
+	if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	//llinfos << "Rezzing object" << llendl;
 	make_ui_sound("UISndObjectRezIn");
 	LLViewerInventoryItem* item;
@@ -1400,6 +1412,23 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
 	BOOL volume = (LL_PCODE_VOLUME == obj->getPCode());
 	BOOL attached = obj->isAttachment();
 	BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE;
+
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.0c
+	if (rlv_handler_t::isEnabled())
+	{
+		const LLViewerObject* pObjRoot = obj->getRootEdit();
+		if (gRlvAttachmentLocks.isLockedAttachment(pObjRoot))
+		{
+			return ACCEPT_NO_LOCKED;		// Disallow inventory drops on a locked attachment
+		}
+		else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) )
+		{
+			if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == pObjRoot) )
+				return ACCEPT_NO_LOCKED;	// ... or on a linkset the avie is sitting on under @unsit=n/@sittp=n
+		}
+	}
+// [/RLVa:KB]
+
 	if (attached && !unrestricted)
 	{
 		return ACCEPT_NO_LOCKED;
@@ -1574,6 +1603,14 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
 		return ACCEPT_NO;
 	}
 
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+	// RELEASE-RLVa: [SL-2.0.0] This will need revisiting for "ENABLE_MULTIATTACHMENTS"
+	if ( (rlv_handler_t::isEnabled()) && (!gRlvAttachmentLocks.canAttach(item)) )
+	{
+		return ACCEPT_NO_LOCKED;
+	}
+// [/RLVa:KB]
+
 	if (drop)
 	{
 		if (mSource == SOURCE_LIBRARY)
@@ -1599,6 +1636,14 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
 EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
 	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
 {
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	// RELEASE-RLVa: [SL-2.0.0] Make sure the code below is the only code path to LLToolDragAndDrop::dad3dRezFromObjectOnLand()
+	if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) )
+	{
+		return ACCEPT_NO_LOCKED;
+	}
+// [/RLVa:KB]
+
 	if (mSource == SOURCE_WORLD)
 	{
 		return dad3dRezFromObjectOnLand(obj, face, mask, drop);
@@ -1660,6 +1705,18 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
 EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
 	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
 {
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	// NOTE: if (mask & MASK_CONTROL) then it's a drop rather than a rez, so we let that pass through when @rez=n restricted
+	// (but not when @interact=n restricted unless the drop target is a HUD attachment)
+	// RELEASE-RLVa: [SL-2.0.0] Make sure the code below is the only code path to LLToolDragAndDrop::dad3dRezFromObjectOnObject()
+	if ( (rlv_handler_t::isEnabled()) &&
+		 ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) && ((mask & MASK_CONTROL) == 0) ) ||
+		   ( (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) && (((mask & MASK_CONTROL) == 0) || (!obj->isHUDAttachment())) ) ) )
+	{
+		return ACCEPT_NO_LOCKED;
+	}
+// [/RLVa:KB]
+
 	// handle objects coming from object inventory
 	if (mSource == SOURCE_WORLD)
 	{
@@ -1863,6 +1920,13 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem(
 			return ACCEPT_NO;
 		}
 
+// [RLVa:KB] - Checked: 2010-03-20 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+		if ( (rlv_handler_t::isEnabled()) && (RLV_WEAR_LOCKED == gRlvWearableLocks.canWear(item)) )
+		{
+			return ACCEPT_NO_LOCKED;
+		}
+// [/RLVa:KB]
+
 		if (drop)
 		{
 			// TODO: investigate wearables may not be loaded at this point EXT-8231
diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp
index a00ac10698a9798958d9d435e483c01463eef503..20fffb3012cf5c71068df72a33a9ef9fdf320000 100644
--- a/indra/newview/lltoolface.cpp
+++ b/indra/newview/lltoolface.cpp
@@ -39,6 +39,9 @@
 #include "llviewerobject.h"
 #include "llviewerwindow.h"
 #include "llfloatertools.h"
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //
 // Member functions
@@ -90,6 +93,15 @@ void LLToolFace::pickCallback(const LLPickInfo& pick_info)
 			return;
 		}
 
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+		if ( (rlv_handler_t::isEnabled()) &&
+			 ( (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) || 
+			   ((gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (!gRlvHandler.canTouch(hit_obj, pick_info.mObjectOffset))) ) )
+		{
+			return;
+		}
+// [/RLVa:KB]
+
 		// ...clicked on a world object, try to pick the appropriate face
 
 		if (pick_info.mKeyMask & MASK_SHIFT)
diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp
index b6c0f662e5a8e7cfbd1ce096ddb603842a633c7a..477a3d572b1920890bee23cd382910830aef1845 100644
--- a/indra/newview/lltoolgrab.cpp
+++ b/indra/newview/lltoolgrab.cpp
@@ -57,6 +57,9 @@
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llworld.h"
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 const S32 SLOP_DIST_SQ = 4;
 
@@ -158,7 +161,11 @@ void LLToolGrab::pickCallback(const LLPickInfo& pick_info)
 	}
 
 	// if not over object, do nothing
-	if (!objectp)
+//	if (!objectp)
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Added: RLVa-1.1.0l
+	// Block initiating a drag operation on an object that can't be touched
+	if ( (!objectp) || ((rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(objectp, pick_info.mObjectOffset))) )
+// [/RLVa:KB]
 	{
 		LLToolGrab::getInstance()->setMouseCapture(TRUE);
 		LLToolGrab::getInstance()->mMode = GRAB_NOOBJECT;
@@ -428,6 +435,22 @@ BOOL LLToolGrab::handleHover(S32 x, S32 y, MASK mask)
 		return TRUE;
 	}
 
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	// Block dragging an object beyond touch range when @fartouch=n restricted
+	if ( (rlv_handler_t::isEnabled()) && (GRAB_INACTIVE != mMode) && (GRAB_NOOBJECT != mMode) && (hasMouseCapture()) &&
+		 (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (!gRlvHandler.canTouch(mGrabPick.getObject(), mGrabPick.mObjectOffset)) )
+	{
+		if (gGrabTransientTool)
+		{
+			// Prevent the grab tool from popping up as soon as we kill the drag operation
+			gBasicToolset->selectTool(gGrabTransientTool);
+			gGrabTransientTool = NULL;
+		}
+		setMouseCapture(FALSE);
+		return TRUE;
+	}
+// [/RLVa:KB]
+
 	// Do the right hover based on mode
 	switch( mMode )
 	{
diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp
index 51c0e2eeed31cbd433c9c740fc7f6aed93172942..8f25ec4e9f765a1e018d5515327855bc08d2a173 100644
--- a/indra/newview/lltoolmgr.cpp
+++ b/indra/newview/lltoolmgr.cpp
@@ -55,7 +55,9 @@
 #include "llviewerjoystick.h"
 #include "llviewermenu.h"
 #include "llviewerparcelmgr.h"
-
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // Used when app not active to avoid processing hover.
 LLTool*			gToolNull	= NULL;
@@ -291,7 +293,14 @@ void LLToolMgr::toggleBuildMode()
 			}
 		}
 
-		
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b
+		// TODO-RLVa: [RLVa-1.2.1] Does this code actually still ever trigger?
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT))
+		{
+			LLSelectMgr::getInstance()->deselectAll();
+		}
+// [/RLVa:KB]
+
 		setCurrentToolset(gBasicToolset);
 		getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() );
 
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index d8be70e54698b36ca8b3e7a438609811742aa33d..0d1a56b49457195948d2ecd3aef0b6c4d9ff067b 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -68,6 +68,9 @@
 #include "llui.h"
 #include "llweb.h"
 #include "pipeline.h"	// setHighlightObject
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 extern BOOL gDebugClicks;
 
@@ -184,6 +187,15 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
 	// If it's a left-click, and we have a special action, do it.
 	if (useClickAction(mask, object, parent))
 	{
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+		// Block left-click special actions when fartouch restricted
+		if ( (rlv_handler_t::isEnabled()) && 
+			 (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (!gRlvHandler.canTouch(object, mPick.mObjectOffset)) )
+		{
+			return TRUE;
+		}
+// [/RLVa:KB]
+
 		mClickAction = 0;
 		if (object && object->getClickAction()) 
 		{
@@ -293,6 +305,14 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
 		((object->usePhysics() || (parent && !parent->isAvatar() && parent->usePhysics())) || touchable) 
 		)
 	{
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+		// Triggered by left-clicking on a touchable object
+		if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object, mPick.mObjectOffset)) )
+		{
+			return LLTool::handleMouseDown(x, y, mask);
+		}
+// [/RLVa:KB]
+
 		gGrabTransientTool = this;
 		LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolGrab::getInstance() );
 		return LLToolGrab::getInstance()->handleObjectHit( mPick );
@@ -405,7 +425,11 @@ ECursorType cursor_from_object(LLViewerObject* object)
 	{
 	case CLICK_ACTION_SIT:
 		{
-			if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // not already sitting?
+//			if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // not already sitting?
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.2.0g
+			if ( (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) && 
+				 ((!rlv_handler_t::isEnabled()) || (gRlvHandler.canSit(object, LLToolPie::getInstance()->getHoverPick().mObjectOffset))) )
+// [/RLVa:KB]
 			{
 				cursor = UI_CURSOR_TOOLSIT;
 			}
@@ -500,6 +524,19 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 	LLViewerObject *parent = NULL;
 	LLViewerObject *object = mHoverPick.getObject();
 
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	// Block all special click action cursors when:
+	//   - @fartouch=n restricted and the object is out of range
+	//   - @interact=n restricted and the object isn't a HUD attachment
+	if ( (object) && (rlv_handler_t::isEnabled()) && 
+		( ((gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH))) && (!gRlvHandler.canTouch(object, mHoverPick.mObjectOffset)) || 
+		  ((gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) && (!object->isHUDAttachment())) ) )
+	{
+		gViewerWindow->setCursor(UI_CURSOR_ARROW);
+		return TRUE;
+	}
+// [/RLVa:KB]
+
 	if (object)
 	{
 		parent = object->getRootEdit();
@@ -521,7 +558,13 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 		gViewerWindow->setCursor(cursor);
 		lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
 	}
-	
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Added: RLVa-1.1.0l
+	else if ( (object) && (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object)) )
+	{
+		// Block showing the "grab" or "touch" cursor if we can't touch the object (@fartouch=n is handled above)
+		gViewerWindow->setCursor(UI_CURSOR_ARROW);
+	}
+// [/RLVa:KB]
 	else if ((object && !object->isAvatar() && object->usePhysics()) 
 			 || (parent && !parent->isAvatar() && parent->usePhysics()))
 	{
@@ -861,6 +904,10 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l
 			if (firstname && lastname)
 			{
 				avatar_name = llformat("%s %s", firstname->getString(), lastname->getString());
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+				if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
+					avatar_name = RlvStrings::getAnonym(avatar_name);
+// [/RLVa:KB]
 			}
 			else
 			{
@@ -869,17 +916,29 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l
 			
 			// *HACK: We may select this object, so pretend it was clicked
 			mPick = mHoverPick;
-			LLInspector::Params p;
-			p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
-			p.message(avatar_name);
-			p.image.name("Inspector_I");
-			p.click_callback(boost::bind(showAvatarInspector, hover_object->getID()));
-			p.visible_time_near(6.f);
-			p.visible_time_far(3.f);
-			p.delay_time(0.35f);
-			p.wrap(false);
-			
-			LLToolTipMgr::instance().show(p);
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+			if ( (!rlv_handler_t::isEnabled()) || 
+				 ( (gRlvHandler.canTouch(hover_object, mHoverPick.mObjectOffset)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) )
+			{
+// [/RLVa:KB]
+				LLInspector::Params p;
+				p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
+				p.message(avatar_name);
+				p.image.name("Inspector_I");
+				p.click_callback(boost::bind(showAvatarInspector, hover_object->getID()));
+				p.visible_time_near(6.f);
+				p.visible_time_far(3.f);
+				p.delay_time(0.35f);
+				p.wrap(false);
+				
+				LLToolTipMgr::instance().show(p);
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+			}
+			else
+			{
+				LLToolTipMgr::instance().show(avatar_name);
+			}
+// [/RLVa:KB]
 		}
 	}
 	else
@@ -982,22 +1041,33 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l
 			{
 				// We may select this object, so pretend it was clicked
 				mPick = mHoverPick;
-				LLInspector::Params p;
-				p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
-				p.message(tooltip_msg);
-				p.image.name("Inspector_I");
-				p.click_callback(boost::bind(showObjectInspector, hover_object->getID(), mHoverPick.mObjectFace));
-				p.time_based_media(is_time_based_media);
-				p.web_based_media(is_web_based_media);
-				p.media_playing(is_media_playing);
-				p.click_playmedia_callback(boost::bind(playCurrentMedia, mHoverPick));
-				p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick));
-				p.visible_time_near(6.f);
-				p.visible_time_far(3.f);
-				p.delay_time(0.35f);
-				p.wrap(false);
-				
-				LLToolTipMgr::instance().show(p);
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+				if ( (!rlv_handler_t::isEnabled()) || (gRlvHandler.canTouch(hover_object, mHoverPick.mObjectOffset)) )
+				{
+// [/RLVa:KB]
+					LLInspector::Params p;
+					p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
+					p.message(tooltip_msg);
+					p.image.name("Inspector_I");
+					p.click_callback(boost::bind(showObjectInspector, hover_object->getID(), mHoverPick.mObjectFace));
+					p.time_based_media(is_time_based_media);
+					p.web_based_media(is_web_based_media);
+					p.media_playing(is_media_playing);
+					p.click_playmedia_callback(boost::bind(playCurrentMedia, mHoverPick));
+					p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick));
+					p.visible_time_near(6.f);
+					p.visible_time_far(3.f);
+					p.delay_time(0.35f);
+					p.wrap(false);
+					
+					LLToolTipMgr::instance().show(p);
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+				}
+				else
+				{
+					LLToolTipMgr::instance().show(tooltip_msg);
+				}
+// [/RLVa:KB]
 			}
 		}
 	}
@@ -1009,6 +1079,11 @@ BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, MASK mask)
 {
 	if (!LLUI::sSettingGroups["config"]->getBOOL("ShowHoverTips")) return TRUE;
 	if (!mHoverPick.isValid()) return TRUE;
+// [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+#ifdef RLV_EXTENSION_CMD_INTERACT
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) return TRUE;
+#endif // RLV_EXTENSION_CMD_INTERACT
+// [/RLVa:KB]
 
 	LLViewerObject* hover_object = mHoverPick.getObject();
 	
@@ -1520,16 +1595,29 @@ BOOL LLToolPie::pickRightMouseDownCallback()
 				mute_msg = LLTrans::getString("MuteAvatar");
 			}
 
-			if (is_other_attachment)
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+			// Don't show the context menu on empty selection when fartouch restricted [see LLToolSelect::handleObjectSelection()]
+			if ( (!rlv_handler_t::isEnabled()) || (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) ||
+				 (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) )
 			{
-				gMenuAttachmentOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
-				gMenuAttachmentOther->show(x, y);
+// [/RLVa:KB]
+				if (is_other_attachment)
+				{
+					gMenuAttachmentOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
+					gMenuAttachmentOther->show(x, y);
+				}
+				else
+				{
+					gMenuAvatarOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
+					gMenuAvatarOther->show(x, y);
+				}
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
 			}
 			else
 			{
-				gMenuAvatarOther->getChild<LLUICtrl>("Avatar Mute")->setValue(mute_msg);
-				gMenuAvatarOther->show(x, y);
+				make_ui_sound("UISndInvalidOp");
 			}
+// [/RLVa:KB]
 		}
 		else if (object->isAttachment())
 		{
@@ -1554,10 +1642,24 @@ BOOL LLToolPie::pickRightMouseDownCallback()
 				mute_msg = LLTrans::getString("MuteObject2");
 			}
 			
-			gMenuHolder->getChild<LLUICtrl>("Object Mute")->setValue(mute_msg);
-			gMenuObject->show(x, y);
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.el) | Modified: RLVa-1.1.0l
+			// Don't show the pie menu on empty selection when fartouch/interaction restricted
+			// (not entirely accurate in case of Tools / Select Only XXX [see LLToolSelect::handleObjectSelection()]
+			if ( (!rlv_handler_t::isEnabled()) || (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) ||
+				 (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) )
+			{
+// [/RLVa:KB]
+				gMenuHolder->getChild<LLUICtrl>("Object Mute")->setValue(mute_msg);
+				gMenuObject->show(x, y);
 
-			showVisualContextMenuEffect();
+				showVisualContextMenuEffect();
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.el) | Modified: RLVa-1.1.0l
+			}
+			else
+			{
+				make_ui_sound("UISndInvalidOp");
+			}
+// [/RLVa:KB]
 		}
 	}
 
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index 65cb3e36a768d140375a97090a48f295c4d185b5..1d3453ba0b6428457d2500e50c74042325861f35 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -60,6 +60,9 @@ public:
 	virtual LLTool*		getOverrideTool(MASK mask);
 
 	LLPickInfo&			getPick() { return mPick; }
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+	LLPickInfo&			getHoverPick() { return mHoverPick; }
+// [/RLVa:KB]
 	U8					getClickAction() { return mClickAction; }
 	LLViewerObject*		getClickActionObject() { return mClickActionObject; }
 	LLObjectSelection*	getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; }
diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp
index 93ba3b25587c79ecd6334255ccd5bec27a1b467e..5f2ab5fe5164b8f2c991adf1069864c17935fb55 100644
--- a/indra/newview/lltoolplacer.cpp
+++ b/indra/newview/lltoolplacer.cpp
@@ -43,6 +43,9 @@
 #include "llviewerwindow.h"
 #include "llworld.h"
 #include "llui.h"
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //Headers added for functions moved from viewer.cpp
 #include "llvograss.h"
@@ -123,6 +126,14 @@ BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj,
 		return FALSE;
 	}
 
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-0.2.0f
+	// NOTE: don't use surface_pos_global since for prims it will be the center of the prim while we need center + offset
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (dist_vec_squared(gAgent.getPositionGlobal(), pick.mPosGlobal) > 1.5f * 1.5f) )
+	{
+		return FALSE;
+	}
+// [/RLVa:KB]
+
 	// Find the sim where the surface lives.
 	LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global);
 	if (!regionp)
@@ -240,7 +251,10 @@ BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics )
 	{
 		flags |= FLAGS_USE_PHYSICS;
 	}
-	if (create_selected)
+//	if (create_selected)
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.0.0b
+	if ( (create_selected) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) )
+// [/RLVa:KB]
 	{
 		flags |= FLAGS_CREATE_SELECTED;
 	}
@@ -498,6 +512,13 @@ BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask)
 {
 	BOOL added = TRUE;
 	
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) || (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT))) )
+	{
+		return TRUE; // Callers seem to expect a "did you handle it?" so we return TRUE rather than FALSE
+	}
+// [/RLVa:KB]
+
 	if (gSavedSettings.getBOOL("CreateToolCopySelection"))
 	{
 		added = addDuplicate(x, y);
diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp
index 7c604a04bf7b53f2e130028a5b0c3cc6c5c5a218..3ff7b5cf4848f5db79ce4e195025b531bf06b674 100644
--- a/indra/newview/lltoolselect.cpp
+++ b/indra/newview/lltoolselect.cpp
@@ -45,6 +45,10 @@
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llworld.h"
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c)
+#include "rlvhandler.h"
+#include "llfloaterreg.h"
+// [/RLVa:KB]
 
 // Globals
 //extern BOOL gAllowSelectAvatar;
@@ -78,6 +82,35 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi
 	{
 		object = object->getRootEdit();
 	}
+
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+	if (rlv_handler_t::isEnabled())
+	{
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT))
+		{
+			if (!temp_select)
+				return LLSelectMgr::getInstance()->getSelection();
+			else if (LLToolMgr::instance().inBuildMode())
+				LLToolMgr::instance().toggleBuildMode();
+		}
+		
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && (object) && ((!object->isAttachment()) || (!object->permYouOwner())) &&
+			 (dist_vec_squared(gAgent.getPositionAgent(), object->getPositionRegion()) > 1.5f * 1.5f) )
+		{
+			// NOTE: see behaviour notes for a rather lengthy explanation of why we're doing things this way
+			//if (dist_vec_squared(gAgent.getPositionAgent(), object->getPositionRegion() + pick.mObjectOffset) > 1.5f * 1.5f)
+			if (dist_vec_squared(gAgent.getPositionAgent(), pick.mIntersection) > 1.5f * 1.5f)
+			{
+				if ( (LLFloaterReg::floaterInstanceVisible("build")) && (pick.mKeyMask != MASK_SHIFT) && (pick.mKeyMask != MASK_CONTROL) )
+					LLSelectMgr::getInstance()->deselectAll();
+				return LLSelectMgr::getInstance()->getSelection();
+			}
+			else if (LLToolMgr::instance().inBuildMode())
+				LLToolMgr::instance().toggleBuildMode();
+		}
+	}
+// [/RLVa:KB]
+
 	BOOL select_owned = gSavedSettings.getBOOL("SelectOwnedOnly");
 	BOOL select_movable = gSavedSettings.getBOOL("SelectMovableOnly");
 	
diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp
index 8391c0f832a5bff6d41bcf0ac3d21da6165d9423..e2e229ac0aefbfc580eee2325db5e89de9fa3fe0 100644
--- a/indra/newview/lltracker.cpp
+++ b/indra/newview/lltracker.cpp
@@ -61,6 +61,10 @@
 #include "llworldmapview.h"
 #include "llviewercontrol.h"
 
+// [RLVa:KB]
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 const F32 DESTINATION_REACHED_RADIUS    = 3.0f;
 const F32 DESTINATION_VISITED_RADIUS    = 6.0f;
 
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index cbb1d25f78e51609ad0d4a69900cb5f1ff2d5ea8..f124d717c3453e1433c6d77f8c3c1cd01053c7fa 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -40,6 +40,9 @@
 #include "llworld.h"
 #include "lltoolmgr.h"
 #include "llviewerjoystick.h"
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 // Linden library includes
 #include "lldrawable.h"
@@ -345,7 +348,10 @@ void LLViewerCamera::setPerspective(BOOL for_selection,
 		if (limit_select_distance)
 		{
 			// ...select distance from control
-			z_far = gSavedSettings.getF32("MaxSelectDistance");
+//			z_far = gSavedSettings.getF32("MaxSelectDistance");
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+			z_far = (!gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) ? gSavedSettings.getF32("MaxSelectDistance") : 1.5;
+// [/RLVa:KB]
 		}
 		else
 		{
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index d0ad918c58b05dd954e791a5c21b54e36c0f74a1..ddc313fb6494c2b277c89ebfc5ff911fb779bc5d 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -77,6 +77,9 @@
 #include "llwlparammanager.h"
 #include "llwaterparammanager.h"
 #include "llpostprocess.h"
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 extern LLPointer<LLViewerTexture> gStartTexture;
 
@@ -908,7 +911,11 @@ void render_hud_attachments()
 	glh::matrix4f current_mod = glh_get_current_modelview();
 
 	// clamp target zoom level to reasonable values
-	gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f);
+//	gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f);
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c
+	gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, (!gRlvAttachmentLocks.hasLockedHUD()) ? 0.1f : 0.85f, 1.f);
+// [/RLVa:KB]
+
 	// smoothly interpolate current zoom level
 	gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f));
 
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 87282985751572617025722faa36479c19d26ac2..d76a70de238bfb9ce8448cffdd75457aaae37fdc 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -120,7 +120,9 @@
 #include "llsyswellwindow.h"
 #include "llscriptfloater.h"
 // *NOTE: Please add files in alphabetical order to keep merges easy.
-
+// [RLVa:KB] - Checked: 2010-03-11
+#include "rlvfloaters.h"
+// [/RLVa:KB]
 
 void LLViewerFloaterReg::registerFloaters()
 {
@@ -227,6 +229,10 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("reporter", "floater_report_abuse.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterReporter>);
 	LLFloaterReg::add("reset_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterResetQueue>);
 	LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterRegionInfo>);
+// [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0a
+	LLFloaterReg::add("rlv_behaviours", "floater_rlv_behaviours.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterBehaviours>);
+	LLFloaterReg::add("rlv_locks", "floater_rlv_locks.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<RlvFloaterLocks>);
+// [/RLVa:KB]
 	
 	LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebug>);
 	LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptDebugOutput>);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index daeace0ec5c9f2bf1e856dc13615bcac4e6d891e..bc8ddaa44eae4f8a8cdd2b088e96e797032f3e37 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -104,6 +104,10 @@
 #include "lleconomy.h"
 #include "boost/unordered_map.hpp"
 
+// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 using namespace LLVOAvatarDefines;
 
 static boost::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels;
@@ -1076,7 +1080,10 @@ class LLAdvancedToggleWireframe : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		gUseWireframe = !(gUseWireframe);
+//		gUseWireframe = !(gUseWireframe);
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+		gUseWireframe = (!gUseWireframe) && (!gRlvAttachmentLocks.hasLockedHUD());
+// [/RLVa:KB]
 		LLPipeline::updateRenderDeferred();
 		gPipeline.resetVertexBuffers();
 		return true;
@@ -2365,6 +2372,15 @@ void handle_object_touch()
 
 		LLPickInfo pick = LLToolPie::getInstance()->getPick();
 
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+		// NOTE: fallback code since we really shouldn't be getting an active selection if we can't touch this
+		if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object, pick.mObjectOffset)) )
+		{
+			RLV_ASSERT(false);
+			return;
+		}
+// [/RLVa:KB]
+
 		LLMessageSystem	*msg = gMessageSystem;
 
 		msg->newMessageFast(_PREHASH_ObjectGrab);
@@ -2468,7 +2484,11 @@ bool enable_object_touch(LLUICtrl* ctrl)
 
 void handle_object_open()
 {
-	LLFloaterReg::showInstance("openobject");
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+	if (enable_object_open())
+		LLFloaterReg::showInstance("openobject");
+// [/RLVa:KB]
+//	LLFloaterReg::showInstance("openobject");
 }
 
 bool enable_object_open()
@@ -2695,7 +2715,10 @@ bool enable_object_edit()
 	} 
 	else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound())
 	{
-		enable = true;
+//		enable = true;
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+		enable = !gRlvHandler.hasBehaviour(RLV_BHVR_EDIT);
+// [/RLVa:KB]
 	}
 
 	return enable;
@@ -2728,7 +2751,10 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t
 			{
 				LLVOAvatar::attachment_map_t::iterator curiter = iter++;
 				LLViewerJointAttachment* attachment = curiter->second;
-				if (attachment->getNumObjects() > 0)
+//				if (attachment->getNumObjects() > 0)
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+				if ( (attachment->getNumObjects() > 0) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(attachment))) )
+// [/RLVa:KB]
 				{
 					new_value = true;
 					break;
@@ -2771,7 +2797,10 @@ bool enable_object_mute()
 		bool is_linden =
 			lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden");
 		bool is_self = avatar->isSelf();
-		return !is_linden && !is_self;
+//		return !is_linden && !is_self;
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+		return !is_linden && !is_self && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES);
+// [/RLVa:KB]
 	}
 	else
 	{
@@ -2794,6 +2823,10 @@ class LLObjectMute : public view_listener_t
 		LLVOAvatar* avatar = find_avatar_from_object(object); 
 		if (avatar)
 		{
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.0.0e
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
+				return true;
+// [/RLVa:KB]
 			id = avatar->getID();
 
 			LLNameValue *firstname = avatar->getNVPair("FirstName");
@@ -3067,6 +3100,14 @@ void handle_avatar_eject(const LLSD& avatar_id)
 			LLSD payload;
 			payload["avatar_id"] = avatar->getID();
 			std::string fullname = avatar->getFullname();
+// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e)
+/*
+			if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!fullname.empty()) )
+			{
+				fullname = RlvStrings::getAnonym(fullname);
+			}
+*/
+// [/RLVa:KB]
 
 			const LLVector3d& pos = avatar->getPositionGlobal();
 			LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel();
@@ -3154,7 +3195,10 @@ class LLAvatarGiveCard : public view_listener_t
 	{
 		llinfos << "handle_give_card()" << llendl;
 		LLViewerObject* dest = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-		if(dest && dest->isAvatar())
+//		if(dest && dest->isAvatar())
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+		if ( (dest && dest->isAvatar()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
+// [/RLVa:KB]
 		{
 			bool found_name = false;
 			LLSD args;
@@ -3383,7 +3427,10 @@ class LLSelfStandUp : public view_listener_t
 
 bool enable_standup_self()
 {
-    return isAgentAvatarValid() && gAgentAvatarp->isSitting();
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g
+	return isAgentAvatarValid() && gAgentAvatarp->isSitting() && !gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT);
+// [/RLVa:KB]
+//	return isAgentAvatarValid() && gAgentAvatarp->isSitting();
 }
 
 class LLSelfSitDown : public view_listener_t
@@ -3397,7 +3444,10 @@ class LLSelfSitDown : public view_listener_t
 
 bool enable_sitdown_self()
 {
-    return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying();
+// [RLVa:KB] - Checked: 2010-08-28 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+	return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying() && !gRlvHandler.hasBehaviour(RLV_BHVR_SIT);
+// [/RLVa:KB]
+//    return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying();
 }
 
 // Used from the login screen to aid in UI work on side tray
@@ -3612,7 +3662,10 @@ class LLAvatarEnableAddFriend : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
-		bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID());
+//		bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID());
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+		bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES));
+// [/RLVa:KB]
 		return new_value;
 	}
 };
@@ -3650,7 +3703,10 @@ class LLEditEnableCustomizeAvatar : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		bool new_value = gAgentWearables.areWearablesLoaded();
+//		bool new_value = gAgentWearables.areWearablesLoaded();
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g
+		bool new_value = gAgentWearables.areWearablesLoaded() && ((!rlv_handler_t::isEnabled()) || (gRlvHandler.canStand()));
+// [/RLVa:KB]
 		return new_value;
 	}
 };
@@ -3665,6 +3721,16 @@ class LLEnableEditShape : public view_listener_t
 
 bool is_object_sittable()
 {
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.1.0j
+	// RELEASE-RLVa: [SL-2.0.0] Make sure we're examining the same object that handle_sit_or_stand() will request a sit for
+	if (rlv_handler_t::isEnabled())
+	{
+		const LLPickInfo& pick = LLToolPie::getInstance()->getPick();
+		if ( (pick.mObjectID.notNull()) && (!gRlvHandler.canSit(pick.getObject(), pick.mObjectOffset)) )
+			return false;
+	}
+// [/RLVa:KB]
+
 	LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
 
 	if (object && object->getPCode() == LL_PCODE_VOLUME)
@@ -3696,8 +3762,23 @@ void handle_object_sit_or_stand()
 
 	// get object selection offset 
 
-	if (object && object->getPCode() == LL_PCODE_VOLUME)
+//	if (object && object->getPCode() == LL_PCODE_VOLUME)
+// [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c
+	if ( (object && object->getPCode() == LL_PCODE_VOLUME) && 
+		 ((!rlv_handler_t::isEnabled()) || (gRlvHandler.canSit(object, pick.mObjectOffset))) )
+// [/RLVa:KB]
 	{
+// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) )
+		{
+			if (gAgentAvatarp->isSitting())
+			{
+				gAgent.standUp();
+				return;
+			}
+			gRlvHandler.setSitSource(gAgent.getPositionGlobal());
+		}
+// [/RLVa:KB]
 
 		gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
 		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
@@ -3727,6 +3808,13 @@ class LLLandSit : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c
+		if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) )
+		{
+			return true;
+		}
+// [/RLVa:KB]
+
 		gAgent.standUp();
 		LLViewerParcelMgr::getInstance()->deselectLand();
 
@@ -4173,6 +4261,17 @@ void handle_take_copy()
 {
 	if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
 
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+	if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStand()) )
+	{
+		// Allow only if the avie isn't sitting on any of the selected objects
+		LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
+		RlvSelectIsSittingOn f(gAgentAvatarp->getRoot());
+		if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE)) )
+			return;
+	}
+// [/RLVa:KB]
+
 	const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
 	derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id);
 }
@@ -4183,6 +4282,9 @@ class LLObjectReturn : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true;
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b
+		if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) return true;
+// [/RLVa:KB]
 		
 		mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
 
@@ -4250,6 +4352,9 @@ class LLObjectEnableReturn : public view_listener_t
 			}
 		}
 #endif
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b
+		new_value &= (!rlv_handler_t::isEnabled()) || (rlvCanDeleteOrReturn());
+// [/RLVa:KB]
 		return new_value;
 	}
 };
@@ -4265,11 +4370,14 @@ void handle_take()
 {
 	// we want to use the folder this was derezzed from if it's
 	// available. Otherwise, derez to the normal place.
-	if(LLSelectMgr::getInstance()->getSelection()->isEmpty())
+//	if(LLSelectMgr::getInstance()->getSelection()->isEmpty())
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b
+	if ( (LLSelectMgr::getInstance()->getSelection()->isEmpty()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) )
+// [/RLVa:KB]
 	{
 		return;
 	}
-	
+
 	BOOL you_own_everything = TRUE;
 	BOOL locked_but_takeable_object = FALSE;
 	LLUUID category_id;
@@ -4382,7 +4490,10 @@ bool confirm_take(const LLSD& notification, const LLSD& response)
 // one item selected can be copied to inventory.
 BOOL enable_take()
 {
-	if (sitting_on_selection())
+//	if (sitting_on_selection())
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b
+	if ( (sitting_on_selection()) || ((rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn())) )
+// [/RLVa:KB]
 	{
 		return FALSE;
 	}
@@ -4882,6 +4993,17 @@ class LLToolsEnableUnlink : public view_listener_t
 		bool new_value = LLSelectMgr::getInstance()->selectGetAllRootsValid() &&
 			first_editable_object &&
 			!first_editable_object->isAttachment();
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g
+		if ( (new_value) && (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && 
+			 (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) )
+		{
+			// Allow only if the avie isn't sitting on any of the selected objects
+			LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection();
+			RlvSelectIsSittingOn f(gAgentAvatarp->getRoot());
+			if (handleSel->getFirstRootNode(&f, TRUE))
+				new_value = false;
+		}
+// [/RLVa:KB]
 		return new_value;
 	}
 };
@@ -4890,6 +5012,17 @@ class LLToolsUnlink : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g
+		if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStand()) )
+		{
+			// Allow only if the avie isn't sitting on any of the selected objects
+			LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
+			RlvSelectIsSittingOn f(gAgentAvatarp->getRoot());
+			if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE)) )
+				return true;
+		}
+// [/RLVa:KB]
+
 		LLSelectMgr::getInstance()->sendDelink();
 		return true;
 	}
@@ -4909,8 +5042,12 @@ class LLToolsReleaseKeys : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		gAgent.forceReleaseControls();
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
+			return true;
+// [/RLVa:KB]
 
+		gAgent.forceReleaseControls();
 		return true;
 	}
 };
@@ -4919,7 +5056,11 @@ class LLToolsEnableReleaseKeys : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
-		return gAgent.anyControlGrabbed();
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a
+		return (gAgent.anyControlGrabbed()) && 
+			( (!rlv_handler_t::isEnabled()) || (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) );
+// [/RLVa:KB]
+//		return gAgent.anyControlGrabbed();
 	}
 };
 
@@ -5195,6 +5336,16 @@ void show_debug_menus()
 
 		gMenuBarView->setItemVisible("Advanced", debug);
 // 		gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden
+
+// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+		// NOTE: this is supposed to execute whether RLVa is enabled or not
+		LLMenuGL* pAdvancedMenu = gMenuBarView->findChildMenuByName("Advanced", FALSE);
+		if (pAdvancedMenu)
+		{
+			pAdvancedMenu->setItemVisible("RLVa", rlv_handler_t::isEnabled());
+			pAdvancedMenu->setItemEnabled("RLVa", rlv_handler_t::isEnabled());
+		}
+// [/RLVa:KB]
 		
 		gMenuBarView->setItemVisible("Debug", qamode);
 		gMenuBarView->setItemEnabled("Debug", qamode);
@@ -5442,7 +5593,10 @@ class LLAvatarInviteToGroup : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
-		if(avatar)
+//		if(avatar)
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+		if ( (avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
+// [/RLVa:KB]
 		{
 			LLAvatarActions::inviteToGroup(avatar->getID());
 		}
@@ -5455,7 +5609,10 @@ class LLAvatarAddFriend : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
-		if(avatar && !LLAvatarActions::isFriend(avatar->getID()))
+//		if(avatar && !LLAvatarActions::isFriend(avatar->getID()))
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+		if ( (avatar && !LLAvatarActions::isFriend(avatar->getID())) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
+// [/RLVa:KB]
 		{
 			request_friendship(avatar->getID());
 		}
@@ -5468,7 +5625,10 @@ class LLAvatarAddContact : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
-		if(avatar)
+//		if(avatar)
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+		if ( (avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
+// [/RLVa:KB]
 		{
 			create_inventory_callingcard(avatar->getID());
 		}
@@ -5532,7 +5692,10 @@ bool enable_pay_avatar()
 {
 	LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
 	LLVOAvatar* avatar = find_avatar_from_object(obj);
-	return (avatar != NULL);
+//	return (avatar != NULL);
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+	return (avatar != NULL) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES));
+// [/RLVa:KB]
 }
 
 bool enable_pay_object()
@@ -5552,7 +5715,10 @@ bool enable_pay_object()
 bool enable_object_stand_up()
 {
 	// 'Object Stand Up' menu item is enabled when agent is sitting on selection
-	return sitting_on_selection();
+//	return sitting_on_selection();
+// [RLVa:KB] - Checked: 2010-07-24 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+	return sitting_on_selection() && ( (!rlv_handler_t::isEnabled()) || (gRlvHandler.canStand()) );
+// [/RLVa:KB]
 }
 
 bool enable_object_sit(LLUICtrl* ctrl)
@@ -5577,6 +5743,17 @@ bool enable_object_sit(LLUICtrl* ctrl)
 			gMenuHolder->childSetText(item_name, get_default_item_label(item_name));
 		}
 	}
+
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c
+		// RELEASE-RLVA: [SL-2.0.0] Make this match what happens in handle_object_sit_or_stand()
+		if (rlv_handler_t::isEnabled())
+		{
+			const LLPickInfo& pick = LLToolPie::getInstance()->getPick();
+			if (pick.mObjectID.notNull())
+				sitting_on_sel = !gRlvHandler.canSit(pick.getObject(), pick.mObjectOffset);
+		}
+// [/RLVa:KB]
+
 	return !sitting_on_sel && is_object_sittable();
 }
 
@@ -5791,7 +5968,10 @@ class LLShowAgentProfile : public view_listener_t
 		}
 
 		LLVOAvatar* avatar = find_avatar_from_object(agent_id);
-		if (avatar)
+//		if (avatar)
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+		if ( (avatar) && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (gAgent.getID() == agent_id)) )
+// [/RLVa:KB]
 		{
 			LLAvatarActions::showProfile(avatar->getID());
 		}
@@ -5875,6 +6055,19 @@ private:
 			LLViewerJointAttachment* attachment_point = NULL;
 			if (index > 0)
 				attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL);
+
+// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a
+			// RELEASE-RLVa: [SL-2.1.2] This will need revisiting when LL deprecates the "MultipleAttachment" debug setting
+			if ( (rlv_handler_t::isEnabled()) &&
+				 ( ((index == 0) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY))) ||		// Can't wear on default attach point
+				   ((index > 0) && (RLV_WEAR_LOCKED == gRlvAttachmentLocks.canAttach(attachment_point))) ||	// or replace a locked attachment
+				   (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) )												// Attach on rezzed object == "Take"
+			{
+				setObjectSelection(NULL); // Clear the selection or it'll get stuck
+				return true;
+			}
+// [/RLVa:KB]
+
 			confirmReplaceAttachment(0, attachment_point);
 		}
 		return true;
@@ -6019,6 +6212,24 @@ class LLAttachmentDrop : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0e) | Modified: RLVa-1.0.5
+		if (rlv_handler_t::isEnabled())
+		{
+			if (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE))
+			{
+				// NOTE: copy/paste of the code in enable_detach()
+				LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection();
+				RlvSelectHasLockedAttach f;
+				if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE)) )
+					return true;
+			}
+			if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ))
+			{
+				return true;
+			}
+		}
+// [/RLVa:KB]
+
 		LLSD payload;
 		LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
 
@@ -6043,7 +6254,10 @@ class LLAttachmentDetachFromPoint : public view_listener_t
 	bool handleEvent(const LLSD& user_data)
 	{
 		const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL);
-		if (attachment->getNumObjects() > 0)
+//		if (attachment->getNumObjects() > 0)
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+		if ( (attachment->getNumObjects() > 0) && ((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(attachment))) )
+// [/RLVa:KB]
 		{
 			gMessageSystem->newMessage("ObjectDetach");
 			gMessageSystem->nextBlockFast(_PREHASH_AgentData);
@@ -6055,6 +6269,10 @@ class LLAttachmentDetachFromPoint : public view_listener_t
 				 iter++)
 			{
 				LLViewerObject *attached_object = (*iter);
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+				if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(attached_object)) )
+					continue;
+// [/RLVa:KB]
 				gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
 				gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID());
 			}
@@ -6066,6 +6284,11 @@ class LLAttachmentDetachFromPoint : public view_listener_t
 
 static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data)
 {
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	// RELEASE-RLVa: [2010-02-27] This will need rewriting once multiple attachments can be attached to the same point
+	bool fRlvEnable = true;
+	bool fRlvHasLockedAttachment = false;	// Remove once multiple attachments can be attached to the same point
+// [/RLVa:KB]
 	std::string label;
 	LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl);
 	if (menu)
@@ -6081,6 +6304,12 @@ static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data)
 				const LLViewerObject* attached_object = (*attachment_iter);
 				if (attached_object)
 				{
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+					// RELEASE-RLVa: [SL-2.0.0] This will need removing for "ENABLE_MULTIATTACHMENTS"
+					if (rlv_handler_t::isEnabled())
+						fRlvHasLockedAttachment |= gRlvAttachmentLocks.isLockedAttachment(attached_object);
+// [/RLVa:KB]
+
 					LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID());
 					if (itemp)
 					{
@@ -6090,9 +6319,19 @@ static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data)
 				}
 			}
 		}
+
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+		// Remove fHasLockedAttachment once multiple attachments can be attached to the same point
+		if (rlv_handler_t::isEnabled())
+			fRlvEnable = (!fRlvHasLockedAttachment) && (!gRlvAttachmentLocks.isLockedAttachmentPoint(attachment, RLV_LOCK_ADD));
+// [/RLVa:KB]
+
 		menu->setLabel(label);
 	}
-	return true;
+//	return true;
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	return fRlvEnable;
+// [/RLVa:KB]
 }
 
 class LLAttachmentDetach : public view_listener_t
@@ -6131,6 +6370,17 @@ class LLAttachmentDetach : public view_listener_t
 			return true;
 		}
 
+// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0a) | Modified: RLVa-1.0.5
+		// NOTE: copy/paste of the code in enable_detach()
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
+		{
+			LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection();
+			RlvSelectHasLockedAttach f;
+			if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE)) )
+				return true;
+		}
+// [/RLVa:KB]
+
 		// The sendDetach() method works on the list of selected
 		// objects.  Thus we need to clear the list, make sure it only
 		// contains the object the user clicked, send the message,
@@ -6216,7 +6466,10 @@ class LLAttachmentEnableDrop : public view_listener_t
 		}
 		
 		//now check to make sure that the item is actually in the inventory before we enable dropping it
-		bool new_value = enable_detach() && can_build && item;
+//		bool new_value = enable_detach() && can_build && item;
+// [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.0.0b) | Modified: RLVa-1.0.0b
+		bool new_value = enable_detach() && can_build && item && (!gRlvHandler.hasBehaviour(RLV_BHVR_REZ));
+// [/RLVa:KB]
 
 		return new_value;
 	}
@@ -6241,6 +6494,20 @@ BOOL enable_detach(const LLSD&)
 		// ...if it's you, good to detach
 		if (avatar->getID() == gAgent.getID())
 		{
+// [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0a) | Modified: RLVa-1.0.5
+			// NOTE: this code is reused as-is in LLAttachmentDetach::handleEvent() and LLAttachmentDrop::handleEvent()
+			//       so any changes here should be reflected there as well
+
+			// RELEASE-RLVa: [SL-2.0.0] LLSelectMgr::sendDetach() and LLSelectMgr::sendDropAttachment() call sendListToRegions with
+			//                          SEND_ONLY_ROOTS so we only need to examine the roots which saves us time
+			if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
+			{
+				LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection();
+				RlvSelectHasLockedAttach f;
+				if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE)) )
+					return FALSE;
+			}
+// [/RLVa:KB]
 			return TRUE;
 		}
 
@@ -6260,8 +6527,32 @@ class LLAttachmentEnableDetach : public view_listener_t
 };
 
 // Used to tell if the selected object can be attached to your avatar.
-BOOL object_selected_and_point_valid()
+//BOOL object_selected_and_point_valid()
+// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+BOOL object_selected_and_point_valid(const LLSD& sdParam)
+// [/RLVa:KB]
 {
+// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a
+	if (rlv_handler_t::isEnabled())
+	{
+		if (!isAgentAvatarValid())
+			return FALSE;
+
+		// RELEASE-RLVa: [SL-2.1.1] Look at the caller graph for this function on every new release
+		//   - object_is_wearable() => dead code [sdParam == 0 => default attach point => OK!]
+		//   - enabler set up in LLVOAvatarSelf::buildMenus() => Rezzed prim / Put On / "Attach To" [sdParam == idxAttachPt]
+		// RELEASE-RLVa: [SL-2.1.2] This will need revisiting when LL deprecates the "MultipleAttachment" debug setting
+		const LLViewerJointAttachment* pAttachPt = 
+			get_if_there(gAgentAvatarp->mAttachmentPoints, sdParam.asInteger(), (LLViewerJointAttachment*)NULL);
+		if ( ((!pAttachPt) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY))) ||	// Can't wear on default attach point
+			 ((pAttachPt) && (RLV_WEAR_LOCKED == gRlvAttachmentLocks.canAttach(pAttachPt))) ||	// or replace a locked attachment
+			 (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) )											// Attach on rezzed object == "Take"
+		{
+			return FALSE;
+		}
+	}
+// [/RLVa:KB]
+
 	LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
 	for (LLObjectSelection::root_iterator iter = selection->root_begin();
 		 iter != selection->root_end(); iter++)
@@ -6289,9 +6580,12 @@ BOOL object_selected_and_point_valid()
 }
 
 
+// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+/*
 BOOL object_is_wearable()
 {
-	if (!object_selected_and_point_valid())
+//	if (!object_selected_and_point_valid())
+	if (!object_selected_and_point_valid(LLSD(0)))
 	{
 		return FALSE;
 	}
@@ -6311,7 +6605,8 @@ BOOL object_is_wearable()
 	}
 	return FALSE;
 }
-
+*/
+// [/RLVa:KB]
 
 class LLAttachmentPointFilled : public view_listener_t
 {
@@ -6321,7 +6616,12 @@ class LLAttachmentPointFilled : public view_listener_t
 		LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger());
 		if (found_it != gAgentAvatarp->mAttachmentPoints.end())
 		{
-			enable = found_it->second->getNumObjects() > 0;
+//			enable = found_it->second->getNumObjects() > 0;
+// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+			// Enable the option if there is at least one attachment on this attachment point that can be detached
+			enable = (found_it->second->getNumObjects() > 0) &&
+				((!rlv_handler_t::isEnabled()) || (gRlvAttachmentLocks.canDetach(found_it->second)));
+// [/RLVa:KB]
 		}
 		return enable;
 	}
@@ -6332,7 +6632,10 @@ class LLAvatarSendIM : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
-		if(avatar)
+//		if(avatar)
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+		if ( (avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
+// [/RLVa:KB]
 		{
 			LLAvatarActions::startIM(avatar->getID());
 		}
@@ -6345,7 +6648,10 @@ class LLAvatarCall : public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
-		if(avatar)
+//		if(avatar)
+// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+		if ( (avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) )
+// [/RLVa:KB]
 		{
 			LLAvatarActions::startCall(avatar->getID());
 		}
@@ -6353,6 +6659,13 @@ class LLAvatarCall : public view_listener_t
 	}
 };
 
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+bool enable_avatar_call()
+{
+	return (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (LLAvatarActions::canCall());
+}
+// [/RLVa:KB]
+
 namespace
 {
 	struct QueueObjects : public LLSelectedObjectFunctor
@@ -6415,6 +6728,17 @@ class LLToolsSelectedScriptAction : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a
+		// We'll allow resetting the scripts of objects on a non-attachable attach point since they wouldn't be able to circumvent anything
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) )
+		{
+			LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection();
+			RlvSelectHasLockedAttach f;
+			if ( (hSel->isAttachment()) && (hSel->getFirstNode(&f)) )
+				return true;
+		}
+// [/RLVa:KB]
+
 		std::string action = userdata.asString();
 		bool mono = false;
 		std::string msg, name;
@@ -6515,12 +6839,30 @@ void handle_selected_texture_info(void*)
 
 void handle_test_male(void*)
 {
+// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+	// TODO-RLVa: [RLVa-1.2.1] Is there any reason to still block this?
+	if ( (rlv_handler_t::isEnabled()) && 
+		 ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY))) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit");
 	//gGestureList.requestResetFromServer( TRUE );
 }
 
 void handle_test_female(void*)
 {
+// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+	// TODO-RLVa: [RLVa-1.2.1] Is there any reason to still block this?
+	if ( (rlv_handler_t::isEnabled()) && 
+		 ((gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY))) )
+	{
+		return;
+	}
+// [/RLVa:KB]
+
 	LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit");
 	//gGestureList.requestResetFromServer( FALSE );
 }
@@ -6722,7 +7064,12 @@ bool enable_object_take_copy()
 			{
 				virtual bool apply(LLViewerObject* obj)
 				{
-					return (!obj->permCopy() || obj->isAttachment());
+//					return (!obj->permCopy() || obj->isAttachment());
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g
+					return (!obj->permCopy() || obj->isAttachment()) || 
+						   ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && 
+						     (gAgentAvatarp->getRoot() == obj) );
+// [/RLVa:KB]
 				}
 			} func;
 			const bool firstonly = true;
@@ -6876,6 +7223,9 @@ class LLWorldEnableTeleportHome : public view_listener_t
 		LLViewerRegion* regionp = gAgent.getRegion();
 		bool agent_on_prelude = (regionp && regionp->isPrelude());
 		bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude;
+// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-1.1.0j
+		enable_teleport_home &= !gRlvHandler.hasBehaviour(RLV_BHVR_TPLM);
+// [/RLVa:KB]
 		return enable_teleport_home;
 	}
 };
@@ -7337,6 +7687,11 @@ class LLViewHighlightTransparent : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!LLDrawPoolAlpha::sShowDebugAlpha))
+			return true;
+// [/RLVa:KB]
+
 		LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha;
 		return true;
 	}
@@ -7523,6 +7878,11 @@ class LLViewShowHUDAttachments : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
 	{
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c
+		if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedHUD()) && (LLPipeline::sShowHUDAttachments) )
+			return true;
+// [/RLVa:KB]
+
 		LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments;
 		return true;
 	}
@@ -7543,8 +7903,15 @@ class LLEditEnableTakeOff : public view_listener_t
 	{
 		std::string clothing = userdata.asString();
 		LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
-		if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT)
+//		if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT)
+// [RLVa:KB] - Checked: 2010-03-20 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+		// NOTE: see below - enable if there is at least one wearable on this type that can be removed
+		if ( (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) && 
+			 ((!rlv_handler_t::isEnabled()) || (gRlvWearableLocks.canRemove(type))) )
+// [/RLVa:KB]
+		{
 			return LLAgentWearables::selfHasWearable(type);
+		}
 		return false;
 	}
 };
@@ -7565,6 +7932,22 @@ class LLEditTakeOff : public view_listener_t
 			{
 				// MULTI-WEARABLES: assuming user wanted to remove top shirt.
 				U32 wearable_index = gAgentWearables.getWearableCount(type) - 1;
+
+// [RLVa:KB] - Checked: 2010-06-09 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+				if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearable(type)) )
+				{
+					// We'll use the first wearable we come across that can be removed (moving from top to bottom)
+					for (; wearable_index >= 0; wearable_index--)
+					{
+						const LLWearable* pWearable = gAgentWearables.getWearable(type, wearable_index);
+						if (!gRlvWearableLocks.isLockedWearable(pWearable))
+							break;
+					}
+					if (wearable_index < 0)
+						return true;	// No wearable found that can be removed
+				}
+// [/RLVa:KB]
+
 				LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(gAgentWearables.getWearableInventoryItem(type,wearable_index));
 				LLWearableBridge::removeItemFromAvatar(item);
 			}
@@ -7618,6 +8001,12 @@ class LLWorldEnvSettings : public view_listener_t
 			return true;
 		}
 		
+// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-1.0.0g
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV))
+		{
+			return true;
+		} else
+// [/RLVa:KB]
 		if (tod == "sunrise")
 		{
 			// set the value, turn off animation
@@ -8137,7 +8526,10 @@ void initialize_menus()
 	commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD()));
 	view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM");
 	view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call");
-	enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
+//	enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
+// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b
+	enable.add("Avatar.EnableCall", boost::bind(&enable_avatar_call));
+// [/RLVa:KB]
 	view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
 	
 	view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend");
@@ -8165,7 +8557,10 @@ void initialize_menus()
 	enable.add("Object.EnableOpen", boost::bind(&enable_object_open));
 	enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1));
 	enable.add("Object.EnableDelete", boost::bind(&enable_object_delete));
-	enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid));
+//	enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid));
+// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid, _2));
+// [/RLVa:KB]
 
 	enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up));
 	enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1));
@@ -8220,4 +8615,12 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected");
 	view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
 
+// [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0g) | Added: RLVa-1.2.0
+	commit.add("RLV.ToggleEnabled", boost::bind(&rlvMenuToggleEnabled));
+	enable.add("RLV.CheckEnabled", boost::bind(&rlvMenuCheckEnabled));
+	if (rlv_handler_t::isEnabled())
+	{
+		enable.add("RLV.EnableIfNot", boost::bind(&rlvMenuEnableIfNot, _2));
+	}
+// [/RLVa:KB]
 }
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 82bc084f6820f144c54fe4284062497ae1c99fd3..4c34792dc6f1964e24ddfbb0c762233da06fc998 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -99,6 +99,11 @@
 #include "llagentui.h"
 #include "llpanelblockedlist.h"
 #include "llpanelplaceprofile.h"
+// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+#include "rlvinventory.h"
+#include "rlvui.h"
+// [/RLVa:KB]
 
 #include <boost/algorithm/string/split.hpp> //
 #include <boost/regex.hpp>
@@ -1376,7 +1381,14 @@ void LLOfferInfo::send_auto_receive_response(void)
 	if(IM_INVENTORY_OFFERED == mIM)
 	{
 		// add buddy to recent people list
-		LLRecentPeople::instance().add(mFromID);
+//		LLRecentPeople::instance().add(mFromID);
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+		// RELEASE-RLVa: [RLVa-1.2.0] Make sure this stays in sync with the condition in inventory_offer_handler()
+		if ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (!RlvUtil::isNearbyAgent(mFromID)) || (RlvUIEnabler::hasOpenIM(mFromID)))
+		{
+			LLRecentPeople::instance().add(mFromID);
+		}
+// [/RLVa:KB]
 	}
 }
 
@@ -1447,6 +1459,21 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
 				// This is an offer from an agent. In this case, the back
 				// end has already copied the items into your inventory,
 				// so we can fetch it out of our inventory.
+// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+#ifdef RLV_EXTENSION_GIVETORLV_A2A
+				if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && (LLAssetType::AT_CATEGORY == mType) && 
+					 (RlvInventory::instance().getSharedRoot()) && (mDesc.find(RLV_PUTINV_PREFIX) == 0) )
+				{
+					RlvGiveToRLVAgentOffer* pOfferObserver = new RlvGiveToRLVAgentOffer(mObjectID);
+					pOfferObserver->startFetch();
+					if (pOfferObserver->isFinished())
+						pOfferObserver->done();
+					else
+						gInventory.addObserver(pOfferObserver);
+				}
+#endif // RLV_EXTENSION_GIVETORLV_A2A
+// [/RLVa:KB]
+
 				LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string);
 				open_agent_offer->startFetch();
 				if(catp || (itemp && itemp->isFinished()))
@@ -1611,12 +1638,27 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
 		}
 		else
 		{
-			std::string first_name, last_name;
-			if (gCacheName->getName(mFromID, first_name, last_name))
+//			std::string first_name, last_name;
+//			if (gCacheName->getName(mFromID, first_name, last_name))
+// [RLVa:KB] - Checked: 2010-04-022 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+			std::string strFullName;
+			if (gCacheName->getFullName(mFromID, strFullName))
+// [/RLVa:KB]
 			{
+// [RLVa:KB] - Checked: 2010-04-022 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+				// RELEASE-RLVa: [RLVa-1.2.0] Make sure this stays in sync with the condition in inventory_offer_handler()
+				if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(mFromID)) &&
+					 (!RlvUIEnabler::hasOpenIM(mFromID)) )
+				{
+					strFullName = RlvStrings::getAnonym(strFullName);
+				}
 				from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName 
-				+ LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + first_name + " " + last_name;
-				chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + first_name + " " + last_name;
+					+ LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + strFullName;
+				chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + strFullName;
+// [/RLVa:KB]
+//				from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName 
+//				+ LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + first_name + " " + last_name;
+//				chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + first_name + " " + last_name;
 			}
 			else
 			{
@@ -1639,6 +1681,26 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
 			// ACCEPT. The math for the dialog works, because the accept
 			// for inventory_offered, task_inventory_offer or
 			// group_notice_inventory is 1 greater than the offer integer value.
+
+// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+			// Only change the inventory offer's destination folder to the shared root if:
+			//   - the user has enabled the feature
+			//   - the inventory offer came from a script (and specifies a folder)
+			//   - the name starts with the prefix - mDesc format: '[OBJECTNAME]'  ( http://slurl.com/... )
+			if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && 
+				 (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) )
+			{
+				const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot();
+				if (pRlvRoot)
+				{
+					mFolderID = pRlvRoot->getUUID();
+
+					RlvGiveToRLVTaskOffer* pOfferObserver = new RlvGiveToRLVTaskOffer(mTransactionID);
+					gInventory.addObserver(pOfferObserver);
+				}
+			}
+// [/RLVa:KB]
+
 			// Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, 
 			// or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
 			msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
@@ -1829,6 +1891,15 @@ void inventory_offer_handler(LLOfferInfo* info)
 	// Object -> Agent Inventory Offer
 	if (info->mFromObject)
 	{
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+		// Only filter if the object owner is a nearby agent
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) )
+		{
+			payload["rlv_shownames"] = TRUE;
+			args["NAME"] = args["NAME_SLURL"] = RlvStrings::getAnonym(info->mFromName);
+		}
+// [/RLVa:KB]
+
 		// Inventory Slurls don't currently work for non agent transfers, so only display the object name.
 		args["ITEM_SLURL"] = msg;
 		// Note: sets inventory_task_offer_callback as the callback
@@ -1840,6 +1911,16 @@ void inventory_offer_handler(LLOfferInfo* info)
 	}
 	else // Agent -> Agent Inventory Offer
 	{
+// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+		// Only filter if the offer is from a nearby agent and if there's no open IM session (doesn't necessarily have to be focused)
+		if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) &&
+			 (!RlvUIEnabler::hasOpenIM(info->mFromID)) )
+		{
+			payload["rlv_shownames"] = TRUE;
+			args["NAME"] = args["NAME_SLURL"] = RlvStrings::getAnonym(info->mFromName);
+		}
+// [/RLVa:KB]
+
 		p.responder = info;
 		// Note: sets inventory_offer_callback as the callback
 		// *TODO fix memory leak
@@ -2109,7 +2190,18 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 			// do nothing -- don't distract newbies in
 			// Prelude with global IMs
 		}
-		else if (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM)
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
+		else if ( (rlv_handler_t::isEnabled()) && (offline == IM_ONLINE) && ("@version" == message) )
+		{
+			// TODO-RLVa: [RLVa-1.2.1] Should we send our version string if the other party is muted?
+			RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(), session_id);
+		}
+// [/RLVa:KB]
+//		else if (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM)
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0a) | Modified: RLVa-1.0.0g
+		else if ( (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM) && 
+			      ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) || (gRlvHandler.isException(RLV_BHVR_RECVIM, from_id))) )
+// [/RLVa:KB]
 		{
 			// return a standard "busy" message, but only do it to online IM 
 			// (i.e. not other auto responses and not store-and-forward IM)
@@ -2180,6 +2272,23 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 		else
 		{
 			// standard message, not from system
+			bool mute_im = is_muted;
+			if(accept_im_from_only_friend&&!is_friend)
+			{
+				mute_im = true;
+			}
+
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a
+			// Don't block offline IMs, or IMs from Lindens
+			if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!is_linden) &&
+				 (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) && (!gRlvHandler.isException(RLV_BHVR_RECVIM, from_id)) )
+			{
+				if (!mute_im)
+					RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id);
+				message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM);
+			}
+// [/RLVa:KB]
+
 			std::string saved;
 			if(offline == IM_OFFLINE)
 			{
@@ -2191,11 +2300,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 
 			LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL;
 
+/*
 			bool mute_im = is_muted;
 			if(accept_im_from_only_friend&&!is_friend)
 			{
 				mute_im = true;
 			}
+*/
 			if (!mute_im || is_linden) 
 			{
 				gIMMgr->addMessage(
@@ -2412,6 +2523,15 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 				bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0];
 				info->mType = (LLAssetType::EType) bucketp->asset_type;
 				info->mObjectID = bucketp->object_id;
+
+// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e)
+/*
+				if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (gRlvHandler.isAgentNearby(from_id)) )
+				{
+					name = RlvStrings::getAnonym(name);
+				}
+*/
+// [/RLVa:KB]
 			}
 			else
 			{
@@ -2462,7 +2582,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 
 	case IM_INVENTORY_ACCEPTED:
 	{
-		args["NAME"] = name;
+//		args["NAME"] = name;
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+		// Only filter the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open
+		bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && 
+			(!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id));
+		args["NAME"] = (!fRlvFilterName) ? name : RlvStrings::getAnonym(name);
+// [/RLVa:KB]
 		LLSD payload;
 		payload["from_id"] = from_id;
 		LLNotificationsUtil::add("InventoryAccepted", args, payload);
@@ -2470,7 +2596,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 	}
 	case IM_INVENTORY_DECLINED:
 	{
-		args["NAME"] = name;
+//		args["NAME"] = name;
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+		// Only filter the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open
+		bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && 
+			(!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id));
+		args["NAME"] = (!fRlvFilterName) ? name : RlvStrings::getAnonym(name);
+// [/RLVa:KB]
 		LLSD payload;
 		payload["from_id"] = from_id;
 		LLNotificationsUtil::add("InventoryDeclined", args, payload);
@@ -2498,10 +2630,37 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 
 		// Only show messages if we have a session open (which
 		// should happen after you get an "invitation"
+/*
 		if ( !gIMMgr->hasSession(session_id) )
 		{
 			return;
 		}
+*/
+// [RLVa:KB] - Checked: 2010-03-23 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a
+		LLIMModel::LLIMSession* pIMSession = LLIMModel::instance().findIMSession(session_id);
+		if (!pIMSession)
+		{
+			return;
+		}
+
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM))
+		{
+			switch (pIMSession->mSessionType)
+			{
+				case LLIMModel::LLIMSession::GROUP_SESSION:	// Group chat: allow if group is a sendim exception
+					if ( (from_id != gAgent.getID()) && (!gRlvHandler.isException(RLV_BHVR_RECVIM, session_id)) )
+						return;
+					break;
+				case LLIMModel::LLIMSession::ADHOC_SESSION:	// Conference chat: allow if the sender is a sendim exception
+					if ( (from_id != gAgent.getID()) && (!gRlvHandler.isException(RLV_BHVR_RECVIM, from_id)) )
+						message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM);
+					break;
+				default:
+					RLV_ASSERT(false);
+					return;
+			}
+		}
+// [/RLVa:KB]
 
 		// standard message, not from system
 		std::string saved;
@@ -2564,6 +2723,30 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 
 			LLSD query_string;
 			query_string["owner"] = from_id;
+// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+			if (rlv_handler_t::isEnabled())
+			{
+				// NOTE: the chat message itself will be filtered in LLNearbyChatHandler::processChat()
+				if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!from_group) && (RlvUtil::isNearbyAgent(from_id)) )
+				{
+					std::string strOwnerName;
+					if (gCacheName->getFullName(from_id, strOwnerName))
+					{
+						query_string["owner"] = LLUUID::null;
+						query_string["owner_name"] = RlvStrings::getAnonym(strOwnerName);
+					}
+
+					RlvUtil::filterNames(name);
+					chat.mFromName = name;
+				}
+				if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+				{
+					std::string::size_type idxPos = location.find('/');
+					if ( (std::string::npos != idxPos) && (RlvUtil::isNearbyRegion(location.substr(0, idxPos))) )
+						location = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+				}
+			}
+// [/RLVa:KB]
 			query_string["slurl"] = location;
 			query_string["name"] = name;
 			if (from_group)
@@ -2664,6 +2847,26 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 					region_access_icn = LLViewerRegion::getAccessIcon(region_access);
 				}
 
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0d
+				if (rlv_handler_t::isEnabled())
+				{
+					// Block if: 1) @tplure=n restricted (and sender isn't an exception), or 2) @unsit=n restricted and currently sitting
+					if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_TPLURE)) && (!gRlvHandler.isException(RLV_BHVR_TPLURE, from_id)) ) || 
+						 ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) ) )
+					{
+						RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLURE_REMOTE));
+						return;
+					}
+
+					// Censor lure message if: 1) @revcim=n restricted (and sender isn't an exception), or 2) @showloc=n restricted
+					if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) && (!gRlvHandler.isException(RLV_BHVR_RECVIM, from_id)) ) ||
+						 (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) )
+					{
+						message = RlvStrings::getString(RLV_STRING_HIDDEN);
+					}
+				}
+// [/RLVa:KB]
+
 				LLSD args;
 				// *TODO: Translate -> [FIRST] [LAST] (maybe)
 				args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString();
@@ -2675,10 +2878,23 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 				payload["lure_id"] = session_id;
 				payload["godlike"] = FALSE;
 
-			    LLNotification::Params params("TeleportOffered");
-			    params.substitutions = args;
-			    params.payload = payload;
-			    LLPostponedNotification::add<LLPostponedOfferNotification>(	params, from_id, false);
+				LLNotification::Params params("TeleportOffered");
+				params.substitutions = args;
+				params.payload = payload;
+
+// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-0.2.0b
+				if ( (rlv_handler_t::isEnabled()) &&
+					 ((gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTP)) || (gRlvHandler.isException(RLV_BHVR_ACCEPTTP, from_id))) )
+				{
+					gRlvHandler.setCanCancelTp(false);
+					LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0);
+				}
+				else
+				{
+					LLPostponedNotification::add<LLPostponedOfferNotification>(	params, from_id, false);
+				}
+// [/RLVa:KB]
+//				LLPostponedNotification::add<LLPostponedOfferNotification>(	params, from_id, false);
 			}
 		}
 		break;
@@ -2963,8 +3179,13 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 		chat.mPosAgent = chatter->getPositionAgent();
 
 		// Make swirly things only for talking objects. (not script debug messages, though)
-		if (chat.mSourceType == CHAT_SOURCE_OBJECT 
-			&& chat.mChatType != CHAT_TYPE_DEBUG_MSG)
+//		if (chat.mSourceType == CHAT_SOURCE_OBJECT 
+//			&& chat.mChatType != CHAT_TYPE_DEBUG_MSG)
+// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0b) | Modified: RLVa-1.0.0g
+		// Don't show swirly things for llOwnerSay() chat here because we handle those further down
+		if ( ((chat.mSourceType == CHAT_SOURCE_OBJECT) && (chat.mChatType != CHAT_TYPE_DEBUG_MSG)) &&
+			 ((!rlv_handler_t::isEnabled()) || (CHAT_TYPE_OWNER != chat.mChatType)) )
+// [/RLVa:KB]
 		{
 			LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent());
 			psc->setSourceObject(chatter);
@@ -2997,6 +3218,75 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 		color.setVec(1.f,1.f,1.f,1.f);
 		msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg);
 
+// [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+		if ( (rlv_handler_t::isEnabled()) && (CHAT_TYPE_START != chat.mChatType) && (CHAT_TYPE_STOP != chat.mChatType) )
+		{
+			// NOTE: chatter can be NULL (may not have rezzed yet, or could be another avie's HUD attachment)
+			BOOL is_attachment = (chatter) ? chatter->isAttachment() : FALSE;
+
+			// Filtering "rules":
+			//   avatar  => filter all avie text (unless it's this avie or they're an exemption)
+			//   objects => filter everything except attachments this avie owns (never filter llOwnerSay chat)
+			if ( ( (CHAT_SOURCE_AGENT == chat.mSourceType) && (from_id != gAgent.getID()) ) || 
+				 ( (CHAT_SOURCE_OBJECT == chat.mSourceType) && ((!is_owned_by_me) || (!is_attachment)) && 
+				   (CHAT_TYPE_OWNER != chat.mChatType) ) )
+			{
+				if (!RlvUtil::isEmote(mesg))
+				{
+					if ( (gRlvHandler.hasBehaviour(RLV_BHVR_RECVCHAT)) && (!gRlvHandler.isException(RLV_BHVR_RECVCHAT, from_id)) )
+						gRlvHandler.filterChat(mesg, false);
+				}
+				else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_RECVEMOTE)) && (!gRlvHandler.isException(RLV_BHVR_RECVEMOTE, from_id)) )
+				{
+					mesg = "/me ...";
+				}
+			}
+
+			// Filtering "rules":
+			//   avatar => filter only their name (unless it's this avie)
+			//   other  => filter everything except attachments this avie owns but then we still do filter their text
+			if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) &&
+				 ((CHAT_SOURCE_AGENT != chat.mSourceType) || (chat.mFromID != gAgent.getID())) )
+			{
+				if (CHAT_SOURCE_AGENT == chat.mSourceType)
+				{
+					chat.mFromName = RlvStrings::getAnonym(from_name);
+					chat.mRlvNamesFiltered = TRUE;
+				} 
+				else if ( (!is_owned_by_me) || (!is_attachment) )
+				{
+					RlvUtil::filterNames(chat.mFromName);
+				}
+			}
+
+			// Create an "objectim" URL for objects if we're either @shownames or @showloc restricted
+			// (we need to do this now because we won't be have enough information to do it later on)
+			if ( (CHAT_SOURCE_OBJECT == chat.mSourceType) && 
+				 ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))) )
+			{
+				LLSD sdQuery; std::string strOwnerName, strQuery;
+				sdQuery["name"] = chat.mFromName;
+
+				sdQuery["owner"] = owner_id;
+				if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && 
+					 (!is_owned_by_me) && (gCacheName->getFullName(owner_id, strOwnerName)) )
+				{
+					sdQuery["owner"] = LLUUID::null;
+					sdQuery["owner_name"] = RlvStrings::getAnonym(strOwnerName);
+				}
+
+				const LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
+				if (pRegion)
+				{
+					sdQuery["slurl"] = LLSLURL(pRegion->getName(), LLVector3d(chat.mPosAgent)).getSLURLString();
+				}
+
+				strQuery = LLURI::mapToQueryString(sdQuery);
+				chat.mURL = LLSLURL("objectim", from_id, strQuery).getSLURLString();
+			}
+		}
+// [/RLVa:KB]
+
 		BOOL ircstyle = FALSE;
 
 		// Look for IRC-style emotes here so chatbubbles work
@@ -3046,8 +3336,98 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 			case CHAT_TYPE_WHISPER:
 				verb = LLTrans::getString("whisper") + " ";
 				break;
-			case CHAT_TYPE_DEBUG_MSG:
 			case CHAT_TYPE_OWNER:
+// [RLVa:KB] - Checked: 2010-02-XX (RLVa-1.2.0a) | Modified: RLVa-1.1.0f
+				// TODO-RLVa: [RLVa-1.2.0] consider rewriting this before a RLVa-1.2.0 release
+				if ( (rlv_handler_t::isEnabled()) && (mesg.length() > 3) && (RLV_CMD_PREFIX == mesg[0]) && (CHAT_TYPE_OWNER == chat.mChatType) )
+				{
+					mesg.erase(0, 1);
+					LLStringUtil::toLower(mesg);
+
+					std::string strExecuted, strFailed, strRetained, *pstr;
+
+					boost_tokenizer tokens(mesg, boost::char_separator<char>(",", "", boost::drop_empty_tokens));
+					for (boost_tokenizer::iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken)
+					{
+						std::string strCmd = *itToken;
+
+						ERlvCmdRet eRet = gRlvHandler.processCommand(from_id, strCmd, true);
+						if ( (RlvSettings::getDebug()) &&
+							 ( (!RlvSettings::getDebugHideUnsetDup()) || 
+							   ((RLV_RET_SUCCESS_UNSET != eRet) && (RLV_RET_SUCCESS_DUPLICATE != eRet)) ) )
+						{
+							if ( RLV_RET_SUCCESS == (eRet & RLV_RET_SUCCESS) )	
+								pstr = &strExecuted;
+							else if ( RLV_RET_FAILED == (eRet & RLV_RET_FAILED) )
+								pstr = &strFailed;
+							else if (RLV_RET_RETAINED == eRet)
+								pstr = &strRetained;
+							else
+							{
+								RLV_ASSERT(false);
+								pstr = &strFailed;
+							}
+
+							const char* pstrSuffix = RlvStrings::getStringFromReturnCode(eRet);
+							if (pstrSuffix)
+								strCmd.append(" (").append(pstrSuffix).append(")");
+
+							if (!pstr->empty())
+								pstr->push_back(',');
+							pstr->append(strCmd);
+						}
+					}
+
+					if (RlvForceWear::instanceExists())
+						RlvForceWear::instance().done();
+
+					if ( (!RlvSettings::getDebug()) || ((strExecuted.empty()) && (strFailed.empty()) && (strRetained.empty())) )
+						return;
+
+					// Silly people want comprehensive debug messages, blah :p
+					if ( (!strExecuted.empty()) && (strFailed.empty()) && (strRetained.empty()) )
+					{
+						verb = " executes: @";
+						mesg = strExecuted;
+					}
+					else if ( (strExecuted.empty()) && (!strFailed.empty()) && (strRetained.empty()) )
+					{
+						verb = " failed: @";
+						mesg = strFailed;
+					}
+					else if ( (strExecuted.empty()) && (strFailed.empty()) && (!strRetained.empty()) )
+					{
+						verb = " retained: @";
+						mesg = strRetained;
+					}
+					else
+					{
+						verb = ": @";
+						if (!strExecuted.empty())
+							mesg += "\n    - executed: @" + strExecuted;
+						if (!strFailed.empty())
+							mesg += "\n    - failed: @" + strFailed;
+						if (!strRetained.empty())
+							mesg += "\n    - retained: @" + strRetained;
+					}
+
+					break;
+				}
+// [/RLVa:KB]
+// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0b) | Modified: RLVa-1.0.0g
+				// Copy/paste from above
+				if  ( (rlv_handler_t::isEnabled()) && (chatter) && (chat.mSourceType == CHAT_SOURCE_OBJECT) )
+				{
+					LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent());
+					psc->setSourceObject(chatter);
+					psc->setColor(color);
+					//We set the particles to be owned by the object's owner, 
+					//just in case they should be muted by the mute list
+					psc->setOwnerUUID(owner_id);
+					LLViewerPartSim::getInstance()->addPartSource(psc);
+				}
+// [/RLVa:KB]
+			case CHAT_TYPE_DEBUG_MSG:
 			case CHAT_TYPE_NORMAL:
 				verb = "";
 				break;
@@ -3128,7 +3508,10 @@ void process_teleport_start(LLMessageSystem *msg, void**)
 	U32 teleport_flags = 0x0;
 	msg->getU32("Info", "TeleportFlags", teleport_flags);
 
-	if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
+//	if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
+// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0b
+	if ( (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) || (!gRlvHandler.getCanCancelTp()) )
+// [/RLVa:KB]
 	{
 		gViewerWindow->setProgressCancelButtonVisible(FALSE);
 	}
@@ -3163,7 +3546,10 @@ void process_teleport_progress(LLMessageSystem* msg, void**)
 	}
 	U32 teleport_flags = 0x0;
 	msg->getU32("Info", "TeleportFlags", teleport_flags);
-	if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
+//	if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
+// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0b
+	if ( (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) || (!gRlvHandler.getCanCancelTp()) )
+// [/RLVa:KB]
 	{
 		gViewerWindow->setProgressCancelButtonVisible(FALSE);
 	}
@@ -5352,7 +5738,7 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp
 			if (viewregion)
 			{
 				// got the region, so include the region and 3d coordinates of the object
-				notice.setArg("[REGIONNAME]", viewregion->getName());				
+				notice.setArg("[REGIONNAME]", viewregion->getName());
 				std::string formatpos = llformat("%.1f, %.1f,%.1f", objpos[VX], objpos[VY], objpos[VZ]);
 				notice.setArg("[REGIONPOS]", formatpos);
 
@@ -5360,7 +5746,15 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp
 			}
 		}
 
-		if (!foundpos)
+// [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.0.0a
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		{
+			notice.setArg("[REGIONNAME]", RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
+			notice.setArg("[REGIONPOS]", RlvStrings::getString(RLV_STRING_HIDDEN));
+		}
+		else if (!foundpos)
+// [/RLVa:KB]
+//		if (!foundpos)
 		{
 			// unable to determine location of the object
 			notice.setArg("[REGIONNAME]", "(unknown region)");
@@ -5565,8 +5959,32 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
 		payload["object_name"] = object_name;
 		payload["owner_name"] = owner_name;
 
+// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Modified: RLVa-0.2.0e
+		S32 rlvQuestionsOther = questions;
+
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTPERMISSION))
+		{
+			const LLViewerObject* pObj = gObjectList.findObject(taskid);
+			if (pObj)
+			{
+//				if (pObj->permYouOwner())
+//				{
+					// PERMISSION_TAKE_CONTROLS and PERMISSION_ATTACH are only auto-granted to objects this avie owns
+					rlvQuestionsOther &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS] | 
+						LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH]);
+//				}
+			}
+		}
+
+		if ( (!caution) && (!rlvQuestionsOther) )
+		{
+			LLNotifications::instance().forceResponse(
+				LLNotification::Params("ScriptQuestion").substitutions(args).payload(payload), 0/*YES*/);
+		}
+		else if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
+// [/RLVa:KB]
 		// check whether cautions are even enabled or not
-		if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
+//		if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
 		{
 			// display the caution permissions prompt
 			LLNotificationsUtil::add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload);
@@ -5914,6 +6332,22 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response)
 
 	if(0 == option)
 	{
+// [RLVa:KB] - Checked: 2010-04-09 (RLVa-1.2.0e) | Modified: RLVa-0.2.0b
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM))
+		{
+			// Filter the teleport offer text unless everyone is a sendim exception
+			for (LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray(); 
+					it != notification["payload"]["ids"].endArray(); ++it)
+			{
+				if (!gRlvHandler.isException(RLV_BHVR_SENDIM, it->asUUID()))
+				{
+					text = RlvStrings::getString(RLV_STRING_HIDDEN);
+					break;
+				}
+			}
+		}
+// [/RLVa:KB]
+
 		LLMessageSystem* msg = gMessageSystem;
 		msg->newMessageFast(_PREHASH_StartLure);
 		msg->nextBlockFast(_PREHASH_AgentData);
@@ -5968,13 +6402,29 @@ void handle_lure(const uuid_vec_t& ids)
 	if (!gAgent.getRegion()) return;
 
 	LLSD edit_args;
-	edit_args["REGION"] = gAgent.getRegion()->getName();
+// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a
+	edit_args["REGION"] = 
+		(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? gAgent.getRegion()->getName() : RlvStrings::getString(RLV_STRING_HIDDEN);
+// [/RLVa:KB]
+//	edit_args["REGION"] = gAgent.getRegion()->getName();
 
 	LLSD payload;
 	for (LLDynamicArray<LLUUID>::const_iterator it = ids.begin();
 		it != ids.end();
 		++it)
 	{
+// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a
+		// Only allow offering teleports if everyone is a @tplure exception or able to map this avie under @showloc=n
+		if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+		{
+			const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(*it);
+			if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, *it, RLV_CHECK_PERMISSIVE)) &&
+				 ((!pBuddyInfo) || (!pBuddyInfo->isOnline()) || (!pBuddyInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))) )
+			{
+				return;
+			}
+		}
+// [/RLVa:KB]
 		payload["ids"].append(*it);
 	}
 	if (gAgent.isGodlike())
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 25cc24da95c36f85c0dc0d15cd4d03d2b01e1971..b3194ecdc7b965e961377f23277f122464ecebdc 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -99,6 +99,9 @@
 #include "lltrans.h"
 #include "llsdutil.h"
 #include "llmediaentry.h"
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 //#define DEBUG_UPDATE_TYPE
 
@@ -1093,6 +1096,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 					coloru.mV[3] = 255 - coloru.mV[3];
 					mText->setColor(LLColor4(coloru));
 					mText->setStringUTF8(temp_string);
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.0f
+					if (rlv_handler_t::isEnabled())
+					{
+						mText->setObjectText(temp_string);
+					}
+// [/RLVa:KB]
 					
 					if (mDrawable.notNull())
 					{
@@ -1485,6 +1494,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 					coloru.mV[3] = 255 - coloru.mV[3];
 					mText->setColor(LLColor4(coloru));
 					mText->setStringUTF8(temp_string);
+// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.0f
+					if (rlv_handler_t::isEnabled())
+					{
+						mText->setObjectText(temp_string);
+					}
+// [/RLVa:KB]
 
 					setChanged(TEXTURE);
 				}
@@ -1655,6 +1670,25 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 								gObjectList.killObject(this);
 								return retval;
 							}
+// [RLVa:KB] - Checked: 2010-03-16 (RLVa-1.1.0k) | Added: RLVa-1.1.0k
+							if ( (rlv_handler_t::isEnabled()) && (sent_parentp->isAvatar()) && (sent_parentp->getID() == gAgent.getID()) )
+							{
+								// Rezzed object that's being worn as an attachment (we're assuming this will be due to llAttachToAvatar())
+								S32 idxAttachPt = ATTACHMENT_ID_FROM_STATE(getState());
+								if (gRlvAttachmentLocks.isLockedAttachmentPoint(idxAttachPt, RLV_LOCK_ADD))
+								{
+									// If this will end up on an "add locked" attachment point then treat the attach as a user action
+									LLNameValue* nvItem = getNVPair("AttachItemID");
+									if (nvItem)
+									{
+										LLUUID idItem(nvItem->getString());
+										// URGENT-RLVa: [RLVa-1.2.0] At the moment llAttachToAvatar always seems to *add*
+										if (idItem.notNull())
+											RlvAttachmentLockWatchdog::instance().onWearAttachment(idItem, RLV_WEAR_ADD);
+									}
+								}
+							}
+// [/RLVa:KB]
 							sent_parentp->addChild(this);
 							// make sure this object gets a non-damped update
 							if (sent_parentp->mDrawable.notNull())
@@ -4897,7 +4931,10 @@ BOOL LLViewerObject::permTransfer() const
 // given you modify rights to.  JC
 BOOL LLViewerObject::allowOpen() const
 {
-	return !flagInventoryEmpty() && (permYouOwner() || permModify());
+// [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b
+	return !flagInventoryEmpty() && (permYouOwner() || permModify()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_EDIT));
+// [/RLVa:KB]
+//	return !flagInventoryEmpty() && (permYouOwner() || permModify());
 }
 
 LLViewerObject::LLInventoryCallbackInfo::~LLInventoryCallbackInfo()
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index bcc2cb164f2804cf0ce7a83f798f39c4c7a64b25..b50785ca594485f8cac1a144ade4e3cdf6816990 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -328,7 +328,10 @@ public:
 
 	void sendShapeUpdate();
 
-	U8 getState()							{ return mState; }
+//	U8 getState()							{ return mState; }
+// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	U8 getState() const						{ return mState; }
+// [/RLVa:KB]
 
 	F32 getAppAngle() const					{ return mAppAngle; }
 	F32 getPixelArea() const				{ return mPixelArea; }
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 13db913f605255feff69c80d6d26e85d73311389..e0b08ebc1fd61c31c3e65287e659779b7a65c984 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -197,6 +197,10 @@
 #include "llviewerwindowlistener.h"
 #include "llpaneltopinfobar.h"
 
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c)
+#include "rlvhandler.h"
+// [/RLVa:KB]
+
 #if LL_WINDOWS
 #include <tchar.h> // For Unicode conversion methods
 #endif
@@ -3168,6 +3172,15 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls,
 						{
 							moveable_object_selected = TRUE;
 							this_object_movable = TRUE;
+
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g
+							if ( (rlv_handler_t::isEnabled()) && 
+								 ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) )
+							{
+								if ((isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == object->getRootEdit()))
+									moveable_object_selected = this_object_movable = FALSE;
+							}
+// [/RLVa:KB]
 						}
 						all_selected_objects_move = all_selected_objects_move && this_object_movable;
 						all_selected_objects_modify = all_selected_objects_modify && object->permModify();
@@ -3435,17 +3448,42 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
 			}
 
 	else // check ALL objects
-			{
+	{
 		found = gPipeline.lineSegmentIntersectInHUD(mouse_hud_start, mouse_hud_end, pick_transparent,
 													face_hit, intersection, uv, normal, binormal);
 
-		if (!found) // if not found in HUD, look in world:
+// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c
+		if ( (rlv_handler_t::isEnabled()) && (found) &&
+			 (LLToolCamera::getInstance()->hasMouseCapture()) && (gKeyboard->currentMask(TRUE) & MASK_ALT) )
+		{
+			found = NULL;
+		}
+// [/RLVa:KB]
 
-			{
+		if (!found) // if not found in HUD, look in world:
+		{
 			found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent,
 														  face_hit, intersection, uv, normal, binormal);
-			}
 
+// [RLVa:KB] - Checked: 2010-01-02 (RLVa-1.1.0l) | Added: RLVa-1.1.0l
+#ifdef RLV_EXTENSION_CMD_INTERACT
+			if ( (rlv_handler_t::isEnabled()) && (found) && (gRlvHandler.hasBehaviour(RLV_BHVR_INTERACT)) )
+			{
+				// Allow picking if:
+				//   - the drag-and-drop tool is active (allows inventory offers)
+				//   - the camera tool is active
+				//   - the pie tool is active *and* we picked our own avie (allows "mouse steering" and the self pie menu)
+				LLTool* pCurTool = LLToolMgr::getInstance()->getCurrentTool();
+				if ( (LLToolDragAndDrop::getInstance() != pCurTool) && 
+					 (!LLToolCamera::getInstance()->hasMouseCapture()) &&
+					 ((LLToolPie::getInstance() != pCurTool) || (gAgent.getID() != found->getID())) )
+				{
+					found = NULL;
+				}
+			}
+#endif // RLV_EXTENSION_CMD_INTERACT
+// [/RLVa:KB]
+		}
 	}
 
 	return found;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 8b9a511f9db2e0e68955bf9e6970c8c06eeb0e1d..53e85713380a70936b921c37f0ca743986f3029c 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -85,6 +85,9 @@
 #include "llanimstatelabels.h"
 #include "lltrans.h"
 #include "llappearancemgr.h"
+// [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #include "llgesturemgr.h" //needed to trigger the voice gesticulations
 #include "llvoiceclient.h"
@@ -2757,12 +2760,18 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 	const F32 time_visible = mTimeVisible.getElapsedTimeF32();
 	const F32 NAME_SHOW_TIME = gSavedSettings.getF32("RenderNameShowTime");	// seconds
 	const F32 FADE_DURATION = gSavedSettings.getF32("RenderNameFadeDuration"); // seconds
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Added: RLVa-0.2.0b
+	bool fRlvShowNames = gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES);
+// [/RLVa:KB]
 	BOOL visible_avatar = isVisible() || mNeedsAnimUpdate;
 	BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping);
 	BOOL render_name =	visible_chat ||
-		(visible_avatar &&
-		 ((sRenderName == RENDER_NAME_ALWAYS) ||
-		  (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME)));
+		                (visible_avatar &&
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Added: RLVa-1.0.0h
+						( (!fRlvShowNames) || (RlvSettings::getShowNameTags()) ) &&
+// [/RLVa:KB]
+		                ((sRenderName == RENDER_NAME_ALWAYS) ||
+		                 (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME)));
 	// If it's your own avatar, don't draw in mouselook, and don't
 	// draw if we're specifically hiding our own name.
 	if (isSelf())
@@ -2782,7 +2791,18 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 			new_name = TRUE;
 		}
 		
-		if (sRenderGroupTitles != mRenderGroupTitles)
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Added: RLVa-0.2.0b
+		if (fRlvShowNames)
+		{
+			if (mRenderGroupTitles)
+			{
+				mRenderGroupTitles = FALSE;
+				new_name = TRUE;
+			}
+		}
+		else if (sRenderGroupTitles != mRenderGroupTitles)
+// [/RLVa]
+//		if (sRenderGroupTitles != mRenderGroupTitles)
 		{
 			mRenderGroupTitles = sRenderGroupTitles;
 			new_name = TRUE;
@@ -2905,27 +2925,38 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last)
 				)
 			{
 				std::string line;
-				if (!sRenderGroupTitles)
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Added: RLVa-0.2.0b
+				if (!fRlvShowNames)
 				{
-					// If all group titles are turned off, stack first name
-					// on a line above last name
-					line += firstname->getString();
-					line += "\n";
-				}
-				else if (title && title->getString() && title->getString()[0] != '\0')
-				{
-					line += title->getString();
-					LLStringFn::replace_ascii_controlchars(line,LL_UNKNOWN_CHAR);
-					line += "\n";
-					line += firstname->getString();
+// [/RLVa:KB]
+					if (!sRenderGroupTitles)
+					{
+						// If all group titles are turned off, stack first name
+						// on a line above last name
+						line += firstname->getString();
+						line += "\n";
+					}
+					else if (title && title->getString() && title->getString()[0] != '\0')
+					{
+						line += title->getString();
+						LLStringFn::replace_ascii_controlchars(line,LL_UNKNOWN_CHAR);
+						line += "\n";
+						line += firstname->getString();
+					}
+					else
+					{
+						line += firstname->getString();
+					}
+
+					line += " ";
+					line += lastname->getString();
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Added: RLVa-0.2.0b
 				}
 				else
 				{
-					line += firstname->getString();
+					line = RlvStrings::getAnonym(line.assign(firstname->getString()).append(" ").append(lastname->getString()));
 				}
-
-				line += " ";
-				line += lastname->getString();
+// [/RLVa:KB]
 				BOOL need_comma = FALSE;
 
 				if (is_away || is_muted || is_busy)
@@ -5727,6 +5758,13 @@ void LLVOAvatar::sitDown(BOOL bSitting)
 	{
 		// Update Movement Controls according to own Sitting mode
 		LLFloaterMove::setSittingMode(bSitting);
+
+// [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+		if (rlv_handler_t::isEnabled())
+		{
+			gRlvHandler.onSitOrStand(bSitting);
+		}
+// [/RLVa:KB]
 	}
 }
 
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 1a5d7289f4d52bf35a897bb199527b1481e5d933..4adb65b2d957ef9d3cc7c54a0d6c2f74e851f4aa 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -57,6 +57,9 @@
 #include "llviewerstats.h"
 #include "llviewerregion.h"
 #include "llappearancemgr.h"
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #if LL_MSVC
 // disable boost::lexical_cast warning
@@ -326,6 +329,7 @@ BOOL LLVOAvatarSelf::buildMenus()
 					item_params.name =(item_params.label );
 					item_params.on_click.function_name = "Object.AttachToAvatar";
 					item_params.on_click.parameter = iter->first;
+					// [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid()
 					item_params.on_enable.function_name = "Object.EnableWear";
 					item_params.on_enable.parameter = iter->first;
 					LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
@@ -400,6 +404,7 @@ BOOL LLVOAvatarSelf::buildMenus()
 			item_params.name =(item_params.label );
 			item_params.on_click.function_name = "Object.AttachToAvatar";
 			item_params.on_click.parameter = iter->first;
+			// [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid()
 			item_params.on_enable.function_name = "Object.EnableWear";
 			item_params.on_enable.parameter = iter->first;
 			LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
@@ -443,6 +448,7 @@ BOOL LLVOAvatarSelf::buildMenus()
 			item_params.name =(item_params.label );
 			item_params.on_click.function_name = "Object.AttachToAvatar";
 			item_params.on_click.parameter = iter->first;
+			// [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid()
 			item_params.on_enable.function_name = "Object.EnableWear";
 			item_params.on_enable.parameter = iter->first;
 			//* TODO: Skinning:
@@ -509,6 +515,7 @@ BOOL LLVOAvatarSelf::buildMenus()
 				item_params.label = LLTrans::getString(attachment->getName());
 				item_params.on_click.function_name = "Object.AttachToAvatar";
 				item_params.on_click.parameter = attach_index;
+				// [RLVa:KB] - No changes, but we do need the parameter to always be idxAttachPt for object_selected_and_point_valid()
 				item_params.on_enable.function_name = "Object.EnableWear";
 				item_params.on_enable.parameter = attach_index;
 
@@ -1067,6 +1074,20 @@ LLViewerObject* LLVOAvatarSelf::getWornAttachment(const LLUUID& inv_item_id)
 	return NULL;
 }
 
+// [RLVa:KB] - Checked: 2010-03-14 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+LLViewerJointAttachment* LLVOAvatarSelf::getWornAttachmentPoint(const LLUUID& idItem) const
+{
+	const LLUUID& idItemBase = gInventory.getLinkedItemID(idItem);
+	for (attachment_map_t::const_iterator itAttachPt = mAttachmentPoints.begin(); itAttachPt != mAttachmentPoints.end(); ++itAttachPt)
+	{
+		LLViewerJointAttachment* pAttachPt = itAttachPt->second;
+ 		if (pAttachPt->getAttachedObject(idItemBase))
+			return pAttachPt;
+	}
+	return NULL;
+}
+// [/RLVa:KB]
+
 const std::string LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id) const
 {
 	const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id);
@@ -1104,6 +1125,18 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
 		LLAppearanceMgr::instance().registerAttachment(attachment_id);
 		// Clear any pending requests once the attachment arrives.
 		removeAttachmentRequest(attachment_id);
+
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a
+		// NOTE: RLVa event handlers should be invoked *after* LLVOAvatar::attachObject() calls LLViewerJointAttachment::addObject()
+		if (rlv_handler_t::isEnabled())
+		{
+			RlvAttachmentLockWatchdog::instance().onAttach(viewer_object, attachment);
+			gRlvHandler.onAttach(viewer_object, attachment);
+
+			if ( (attachment->getIsHUDAttachment()) && (!gRlvAttachmentLocks.hasLockedHUD()) )
+				gRlvAttachmentLocks.updateLockedHUD();
+		}
+// [/RLVa:KB]
 	}
 
 	return attachment;
@@ -1113,6 +1146,23 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
 BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
 {
 	const LLUUID attachment_id = viewer_object->getAttachmentItemID();
+
+// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+	// NOTE: RLVa event handlers should be invoked *before* LLVOAvatar::detachObject() calls LLViewerJointAttachment::removeObject()
+	if (rlv_handler_t::isEnabled())
+	{
+		for (attachment_map_t::const_iterator itAttachPt = mAttachmentPoints.begin(); itAttachPt != mAttachmentPoints.end(); ++itAttachPt)
+		{
+			const LLViewerJointAttachment* pAttachPt = itAttachPt->second;
+			if (pAttachPt->isObjectAttached(viewer_object))
+			{
+				RlvAttachmentLockWatchdog::instance().onDetach(viewer_object, pAttachPt);
+				gRlvHandler.onDetach(viewer_object, pAttachPt);
+			}
+		}
+	}
+// [/RLVa:KB]
+
 	if (LLVOAvatar::detachObject(viewer_object))
 	{
 		// the simulator should automatically handle permission revocation
@@ -1145,6 +1195,11 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
 			LLAppearanceMgr::instance().unregisterAttachment(attachment_id);
 		}
 		
+// [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+		if ( (rlv_handler_t::isEnabled()) && (viewer_object->isHUDAttachment()) && (gRlvAttachmentLocks.hasLockedHUD()) )
+			gRlvAttachmentLocks.updateLockedHUD();
+// [/RLVa:KB]
+
 		return TRUE;
 	}
 	return FALSE;
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index eb2475f666022181efc42456a912c95e15b03a54..9911cb4997ae0f636c490b36af2e17d086b25923 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -289,6 +289,9 @@ public:
 	void				addAttachmentRequest(const LLUUID& inv_item_id);
 	void				removeAttachmentRequest(const LLUUID& inv_item_id);
 	LLViewerObject* 	getWornAttachment(const LLUUID& inv_item_id);
+// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i
+	LLViewerJointAttachment* getWornAttachmentPoint(const LLUUID& inv_item_id) const;
+// [/RLVa:KB]
 	const std::string   getAttachedPointName(const LLUUID& inv_item_id) const;
 	/*virtual*/ const LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object);
 	/*virtual*/ BOOL 	detachObject(LLViewerObject *viewer_object);
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 761e12020bb3ed36776c6acb351a08a4a32d0fa2..55dfbbf6776ad434b91005560119e415bba489bf 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -63,6 +63,9 @@
 #include "llmediadataclient.h"
 #include "llagent.h"
 #include "llviewermediafocus.h"
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 const S32 MIN_QUIET_FRAMES_COALESCE = 30;
 const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
@@ -3222,7 +3225,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 
-	if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects)
+//	if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects)
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Modified: RLVa-1.0.5a
+	const LLViewerObject* pObj = facep->getViewerObject();
+	if ( (pObj->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) && 
+		 ((!rlv_handler_t::isEnabled()) || (!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj))) )
+// [/RVLa:KB]
 	{
 		return;
 	}
diff --git a/indra/newview/llwearabletype.cpp b/indra/newview/llwearabletype.cpp
index d2e62c86ab788aee5b6b9a9adf0dc584959db6a7..0435f24f5418b28337a9eb9dea27cfb3015965db 100644
--- a/indra/newview/llwearabletype.cpp
+++ b/indra/newview/llwearabletype.cpp
@@ -58,6 +58,12 @@ class LLWearableDictionary : public LLSingleton<LLWearableDictionary>,
 {
 public:
 	LLWearableDictionary();
+
+// [RLVa:KB] - Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+protected:
+	// The default implementation asserts on 'notFound()' and returns -1 which isn't a valid EWearableType
+	virtual LLWearableType::EType notFound() const { return LLWearableType::WT_INVALID; }
+// [/RLVa:KB]
 };
 
 LLWearableDictionary::LLWearableDictionary()
@@ -94,6 +100,10 @@ const std::string& LLWearableType::getTypeName(LLWearableType::EType type)
 { 
 	const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
 	const WearableEntry *entry = dict->lookup(type);
+// [RLVa:KB] - Checked: 2010-05-15 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+	if (!entry)
+		entry = dict->lookup(WT_INVALID);
+// [/RLVa:KB]
 	return entry->mName;
 }
 
@@ -102,6 +112,10 @@ const std::string& LLWearableType::getTypeDefaultNewName(LLWearableType::EType t
 { 
 	const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
 	const WearableEntry *entry = dict->lookup(type);
+// [RLVa:KB] - Checked: 2010-05-15 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+	if (!entry)
+		entry = dict->lookup(WT_INVALID);
+// [/RLVa:KB]
 	return entry->mDefaultNewName;
 }
 
@@ -110,6 +124,10 @@ const std::string& LLWearableType::getTypeLabel(LLWearableType::EType type)
 { 
 	const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
 	const WearableEntry *entry = dict->lookup(type);
+// [RLVa:KB] - Checked: 2010-05-15 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+	if (!entry)
+		entry = dict->lookup(WT_INVALID);
+// [/RLVa:KB]
 	return entry->mLabel;
 }
 
@@ -118,6 +136,10 @@ LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type)
 {
 	const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
 	const WearableEntry *entry = dict->lookup(type);
+// [RLVa:KB] - Checked: 2010-05-15 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+	if (!entry)
+		entry = dict->lookup(WT_INVALID);
+// [/RLVa:KB]
 	return entry->mAssetType;
 }
 
@@ -126,6 +148,10 @@ LLInventoryIcon::EIconName LLWearableType::getIconName(LLWearableType::EType typ
 {
 	const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
 	const WearableEntry *entry = dict->lookup(type);
+// [RLVa:KB] - Checked: 2010-05-15 (RLVa-1.2.0g) | Added: RLVa-1.2.0g
+	if (!entry)
+		entry = dict->lookup(WT_INVALID);
+// [/RLVa:KB]
 	return entry->mIconName;
 }
 
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 0c17b5e297c00e4001b731d62fa3b5d9e6758718..717b909a55dbc35cd7b902ac797d3b7372ae643e 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -55,6 +55,9 @@
 #include "llviewerregion.h"
 #include "llviewerwindow.h"
 #include "lltrans.h"
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #include "llglheaders.h"
 
@@ -992,7 +995,13 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4&
 	text_x = llclamp(text_x, half_text_width + TEXT_PADDING, getRect().getWidth() - half_text_width - TEXT_PADDING);
 	text_y = llclamp(text_y + vert_offset, TEXT_PADDING + vert_offset, getRect().getHeight() - llround(font->getLineHeight()) - TEXT_PADDING - vert_offset);
 
+//	if (label != "")
+// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) | Added: RLVa-1.0.0a
 	if (label != "")
+/*
+	if ( (label != "") && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) )
+*/
+// [/RLVa:KB]
 	{
 		font->renderUTF8(
 			label, 0,
@@ -1052,7 +1061,12 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
 	{
 		LLViewerRegion *region = gAgent.getRegion();
 
-		std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str());
+// [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+		std::string message = llformat("%s (%s)", 
+			(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? info->getName().c_str() : RlvStrings::getString(RLV_STRING_HIDDEN_REGION).c_str(), 
+			info->getAccessString().c_str());
+// [/RLVa:KB]
+//		std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str());
 
 		if (!info->isDown())
 		{
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index e4c2ca9ae39ec5a408a5209332dfabbcc1095093..d347335a6e095de18c0c2c9e9b0bed64d75f6404 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -98,7 +98,9 @@
 #include "llspatialpartition.h"
 #include "llmutelist.h"
 #include "lltoolpie.h"
-
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d)
+#include "rlvhandler.h"
+// [/RLVa:KB]
 
 #ifdef _DEBUG
 // Debug indices is disabled for now for debug performance - djs 4/24/02
@@ -2330,8 +2332,13 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 	
 	if (LLSelectMgr::getInstance()->mHideSelectedObjects)
 	{
-		if (drawablep->getVObj().notNull() &&
-			drawablep->getVObj()->isSelected())
+//		if (drawablep->getVObj().notNull() &&
+//			drawablep->getVObj()->isSelected())
+// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) | Modified: RLVa-1.0.5a
+		const LLViewerObject* pObj = drawablep->getVObj();
+		if ( (pObj) && (pObj->isSelected()) && 
+			 ((!rlv_handler_t::isEnabled()) || (!pObj->isHUDAttachment()) || (!gRlvAttachmentLocks.isLockedAttachment(pObj))) )
+// [/RVLa:KB]
 		{
 			return;
 		}
diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4dae07fdf6286002a0996e5a63df530992889170
--- /dev/null
+++ b/indra/newview/rlvcommon.cpp
@@ -0,0 +1,578 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
+#include "llagentui.h"
+#include "llappviewer.h"
+#include "llinstantmessage.h"
+#include "llnotificationsutil.h"
+#include "lluictrlfactory.h"
+#include "llversionviewer.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llworld.h"
+
+#include "rlvcommon.h"
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+
+// ============================================================================
+// RlvNotifications
+//
+
+#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR
+// Checked: 2009-12-05 (RLVa-1.1.0h) | Added: RLVa-1.1.0h
+/*
+void RlvNotifications::notifyBehaviour(ERlvBehaviour eBhvr, ERlvParamType eType)
+{
+	const std::string& strMsg = RlvStrings::getBehaviourNotificationString(eBhvr, eType);
+	if (!strMsg.empty())
+	{
+		LLSD argsNotify;
+		argsNotify["MESSAGE"] = strMsg;
+		LLNotifications::instance().add("SystemMessageTip", argsNotify);
+	}
+}
+*/
+#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR
+
+// Checked: 2009-11-13 (RLVa-1.1.0b) | Modified: RLVa-1.1.0b
+/*
+void RlvNotifications::warnGiveToRLV()
+{
+	if ( (gSavedSettings.getWarning(RLV_SETTING_FIRSTUSE_GIVETORLV)) && (RlvSettings::getForbidGiveToRLV()) )
+		LLNotifications::instance().add(RLV_SETTING_FIRSTUSE_GIVETORLV, LLSD(), LLSD(), &RlvNotifications::onGiveToRLVConfirmation);
+}
+*/
+
+// Checked: 2009-11-13 (RLVa-1.1.0b) | Modified: RLVa-1.1.0b
+/*
+void RlvNotifications::onGiveToRLVConfirmation(const LLSD& notification, const LLSD& response)
+{
+	gSavedSettings.setWarning(RLV_SETTING_FIRSTUSE_GIVETORLV, FALSE);
+
+	S32 idxOption = LLNotification::getSelectedOption(notification, response);
+	if ( (0 == idxOption) || (1 == idxOption) )
+		gSavedSettings.setBOOL(RLV_SETTING_FORBIDGIVETORLV, (idxOption == 1));
+}
+*/
+
+// =========================================================================
+// RlvSettings
+//
+
+#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+BOOL RlvSettings::fCompositeFolders = FALSE;
+#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+BOOL RlvSettings::fLegacyNaming = TRUE;
+BOOL RlvSettings::fNoSetEnv = FALSE;
+BOOL RlvSettings::fShowNameTags = FALSE;
+
+// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0i
+void RlvSettings::initClass()
+{
+	static bool fInitialized = false;
+	if (!fInitialized)
+	{
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		fCompositeFolders = rlvGetSettingBOOL(RLV_SETTING_ENABLECOMPOSITES, FALSE);
+		if (gSavedSettings.controlExists(RLV_SETTING_ENABLECOMPOSITES))
+			gSavedSettings.getControl(RLV_SETTING_ENABLECOMPOSITES)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &fCompositeFolders));
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+		fLegacyNaming = rlvGetSettingBOOL(RLV_SETTING_ENABLELEGACYNAMING, TRUE);
+		if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING))
+			gSavedSettings.getControl(RLV_SETTING_ENABLELEGACYNAMING)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &fLegacyNaming));
+
+		fNoSetEnv = rlvGetSettingBOOL(RLV_SETTING_NOSETENV, FALSE);
+
+		fShowNameTags = rlvGetSettingBOOL(RLV_SETTING_SHOWNAMETAGS, FALSE);
+		if (gSavedSettings.controlExists(RLV_SETTING_SHOWNAMETAGS))
+			gSavedSettings.getControl(RLV_SETTING_SHOWNAMETAGS)->getSignal()->connect(boost::bind(&onChangedSettingBOOL, _2, &fShowNameTags));
+
+		fInitialized = true;
+	}
+}
+
+#ifndef RLV_WORKAROUND_REZMULTIPLEATTACH
+BOOL RlvSettings::getEnableSharedWear()
+{
+	// NOTE-RLVa: it's not proper but some code relies on the fact that getEnableSharedWear() returns FALSE if any attach point is locked
+	return 
+		(rlvGetSettingBOOL(RLV_SETTING_ENABLESHAREDWEAR, FALSE)) && // "Enable Shared Wear" is toggled on and...
+		(!gRlvHandler.hasLockedAttachment(RLV_LOCK_ANY));			// no attachment point is non-attachable or non-detachable
+}
+#endif // RLV_WORKAROUND_REZMULTIPLEATTACH
+
+#ifdef RLV_EXTENSION_STARTLOCATION
+	// Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.1d
+	void RlvSettings::updateLoginLastLocation()
+	{
+		if (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION))
+		{
+			BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || (!gRlvHandler.canStand());
+			if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue)
+			{
+				gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue);
+				gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
+			}
+		}
+	}
+#endif // RLV_EXTENSION_STARTLOCATION
+
+// Checked: 2010-02-27 (RLVa-1.2.0a) | Added: RLVa-1.1.0i
+bool RlvSettings::onChangedSettingBOOL(const LLSD& sdValue, BOOL* pfSetting)
+{
+	if (pfSetting)
+		*pfSetting = sdValue.asBoolean();
+	return true;
+}
+
+// ============================================================================
+// RlvStrings
+//
+
+std::vector<std::string> RlvStrings::m_Anonyms;
+std::map<std::string, std::string> RlvStrings::m_StringMap;
+#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR
+std::map<ERlvBehaviour, std::string> RlvStrings::m_BhvrAddMap;
+std::map<ERlvBehaviour, std::string> RlvStrings::m_BhvrRemMap;
+#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR
+
+// Checked: 2010-03-09 (RLVa-1.2.0a) | Added: RLVa-1.1.0h
+void RlvStrings::initClass()
+{
+	static bool fInitialized = false;
+	if (!fInitialized)
+	{
+		LLXMLNodePtr xmlRoot;
+		if ( (!LLUICtrlFactory::getLayeredXMLNode("rlva_strings.xml", xmlRoot)) || (xmlRoot.isNull()) || (!xmlRoot->hasName("rlva_strings")) )
+		{
+			RLV_ERRS << "Problem reading RLVa string XML file" << RLV_ENDL;
+			return;
+		}
+
+		for (LLXMLNode* pNode = xmlRoot->getFirstChild(); pNode != NULL; pNode = pNode->getNextSibling())
+		{
+			if (pNode->hasName("strings"))
+			{
+				std::string strName;
+				for (LLXMLNode* pStringNode = pNode->getFirstChild(); pStringNode != NULL; pStringNode = pStringNode->getNextSibling())
+				{
+					if ( (!pStringNode->hasName("string")) || (!pStringNode->getAttributeString("name", strName)) )
+						continue;
+					m_StringMap[strName] = pStringNode->getTextContents();
+				}
+			}
+			else if (pNode->hasName("anonyms"))
+			{
+				for (LLXMLNode* pAnonymNode = pNode->getFirstChild(); pAnonymNode != NULL; pAnonymNode = pAnonymNode->getNextSibling())
+				{
+					if (!pAnonymNode->hasName("anonym"))
+						continue;
+					m_Anonyms.push_back(pAnonymNode->getTextContents());
+				}
+			}
+			#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR
+			else if (pNode->hasName("behaviour-notifications"))
+			{
+				std::string strBhvr, strType; ERlvBehaviour eBhvr;
+				for (LLXMLNode* pNotifyNode = pNode->getFirstChild(); pNotifyNode != NULL; pNotifyNode = pNotifyNode->getNextSibling())
+				{
+					if ( (!pNotifyNode->hasName("notification")) || (!pNotifyNode->getAttributeString("type", strType)) ||
+						 (!pNotifyNode->getAttributeString("behaviour", strBhvr)) || 
+						 ((eBhvr = RlvCommand::getBehaviourFromString(strBhvr)) == RLV_BHVR_UNKNOWN) )
+					{
+						continue;
+					}
+					if ("add" == strType)
+						m_BhvrAddMap.insert(std::pair<ERlvBehaviour, std::string>(eBhvr, pNotifyNode->getTextContents()));
+					else if ("rem" == strType)
+						m_BhvrRemMap.insert(std::pair<ERlvBehaviour, std::string>(eBhvr, pNotifyNode->getTextContents()));
+				}
+			}
+			#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR
+		}
+
+		if ( (m_StringMap.empty()) || (m_Anonyms.empty()) )
+		{
+			RLV_ERRS << "Problem parsing RLVa string XML file" << RLV_ENDL;
+			return;
+		}
+
+		fInitialized = true;
+	}
+}
+
+// Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a
+const std::string& RlvStrings::getAnonym(const std::string& strName)
+{
+	const char* pszName = strName.c_str(); U32 nHash = 0;
+	
+	// Test with 11,264 SL names showed a 3.33% - 3.82% occurance for each so we *should* get a very even spread
+	for (int idx = 0, cnt = strName.length(); idx < cnt; idx++)
+		nHash += pszName[idx];
+
+	return m_Anonyms[nHash % m_Anonyms.size()];
+}
+
+#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR
+// Checked: 2009-12-05 (RLVa-1.1.0h) | Added: RLVa-1.1.0h
+const std::string& RlvStrings::getBehaviourNotificationString(ERlvBehaviour eBhvr, ERlvParamType eType)
+{
+	if (RLV_TYPE_ADD == eType)
+	{
+		std::map<ERlvBehaviour, std::string>::const_iterator itString = m_BhvrAddMap.find(eBhvr);
+		return (itString != m_BhvrAddMap.end()) ? itString->second : LLStringUtil::null;
+	}
+	else if (RLV_TYPE_REMOVE == eType)
+	{
+		std::map<ERlvBehaviour, std::string>::const_iterator itString = m_BhvrRemMap.find(eBhvr);
+		return (itString != m_BhvrRemMap.end()) ? itString->second : LLStringUtil::null;
+	}
+	return LLStringUtil::null;
+}
+#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR
+
+// Checked: 2009-11-11 (RLVa-1.1.0a) | Added: RLVa-1.1.0a
+const std::string& RlvStrings::getString(const std::string& strStringName)
+{
+	static const std::string strMissing = "(Missing RLVa string)";
+	std::map<std::string, std::string>::const_iterator itString = m_StringMap.find(strStringName);
+	return (itString != m_StringMap.end()) ? itString->second : strMissing;
+}
+
+// Checked: 2009-11-25 (RLVa-1.1.0f) | Added: RLVa-1.1.0f
+const char* RlvStrings::getStringFromReturnCode(ERlvCmdRet eRet)
+{
+	// TODO-RLVa: [2009-11-25] clean this up along with the calling code in process_chat_from_simulator() once we're happy with the output
+	switch (eRet)
+	{
+		case RLV_RET_SUCCESS_UNSET:
+			return "unset";
+		case RLV_RET_SUCCESS_DUPLICATE:
+			return "duplicate";
+		case RLV_RET_FAILED_SYNTAX:
+			return "syntax error";
+		case RLV_RET_FAILED_OPTION:
+			return "invalid option";
+		case RLV_RET_FAILED_PARAM:
+			return "invalid param";
+		case RLV_RET_FAILED_LOCK:
+			return "locked command";
+		case RLV_RET_FAILED_DISABLED:
+			return "disabled command";
+		case RLV_RET_FAILED_UNKNOWN:
+			return "unknown command";
+		case RLV_RET_FAILED_NOSHAREDROOT:
+			return "missing #RLV";
+		// The following are identified by the chat verb
+		case RLV_RET_RETAINED:
+		case RLV_RET_SUCCESS:
+		case RLV_RET_FAILED:
+			break;
+		// The following shouldn't occur
+		case RLV_RET_UNKNOWN:
+		default:
+			RLV_ASSERT(false);
+			break;
+	};
+	return NULL;
+}
+
+// Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
+std::string RlvStrings::getVersion(bool fLegacy /*=false*/) 
+{
+	return llformat("%s viewer v%d.%d.%d (%s %d.%d.%d.%d - RLVa %d.%d.%d)",
+		( (!fLegacy) ? "RestrainedLove" : "RestrainedLife" ),
+		RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH,
+		LLAppViewer::instance()->getSecondLifeTitle().c_str(), LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VERSION_BUILD,
+		RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH);
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+std::string RlvStrings::getVersionAbout()
+{
+	return llformat("RLV v%d.%d.%d / RLVa v%d.%d.%d%c" , 
+		RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH,
+		RLVa_VERSION_MAJOR, RLVa_VERSION_MINOR, RLVa_VERSION_PATCH, 'a' + RLVa_VERSION_BUILD);
+}
+
+
+// Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.1.0a
+std::string RlvStrings::getVersionNum() 
+{
+	return llformat("%d%02d%02d%02d", RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, RLV_VERSION_BUILD);
+}
+
+// Checked: 2010-05-26 (RLVa-1.2.0h) | Added: RLVa-1.2.0g
+bool RlvStrings::hasString(const std::string& strStringName)
+{
+	return m_StringMap.find(strStringName) != m_StringMap.end();
+}
+
+// ============================================================================
+// RlvUtil
+//
+
+bool RlvUtil::m_fForceTp = false;
+
+// Checked: 2009-07-04 (RLVa-1.0.0a) | Modified: RLVa-1.0.0a
+void RlvUtil::filterLocation(std::string& strUTF8Text)
+{
+	// TODO-RLVa: if either the region or parcel name is a simple word such as "a" or "the" then confusion will ensue?
+	//            -> not sure how you would go about preventing this though :|...
+
+	// Filter any mention of the surrounding region names
+	LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList();
+	const std::string& strHiddenRegion = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
+	for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion)
+		rlvStringReplace(strUTF8Text, (*itRegion)->getName(), strHiddenRegion);
+
+	// Filter any mention of the parcel name
+	LLViewerParcelMgr* pParcelMgr = LLViewerParcelMgr::getInstance();
+	if (pParcelMgr)
+		rlvStringReplace(strUTF8Text, pParcelMgr->getAgentParcelName(), RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL));
+}
+
+// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+void RlvUtil::filterNames(std::string& strUTF8Text)
+{
+	std::vector<LLUUID> idAgents;
+	LLWorld::getInstance()->getAvatars(&idAgents, NULL);
+
+	std::string strFullName;
+	for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++)
+	{
+		// LLCacheName::getFullName() will add the UUID to the lookup queue if we don't know it yet
+		if (gCacheName->getFullName(idAgents[idxAgent], strFullName))
+			rlvStringReplace(strUTF8Text, strFullName, RlvStrings::getAnonym(strFullName));
+	}
+}
+
+// Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+void RlvUtil::forceTp(const LLVector3d &posDest)
+{
+	m_fForceTp = true;
+	gAgent.teleportViaLocation(posDest);
+	m_fForceTp = false;
+}
+
+// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+bool RlvUtil::isNearbyAgent(const LLUUID& idAgent)
+{
+	// Sanity check since we call this with notification payloads as well and those strings tend to change from one release to another
+	RLV_ASSERT(idAgent.notNull());
+	if ( (idAgent.notNull()) && (gAgent.getID() != idAgent) )
+	{
+		std::vector<LLUUID> idAgents;
+		LLWorld::getInstance()->getAvatars(&idAgents, NULL);
+
+		for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++)
+			if (idAgents[idxAgent] == idAgent)
+				return true;
+	}
+	return false;
+}
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+bool RlvUtil::isNearbyRegion(const std::string& strRegion)
+{
+	LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList();
+	for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion)
+		if ((*itRegion)->getName() == strRegion)
+			return true;
+	return false;
+}
+
+// Checked: 2010-04-08 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+void RlvUtil::notifyFailedAssertion(const char* pstrAssert, const char* pstrFile, int nLine)
+{
+	LLSD argsNotify;
+	argsNotify["MESSAGE"] = llformat("RLVa assertion failure: %s (%s - %d)", pstrAssert, pstrFile, nLine);
+	LLNotificationsUtil::add("SystemMessageTip", argsNotify);
+}
+
+// Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
+void RlvUtil::sendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession)
+{
+	// [See process_improved_im()]
+	std::string strFullName;
+	LLAgentUI::buildFullname(strFullName);
+
+	pack_instant_message(gMessageSystem, gAgent.getID(), FALSE, gAgent.getSessionID(), idTo, strFullName,
+		strMsg, IM_ONLINE, IM_BUSY_AUTO_RESPONSE, idSession);
+	gAgent.sendReliableMessage();
+}
+
+// Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.0.1e
+bool RlvUtil::sendChatReply(S32 nChannel, const std::string& strUTF8Text)
+{
+	if (!isValidReplyChannel(nChannel))
+		return false;
+
+	// Copy/paste from send_chat_from_viewer()
+	gMessageSystem->newMessageFast(_PREHASH_ChatFromViewer);
+	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	gMessageSystem->nextBlockFast(_PREHASH_ChatData);
+	gMessageSystem->addStringFast(_PREHASH_Message, strUTF8Text);
+	gMessageSystem->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT);
+	gMessageSystem->addS32("Channel", nChannel);
+	gAgent.sendReliableMessage();
+	LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT);
+
+	return true;
+}
+
+// ============================================================================
+// Generic menu enablers
+//
+
+// Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+bool rlvMenuCheckEnabled()
+{
+	return rlv_handler_t::isEnabled();
+}
+
+// Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+bool rlvMenuToggleEnabled()
+{
+	gSavedSettings.setBOOL(RLV_SETTING_MAIN, !rlv_handler_t::isEnabled());
+
+	LLSD args;
+	args["MESSAGE"] = 
+		llformat("RestrainedLove Support will be %s after you restart", (rlv_handler_t::isEnabled()) ? "disabled" : "enabled" );
+	LLNotificationsUtil::add("GenericAlert", args);
+	
+	return true;
+}
+
+// Checked: 2010-04-23 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+bool rlvMenuEnableIfNot(const LLSD& sdParam)
+{
+	bool fEnable = true;
+	if (rlv_handler_t::isEnabled())
+	{
+		ERlvBehaviour eBhvr = RlvCommand::getBehaviourFromString(sdParam.asString());
+		fEnable = (eBhvr != RLV_BHVR_UNKNOWN) ? !gRlvHandler.hasBehaviour(eBhvr) : true;
+	}
+	return fEnable;
+}
+
+// ============================================================================
+// Selection functors
+//
+
+// Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-0.2.0f
+bool RlvSelectHasLockedAttach::apply(LLSelectNode* pNode)
+{
+	return (pNode->getObject()) ? gRlvAttachmentLocks.isLockedAttachment(pNode->getObject()->getRootEdit()) : false;
+}
+
+// Checked: 2009-07-05 (RLVa-1.0.0b) | Modified: RLVa-0.2.0f
+bool RlvSelectIsOwnedByOrGroupOwned::apply(LLSelectNode* pNode)
+{
+	return (pNode->mPermissions->isGroupOwned()) || (pNode->mPermissions->getOwner() == m_idAgent);
+}
+
+// Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-0.2.0f
+bool RlvSelectIsSittingOn::apply(LLSelectNode* pNode)
+{
+	return (pNode->getObject()) && (pNode->getObject()->getRootEdit() == m_pObject);
+}
+
+// ============================================================================
+// Predicates
+//
+
+// Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+bool rlvPredIsWearableItem(const LLViewerInventoryItem* pItem)
+{
+	// RELEASE-RLVa: [SL-2.0.0] This will need rewriting for "ENABLE_MULTIATTACHMENTS"
+	if (pItem)
+	{
+		if (RlvForceWear::isWearingItem(pItem))
+			return true; // Special exception for currently worn items
+		switch (pItem->getType())
+		{
+			case LLAssetType::AT_BODYPART:
+				// NOTE: only one body part of each type is allowed so the only way to wear one is if we can replace the current one
+				return (gRlvWearableLocks.canWear(pItem) & RLV_WEAR_REPLACE);
+			case LLAssetType::AT_CLOTHING:
+				return (RLV_WEAR_LOCKED != gRlvWearableLocks.canWear(pItem));
+			case LLAssetType::AT_OBJECT:
+				return gRlvAttachmentLocks.canAttach(pItem);
+			case LLAssetType::AT_GESTURE:
+				return true;
+			default:
+				RLV_ASSERT(false);
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+bool rlvPredIsNotWearableItem(const LLViewerInventoryItem* pItem)
+{
+	return !rlvPredIsWearableItem(pItem);
+}
+
+// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+bool rlvPredIsRemovableItem(const LLViewerInventoryItem* pItem)
+{
+	if (pItem)
+	{
+		switch (pItem->getType())
+		{
+			case LLAssetType::AT_BODYPART:
+			case LLAssetType::AT_CLOTHING:
+				return gRlvWearableLocks.canRemove(pItem);
+			case LLAssetType::AT_OBJECT:
+				return gRlvAttachmentLocks.canDetach(pItem);
+			case LLAssetType::AT_GESTURE:
+				return true;
+			default:
+				RLV_ASSERT(false);
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+bool rlvPredIsNotRemovableItem(const LLViewerInventoryItem* pItem)
+{
+	return !rlvPredIsRemovableItem(pItem);
+}
+
+// ============================================================================
+// Various public helper functions
+//
+
+// Checked: 2009-11-15 (RLVa-1.1.0c) | Added: RLVa-1.1.0c
+/*
+BOOL rlvEnableSharedWearEnabler(void* pParam)
+{
+	return false;
+	// Visually disable the "Enable Shared Wear" option when at least one attachment is non-detachable
+	return (!gRlvHandler.hasLockedAttachment(RLV_LOCK_REMOVE));
+}
+*/
+
+// ============================================================================
diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h
new file mode 100644
index 0000000000000000000000000000000000000000..f29fe3abb48ac09630066c5717b38daa9f7f9cce
--- /dev/null
+++ b/indra/newview/rlvcommon.h
@@ -0,0 +1,242 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_COMMON_H
+#define RLV_COMMON_H
+
+#include "llinventorymodel.h"
+#include "llselectmgr.h"
+#include "llviewercontrol.h"
+#include "llviewerinventory.h"
+
+#include "rlvdefines.h"
+
+// ============================================================================
+// Forward declarations
+//
+
+class RlvCommand;
+
+// ============================================================================
+// RlvSettings
+//
+
+inline BOOL rlvGetSettingBOOL(const std::string& strSetting, BOOL fDefault)
+{
+	RLV_ASSERT_DBG(gSavedSettings.controlExists(strSetting));
+	return (gSavedSettings.controlExists(strSetting)) ? gSavedSettings.getBOOL(strSetting) : fDefault;
+}
+inline BOOL rlvGetPerUserSettingsBOOL(const std::string& strSetting, BOOL fDefault)
+{
+	RLV_ASSERT_DBG(gSavedPerAccountSettings.controlExists(strSetting));
+	return (gSavedPerAccountSettings.controlExists(strSetting)) ? gSavedPerAccountSettings.getBOOL(strSetting) : fDefault;
+}
+
+class RlvSettings
+{
+public:
+	static BOOL getDebug()					{ return rlvGetSettingBOOL(RLV_SETTING_DEBUG, FALSE); }
+	static BOOL getForbidGiveToRLV()		{ return rlvGetSettingBOOL(RLV_SETTING_FORBIDGIVETORLV, TRUE); }
+	static BOOL getNoSetEnv()				{ return fNoSetEnv; }
+
+	static BOOL getDebugHideUnsetDup()		{ return rlvGetSettingBOOL(RLV_SETTING_DEBUGHIDEUNSETDUP, FALSE); }
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	static BOOL getEnableComposites()		{ return fCompositeFolders; }
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	static BOOL getEnableLegacyNaming()		{ return fLegacyNaming; }
+	static BOOL getEnableSharedWear();
+	static BOOL getHideLockedLayers()		{ return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDLAYER, FALSE); }		
+	static BOOL getHideLockedAttach()		{ return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDATTACH, FALSE); }
+	static BOOL getHideLockedInventory()	{ return rlvGetSettingBOOL(RLV_SETTING_HIDELOCKEDINVENTORY, FALSE); }
+	static BOOL getSharedInvAutoRename()	{ return rlvGetSettingBOOL(RLV_SETTING_SHAREDINVAUTORENAME, TRUE); }
+	static BOOL getShowNameTags()			{ return fShowNameTags; }
+
+	#ifdef RLV_EXTENSION_STARTLOCATION
+	static BOOL getLoginLastLocation()		{ return rlvGetPerUserSettingsBOOL(RLV_SETTING_LOGINLASTLOCATION, TRUE); }
+	static void updateLoginLastLocation();
+	#endif // RLV_EXTENSION_STARTLOCATION
+
+	static void initClass();
+protected:
+	static bool onChangedSettingBOOL(const LLSD& sdValue, BOOL* pfSetting);
+
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	static BOOL fCompositeFolders;
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	static BOOL fLegacyNaming;
+	static BOOL fNoSetEnv;
+	static BOOL fShowNameTags;
+};
+
+#ifdef RLV_WORKAROUND_REZMULTIPLEATTACH
+inline BOOL RlvSettings::getEnableSharedWear()
+{
+	return FALSE;
+}
+#endif // RLV_WORKAROUND_REZMULTIPLEATTACH
+
+// ============================================================================
+// RlvStrings
+//
+
+class RlvStrings
+{
+public:
+	static void initClass();
+
+	static const std::string& getAnonym(const std::string& strName);		// @shownames
+	static const std::string& getBehaviourNotificationString(ERlvBehaviour eBhvr, ERlvParamType eType);
+	static const std::string& getString(const std::string& strStringName);
+	static const char*        getStringFromReturnCode(ERlvCmdRet eRet);
+	static std::string        getVersion(bool fLegacy = false);				// @version
+	static std::string        getVersionAbout();							// Shown in Help / About
+	static std::string        getVersionNum();								// @versionnum
+	static bool               hasString(const std::string& strStringName);
+
+protected:
+	static std::vector<std::string> m_Anonyms;
+	static std::map<std::string, std::string> m_StringMap;
+	#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR
+	static std::map<ERlvBehaviour, std::string> m_BhvrAddMap;
+	static std::map<ERlvBehaviour, std::string> m_BhvrRemMap;
+	#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR
+};
+
+// ============================================================================
+// RlvUtil - Collection of (static) helper functions
+//
+
+class RlvUtil
+{
+public:
+	static bool isEmote(const std::string& strUTF8Text);
+	static bool isNearbyAgent(const LLUUID& idAgent);						// @shownames
+	static bool isNearbyRegion(const std::string& strRegion);				// @showloc
+
+	static void filterLocation(std::string& strUTF8Text);					// @showloc
+	static void filterNames(std::string& strUTF8Text);						// @shownames
+
+	static bool isForceTp()	{ return m_fForceTp; }
+	static void forceTp(const LLVector3d& posDest);							// Ignores restrictions that might otherwise prevent tp'ing
+
+	static void notifyFailedAssertion(const char* pstrAssert, const char* pstrFile, int nLine);
+
+	static void sendBusyMessage(const LLUUID& idTo, const std::string& strMsg, const LLUUID& idSession = LLUUID::null);
+	static bool isValidReplyChannel(S32 nChannel);
+	static bool sendChatReply(S32 nChannel, const std::string& strUTF8Text);
+	static bool sendChatReply(const std::string& strChannel, const std::string& strUTF8Text);
+
+protected:
+	static bool m_fForceTp;													// @standtp
+};
+
+// ============================================================================
+// Extensibility classes
+//
+
+class RlvCommandHandler
+{
+public:
+	virtual ~RlvCommandHandler() {}
+	virtual bool onAddRemCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet) { return false; }
+	virtual bool onClearCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet)  { return false; }
+	virtual bool onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet)  { return false; }
+	virtual bool onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet)  { return false; }
+};
+typedef bool (RlvCommandHandler::*rlvCommandHandler)(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet);
+
+// ============================================================================
+// Generic menu enablers
+//
+
+bool rlvMenuCheckEnabled();
+bool rlvMenuToggleEnabled();
+bool rlvMenuEnableIfNot(const LLSD& sdParam);
+
+// ============================================================================
+// Selection functors
+//
+
+struct RlvSelectHasLockedAttach : public LLSelectedNodeFunctor
+{
+	RlvSelectHasLockedAttach() {}
+	virtual bool apply(LLSelectNode* pNode);
+};
+
+struct RlvSelectIsOwnedByOrGroupOwned : public LLSelectedNodeFunctor
+{
+	RlvSelectIsOwnedByOrGroupOwned(const LLUUID& uuid) : m_idAgent(uuid) {}
+	virtual bool apply(LLSelectNode* pNode);
+protected:
+	LLUUID m_idAgent;
+};
+
+struct RlvSelectIsSittingOn : public LLSelectedNodeFunctor
+{
+	RlvSelectIsSittingOn(LLXform* pObject) : m_pObject(pObject) {}
+	virtual bool apply(LLSelectNode* pNode);
+protected:
+	LLXform* m_pObject;
+};
+
+// ============================================================================
+// Predicates
+//
+
+bool rlvPredIsWearableItem(const LLViewerInventoryItem* pItem);
+bool rlvPredIsNotWearableItem(const LLViewerInventoryItem* pItem);
+bool rlvPredIsRemovableItem(const LLViewerInventoryItem* pItem);
+bool rlvPredIsNotRemovableItem(const LLViewerInventoryItem* pItem);
+
+struct RlvPredIsEqualOrLinkedItem
+{
+	RlvPredIsEqualOrLinkedItem(const LLViewerInventoryItem* pItem) : m_pItem(pItem) {}
+	RlvPredIsEqualOrLinkedItem(const LLUUID& idItem) { m_pItem = gInventory.getItem(idItem); }
+
+	bool operator()(const LLViewerInventoryItem* pItem) const
+	{
+		return (m_pItem) && (pItem) && (m_pItem->getLinkedUUID() == pItem->getLinkedUUID());
+	}
+protected:
+	const LLViewerInventoryItem* m_pItem;
+};
+
+// ============================================================================
+// Inlined class member functions
+//
+
+// Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.2a
+inline bool RlvUtil::isEmote(const std::string& strUTF8Text)
+{
+	return (strUTF8Text.length() > 4) && ( (strUTF8Text.compare(0, 4, "/me ") == 0) || (strUTF8Text.compare(0, 4, "/me'") == 0) );
+}
+
+// Checked: 2010-03-09 (RLVa-1.2.0b) | Added: RLVa-1.0.2a
+inline bool RlvUtil::isValidReplyChannel(S32 nChannel)
+{
+	return (nChannel > 0) && (CHAT_CHANNEL_DEBUG != nChannel);
+}
+
+// Checked: 2009-08-05 (RLVa-1.0.1e) | Added: RLVa-1.0.0e
+inline bool RlvUtil::sendChatReply(const std::string& strChannel, const std::string& strUTF8Text)
+{
+	S32 nChannel;
+	return (LLStringUtil::convertToS32(strChannel, nChannel)) ? sendChatReply(nChannel, strUTF8Text) : false;
+}
+
+// ============================================================================
+
+#endif // RLV_COMMON_H
diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ce241fd6e70d0f824e242791cbcb7c59c850101
--- /dev/null
+++ b/indra/newview/rlvdefines.h
@@ -0,0 +1,316 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_DEFINES_H
+#define RLV_DEFINES_H
+
+// ============================================================================
+// Extensions
+//
+
+// Provides access to "advanced" features through the RLVa debug menu
+#define RLV_EXTENSION_FLOATER_RESTRICTIONS	// Enables the Advanced / RLVa / Restrictions... floater
+#define RLV_EXTENSION_HIDELOCKED			// "Hide locked layers", "Hide locked attachments" and "Hide locked inventory"
+
+// Extensions
+#define RLV_EXTENSION_CMD_GETSETDEBUG_EX	// Extends the debug variables accessible through @getdebug_xxx/@setdebug_xxx
+#define RLV_EXTENSION_CMD_FINDFOLDERS		// @findfolders:<option>=<channel> - @findfolder with multiple results
+#define RLV_EXTENSION_FLAG_NOSTRIP			// Layers and attachments marked as "nostrip" are exempt from @detach/@remoutfit
+#define RLV_EXTENSION_FORCEWEAR_GESTURES	// @attach*/detach* commands also (de)activate gestures
+#define RLV_EXTENSION_GIVETORLV_A2A			// Allow "Give to #RLV" on avatar-to-avatar inventory offers
+#define RLV_EXTENSION_NOTIFY_BEHAVIOUR		// Provides the option to show a customizable notification whenever a behaviour gets (un)set
+#define RLV_EXTENSION_STARTLOCATION			// Reenables "Start Location" at login if not @tploc=n or @unsit=n restricted at last logoff
+//#define RLV_EXPERIMENTAL					// Enables/disables experimental features en masse
+#define RLV_EXPERIMENTAL_CMDS				// Enables/disables experimental commands en masse
+
+// Experimental features
+#ifdef RLV_EXPERIMENTAL
+	// Stable (will mature to RLV_EXTENSION_XXX in next release if no bugs are found)
+
+	// Under testing (stable, but requires further testing - safe for public release but may be quirky)
+	#define RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+	// Under development (don't include in public release)
+	#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
+		#define RLV_EXPERIMENTAL_FIRSTUSE				// Enables a number of "first use" popups
+	#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
+#endif // RLV_EXPERIMENTAL
+
+// Experimental commands (not part of the RLV API spec, disabled on public releases)
+#ifdef RLV_EXPERIMENTAL_CMDS
+	#define RLV_EXTENSION_CMD_ALLOWIDLE		// Forces "Away" status when idle (effect is the same as setting AllowIdleAFK to TRUE)
+//	#define RLV_EXTENSION_CMD_GETXXXNAMES	// @get[add|rem]attachnames:<option>=<channel> and @get[add|rem]outfitnames=<channel>
+	#define RLV_EXTENSION_CMD_INTERACT		// @interact=n
+	#define RLV_EXTENSION_CMD_TOUCHXXX		// @touch:uuid=n|y, @touchworld[:<uuid>]=n|y, @touchattach[:<uuid>]=n|y, @touchud[:<uuid>]=n|y
+#endif // RLV_EXPERIMENTAL_CMDS
+
+// Workarounds
+#define RLV_WORKAROUND_REZMULTIPLEATTACH	// See http://jira.secondlife.com/browse/SVC-5383 ; disables "Shared Wear"
+
+// ============================================================================
+// Defines
+//
+
+// Version of the specifcation we support
+const S32 RLV_VERSION_MAJOR = 2;
+const S32 RLV_VERSION_MINOR = 1;
+const S32 RLV_VERSION_PATCH = 2;
+const S32 RLV_VERSION_BUILD = 0;
+
+// Implementation version
+const S32 RLVa_VERSION_MAJOR = 1;
+const S32 RLVa_VERSION_MINOR = 2;
+const S32 RLVa_VERSION_PATCH = 1;
+const S32 RLVa_VERSION_BUILD = 2;
+
+// Uncomment before a final release
+//#define RLV_RELEASE
+
+// The official viewer version we're patching against
+#define RLV_MAKE_TARGET(x, y, z)	((x << 16) | (y << 8) | z)
+#define RLV_TARGET					RLV_MAKE_TARGET(2, 1, 2)
+
+// Defining these makes it easier if we ever need to change our tag
+#define RLV_WARNS		LL_WARNS("RLV")
+#define RLV_INFOS		LL_INFOS("RLV")
+#define RLV_DEBUGS		LL_DEBUGS("RLV")
+#define RLV_ENDL		LL_ENDL
+#define RLV_VERIFY(f)	if (!(f)) { RlvUtil::notifyFailedAssertion(#f, __FILE__, __LINE__); }
+
+#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
+	// Turn on extended debugging information
+	#define RLV_DEBUG
+	// Make sure we halt execution on errors
+	#define RLV_ERRS				LL_ERRS("RLV")
+	// Keep our asserts separate from LL's
+	#define RLV_ASSERT(f)			if (!(f)) { RLV_ERRS << "ASSERT (" << #f << ")" << RLV_ENDL; }
+	#define RLV_ASSERT_DBG(f)		RLV_ASSERT(f)
+#else
+	// Don't halt execution on errors in release
+	#define RLV_ERRS				LL_WARNS("RLV")
+	// We don't want to check assertions in release builds
+	#ifdef RLV_RELEASE
+		#define RLV_ASSERT(f)		RLV_VERIFY(f)
+		#define RLV_ASSERT_DBG(f)
+	#else
+		#define RLV_ASSERT(f)
+		#define RLV_ASSERT_DBG(f)
+	#endif // RLV_RELEASE
+#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
+
+#define RLV_ROOT_FOLDER					"#RLV"
+#define RLV_CMD_PREFIX					'@'
+#define RLV_PUTINV_PREFIX				"#RLV/~"
+#define RLV_SETROT_OFFSET				F_PI_BY_TWO		// @setrot is off by 90° with the rest of SL
+
+#define RLV_FOLDER_FLAG_NOSTRIP			"nostrip"
+#define RLV_FOLDER_PREFIX_HIDDEN		'.'
+#define RLV_FOLDER_PREFIX_PUTINV    	'~'
+
+// ============================================================================
+// Enumeration declarations
+//
+
+// NOTE: any changes to this enumeration should be reflected in RlvCommand::initLookupTable()
+enum ERlvBehaviour {
+	RLV_BHVR_DETACH = 0,			// "detach"
+	RLV_BHVR_ATTACH,				// "attach"
+	RLV_BHVR_ADDATTACH,				// "addattach"
+	RLV_BHVR_REMATTACH,				// "remattach"
+	RLV_BHVR_ADDOUTFIT,				// "addoutfit"
+	RLV_BHVR_REMOUTFIT,				// "remoutfit"
+	RLV_BHVR_EMOTE,					// "emote"
+	RLV_BHVR_SENDCHAT,				// "sendchat"
+	RLV_BHVR_RECVCHAT,				// "recvchat"
+	RLV_BHVR_RECVEMOTE,				// "recvemote"
+	RLV_BHVR_REDIRCHAT,				// "redirchat"
+	RLV_BHVR_REDIREMOTE,			// "rediremote"
+	RLV_BHVR_CHATWHISPER,			// "chatwhisper"
+	RLV_BHVR_CHATNORMAL,			// "chatnormal"
+	RLV_BHVR_CHATSHOUT,				// "chatshout"
+	RLV_BHVR_SENDCHANNEL,			// "sendchannel"
+	RLV_BHVR_SENDIM,				// "sendim"
+	RLV_BHVR_RECVIM,				// "recvim"
+	RLV_BHVR_PERMISSIVE,			// "permissive"
+	RLV_BHVR_NOTIFY,				// "notify"
+	RLV_BHVR_SHOWINV,				// "showinv"
+	RLV_BHVR_SHOWMINIMAP,			// "showminimap"
+	RLV_BHVR_SHOWWORLDMAP,			// "showworldmap"
+	RLV_BHVR_SHOWLOC,				// "showloc"
+	RLV_BHVR_SHOWNAMES,				// "shownames"
+	RLV_BHVR_SHOWHOVERTEXT,			// "showhovertext"
+	RLV_BHVR_SHOWHOVERTEXTHUD,		// "showhovertexthud"
+	RLV_BHVR_SHOWHOVERTEXTWORLD,	// "showhovertextworld"
+	RLV_BHVR_SHOWHOVERTEXTALL,		// "showhovertextall"
+	RLV_BHVR_TPLM,					// "tplm"
+	RLV_BHVR_TPLOC,					// "tploc"
+	RLV_BHVR_TPLURE,				// "tplure"
+	RLV_BHVR_VIEWNOTE,				// "viewnote"
+	RLV_BHVR_VIEWSCRIPT,			// "viewscript"
+	RLV_BHVR_VIEWTEXTURE,			// "viewtexture"
+	RLV_BHVR_ACCEPTPERMISSION,		// "acceptpermission"
+	RLV_BHVR_ACCEPTTP,				// "accepttp"
+	RLV_BHVR_ALLOWIDLE,				// "allowidle"
+	RLV_BHVR_EDIT,					// "edit"
+	RLV_BHVR_REZ,					// "rez"
+	RLV_BHVR_FARTOUCH,				// "fartouch"
+	RLV_BHVR_INTERACT,				// "interact"
+	RLV_BHVR_TOUCH,					// "touch"
+	RLV_BHVR_TOUCHATTACH,			// "touchattach"
+	RLV_BHVR_TOUCHHUD,				// "touchhud"
+	RLV_BHVR_TOUCHWORLD,			// "touchworld"
+	RLV_BHVR_FLY,					// "fly"
+	RLV_BHVR_UNSIT,					// "unsit"
+	RLV_BHVR_SIT,					// "sit"
+	RLV_BHVR_SITTP,					// "sittp"
+	RLV_BHVR_STANDTP,				// "standtp"
+	RLV_BHVR_SETDEBUG,				// "setdebug"
+	RLV_BHVR_SETENV,				// "setenv"
+	RLV_BHVR_DETACHME,				// "detachme"
+	RLV_BHVR_ATTACHOVER,			// "attachover"
+	RLV_BHVR_ATTACHTHIS,			// "attachthis"
+	RLV_BHVR_ATTACHTHISOVER,		// "attachthisover"
+	RLV_BHVR_DETACHTHIS,			// "detachthis"
+	RLV_BHVR_ATTACHALL,				// "attachall"
+	RLV_BHVR_ATTACHALLOVER,			// "attachallover"
+	RLV_BHVR_DETACHALL,				// "detachall"
+	RLV_BHVR_ATTACHALLTHIS,			// "attachallthis"
+	RLV_BHVR_ATTACHALLTHISOVER,		// "attachallthisover"
+	RLV_BHVR_DETACHALLTHIS,			// "detachallthis"
+	RLV_BHVR_TPTO,					// "tpto"
+	RLV_BHVR_VERSION,				// "version"
+	RLV_BHVR_VERSIONNEW,			// "versionnew"
+	RLV_BHVR_VERSIONNUM,			// "versionnum"
+	RLV_BHVR_GETATTACH,				// "getattach"
+	RLV_BHVR_GETATTACHNAMES,		// "getattachnames"
+	RLV_BHVR_GETADDATTACHNAMES,		// "getaddattachnames"
+	RLV_BHVR_GETREMATTACHNAMES,		// "getremattachnames"
+	RLV_BHVR_GETOUTFIT,				// "getoutfit"
+	RLV_BHVR_GETOUTFITNAMES,		// "getoutfitnames"
+	RLV_BHVR_GETADDOUTFITNAMES,		// "getaddoutfitnames"
+	RLV_BHVR_GETREMOUTFITNAMES,		// "getremoutfitnames"
+	RLV_BHVR_FINDFOLDER,			// "findfolder"
+	RLV_BHVR_FINDFOLDERS,			// "findfolders"
+	RLV_BHVR_GETPATH,				// "getpath"
+	RLV_BHVR_GETPATHNEW,			// "getpathnew"
+	RLV_BHVR_GETINV,				// "getinv"
+	RLV_BHVR_GETINVWORN,			// "getinvworn"
+	RLV_BHVR_GETSITID,				// "getsitid"
+	RLV_BHVR_GETSTATUS,				// "getstatus"
+	RLV_BHVR_GETSTATUSALL,			// "getstatusall"
+
+	RLV_BHVR_COUNT,
+	RLV_BHVR_UNKNOWN
+};
+
+enum ERlvParamType {
+	RLV_TYPE_UNKNOWN,
+	RLV_TYPE_ADD,					// <param> == "n"|"add"
+	RLV_TYPE_REMOVE,				// <param> == "y"|"rem"
+	RLV_TYPE_FORCE,					// <param> == "force"
+	RLV_TYPE_REPLY,					// <param> == <number>
+	RLV_TYPE_CLEAR
+};
+
+enum ERlvCmdRet {
+	RLV_RET_UNKNOWN     = 0x0000,	// Unknown error (should only be used internally)
+	RLV_RET_RETAINED,				// Command was retained
+	RLV_RET_SUCCESS     = 0x0100,	// Command executed succesfully
+	RLV_RET_SUCCESS_UNSET,			// Command executed succesfully (RLV_TYPE_REMOVE for an unrestricted behaviour)
+	RLV_RET_SUCCESS_DUPLICATE,		// Command executed succesfully (RLV_TYPE_ADD for an already restricted behaviour)
+	RLV_RET_FAILED      = 0x0200,	// Command failed (general failure)
+	RLV_RET_FAILED_SYNTAX,			// Command failed (syntax error)
+	RLV_RET_FAILED_OPTION,			// Command failed (invalid option)
+	RLV_RET_FAILED_PARAM,			// Command failed (invalid param)
+	RLV_RET_FAILED_LOCK,			// Command failed (command is locked by another object)
+	RLV_RET_FAILED_DISABLED,		// Command failed (command disabled by user)
+	RLV_RET_FAILED_UNKNOWN,			// Command failed (unknown command)
+	RLV_RET_FAILED_NOSHAREDROOT,	// Command failed (missing #RLV)
+};
+
+enum ERlvExceptionCheck
+{
+	RLV_CHECK_PERMISSIVE,			// Exception can be set by any object
+	RLV_CHECK_STRICT,				// Exception must be set by all objects holding the restriction
+	RLV_CHECK_DEFAULT				// Permissive or strict will be determined by currently enforced restrictions
+};
+
+enum ERlvLockMask
+{
+	RLV_LOCK_ADD    = 0x01,
+	RLV_LOCK_REMOVE = 0x02,
+	RLV_LOCK_ANY    = RLV_LOCK_ADD | RLV_LOCK_REMOVE
+};
+
+enum ERlvWearMask
+{
+	RLV_WEAR_LOCKED  = 0x00,		// User can not wear the item at all
+	RLV_WEAR_ADD     = 0x01,		// User can wear the item in addition to what's already worn
+	RLV_WEAR_REPLACE = 0x02,		// User can wear the item and replace what's currently worn
+	RLV_WEAR         = 0x03			// Convenience: combines RLV_WEAR_ADD and RLV_WEAR_REPLACE
+};
+
+enum ERlvAttachGroupType
+{
+	RLV_ATTACHGROUP_HEAD = 0,
+	RLV_ATTACHGROUP_TORSO,
+	RLV_ATTACHGROUP_ARMS,
+	RLV_ATTACHGROUP_LEGS,
+	RLV_ATTACHGROUP_HUD,
+	RLV_ATTACHGROUP_COUNT,
+	RLV_ATTACHGROUP_INVALID
+};
+
+// ============================================================================
+// Settings
+//
+
+#define RLV_SETTING_MAIN				"RestrainedLove"
+#define RLV_SETTING_DEBUG				"RestrainedLoveDebug"
+#define RLV_SETTING_NOSETENV			"RestrainedLoveNoSetEnv"
+#define RLV_SETTING_FORBIDGIVETORLV		"RestrainedLoveForbidGiveToRLV"
+
+#define RLV_SETTING_DEBUGHIDEUNSETDUP   "RLVaDebugHideUnsetDuplicate"
+#define RLV_SETTING_ENABLECOMPOSITES	"RLVaEnableCompositeFolders"
+#define RLV_SETTING_ENABLELEGACYNAMING	"RLVaEnableLegacyNaming"
+#define RLV_SETTING_ENABLESHAREDWEAR	"RLVaEnableSharedWear"
+#define RLV_SETTING_HIDELOCKEDLAYER		"RLVaHideLockedLayers"
+#define RLV_SETTING_HIDELOCKEDATTACH	"RLVaHideLockedAttachments"
+#define RLV_SETTING_HIDELOCKEDINVENTORY	"RLVaHideLockedInventory"
+#define RLV_SETTING_LOGINLASTLOCATION	"RLVaLoginLastLocation"
+#define RLV_SETTING_SHAREDINVAUTORENAME	"RLVaSharedInvAutoRename"
+#define RLV_SETTING_SHOWNAMETAGS		"RLVaShowNameTags"
+
+#define RLV_SETTING_FIRSTUSE_PREFIX		"FirstRLV"
+#define RLV_SETTING_FIRSTUSE_GIVETORLV	RLV_SETTING_FIRSTUSE_PREFIX"GiveToRLV"
+
+// ============================================================================
+// Strings
+//
+
+#define RLV_STRING_HIDDEN					"hidden_generic"
+#define RLV_STRING_HIDDEN_PARCEL			"hidden_parcel"
+#define RLV_STRING_HIDDEN_REGION			"hidden_region"
+
+#define RLV_STRING_BLOCKED_RECVIM			"blocked_recvim"
+#define RLV_STRING_BLOCKED_RECVIM_REMOTE	"blocked_recvim_remote"
+#define RLV_STRING_BLOCKED_SENDIM			"blocked_sendim"
+#define RLV_STRING_BLOCKED_VIEWXXX			"blocked_viewxxx"
+#define RLV_STRING_BLOCKED_TPLURE_REMOTE	"blocked_tplure_remote"
+
+// ============================================================================
+
+#endif // RLV_DEFINES_H
diff --git a/indra/newview/rlvextensions.cpp b/indra/newview/rlvextensions.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2e38ecd06b5d93164b43fc3f3f5001a8e0d54e6d
--- /dev/null
+++ b/indra/newview/rlvextensions.cpp
@@ -0,0 +1,552 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+//#include "llagent.h"
+#include "llagentcamera.h"
+#include "llviewercontrol.h"
+//#include "llviewerwindow.h"
+//#include "llvoavatar.h"
+#include "llwlparammanager.h"
+
+#include "rlvextensions.h"
+#include "rlvhandler.h"
+
+// ============================================================================
+
+std::map<std::string, S16> RlvExtGetSet::m_DbgAllowed;
+std::map<std::string, std::string> RlvExtGetSet::m_PseudoDebug;
+
+// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h
+RlvExtGetSet::RlvExtGetSet()
+{
+	if (!m_DbgAllowed.size())	// m_DbgAllowed is static and should only be initialized once
+	{
+		m_DbgAllowed.insert(std::pair<std::string, S16>("AvatarSex", DBG_READ | DBG_WRITE | DBG_PSEUDO));
+		m_DbgAllowed.insert(std::pair<std::string, S16>("RenderResolutionDivisor", DBG_READ | DBG_WRITE));
+		#ifdef RLV_EXTENSION_CMD_GETSETDEBUG_EX
+			m_DbgAllowed.insert(std::pair<std::string, S16>(RLV_SETTING_FORBIDGIVETORLV, DBG_READ));
+			m_DbgAllowed.insert(std::pair<std::string, S16>(RLV_SETTING_NOSETENV, DBG_READ));
+			m_DbgAllowed.insert(std::pair<std::string, S16>("WindLightUseAtmosShaders", DBG_READ));
+		#endif // RLV_EXTENSION_CMD_GETSETDEBUG_EX
+
+		// Cache persistance of every setting
+		LLControlVariable* pSetting;
+		for (std::map<std::string, S16>::iterator itDbg = m_DbgAllowed.begin(); itDbg != m_DbgAllowed.end(); ++itDbg)
+		{
+			if ( ((pSetting = gSavedSettings.getControl(itDbg->first)) != NULL) && (pSetting->isPersisted()) )
+				itDbg->second |= DBG_PERSIST;
+		}
+	}
+}
+
+// Checked: 2009-05-17 (RLVa-0.2.0a)
+bool RlvExtGetSet::onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet)
+{
+	return processCommand(rlvCmd, cmdRet);
+}
+
+// Checked: 2009-05-17 (RLVa-0.2.0a)
+bool RlvExtGetSet::onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet)
+{
+	return processCommand(rlvCmd, cmdRet);
+}
+
+// Checked: 2009-12-23 (RLVa-1.1.0k) | Modified: RLVa-1.1.0k
+bool RlvExtGetSet::processCommand(const RlvCommand& rlvCmd, ERlvCmdRet& eRet)
+{
+	std::string strBehaviour = rlvCmd.getBehaviour(), strGetSet, strSetting;
+	int idxSetting = strBehaviour.find('_');
+	if ( (strBehaviour.length() >= 6) && (-1 != idxSetting) && ((int)strBehaviour.length() > idxSetting + 1) )
+	{
+		strSetting = strBehaviour.substr(idxSetting + 1);
+		strBehaviour.erase(idxSetting);	// Get rid of "_<setting>"
+
+		strGetSet = strBehaviour.substr(0, 3);
+		strBehaviour.erase(0, 3);		// Get rid of get/set
+
+		if ("debug" == strBehaviour)
+		{
+			if ( ("get" == strGetSet) && (RLV_TYPE_REPLY == rlvCmd.getParamType()) )
+			{
+				RlvUtil::sendChatReply(rlvCmd.getParam(), onGetDebug(strSetting));
+				eRet = RLV_RET_SUCCESS;
+				return true;
+			}
+			else if ( ("set" == strGetSet) && (RLV_TYPE_FORCE == rlvCmd.getParamType()) )
+			{
+				if (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETDEBUG, rlvCmd.getObjectID()))
+					eRet = onSetDebug(strSetting, rlvCmd.getOption());
+				return true;
+			}
+		}
+		else if ("env" == strBehaviour)
+		{
+			if ( ("get" == strGetSet) && (RLV_TYPE_REPLY == rlvCmd.getParamType()) )
+			{
+				RlvUtil::sendChatReply(rlvCmd.getParam(), onGetEnv(strSetting));
+				eRet = RLV_RET_SUCCESS;
+				return true;
+			}
+			else if ( ("set" == strGetSet) && (RLV_TYPE_FORCE == rlvCmd.getParamType()) )
+			{
+				if (!gRlvHandler.hasBehaviourExcept(RLV_BHVR_SETENV, rlvCmd.getObjectID()))
+					eRet = onSetEnv(strSetting, rlvCmd.getOption());
+				return true;
+			}
+		}
+	}
+	else if ("setrot" == rlvCmd.getBehaviour())
+	{
+		// NOTE: if <option> is invalid (or missing) altogether then RLV-1.17 will rotate to 0.0 (which is actually PI / 4)
+		F32 nAngle = 0.0f;
+		if (LLStringUtil::convertToF32(rlvCmd.getOption(), nAngle))
+		{
+			nAngle = RLV_SETROT_OFFSET - nAngle;
+
+			gAgentCamera.startCameraAnimation();
+
+			LLVector3 at(LLVector3::x_axis);
+			at.rotVec(nAngle, LLVector3::z_axis);
+			at.normalize();
+			gAgent.resetAxes(at);
+
+			eRet = RLV_RET_SUCCESS;
+		}
+		else
+			eRet = RLV_RET_FAILED_OPTION;
+		return true;
+	}
+	return false;
+}
+
+// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h
+bool RlvExtGetSet::findDebugSetting(std::string& strSetting, S16& flags)
+{
+	LLStringUtil::toLower(strSetting);	// Convenience for non-RLV calls
+
+	std::string strTemp;
+	for (std::map<std::string, S16>::const_iterator itSetting = m_DbgAllowed.begin(); itSetting != m_DbgAllowed.end(); ++itSetting)
+	{
+		strTemp = itSetting->first;
+		LLStringUtil::toLower(strTemp);
+		
+		if (strSetting == strTemp)
+		{
+			strSetting = itSetting->first;
+			flags = itSetting->second;
+			return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2009-06-03 (RLVa-0.2.0h) | Added: RLVa-0.2.0h
+S16 RlvExtGetSet::getDebugSettingFlags(const std::string& strSetting)
+{
+	std::map<std::string, S16>::const_iterator itSetting = m_DbgAllowed.find(strSetting);
+	return (itSetting != m_DbgAllowed.end()) ? itSetting->second : 0;
+}
+
+// Checked: 2009-06-03 (RLVa-0.2.0h) | Modified: RLVa-0.2.0h
+std::string RlvExtGetSet::onGetDebug(std::string strSetting)
+{
+	S16 dbgFlags;
+	if ( (findDebugSetting(strSetting, dbgFlags)) && ((dbgFlags & DBG_READ) == DBG_READ) )
+	{
+		if ((dbgFlags & DBG_PSEUDO) == 0)
+		{
+			LLControlVariable* pSetting = gSavedSettings.getControl(strSetting);
+			if (pSetting)
+			{
+				switch (pSetting->type())
+				{
+					case TYPE_U32:
+						return llformat("%u", gSavedSettings.getU32(strSetting));
+					case TYPE_S32:
+						return llformat("%d", gSavedSettings.getS32(strSetting));
+					case TYPE_BOOLEAN:
+						return llformat("%d", gSavedSettings.getBOOL(strSetting));
+					default:
+						RLV_ERRS << "Unexpected debug setting type" << LL_ENDL;
+						break;
+				}
+			}
+		}
+		else
+		{
+			return onGetPseudoDebug(strSetting);
+		}
+	}
+	return std::string();
+}
+
+// Checked: 2009-10-03 (RLVa-1.0.4e) | Added: RLVa-1.0.4e
+std::string RlvExtGetSet::onGetPseudoDebug(const std::string& strSetting)
+{
+	// Skip sanity checking because it's all done in RlvExtGetSet::onGetDebug() already
+	if ("AvatarSex" == strSetting)
+	{
+		std::map<std::string, std::string>::const_iterator itPseudo = m_PseudoDebug.find(strSetting);
+		if (itPseudo != m_PseudoDebug.end())
+		{
+			return itPseudo->second;
+		}
+		else
+		{
+			if (isAgentAvatarValid())
+				return llformat("%d", (gAgentAvatarp->getSex() == SEX_MALE)); // [See LLFloaterCustomize::LLFloaterCustomize()]
+		}
+	}
+	return std::string();
+}
+
+// Checked: 2009-10-10 (RLVa-1.0.4e) | Modified: RLVa-1.0.4e
+ERlvCmdRet RlvExtGetSet::onSetDebug(std::string strSetting, const std::string& strValue)
+{
+	S16 dbgFlags; ERlvCmdRet eRet = RLV_RET_FAILED_UNKNOWN;
+	if ( (findDebugSetting(strSetting, dbgFlags)) && ((dbgFlags & DBG_WRITE) == DBG_WRITE) )
+	{
+		eRet = RLV_RET_FAILED_OPTION;
+		if ((dbgFlags & DBG_PSEUDO) == 0)
+		{
+			LLControlVariable* pSetting = gSavedSettings.getControl(strSetting);
+			if (pSetting)
+			{
+				U32 u32Value; S32 s32Value; BOOL fValue;
+				switch (pSetting->type())
+				{
+					case TYPE_U32:
+						if (LLStringUtil::convertToU32(strValue, u32Value))
+						{
+							gSavedSettings.setU32(strSetting, u32Value);
+							eRet = RLV_RET_SUCCESS;
+						}
+						break;
+					case TYPE_S32:
+						if (LLStringUtil::convertToS32(strValue, s32Value))
+						{
+							gSavedSettings.setS32(strSetting, s32Value);
+							eRet = RLV_RET_SUCCESS;
+						}
+						break;
+					case TYPE_BOOLEAN:
+						if (LLStringUtil::convertToBOOL(strValue, fValue))
+						{
+							gSavedSettings.setBOOL(strSetting, fValue);
+							eRet = RLV_RET_SUCCESS;
+						}
+						break;
+					default:
+						RLV_ERRS << "Unexpected debug setting type" << LL_ENDL;
+						eRet = RLV_RET_FAILED;
+						break;
+				}
+
+				// Default settings should persist if they were marked that way, but non-default settings should never persist
+				pSetting->setPersist( (pSetting->isDefault()) ? ((dbgFlags & DBG_PERSIST) == DBG_PERSIST) : false );
+			}
+		}
+		else
+		{
+			eRet = onSetPseudoDebug(strSetting, strValue);
+		}
+	}
+	return eRet;
+}
+
+// Checked: 2009-10-10 (RLVa-1.0.4e) | Modified: RLVa-1.0.4e
+ERlvCmdRet RlvExtGetSet::onSetPseudoDebug(const std::string& strSetting, const std::string& strValue)
+{
+	ERlvCmdRet eRet = RLV_RET_FAILED_OPTION;
+	if ("AvatarSex" == strSetting)
+	{
+		BOOL fValue;
+		if (LLStringUtil::convertToBOOL(strValue, fValue))
+		{
+			m_PseudoDebug[strSetting] = strValue;
+			eRet = RLV_RET_SUCCESS;
+		}
+	}
+	return eRet;
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+std::string RlvExtGetSet::onGetEnv(std::string strSetting)
+{
+	LLWLParamManager* pWLParams = LLWLParamManager::instance(); bool fErr;
+	WLFloatControl* pFloat = NULL;
+	WLColorControl* pColour = NULL;
+
+	F32 nValue = 0.0f;
+	if ("daytime" == strSetting)
+	{
+		nValue = (pWLParams->mAnimator.mIsRunning && pWLParams->mAnimator.mUseLindenTime) ? -1.0f : pWLParams->mAnimator.getDayTime();
+	}
+	else if ("preset" == strSetting)
+	{
+		return (pWLParams->mAnimator.mIsRunning && pWLParams->mAnimator.mUseLindenTime) ? std::string() : pWLParams->mCurParams.mName;
+	}
+	else if ( ("sunglowfocus" == strSetting) || ("sunglowsize" == strSetting) )
+	{
+		pWLParams->mGlow = pWLParams->mCurParams.getVector(pWLParams->mGlow.mName, fErr);
+		RLV_ASSERT_DBG(!fErr);
+
+		if ("sunglowfocus" == strSetting) 
+			nValue = -pWLParams->mGlow.b / 5.0f;
+		else
+			nValue = 2 - pWLParams->mGlow.r / 20.0f;
+	}
+	else if ("starbrightness" == strSetting)		nValue = pWLParams->mCurParams.getStarBrightness();
+	else if ("eastangle" == strSetting)				nValue = pWLParams->mCurParams.getEastAngle() / F_TWO_PI;
+	else if ("sunmoonposition" == strSetting)		nValue = pWLParams->mCurParams.getSunAngle() / F_TWO_PI;
+	else if ("cloudscrollx" == strSetting)			nValue = pWLParams->mCurParams.getCloudScrollX() - 10.0f;
+	else if ("cloudscrolly" == strSetting)			nValue = pWLParams->mCurParams.getCloudScrollY() - 10.0f;
+	// Float controls
+	else if ("cloudcoverage" == strSetting)			pFloat = &pWLParams->mCloudCoverage;
+	else if ("cloudscale" == strSetting)			pFloat = &pWLParams->mCloudScale;
+	else if ("densitymultiplier" == strSetting)		pFloat = &pWLParams->mDensityMult;
+	else if ("distancemultiplier" == strSetting)	pFloat = &pWLParams->mDistanceMult;
+	else if ("maxaltitude" == strSetting)			pFloat = &pWLParams->mMaxAlt;
+	else if ("scenegamma" == strSetting)			pFloat = &pWLParams->mWLGamma;
+	// Colour controls
+	else if ("hazedensity" == strSetting)			pColour = &pWLParams->mHazeDensity;
+	else if ("hazehorizon" == strSetting)			pColour = &pWLParams->mHazeHorizon;
+	else
+	{
+		char ch = strSetting[strSetting.length() - 1];
+		// HACK-RLVa: not entirely proper (creates new synonyms)
+		if ('x' == ch)		ch = 'r';
+		else if ('y' == ch)	ch = 'g';
+		else if ('d' == ch)	ch = 'b';
+
+		if ( ('r' == ch) || ('g' == ch) || ('b' == ch) || ('i' == ch) )
+		{
+			strSetting.erase(strSetting.length() - 1, 1);
+			
+			if ("ambient" == strSetting)			pColour = &pWLParams->mAmbient;
+			else if ("bluedensity" == strSetting)	pColour = &pWLParams->mBlueDensity;
+			else if ("bluehorizon" == strSetting)	pColour = &pWLParams->mBlueHorizon;
+			else if ("sunmooncolor" == strSetting)	pColour = &pWLParams->mSunlight;
+			else if ("cloudcolor" == strSetting)	pColour = &pWLParams->mCloudColor;
+			else if ("cloud" == strSetting)			pColour = &pWLParams->mCloudMain;
+			else if ("clouddetail" == strSetting)	pColour = &pWLParams->mCloudDetail;
+
+			if (pColour)
+			{
+				*pColour = pWLParams->mCurParams.getVector(pColour->mName, fErr);
+				RLV_ASSERT_DBG(!fErr);
+
+				if ('r' == ch)		nValue = pColour->r;
+				else if ('g' == ch)	nValue = pColour->g;
+				else if ('b' == ch)	nValue = pColour->b;
+				else if (('i' == ch) && (pColour->hasSliderName)) nValue = llmax(pColour->r, pColour->g, pColour->b);
+
+				if (pColour->isBlueHorizonOrDensity)	nValue /= 2.0f;
+				else if (pColour->isSunOrAmbientColor)	nValue /= 3.0f;
+			}
+		}
+	}
+
+	if (pFloat)
+	{
+		*pFloat = pWLParams->mCurParams.getVector(pFloat->mName, fErr);
+		RLV_ASSERT_DBG(!fErr);
+		nValue = pFloat->x * pFloat->mult;;
+	}
+	else if (pColour)
+	{
+		*pColour = pWLParams->mCurParams.getVector(pColour->mName, fErr);
+		RLV_ASSERT_DBG(!fErr);
+		nValue = pColour->r;
+	}
+
+	return llformat("%f", nValue);
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+ERlvCmdRet RlvExtGetSet::onSetEnv(std::string strSetting, const std::string& strValue)
+{
+	LLWLParamManager* pWLParams = LLWLParamManager::instance(); bool fErr;
+	WLFloatControl* pFloat = NULL;
+	WLColorControl* pColour = NULL;
+
+	F32 nValue = 0.0f;
+	// Sanity check - make sure strValue specifies a number for all settings except "preset"
+	if ( (RlvSettings::getNoSetEnv()) || ( (!LLStringUtil::convertToF32(strValue, nValue)) && ("preset" != strSetting) ))
+		return RLV_RET_FAILED_OPTION;
+
+	// Not quite correct, but RLV-1.16.0 will halt the default daytime cycle on invalid commands so we need to as well
+	pWLParams->mAnimator.mIsRunning = false;
+	pWLParams->mAnimator.mUseLindenTime = false;
+
+	// See LLWorldEnvSettings::handleEvent()
+	if ("daytime" == strSetting)
+	{
+		if (0.0f <= nValue)
+		{
+			pWLParams->mAnimator.setDayTime(llmin(nValue, 1.0f));
+			pWLParams->mAnimator.update(pWLParams->mCurParams);
+		}
+		else
+		{
+			pWLParams->mAnimator.mIsRunning = true;
+			pWLParams->mAnimator.mUseLindenTime = true;	
+		}
+		return RLV_RET_SUCCESS;
+	}
+	// See LLFloaterWindLight::onChangePresetName()
+	else if ("preset" == strSetting)
+	{
+		pWLParams->loadPreset(strValue, true);
+		return RLV_RET_SUCCESS;
+	}
+	// See LLFloaterWindLight::onGlowRMoved() / LLFloaterWindLight::onGlowBMoved()
+	else if ( ("sunglowfocus" == strSetting) || ("sunglowsize" == strSetting) )
+	{
+		pWLParams->mGlow = pWLParams->mCurParams.getVector(pWLParams->mGlow.mName, fErr);
+		RLV_ASSERT_DBG(!fErr);
+
+		if ("sunglowfocus" == strSetting) 
+			pWLParams->mGlow.b = -nValue * 5;
+		else
+			pWLParams->mGlow.r = (2 - nValue) * 20;
+		pWLParams->mGlow.update(pWLParams->mCurParams);
+
+		pWLParams->propagateParameters();
+		return RLV_RET_SUCCESS;
+	}
+	// See LLFloaterWindLight::onStarAlphaMoved
+	else if ("starbrightness" == strSetting)
+	{
+		pWLParams->mCurParams.setStarBrightness(nValue);
+		return RLV_RET_SUCCESS;
+	}
+	// See LLFloaterWindLight::onSunMoved()
+	else if ( ("eastangle" == strSetting) || ("sunmoonposition" == strSetting) )	
+	{
+		if ("eastangle" == strSetting)	
+			pWLParams->mCurParams.setEastAngle(F_TWO_PI * nValue);
+		else
+			pWLParams->mCurParams.setSunAngle(F_TWO_PI * nValue);
+
+		pWLParams->propagateParameters();
+		return RLV_RET_SUCCESS;
+	}
+	// See LLFloaterWindLight::onCloudScrollXMoved() / LLFloaterWindLight::onCloudScrollYMoved() 
+	else if ("cloudscrollx" == strSetting)
+	{
+		pWLParams->mCurParams.setCloudScrollX(nValue + 10.0f);
+		return RLV_RET_SUCCESS;
+	}
+	else if ("cloudscrolly" == strSetting)
+	{
+		pWLParams->mCurParams.setCloudScrollY(nValue + 10.0f);
+		return RLV_RET_SUCCESS;
+	}
+	// See LLFloaterWindLight::onFloatControlMoved()
+	else if ("cloudcoverage" == strSetting)			pFloat = &pWLParams->mCloudCoverage;
+	else if ("cloudscale" == strSetting)			pFloat = &pWLParams->mCloudScale;
+	else if ("densitymultiplier" == strSetting)		pFloat = &pWLParams->mDensityMult;
+	else if ("distancemultiplier" == strSetting)	pFloat = &pWLParams->mDistanceMult;
+	else if ("maxaltitude" == strSetting)			pFloat = &pWLParams->mMaxAlt;
+	else if ("scenegamma" == strSetting)			pFloat = &pWLParams->mWLGamma;
+	// See LLFloaterWindLight::onColorControlRMoved()
+	else if ("hazedensity" == strSetting)	        pColour = &pWLParams->mHazeDensity;
+	else if ("hazehorizon" == strSetting)	        pColour = &pWLParams->mHazeHorizon;
+
+	if (pFloat)
+	{
+		*pFloat = pWLParams->mCurParams.getVector(pFloat->mName, fErr);
+		RLV_ASSERT_DBG(!fErr);
+
+		pFloat->x = nValue / pFloat->mult;
+		pFloat->update(pWLParams->mCurParams);
+		pWLParams->propagateParameters();
+		return RLV_RET_SUCCESS;
+	} 
+	else if (pColour)
+	{
+		*pColour = pWLParams->mCurParams.getVector(pColour->mName, fErr);
+		RLV_ASSERT_DBG(!fErr);
+
+		pColour->r = nValue;
+		pColour->update(pWLParams->mCurParams);
+		pWLParams->propagateParameters();
+		return RLV_RET_SUCCESS;
+	}
+
+	// RGBI settings
+	char ch = strSetting[strSetting.length() - 1];
+	if ('x' == ch)		ch = 'r';
+	else if ('y' == ch)	ch = 'g';
+	else if ('d' == ch)	ch = 'b';
+
+	if ( ('r' == ch) || ('g' == ch) || ('b' == ch) || ('i' == ch) )
+	{
+		strSetting.erase(strSetting.length() - 1, 1);
+		
+		if ("ambient" == strSetting)			pColour = &pWLParams->mAmbient;
+		else if ("bluedensity" == strSetting)	pColour = &pWLParams->mBlueDensity;
+		else if ("bluehorizon" == strSetting)	pColour = &pWLParams->mBlueHorizon;
+		else if ("sunmooncolor" == strSetting)	pColour = &pWLParams->mSunlight;
+		else if ("cloudcolor" == strSetting)	pColour = &pWLParams->mCloudColor;
+		else if ("cloud" == strSetting)			pColour = &pWLParams->mCloudMain;
+		else if ("clouddetail" == strSetting)	pColour = &pWLParams->mCloudDetail;
+
+		if (pColour)
+		{
+			*pColour = pWLParams->mCurParams.getVector(pColour->mName, fErr);
+			RLV_ASSERT_DBG(!fErr);
+
+			if (pColour->isBlueHorizonOrDensity)   nValue *= 2.0f;
+			else if (pColour->isSunOrAmbientColor) nValue *= 3.0f;
+
+			if ('i' == ch)									// (See: LLFloaterWindLight::onColorControlIMoved)
+			{
+				if (!pColour->hasSliderName)
+					return RLV_RET_FAILED_UNKNOWN;
+
+				F32 curMax = llmax(pColour->r, pColour->g, pColour->b);
+				if ( (0.0f == nValue) || (0.0f == curMax) )
+					pColour->r = pColour->g = pColour->b = pColour->i = nValue;
+				else
+				{
+					F32 nDelta = (nValue - curMax) / curMax;
+					pColour->r *= (1.0f + nDelta);
+					pColour->g *= (1.0f + nDelta);
+					pColour->b *= (1.0f + nDelta);
+					pColour->i = nValue;
+				}
+			}
+			else											// (See: LLFloaterWindLight::onColorControlRMoved)
+			{
+				F32* pnValue = ('r' == ch) ? &pColour->r : ('g' == ch) ? &pColour->g : ('b' == ch) ? &pColour->b : NULL;
+				if (pnValue)
+					*pnValue = nValue;
+				pColour->i = llmax(pColour->r, pColour->g, pColour->b);
+			}
+
+			pColour->update(pWLParams->mCurParams);
+			pWLParams->propagateParameters();
+
+			return RLV_RET_SUCCESS;
+		}
+	}
+	return RLV_RET_FAILED_UNKNOWN;
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvextensions.h b/indra/newview/rlvextensions.h
new file mode 100644
index 0000000000000000000000000000000000000000..ed6bfc4928ae6fba54ecab51dad7fd2cb9d16658
--- /dev/null
+++ b/indra/newview/rlvextensions.h
@@ -0,0 +1,60 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_EXTENSIONS_H
+#define RLV_EXTENSIONS_H
+
+#include "rlvcommon.h"
+
+// ============================================================================
+/*
+ * RlvExtGetSet
+ * ============
+ * Implements @get_XXX:<option>=<channel> and @set_XXX:<option>=force
+ *
+ */
+
+class RlvExtGetSet : public RlvCommandHandler
+{
+public:
+	RlvExtGetSet();
+	virtual ~RlvExtGetSet() {}
+
+	virtual bool onForceCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet);
+	virtual bool onReplyCommand(const RlvCommand& rlvCmd, ERlvCmdRet& cmdRet);
+protected:
+	std::string onGetDebug(std::string strSetting);
+	std::string onGetPseudoDebug(const std::string& strSetting);
+	ERlvCmdRet  onSetDebug(std::string strSetting, const std::string& strValue);
+	ERlvCmdRet  onSetPseudoDebug(const std::string& strSetting, const std::string& strValue);
+
+	std::string onGetEnv(std::string strSetting);
+	ERlvCmdRet  onSetEnv(std::string strSetting, const std::string& strValue);
+
+	bool processCommand(const RlvCommand& rlvCmd, ERlvCmdRet& eRet);
+
+public:
+	enum { DBG_READ = 0x01, DBG_WRITE = 0x02, DBG_PERSIST = 0x04, DBG_PSEUDO = 0x08 };
+	static std::map<std::string, S16> m_DbgAllowed;
+	static std::map<std::string, std::string> m_PseudoDebug;
+
+	static bool findDebugSetting(/*[in,out]*/ std::string& strSetting, /*[out]*/ S16& flags);
+	static S16  getDebugSettingFlags(const std::string& strSetting);
+};
+
+// ============================================================================
+
+#endif // RLV_EXTENSIONS_H
diff --git a/indra/newview/rlvfloaters.cpp b/indra/newview/rlvfloaters.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..16b8b857cdcd617d926e9be26de635fe1f247677
--- /dev/null
+++ b/indra/newview/rlvfloaters.cpp
@@ -0,0 +1,280 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llscrolllistctrl.h"
+#include "llviewerjointattachment.h"
+#include "llviewerobjectlist.h"
+#include "llvoavatarself.h"
+
+#include "rlvfloaters.h"
+#include "rlvhelper.h"
+#include "rlvhandler.h"
+#include "rlvlocks.h"
+
+// ============================================================================
+// Helper functions
+//
+
+// Checked: 2010-03-11 (RLVa-1.2.0a) | Modified: RLVa-1.2.0g
+std::string rlvGetItemNameFromObjID(const LLUUID& idObj, bool fIncludeAttachPt = true)
+{
+	const LLViewerObject* pObj = gObjectList.findObject(idObj);
+	const LLViewerObject* pObjRoot = (pObj) ? pObj->getRootEdit() : NULL;
+	const LLViewerInventoryItem* pItem = ((pObjRoot) && (pObjRoot->isAttachment())) ? gInventory.getItem(pObjRoot->getAttachmentItemID()) : NULL;
+
+	std::string strItemName = (pItem) ? pItem->getName() : idObj.asString();
+	if ( (!fIncludeAttachPt) || (!pObj) || (!pObj->isAttachment()) || (!isAgentAvatarValid()) )
+		return strItemName;
+
+	const LLViewerJointAttachment* pAttachPt = 
+		get_if_there(gAgentAvatarp->mAttachmentPoints, RlvAttachPtLookup::getAttachPointIndex(pObjRoot), (LLViewerJointAttachment*)NULL);
+	std::string strAttachPtName = (pAttachPt) ? pAttachPt->getName() : std::string("Unknown");
+	return llformat("%s (%s, %s)", strItemName.c_str(), strAttachPtName.c_str(), (pObj == pObjRoot) ? "root" : "child");
+}
+
+// ============================================================================
+// RlvFloaterLocks member functions
+//
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+void RlvFloaterBehaviours::onOpen(const LLSD& sdKey)
+{
+	m_ConnRlvCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvFloaterBehaviours::onRlvCommand, this, _1, _2));
+
+	refreshAll();
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+void RlvFloaterBehaviours::onClose(bool fQuitting)
+{
+	m_ConnRlvCommand.disconnect();
+
+	// LLFloaterPay::~LLFloaterPay(): Name callbacks will be automatically disconnected since LLFloater is trackable <- how does that work?
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+void RlvFloaterBehaviours::onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet)
+{
+	// Refresh on any successful @XXX=y|n command
+	if ( (RLV_RET_SUCCESS == eRet) && ((RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType())) )
+	{
+		refreshAll();
+	}
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+void RlvFloaterBehaviours::refreshAll()
+{
+	LLCtrlListInterface* pBhvrList = childGetListInterface("behaviour_list");
+	if (!pBhvrList)
+		return;
+	pBhvrList->operateOnAll(LLCtrlListInterface::OP_DELETE);
+
+	if (!isAgentAvatarValid())
+		return;
+
+	//
+	// Set-up a row we can just reuse
+	//
+	LLSD sdRow;
+	LLSD& sdColumns = sdRow["columns"];
+	sdColumns[0]["column"] = "behaviour";   sdColumns[0]["type"] = "text";
+	sdColumns[1]["column"] = "name"; sdColumns[1]["type"] = "text";
+
+	//
+	// List behaviours
+	//
+	const RlvHandler::rlv_object_map_t* pRlvObjects = gRlvHandler.getObjectMap();
+	for (RlvHandler::rlv_object_map_t::const_iterator itObj = pRlvObjects->begin(), endObj = pRlvObjects->end(); itObj != endObj; ++itObj)
+	{
+		sdColumns[1]["value"] = rlvGetItemNameFromObjID(itObj->first);
+
+		const rlv_command_list_t* pCommands = itObj->second.getCommandList();
+		for (rlv_command_list_t::const_iterator itCmd = pCommands->begin(), endCmd = pCommands->end(); itCmd != endCmd; ++itCmd)
+		{
+			std::string strBhvr = itCmd->asString();
+			
+			LLUUID idOption(itCmd->getOption());
+			if (idOption.notNull())
+			{
+				std::string strLookup;
+				if ( (gCacheName->getFullName(idOption, strLookup)) || (gCacheName->getGroupName(idOption, strLookup)) )
+				{
+					if (strLookup.find("???") == std::string::npos)
+						strBhvr.assign(itCmd->getBehaviour()).append(":").append(strLookup);
+				}
+				else if (m_PendingLookup.end() == std::find(m_PendingLookup.begin(), m_PendingLookup.end(), idOption))
+				{
+					gCacheName->get(idOption, FALSE, boost::bind(&RlvFloaterBehaviours::onAvatarNameLookup, this, _1, _2, _3, _4));
+					m_PendingLookup.push_back(idOption);
+				}
+			}
+
+			sdColumns[0]["value"] = strBhvr;
+
+			pBhvrList->addElement(sdRow, ADD_BOTTOM);
+		}
+	}
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+void RlvFloaterBehaviours::onAvatarNameLookup(const LLUUID& idAgent, const std::string& strFirst, const std::string& strLast, BOOL fGroup)
+{
+	std::list<LLUUID>::iterator itLookup = std::find(m_PendingLookup.begin(), m_PendingLookup.end(), idAgent);
+	if (itLookup != m_PendingLookup.end())
+		m_PendingLookup.erase(itLookup);
+
+	if (getVisible())
+		refreshAll();
+}
+
+// ============================================================================
+// RlvFloaterLocks member functions
+//
+
+// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvFloaterLocks::onOpen(const LLSD& sdKey)
+{
+	m_ConnRlvCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvFloaterLocks::onRlvCommand, this, _1, _2));
+
+	refreshAll();
+}
+
+// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvFloaterLocks::onClose(bool fQuitting)
+{
+	m_ConnRlvCommand.disconnect();
+}
+
+// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvFloaterLocks::onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet)
+{
+	// Refresh on any successful @XXX=y|n command where XXX is any of the attachment or wearable locking behaviours
+	if ( (RLV_RET_SUCCESS == eRet) && ((RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType())) )
+	{
+		switch (rlvCmd.getBehaviourType())
+		{
+			case RLV_BHVR_DETACH:
+			case RLV_BHVR_ADDATTACH:
+			case RLV_BHVR_REMATTACH:
+			case RLV_BHVR_ADDOUTFIT:
+			case RLV_BHVR_REMOUTFIT:
+				refreshAll();
+				break;
+			default:
+				break;
+		}
+	}
+}
+
+// Checked: 2010-03-18 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvFloaterLocks::refreshAll()
+{
+	LLCtrlListInterface* pLockList = childGetListInterface("lock_list");
+	if (!pLockList)
+		return;
+	pLockList->operateOnAll(LLCtrlListInterface::OP_DELETE);
+
+	if (!isAgentAvatarValid())
+		return;
+
+	//
+	// Set-up a row we can just reuse
+	//
+	LLSD sdRow;
+	LLSD& sdColumns = sdRow["columns"];
+	sdColumns[0]["column"] = "lock_type";   sdColumns[0]["type"] = "text";
+	sdColumns[1]["column"] = "lock_addrem"; sdColumns[1]["type"] = "text";
+	sdColumns[2]["column"] = "lock_target"; sdColumns[2]["type"] = "text";
+	sdColumns[3]["column"] = "lock_origin"; sdColumns[3]["type"] = "text";
+
+	//
+	// List attachment locks
+	//
+	sdColumns[0]["value"] = "Attachment";
+	sdColumns[1]["value"] = "rem";
+
+	const RlvAttachmentLocks::rlv_attachobjlock_map_t& attachObjRem = gRlvAttachmentLocks.getAttachObjLocks();
+	for (RlvAttachmentLocks::rlv_attachobjlock_map_t::const_iterator itAttachObj = attachObjRem.begin(); 
+			itAttachObj != attachObjRem.end(); ++itAttachObj)
+	{
+		sdColumns[2]["value"] = rlvGetItemNameFromObjID(itAttachObj->first);
+		sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachObj->second);
+
+		pLockList->addElement(sdRow, ADD_BOTTOM);
+	}
+
+	//
+	// List attachment point locks
+	//
+	sdColumns[0]["value"] = "Attachment Point";
+
+	sdColumns[1]["value"] = "add";
+	const RlvAttachmentLocks::rlv_attachptlock_map_t& attachPtAdd = gRlvAttachmentLocks.getAttachPtLocks(RLV_LOCK_ADD);
+	for (RlvAttachmentLocks::rlv_attachptlock_map_t::const_iterator itAttachPt = attachPtAdd.begin(); 
+			itAttachPt != attachPtAdd.end(); ++itAttachPt)
+	{
+		const LLViewerJointAttachment* pAttachPt = 
+			get_if_there(gAgentAvatarp->mAttachmentPoints, itAttachPt->first, (LLViewerJointAttachment*)NULL);
+		sdColumns[2]["value"] = pAttachPt->getName();
+		sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachPt->second);
+
+		pLockList->addElement(sdRow, ADD_BOTTOM);
+	}
+
+	sdColumns[1]["value"] = "rem";
+	const RlvAttachmentLocks::rlv_attachptlock_map_t& attachPtRem = gRlvAttachmentLocks.getAttachPtLocks(RLV_LOCK_REMOVE);
+	for (RlvAttachmentLocks::rlv_attachptlock_map_t::const_iterator itAttachPt = attachPtRem.begin(); 
+			itAttachPt != attachPtRem.end(); ++itAttachPt)
+	{
+		const LLViewerJointAttachment* pAttachPt = 
+			get_if_there(gAgentAvatarp->mAttachmentPoints, itAttachPt->first, (LLViewerJointAttachment*)NULL);
+		sdColumns[2]["value"] = pAttachPt->getName();
+		sdColumns[3]["value"] = rlvGetItemNameFromObjID(itAttachPt->second);
+
+		pLockList->addElement(sdRow, ADD_BOTTOM);
+	}
+
+	//
+	// List wearable type locks
+	//
+	sdColumns[0]["value"] = "Wearable Type";
+
+	sdColumns[1]["value"] = "add";
+	const RlvWearableLocks::rlv_wearabletypelock_map_t& wearableTypeAdd = gRlvWearableLocks.getWearableTypeLocks(RLV_LOCK_ADD);
+	for (RlvWearableLocks::rlv_wearabletypelock_map_t::const_iterator itWearableType = wearableTypeAdd.begin(); 
+			itWearableType != wearableTypeAdd.end(); ++itWearableType)
+	{
+		sdColumns[2]["value"] = LLWearableType::getTypeLabel(itWearableType->first);
+		sdColumns[3]["value"] = rlvGetItemNameFromObjID(itWearableType->second);
+
+		pLockList->addElement(sdRow, ADD_BOTTOM);
+	}
+
+	sdColumns[1]["value"] = "rem";
+	const RlvWearableLocks::rlv_wearabletypelock_map_t& wearableTypeRem = gRlvWearableLocks.getWearableTypeLocks(RLV_LOCK_REMOVE);
+	for (RlvWearableLocks::rlv_wearabletypelock_map_t::const_iterator itWearableType = wearableTypeRem.begin(); 
+			itWearableType != wearableTypeRem.end(); ++itWearableType)
+	{
+		sdColumns[2]["value"] = LLWearableType::getTypeName(itWearableType->first);
+		sdColumns[3]["value"] = rlvGetItemNameFromObjID(itWearableType->second);
+
+		pLockList->addElement(sdRow, ADD_BOTTOM);
+	}
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvfloaters.h b/indra/newview/rlvfloaters.h
new file mode 100644
index 0000000000000000000000000000000000000000..dbb1fa321275266ba9a1b48db51950447462047a
--- /dev/null
+++ b/indra/newview/rlvfloaters.h
@@ -0,0 +1,101 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_FLOATERS_H
+#define RLV_FLOATERS_H
+
+#include "llfloater.h"
+
+#include "rlvdefines.h"
+#include "rlvcommon.h"
+
+// ============================================================================
+// RlvFloaterLocks class declaration
+//
+
+class RlvFloaterBehaviours : public LLFloater
+{
+	friend class LLFloaterReg;
+private:
+	RlvFloaterBehaviours(const LLSD& sdKey) : LLFloater(sdKey) {}
+
+	/*
+	 * LLFloater overrides
+	 */
+public:
+	virtual void onOpen(const LLSD& sdKey);
+	virtual void onClose(bool fQuitting);
+
+	/*
+	 * Event handlers
+	 */
+protected:
+	void onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet);
+	void onAvatarNameLookup(const LLUUID& idAgent, const std::string& strFirst, const std::string& strLast, BOOL fGroup);
+
+	/*
+	 * Member functions
+	 */
+protected:
+	void refreshAll();
+
+	/*
+	 * Member variables
+	 */
+protected:
+	boost::signals2::connection m_ConnRlvCommand;
+	std::list<LLUUID>           m_PendingLookup;
+};
+
+// ============================================================================
+// RlvFloaterLocks class declaration
+//
+
+class RlvFloaterLocks : public LLFloater
+{
+	friend class LLFloaterReg;
+private:
+	RlvFloaterLocks(const LLSD& sdKey) : LLFloater(sdKey) {}
+
+	/*
+	 * LLFloater overrides
+	 */
+public:
+	virtual void onOpen(const LLSD& sdKey);
+	virtual void onClose(bool fQuitting);
+
+	/*
+	 * Event handlers
+	 */
+protected:
+	void onRlvCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet);
+
+	/*
+	 * Member functions
+	 */
+protected:
+	void refreshAll();
+
+	/*
+	 * Member variables
+	 */
+protected:
+	boost::signals2::connection m_ConnRlvCommand;
+};
+
+// ============================================================================
+
+#endif // RLV_FLOATERS_H
\ No newline at end of file
diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d19da6c10c9a62ef18167ef3548b4ab3495a701b
--- /dev/null
+++ b/indra/newview/rlvhandler.cpp
@@ -0,0 +1,1946 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llagentwearables.h"
+#include "llappviewer.h"
+#include "llcallbacklist.h"
+#include "llviewermessage.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+
+#include "rlvhandler.h"
+#include "rlvinventory.h"
+#include "rlvlocks.h"
+#include "rlvui.h"
+#include "rlvextensions.h"
+
+// ============================================================================
+// Static variable initialization
+//
+
+BOOL RlvHandler::m_fEnabled = FALSE;
+
+rlv_handler_t gRlvHandler;
+
+// ============================================================================
+// Command specific helper functions
+//
+
+// Checked: 2009-08-04 (RLVa-1.0.1d) | Added: RLVa-1.0.1d
+static bool rlvParseNotifyOption(const std::string& strOption, S32& nChannel, std::string& strFilter)
+{
+	boost_tokenizer tokens(strOption, boost::char_separator<char>(";", "", boost::keep_empty_tokens));
+	boost_tokenizer::const_iterator itTok = tokens.begin();
+
+	// Extract and sanity check the first token (required) which is the channel
+	if ( (itTok == tokens.end()) || (!LLStringUtil::convertToS32(*itTok, nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel)) )
+		return false;
+
+	// Second token (optional) is the filter
+	strFilter.clear();
+	if (++itTok != tokens.end())
+	{
+		strFilter = *itTok;
+		++itTok;
+	}
+
+	return (itTok == tokens.end());
+}
+
+// ============================================================================
+// Constructor/destructor
+//
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.1d
+RlvHandler::RlvHandler() : m_fCanCancelTp(true), m_posSitSource(), m_pGCTimer(NULL), m_pWLSnapshot(NULL)
+{
+	// Array auto-initialization to 0 is non-standard? (Compiler warning in VC-8.0)
+	memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT);
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.1d
+RlvHandler::~RlvHandler()
+{
+	//delete m_pGCTimer;	// <- deletes itself
+	delete m_pWLSnapshot;	// <- delete on NULL is harmless
+}
+
+// ============================================================================
+// Behaviour related functions
+//
+
+bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBehaviour, const std::string& strOption, const LLUUID& idObj) const
+{
+	for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
+		if ( (idObj != itObj->second.m_UUID) && (itObj->second.hasBehaviour(eBehaviour, strOption, false)) )
+			return true;
+	return false;
+}
+
+// Checked: 2009-10-04 (RLVa-1.0.4c) | Modified: RLVa-1.0.4c
+bool RlvHandler::isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck typeCheck) const
+{
+	// We need to "strict check" exceptions only if: the restriction is actually in place *and* (isPermissive(eBhvr) == FALSE)
+	if (RLV_CHECK_DEFAULT == typeCheck)
+		typeCheck = ( (hasBehaviour(eBhvr)) && (!isPermissive(eBhvr)) ) ? RLV_CHECK_STRICT : RLV_CHECK_PERMISSIVE;
+
+	std::list<LLUUID> objList;
+	if (RLV_CHECK_STRICT == typeCheck)
+	{
+		// If we're "strict checking" then we need the UUID of every object that currently has 'eBhvr' restricted
+		for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
+			if (itObj->second.hasBehaviour(eBhvr, !hasBehaviour(RLV_BHVR_PERMISSIVE)))
+				objList.push_back(itObj->first);
+	}
+
+	for (rlv_exception_map_t::const_iterator itException = m_Exceptions.lower_bound(eBhvr), 
+			endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException)
+	{
+		if (itException->second.varOption == varOption)
+		{
+			// For permissive checks we just return on the very first match
+			if (RLV_CHECK_PERMISSIVE == typeCheck)
+				return true;
+
+			// For strict checks we don't return until the list is empty (every object with 'eBhvr' restricted also contains the exception)
+			std::list<LLUUID>::iterator itList = std::find(objList.begin(), objList.end(), itException->second.idObject);
+			if (itList != objList.end())
+				objList.erase(itList);
+			if (objList.empty())
+				return true;
+		}
+	}
+	return false;
+}
+
+// ============================================================================
+// Command processing functions
+//
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+void RlvHandler::addCommandHandler(RlvCommandHandler* pCmdHandler)
+{
+	if ( (pCmdHandler) && (std::find(m_CommandHandlers.begin(), m_CommandHandlers.end(), pCmdHandler) == m_CommandHandlers.end()) )
+		m_CommandHandlers.push_back(pCmdHandler);
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+void RlvHandler::removeCommandHandler(RlvCommandHandler* pCmdHandler)
+{
+	if (pCmdHandler)
+		m_CommandHandlers.remove(pCmdHandler);
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0a
+void RlvHandler::clearCommandHandlers()
+{
+	std::list<RlvCommandHandler*>::const_iterator itHandler = m_CommandHandlers.begin();
+	while (itHandler != m_CommandHandlers.end())
+	{
+		delete *itHandler;
+		++itHandler;
+	}
+	m_CommandHandlers.clear();
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+bool RlvHandler::notifyCommandHandlers(rlvCommandHandler f, const RlvCommand& rlvCmd, ERlvCmdRet& eRet, bool fNotifyAll) const
+{
+	std::list<RlvCommandHandler*>::const_iterator itHandler = m_CommandHandlers.begin(); bool fContinue = true; eRet = RLV_RET_UNKNOWN;
+	while ( (itHandler != m_CommandHandlers.end()) && ((fContinue) || (fNotifyAll)) )
+	{
+		ERlvCmdRet eCmdRet = RLV_RET_UNKNOWN;
+		if ((fContinue = !((*itHandler)->*f)(rlvCmd, eCmdRet)) == false)
+			eRet = eCmdRet;
+		++itHandler;
+	}
+	RLV_ASSERT( (fContinue) || (eRet != RLV_RET_UNKNOWN) );
+	return !fContinue;
+}
+
+// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+ERlvCmdRet RlvHandler::processCommand(const RlvCommand& rlvCmd, bool fFromObj)
+{
+	#ifdef RLV_DEBUG
+		RLV_INFOS << "[" << rlvCmd.getObjectID() << "]: " << rlvCmd.asString() << RLV_ENDL;
+	#endif // RLV_DEBUG
+
+	if (!rlvCmd.isValid())
+	{
+		#ifdef RLV_DEBUG
+			RLV_INFOS << "\t-> invalid syntax" << RLV_ENDL;
+		#endif // RLV_DEBUG
+		return RLV_RET_FAILED_SYNTAX;
+	}
+
+	// Using a stack for executing commands solves a few problems:
+	//   - if we passed RlvObject::m_UUID for idObj somewhere and process a @clear then idObj points to invalid/cleared memory at the end
+	//   - if command X triggers command Y along the way then getCurrentCommand()/getCurrentObject() still return Y even when finished
+	m_CurCommandStack.push(&rlvCmd); m_CurObjectStack.push(rlvCmd.getObjectID());
+	const LLUUID& idCurObj = m_CurObjectStack.top();
+
+	ERlvCmdRet eRet = RLV_RET_UNKNOWN;
+	switch (rlvCmd.getParamType())
+	{
+		case RLV_TYPE_ADD:		// Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+			{
+				if ( (m_Behaviours[rlvCmd.getBehaviourType()]) && 
+					 ( (RLV_BHVR_SETDEBUG == rlvCmd.getBehaviourType()) || (RLV_BHVR_SETENV == rlvCmd.getBehaviourType()) ) )
+				{
+					// Some restrictions can only be held by one single object to avoid deadlocks
+					#ifdef RLV_DEBUG
+						RLV_INFOS << "\t- " << rlvCmd.getBehaviour() << " is already set by another object => discarding" << RLV_ENDL;
+					#endif // RLV_DEBUG
+					eRet = RLV_RET_FAILED_LOCK;
+					break;
+				}
+
+				rlv_object_map_t::iterator itObj = m_Objects.find(idCurObj); bool fAdded = false;
+				if (itObj != m_Objects.end())
+				{
+					RlvObject& rlvObj = itObj->second;
+					fAdded = rlvObj.addCommand(rlvCmd);
+				}
+				else
+				{
+					RlvObject rlvObj(idCurObj);
+					fAdded = rlvObj.addCommand(rlvCmd);
+					m_Objects.insert(std::pair<LLUUID, RlvObject>(idCurObj, rlvObj));
+				}
+
+				#ifdef RLV_DEBUG
+					RLV_INFOS << "\t- " << ( (fAdded) ? "adding behaviour" : "skipping duplicate" ) << RLV_ENDL;
+				#endif // RLV_DEBUG
+
+				if (fAdded) {	// If FALSE then this was a duplicate, there's no need to handle those
+					if (!m_pGCTimer)
+						m_pGCTimer = new RlvGCTimer();
+					eRet = processAddRemCommand(rlvCmd);
+//					notifyBehaviourObservers(rlvCmd, !fFromObj);
+				}
+				else
+				{
+					eRet = RLV_RET_SUCCESS_DUPLICATE;
+				}
+			}
+			break;
+		case RLV_TYPE_REMOVE:		// Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+			{
+				rlv_object_map_t::iterator itObj = m_Objects.find(idCurObj); bool fRemoved = false;
+				if (itObj != m_Objects.end())
+					fRemoved = itObj->second.removeCommand(rlvCmd);
+
+				#ifdef RLV_DEBUG
+					RLV_INFOS << "\t- " << ( (fRemoved)	? "removing behaviour"
+														: "skipping remove (unset behaviour or unknown object)") << RLV_ENDL;
+				#endif // RLV_DEBUG
+
+				if (fRemoved) {	// Don't handle non-sensical removes
+					eRet = processAddRemCommand(rlvCmd);
+//					notifyBehaviourObservers(rlvCmd, !fFromObj);
+
+					if (0 == itObj->second.m_Commands.size())
+					{
+						#ifdef RLV_DEBUG
+							RLV_INFOS << "\t- command list empty => removing " << idCurObj << RLV_ENDL;
+						#endif // RLV_DEBUG
+						m_Objects.erase(itObj);
+					}
+				}
+				else
+				{
+					eRet = RLV_RET_SUCCESS_UNSET;
+				}
+			}
+			break;
+		case RLV_TYPE_CLEAR:		// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+			eRet = processClearCommand(rlvCmd);
+			break;
+		case RLV_TYPE_FORCE:		// Checked: 2009-11-26 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+			eRet = processForceCommand(rlvCmd);
+			break;
+		case RLV_TYPE_REPLY:		// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+			eRet = processReplyCommand(rlvCmd);
+			break;
+		case RLV_TYPE_UNKNOWN:		// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+		default:
+			eRet = RLV_RET_FAILED_PARAM;
+			break;
+	}
+	RLV_ASSERT(RLV_RET_UNKNOWN != eRet);
+
+	m_OnCommand(rlvCmd, eRet, !fFromObj);
+
+	#ifdef RLV_DEBUG
+		RLV_INFOS << "\t--> command " << ((eRet & RLV_RET_SUCCESS) ? "succeeded" : "failed") << RLV_ENDL;
+	#endif // RLV_DEBUG
+
+	m_CurCommandStack.pop(); m_CurObjectStack.pop();
+	return eRet;
+}
+
+// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0f
+void RlvHandler::processRetainedCommands(ERlvBehaviour eBhvrFilter /*=RLV_BHVR_UNKNOWN*/, ERlvParamType eTypeFilter /*=RLV_TYPE_UNKNOWN*/)
+{
+	rlv_command_list_t::iterator itCmd = m_Retained.begin(), itCurCmd;
+	while (itCmd != m_Retained.end())
+	{
+		itCurCmd = itCmd++;  // Point the loop iterator ahead
+
+		const RlvCommand& rlvCmd = *itCurCmd;
+		if ( ((RLV_BHVR_UNKNOWN == eBhvrFilter) || (rlvCmd.getBehaviourType() == eBhvrFilter)) && 
+		     ((RLV_TYPE_UNKNOWN == eTypeFilter) || (rlvCmd.getParamType() == eTypeFilter)) )
+		{
+			processCommand(rlvCmd, true);
+			m_Retained.erase(itCurCmd);
+		}
+	}
+}
+
+ERlvCmdRet RlvHandler::processClearCommand(const RlvCommand& rlvCmd)
+{
+	const std::string& strFilter = rlvCmd.getParam(); std::string strCmdRem;
+
+	rlv_object_map_t::const_iterator itObj = m_Objects.find(rlvCmd.getObjectID());
+	if (itObj != m_Objects.end())	// No sense in clearing if we don't have any commands for this object
+	{
+		const RlvObject& rlvObj = itObj->second; bool fContinue = true;
+		for (rlv_command_list_t::const_iterator itCmd = rlvObj.m_Commands.begin(), itCurCmd; 
+				((fContinue) && (itCmd != rlvObj.m_Commands.end())); )
+		{
+			itCurCmd = itCmd++;		// Point itCmd ahead so it won't get invalidated if/when we erase a command
+
+			const RlvCommand& rlvCmdRem = *itCurCmd; strCmdRem = rlvCmdRem.asString();
+			if ( (strFilter.empty()) || (std::string::npos != strCmdRem.find(strFilter)) )
+			{
+				fContinue = (rlvObj.m_Commands.size() > 1); // rlvObj will become invalid once we remove the last command
+				processCommand(rlvCmd.getObjectID(), strCmdRem.append("=y"), false);
+			}
+		}
+	}
+
+	// Let our observers know about clear commands
+	ERlvCmdRet eRet = RLV_RET_SUCCESS;
+	notifyCommandHandlers(&RlvCommandHandler::onClearCommand, rlvCmd, eRet, true);
+
+	return RLV_RET_SUCCESS; // Don't fail clear commands even if the object didn't exist since it confuses people
+}
+
+// ============================================================================
+// Externally invoked event handlers
+//
+
+// Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvHandler::onSitOrStand(bool fSitting)
+{
+	#ifdef RLV_EXTENSION_STARTLOCATION
+	if (rlv_handler_t::isEnabled())
+	{
+		RlvSettings::updateLoginLastLocation();
+	}
+	#endif // RLV_EXTENSION_STARTLOCATION
+
+	if ( (hasBehaviour(RLV_BHVR_STANDTP)) && (!fSitting) && (!m_posSitSource.isExactlyZero()) )
+	{
+		RlvUtil::forceTp(m_posSitSource);
+		m_posSitSource.setZero();
+	}
+}
+
+// Checked: 2010-03-11 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvHandler::onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt)
+{
+	// Assertion - pAttachObj is never NULL always specifies the root
+	RLV_ASSERT( (pAttachObj) && (pAttachObj == pAttachObj->getRootEdit()) );
+	// Sanity check - we need to be called *after* LLViewerJointAttachment::addObject()
+	RLV_ASSERT( (pAttachPt) && (pAttachPt->isObjectAttached(pAttachObj)) );
+	if ( (!pAttachObj) || (!pAttachPt) || (!pAttachPt->isObjectAttached(pAttachObj)) )
+		return;
+
+	// Check if we already have an RlvObject instance for this object or one of its child prims
+	for (rlv_object_map_t::iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
+	{
+		// Only if we haven't been able to find this object (= attachment that rezzed in) or if it's a rezzed prim attached from in-world
+		if ( (!itObj->second.m_fLookup) || (!itObj->second.m_idxAttachPt) )
+		{
+			const LLViewerObject* pObj = gObjectList.findObject(itObj->first);
+			if ( (pObj) && (pObj->getRootEdit()->getID() == pAttachObj->getID()) )
+			{
+				// Reset any lookup information we might have for this object
+				itObj->second.m_fLookup = true;
+				itObj->second.m_idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachObj);
+				itObj->second.m_idRoot = pAttachObj->getID();
+
+				// We need to check this object for an active "@detach=n" and actually lock it down now that it's been attached somewhere
+				if (itObj->second.hasBehaviour(RLV_BHVR_DETACH, false))
+					gRlvAttachmentLocks.addAttachmentLock(pAttachObj->getID(), itObj->second.m_UUID);
+			}
+		}
+	}
+
+	// Fetch the inventory item if it isn't already (we need it in case of a reattach-on-detach) and rename it if appropriate
+	if ( (STATE_STARTED == LLStartUp::getStartupState()) && (gInventory.isInventoryUsable()) )
+	{
+		RlvRenameOnWearObserver* pFetcher = new RlvRenameOnWearObserver(pAttachObj->getAttachmentItemID());
+		pFetcher->startFetch();
+		if (pFetcher->isFinished())
+			pFetcher->done();
+		else
+			gInventory.addObserver(pFetcher);
+	}
+}
+
+// Checked: 2010-03-11 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvHandler::onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt)
+{
+	// Assertion - pAttachObj is never NULL always specifies the root
+	RLV_ASSERT( (pAttachObj) && (pAttachObj == pAttachObj->getRootEdit()) );
+	// Sanity check - we need to be called *before* LLViewerJointAttachment::removeObject()
+	RLV_ASSERT( (pAttachPt) && (pAttachPt->isObjectAttached(pAttachObj)) );
+	if ( (!pAttachObj) || (!pAttachPt) || (!pAttachPt->isObjectAttached(pAttachObj)) )
+		return;
+
+	// If the attachment is no longer attached then then the user "Drop"'ed this attachment somehow
+	if (!pAttachObj->isAttachment())
+	{
+		// Check if we have any RlvObject instances for this object (or any of its child prims)
+		for (rlv_object_map_t::iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
+		{
+			if ( (itObj->second.m_fLookup) && (itObj->second.m_idRoot == pAttachObj->getID()) )
+			{
+				// Clear the attachment point lookup since it's now an in-world prim
+				itObj->second.m_idxAttachPt = false;
+
+				// If this object has an active "@detach=n" then we need to release the attachment lock since it's no longer attached
+				if (itObj->second.hasBehaviour(RLV_BHVR_DETACH, false))
+					gRlvAttachmentLocks.removeAttachmentLock(pAttachObj->getID(), itObj->second.m_UUID);
+			}
+		}
+	}
+	else
+	{
+		// If it's still attached then we need to clean up any restrictions this object (or one of its child prims) may still have set
+		rlv_object_map_t::iterator itObj = m_Objects.begin(), itCurObj;
+		while (itObj != m_Objects.end())
+		{
+			itCurObj = itObj++;	// @clear will invalidate our iterator so point it ahead now
+#ifdef RLV_DEBUG
+			bool itObj = true;
+			RLV_ASSERT(itObj);	// Little hack to push itObj out of scope and prevent it from being accidentally used below
+#endif // RLV_DEBUG
+
+			// NOTE: ObjectKill seems to happen in reverse (child prims are killed before the root is) so we can't use gObjectList here
+			if (itCurObj->second.m_idRoot == pAttachObj->getID())
+			{
+				RLV_INFOS << "Clearing " << itCurObj->first.asString() << ":" << RLV_ENDL;
+				processCommand(itCurObj->second.m_UUID, "clear", true);
+				RLV_INFOS << "\t-> done" << RLV_ENDL;
+			}
+		}
+	}
+}
+
+// Checked: 2010-03-13 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+bool RlvHandler::onGC()
+{
+	rlv_object_map_t::iterator itObj = m_Objects.begin(), itCurObj;
+	while (itObj != m_Objects.end())
+	{
+		itCurObj = itObj++;	// @clear will invalidate our iterator so point it ahead now
+#ifdef RLV_DEBUG
+		bool itObj = true;
+		RLV_ASSERT(itObj);
+#endif // RLV_DEBUG
+
+		const LLViewerObject* pObj = gObjectList.findObject(itCurObj->second.m_UUID);
+		if (!pObj)
+		{
+			// If the RlvObject once existed in gObjectList and now doesn't then expire it right away
+			// If the RlvObject never existed in gObjectList and still doesn't then increase its "lookup misses" counter
+			// but if that reaches 20 (we run every 30 seconds so that's about 10 minutes) then we'll expire it too
+			if ( (itCurObj->second.m_fLookup) || (++itCurObj->second.m_nLookupMisses > 20) )
+			{
+				RLV_INFOS << "Garbage collecting " << itCurObj->first.asString() << ":" << RLV_ENDL;
+				processCommand(itCurObj->first, "clear", true);
+				RLV_INFOS << "\t-> done" << RLV_ENDL;
+			}
+		}
+		else
+		{
+			// Assertion: if the GC encounters an RlvObject instance that hasn't existed in gObjectList up until now then
+			//            it has to be a rezzed prim (if it was an attachment then RlvHandler::onAttach() should have caught it)
+			RLV_ASSERT( (itCurObj->second.m_fLookup) || (!pObj->isAttachment()) );
+			if (!itCurObj->second.m_fLookup)
+			{
+				RLV_INFOS << "Resolved missing object " << itCurObj->first.asString() << RLV_ENDL;
+				itCurObj->second.m_fLookup = true;
+				itCurObj->second.m_idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pObj);
+				itCurObj->second.m_idRoot = pObj->getRootEdit()->getID();
+
+				// NOTE: the following code should NEVER run (see assertion above), but just to be double-triple safety sure
+				//	-> if it does run it likely means that there's a @detach=n in a *child* prim that we couldn't look up in onAttach()
+				//  -> since RLV doesn't currently support @detach=n from child prims it's actually not such a big deal right now but still
+				if ( (pObj->isAttachment()) && (itCurObj->second.hasBehaviour(RLV_BHVR_DETACH, false)) )
+					gRlvAttachmentLocks.addAttachmentLock(pObj->getID(), itCurObj->second.m_UUID);
+			}
+		}
+	}
+
+	RLV_ASSERT(gRlvAttachmentLocks.verifyAttachmentLocks()); // Verify that we haven't leaked any attachment locks somehow
+
+	return (0 != m_Objects.size());	// GC will kill itself if it has nothing to do
+}
+
+// Checked: 2009-11-26 (RLVa-1.1.0f) | Added: RLVa-1.1.0f
+void RlvHandler::onIdleStartup(void* pParam)
+{
+	LLTimer* pTimer = (LLTimer*)pParam;
+	if (LLStartUp::getStartupState() < STATE_STARTED)
+	{
+		// We don't want to run this *too* often
+		if ( (LLStartUp::getStartupState() >= STATE_MISC) && (pTimer->getElapsedTimeF32() >= 2.0) )
+		{
+			gRlvHandler.processRetainedCommands(RLV_BHVR_VERSION, RLV_TYPE_REPLY);
+			gRlvHandler.processRetainedCommands(RLV_BHVR_VERSIONNEW, RLV_TYPE_REPLY);
+			gRlvHandler.processRetainedCommands(RLV_BHVR_VERSIONNUM, RLV_TYPE_REPLY);
+			pTimer->reset();
+		}
+	}
+	else
+	{
+		// Clean-up
+		gIdleCallbacks.deleteFunction(onIdleStartup, pParam);
+		delete pTimer;
+	}
+}
+
+// Checked: 2010-03-09 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvHandler::onLoginComplete()
+{
+	RlvAttachPtLookup::initLookupTable();
+
+	RlvInventory::instance().fetchWornItems();
+	RlvInventory::instance().fetchSharedInventory();
+
+	#ifdef RLV_EXTENSION_STARTLOCATION
+	RlvSettings::updateLoginLastLocation();
+	#endif // RLV_EXTENSION_STARTLOCATION
+
+	LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&RlvHandler::onTeleportFailed, this));
+	LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback(boost::bind(&RlvHandler::onTeleportFinished, this, _1));
+
+	processRetainedCommands();
+}
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+void RlvHandler::onTeleportFailed()
+{
+	setCanCancelTp(true);
+}
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d
+void RlvHandler::onTeleportFinished(const LLVector3d& posArrival)
+{
+	setCanCancelTp(true);
+}
+
+// ============================================================================
+// String/chat censoring functions
+//
+
+size_t utf8str_strlen(const std::string& utf8)
+{
+	const char* pUTF8 = utf8.c_str(); size_t length = 0;
+	for (int idx = 0, cnt = utf8.length(); idx < cnt ;idx++)
+	{
+		// We're looking for characters that don't start with 10 as their high bits
+		if ((pUTF8[idx] & 0xC0) != 0x80)
+			length++;
+	}
+	return length;
+}
+
+std::string utf8str_chtruncate(const std::string& utf8, size_t length)
+{
+	if (0 == length)
+		return std::string();
+	if (utf8.length() <= length)
+		return utf8;
+
+	const char* pUTF8 = utf8.c_str(); int idx = 0;
+	while ( (pUTF8[idx]) && (length > 0) )
+	{
+		// We're looking for characters that don't start with 10 as their high bits
+		if ((pUTF8[idx] & 0xC0) != 0x80)
+			length--;
+		idx++;
+	}
+
+	return utf8.substr(0, idx);
+}
+
+// Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0f
+void RlvHandler::filterChat(std::string& strUTF8Text, bool fFilterEmote) const
+{
+	if (strUTF8Text.empty())
+		return;
+
+	if (RlvUtil::isEmote(strUTF8Text))				// Check if it's an emote
+	{
+		if (fFilterEmote)							// Emote filtering depends on fFilterEmote
+		{
+			if ( (strUTF8Text.find_first_of("\"()*=^_?~") != std::string::npos) || 
+				 (strUTF8Text.find(" -") != std::string::npos) || (strUTF8Text.find("- ") != std::string::npos) || 
+				 (strUTF8Text.find("''") != std::string::npos) )
+			{
+				strUTF8Text = "...";				// Emote contains illegal character (or character sequence)
+			}
+			else if (!hasBehaviour(RLV_BHVR_EMOTE))
+			{
+				int idx = strUTF8Text.find('.');	// Truncate at 20 characters or at the dot (whichever is shorter)
+				strUTF8Text = utf8str_chtruncate(strUTF8Text, ( (idx > 0) && (idx < 20) ) ? idx + 1 : 20);
+			}
+		}
+	} 
+	else if (strUTF8Text[0] == '/')					// Not an emote, but starts with a '/'
+	{
+		if (utf8str_strlen(strUTF8Text) > 7)		// Allow as long if it's 6 characters or less
+			strUTF8Text = "...";
+	}
+	else if ((strUTF8Text.length() < 4) || (strUTF8Text.compare(0, 2, "((")) || (strUTF8Text.compare(strUTF8Text.length() - 2, 2, "))")))
+	{
+		strUTF8Text = "...";						// Regular chat (not OOC)
+	}
+}
+
+// Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0a
+bool RlvHandler::redirectChatOrEmote(const std::string& strUTF8Text) const
+{
+	// Sanity check - @redirchat only for chat and @rediremote only for emotes
+	ERlvBehaviour eBhvr = (!RlvUtil::isEmote(strUTF8Text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE;
+	if (!hasBehaviour(eBhvr))
+		return false;
+
+	if (RLV_BHVR_REDIRCHAT == eBhvr)
+	{
+		std::string strText = strUTF8Text;
+		filterChat(strText, false);
+		if (strText != "...")
+			return false;	// @sendchat wouldn't filter it so @redirchat won't redirect it either
+	}
+
+	for (rlv_exception_map_t::const_iterator itRedir = m_Exceptions.lower_bound(eBhvr), 
+			endRedir = m_Exceptions.upper_bound(eBhvr); itRedir != endRedir; ++itRedir)
+	{
+		S32 nChannel = boost::get<S32>(itRedir->second.varOption);
+		if ( (!hasBehaviour(RLV_BHVR_SENDCHANNEL)) || (isException(RLV_BHVR_SENDCHANNEL, nChannel)) )
+			RlvUtil::sendChatReply(nChannel, strUTF8Text);
+	}
+
+	return true;
+}
+
+// ============================================================================
+// Composite folders
+//
+
+#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	// Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i
+	bool RlvHandler::getCompositeInfo(const LLInventoryCategory* pFolder, std::string* pstrName) const
+	{
+		if (pFolder)
+		{
+			// Composite folder naming: ^\.?[Folder]
+			const std::string& cstrFolder = pFolder->getName();
+			std::string::size_type idxStart = cstrFolder.find('['), idxEnd = cstrFolder.find(']', idxStart);
+			if ( ((0 == idxStart) || (1 == idxStart)) && (idxEnd - idxStart > 1) )
+			{
+				if (pstrName)
+					pstrName->assign(cstrFolder.substr(idxStart + 1, idxEnd - idxStart - 1));
+				return true;
+			}
+		}
+		return false;
+	}
+
+	// Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i
+	bool RlvHandler::getCompositeInfo(const LLUUID& idItem, std::string* pstrName, LLViewerInventoryCategory** ppFolder) const
+	{
+/*
+		LLViewerInventoryCategory* pRlvRoot; LLViewerInventoryItem* pItem;
+		if ( (idItem.notNull()) && ((pRlvRoot = getSharedRoot()) != NULL) && 
+			 (gInventory.isObjectDescendentOf(idItem, pRlvRoot->getUUID())) && ((pItem = gInventory.getItem(idItem)) != NULL) )
+		{
+			// We know it's an item in a folder under the shared root (we need its parent if it's a folded folder)
+			LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID());
+			if (isFoldedFolder(pFolder, true, false))	// Don't check if the folder is a composite folder
+				pFolder = gInventory.getCategory(pFolder->getParentUUID());
+
+			if ( (pFolder) && (getCompositeInfo(pFolder, pstrName)) )
+			{
+				if (ppFolder)
+					*ppFolder = pFolder;
+				return true;
+			}
+		}
+*/
+		return false;
+	}
+#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+#ifdef RLV_EXPERIMENTAL_COMPOSITE_FOLDING
+	// Checked:
+	inline bool RlvHandler::isHiddenCompositeItem(const LLUUID& idItem, const std::string& cstrItemType) const
+	{
+		// An item that's part of a composite folder will be hidden from @getoutfit and @getattach if:
+		//   (1) the composite name specifies either a wearable layer or an attachment point
+		//   (2) the specified wearable layer or attachment point is worn and resides in the folder
+		//   (3) cstrItemType isn't the specified wearable layer or attach point
+		//
+		// Example: #RLV/Separates/Shoes/ChiChi Pumps/.[shoes] with items: "Shoe Base", "Shoe (left foot)" and "Shoe (right foot)"
+		//   -> as long as "Shoe Base" is worn, @getattach should not reflect "left foot", nor "right foot"
+		std::string strComposite; LLViewerInventoryCategory* pFolder;
+		LLWearableType::EType type; S32 idxAttachPt;
+		if ( (getCompositeInfo(idItem, &strComposite, &pFolder)) && (cstrItemType != strComposite) )
+		{
+			LLUUID idCompositeItem;
+			if ((type = LLWearable::typeNameToType(strComposite)) != WT_INVALID)
+			{
+				idCompositeItem = gAgent.getWearableItem(type);
+			}
+			else if ((idxAttachPt = getAttachPointIndex(strComposite, true)) != 0)
+			{
+				LLVOAvatar* pAvatar; LLViewerJointAttachment* pAttachmentPt;
+				if ( ((pAvatar = gAgent.getAvatarObject()) != NULL) && 
+					 ((pAttachmentPt = get_if_there(pAvatar->mAttachmentPoints, idxAttachPt, (LLViewerJointAttachment*)NULL)) != NULL) )
+				{
+					idCompositeItem = pAttachmentPt->getItemID();
+				}
+			}
+
+			if ( (idCompositeItem.notNull()) && (gInventory.isObjectDescendentOf(idCompositeItem, pFolder->getUUID())) )
+				return true;
+		}
+		return false;
+	}
+#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDING
+
+#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	// Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i
+	bool RlvHandler::canTakeOffComposite(const LLInventoryCategory* pFolder) const
+	{
+		// Sanity check - if there's no folder or no avatar then there is nothing to take off
+		LLVOAvatarSelf* pAvatar = gAgent.getAvatarObject();
+		if ( (!pFolder) || (!pAvatar) )
+			return false;
+		// Sanity check - if nothing is locked then we can definitely take it off
+		if ( (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) || 
+			 (!gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_REMOVE)) )
+		{
+			return true;
+		}
+
+/*
+		LLInventoryModel::cat_array_t folders;
+		LLInventoryModel::item_array_t items;
+		RlvWearableItemCollector functor(pFolder->getUUID(), true, false);
+		gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, functor);
+
+		for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++)
+		{
+			const LLViewerInventoryItem* pItem = items.get(idxItem);
+			switch (pItem->getType())
+			{
+				case LLAssetType::AT_BODYPART:
+				case LLAssetType::AT_CLOTHING:
+					{
+						LLWearable* pWearable = gAgent.getWearableFromWearableItem(pItem->getUUID());
+						if ( (pWearable) && (!isRemovable(pWearable->getType())) )
+							return false;	// If one wearable in the folder is non-removeable then the entire folder should be
+					}
+					break;
+				case LLAssetType::AT_OBJECT:
+					{
+						LLViewerObject* pObj = pAvatar->getWornAttachment(pItem->getUUID());
+						if ( (pObj != NULL) && (isLockedAttachment(pObj, RLV_LOCK_REMOVE)) )
+							return false;	// If one attachment in the folder is non-detachable then the entire folder should be
+					}
+					break;
+				default:
+					break;
+			}
+		}
+*/
+		return true;
+	}
+
+	// Checked: 2009-12-18 (RLVa-1.1.0k) | Modified: RLVa-1.1.0i
+	bool RlvHandler::canWearComposite(const LLInventoryCategory* pFolder) const
+	{
+		// Sanity check - if there's no folder or no avatar then there is nothing to wear
+		LLVOAvatar* pAvatar = gAgent.getAvatarObject();
+		if ( (!pFolder) || (!pAvatar) )
+			return false;
+		// Sanity check - if nothing is locked then we can definitely wear it
+		if ( (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) || (!gRlvWearableLocks.hacLockedWearableType(RLV_LOCK_ANY)) )
+			return true;
+
+/*
+		LLInventoryModel::cat_array_t folders;
+		LLInventoryModel::item_array_t items;
+		RlvWearableItemCollector functor(pFolder->getUUID(), true, false);
+		gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, functor);
+
+		for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++)
+		{
+			LLViewerInventoryItem* pItem = items.get(idxItem);
+
+			if (RlvForceWear::isWearingItem(pItem))
+				continue; // Don't examine any items we're already wearing
+
+			// A wearable layer or attachment point:
+			//   - can't be "add locked"
+			//   - can't be worn and "remove locked"
+			//   - can't be worn and have its item belong to a *different* composite folder that we can't take off
+			switch (pItem->getType())
+			{
+				case LLAssetType::AT_BODYPART:
+				case LLAssetType::AT_CLOTHING:
+					{
+						// NOTE: without its asset we don't know what type the wearable is so we need to look at the item's flags instead
+						LLWearableType::EType wtType = (LLWearableType::EType)(pItem->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK);
+						LLViewerInventoryCategory* pFolder;
+						if ( (!isWearable(wtType)) ||
+							 ( (gAgent.getWearable(wtType)) && (!isRemovable(wtType)) ) || 
+							 ( (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(wtType), NULL, &pFolder)) &&
+							   (pFolder->getUUID() != pItem->getParentUUID()) && (!gRlvHandler.canTakeOffComposite(pFolder)) ) )
+						{
+							return false;
+						}
+					}
+					break;
+				case LLAssetType::AT_OBJECT:
+					{
+						// If we made it here then *something* is add/remove locked so we absolutely need to know its attachment point
+						LLViewerJointAttachment* pAttachPt = getAttachPoint(pItem, true); 
+						LLViewerInventoryCategory* pFolder;
+						if ( (!pAttachPt) || (isLockedAttachment(pAttachPt, RLV_LOCK_ADD)) ||
+							 ( (pAttachPt->getObject()) && (isLockedAttachment(pAttachPt, RLV_LOCK_REMOVE)) ) ||
+							 ( (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) &&
+							   (pFolder->getUUID() != pItem->getParentUUID()) && (!gRlvHandler.canTakeOffComposite(pFolder)) ) )
+						{
+							return false;
+						}
+					}
+					break;
+				default:
+					break;
+			}
+		}
+*/
+		return true;
+	}
+#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+// ============================================================================
+// Initialization helper functions
+//
+
+// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+BOOL RlvHandler::setEnabled(BOOL fEnable)
+{
+	// TODO-RLVa: [RLVa-1.2.1] Allow toggling at runtime if we haven't seen any llOwnerSay("@....");
+	if (m_fEnabled == fEnable)
+		return fEnable;
+
+	if (fEnable)
+	{
+		RLV_INFOS << "Enabling Restrained Love API support - " << RlvStrings::getVersion() << RLV_ENDL;
+		m_fEnabled = TRUE;
+
+		// Initialize the command lookup table
+		RlvCommand::initLookupTable();
+
+		// Initialize static classes
+		RlvSettings::initClass();
+		RlvStrings::initClass();
+
+		gRlvHandler.addCommandHandler(new RlvExtGetSet());
+
+		// Make sure we get notified when login is successful
+		if (LLStartUp::getStartupState() < STATE_STARTED)
+			LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&RlvHandler::onLoginComplete, &gRlvHandler));
+		else
+			gRlvHandler.onLoginComplete();
+
+		// Set up RlvUIEnabler
+		RlvUIEnabler::getInstance();
+	}
+
+	return m_fEnabled;
+}
+
+BOOL RlvHandler::canDisable()
+{
+	return FALSE;
+}
+
+void RlvHandler::clearState()
+{
+/*
+	// TODO-RLVa: should restore all RLV controlled debug variables to their defaults
+
+	// Issue @clear on behalf of every object that has a currently active RLV restriction (even if it's just an exception)
+	LLUUID idObj; LLViewerObject* pObj; bool fDetachable;
+	while (m_Objects.size())
+	{
+		idObj = m_Objects.begin()->first; // Need a copy since after @clear the data it points to will no longer exist
+		fDetachable = ((pObj = gObjectList.findObject(idObj)) != NULL) ? isLockedAttachment(pObj, RLV_LOCK_REMOVE) : true;
+
+		processCommand(idObj, "clear", false);
+		if (!fDetachable)
+			processCommand(idObj, "detachme=force", false);
+	}
+
+	// Sanity check - these should all be empty after we issue @clear on the last object
+	if ( (!m_Objects.empty()) || !(m_Exceptions.empty()) || (!m_AttachAdd.empty()) || (!m_AttachRem.empty()) )
+	{
+		RLV_ERRS << "Object, exception or attachment map not empty after clearing state!" << LL_ENDL;
+		m_Objects.clear();
+		m_Exceptions.clear();
+		m_AttachAdd.clear();
+		m_AttachRem.clear();
+	}
+
+	// These all need manual clearing
+	memset(m_LayersAdd, 0, sizeof(S16) * WT_COUNT);
+	memset(m_LayersRem, 0, sizeof(S16) * WT_COUNT);
+	memset(m_Behaviours, 0, sizeof(S16) * RLV_BHVR_COUNT);
+	m_Retained.clear();
+	clearCommandHandlers(); // <- calls delete on all registered command handlers
+
+	// Clear dynamically allocated memory
+	delete m_pGCTimer;
+	m_pGCTimer = NULL;
+	delete m_pWLSnapshot;
+	m_pWLSnapshot = NULL;
+*/
+}
+
+// ============================================================================
+// Command handlers (RLV_TYPE_ADD and RLV_TYPE_REMOVE)
+//
+
+#define VERIFY_OPTION(x)		{ if (!(x)) { eRet = RLV_RET_FAILED_OPTION; break; } }
+#define VERIFY_OPTION_REF(x)	{ if (!(x)) { eRet = RLV_RET_FAILED_OPTION; break; } fRefCount = true; }
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+ERlvCmdRet RlvHandler::processAddRemCommand(const RlvCommand& rlvCmd)
+{
+	// NOTE: - at this point the command has already been:
+	//            * added to the RlvObject
+	//            * removed from the RlvObject (which still exists at this point even if this is the last restriction)
+	//       - the object's UUID may or may not exist in gObjectList (see handling of @detach=n|y)
+	ERlvBehaviour eBhvr = rlvCmd.getBehaviourType(); ERlvParamType eType = rlvCmd.getParamType();
+	
+	ERlvCmdRet eRet = RLV_RET_SUCCESS; bool fRefCount = false; const std::string& strOption = rlvCmd.getOption();
+	switch (eBhvr)
+	{
+		case RLV_BHVR_DETACH:				// @detach[:<option>]=n|y
+			eRet = onAddRemDetach(rlvCmd, fRefCount);
+			break;
+		case RLV_BHVR_ADDATTACH:			// @addattach[:<option>]=n|y
+		case RLV_BHVR_REMATTACH:			// @addattach[:<option>]=n|y
+			eRet = onAddRemAttach(rlvCmd, fRefCount);
+			break;
+		case RLV_BHVR_SETENV:				// @setenv=n|y
+			eRet = onAddRemSetEnv(rlvCmd, fRefCount);
+			break;
+		case RLV_BHVR_ADDOUTFIT:			// @addoutfit[:<layer>]=n|y			- Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+		case RLV_BHVR_REMOUTFIT:			// @remoutfit[:<layer>]=n|y			- Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+			{
+				// If there's an option it should specify a wearable type name (reference count on no option *and* a valid option)
+				RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption());
+				VERIFY_OPTION_REF( (rlvCmdOption.isEmpty()) || (rlvCmdOption.isWearableType()) );
+
+				ERlvLockMask eLock = (RLV_BHVR_ADDOUTFIT == eBhvr) ? RLV_LOCK_ADD : RLV_LOCK_REMOVE;
+				for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++)
+				{
+					if ( (rlvCmdOption.isEmpty()) || ((LLWearableType::EType)idxType == rlvCmdOption.getWearableType()) )
+					{
+						if (RLV_TYPE_ADD == eType)
+							gRlvWearableLocks.addWearableTypeLock((LLWearableType::EType)idxType, rlvCmd.getObjectID(), eLock);
+						else
+							gRlvWearableLocks.removeWearableTypeLock((LLWearableType::EType)idxType, rlvCmd.getObjectID(), eLock);
+					}
+				}
+			}
+			break;
+		case RLV_BHVR_REDIRCHAT:			// @redirchat:<channel>=n|y			- Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_REDIREMOTE:			// @rediremote:<channel>=n|y		- Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h
+			{
+				// There should be an option which should specify a valid reply channel (if there's an empty option the command is invalid)
+				S32 nChannel = 0;
+				VERIFY_OPTION_REF( (LLStringUtil::convertToS32(strOption, nChannel)) && (RlvUtil::isValidReplyChannel(nChannel)) );
+
+				if (RLV_TYPE_ADD == eType) 
+					addException(rlvCmd.getObjectID(), eBhvr, nChannel);
+				else
+					removeException(rlvCmd.getObjectID(), eBhvr, nChannel);
+			}
+			break;
+		case RLV_BHVR_SENDCHANNEL:			// @sendchannel[:<channel>]=n|y		- Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h
+			{
+				// If there's an option then it should be a valid (= positive and non-zero) chat channel
+				S32 nChannel = 0;
+				if ( (LLStringUtil::convertToS32(strOption, nChannel)) && (nChannel > 0) )
+				{
+					if (RLV_TYPE_ADD == eType) 
+						addException(rlvCmd.getObjectID(), eBhvr, nChannel);
+					else
+						removeException(rlvCmd.getObjectID(), eBhvr, nChannel);
+					break;
+				}
+				VERIFY_OPTION_REF(strOption.empty());
+			}
+			break;
+		case RLV_BHVR_NOTIFY:				// @notify:<params>=add|rem			- Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+			{
+				// There should be an option that we can successfully parse (if there's an empty option the command is invalid)
+				S32 nChannel; std::string strFilter;
+				VERIFY_OPTION_REF( (!strOption.empty()) && (rlvParseNotifyOption(strOption, nChannel, strFilter)) );
+
+				if (RLV_TYPE_ADD == eType)
+					RlvBehaviourNotifyHandler::getInstance()->addNotify(rlvCmd.getObjectID(), nChannel, strFilter);
+				else
+					RlvBehaviourNotifyHandler::getInstance()->removeNotify(rlvCmd.getObjectID(), nChannel, strFilter);
+			}
+			break;
+		case RLV_BHVR_SHOWHOVERTEXT:		// @showhovertext:<uuid>=n|y		- Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.1.0h
+			{
+				// There should be an option and it should specify a valid UUID
+				LLUUID idException(strOption);
+				VERIFY_OPTION_REF(idException.notNull());
+
+				if (RLV_TYPE_ADD == eType)
+					addException(rlvCmd.getObjectID(), eBhvr, idException);
+				else
+					removeException(rlvCmd.getObjectID(), eBhvr, idException);
+
+				// Clear/restore the object's hover text as needed
+				LLViewerObject* pObj = gObjectList.findObject(idException);
+				if ( (pObj) && (pObj->mText.notNull()) && (!pObj->mText->getObjectText().empty()) )
+					pObj->mText->setStringUTF8( (RLV_TYPE_ADD == eType) ? "" : pObj->mText->getObjectText());
+			}
+			break;
+#ifdef RLV_EXTENSION_CMD_TOUCHXXX
+		case RLV_BHVR_TOUCH:				// @touch:<uuid>=n					- Checked: 2010-01-01 (RLVa-1.1.0l) | Added: RLVa-1.1.0l
+			{
+				// There should be an option and it should specify a valid UUID
+				LLUUID idException(strOption);
+				VERIFY_OPTION_REF(idException.notNull());
+
+				if (RLV_TYPE_ADD == eType)
+					addException(rlvCmd.getObjectID(), eBhvr, idException);
+				else
+					removeException(rlvCmd.getObjectID(), eBhvr, idException);
+			}
+			break;
+#endif // RLV_EXTENSION_CMD_TOUCHXXX
+		// The following block is only valid if there's no option
+		case RLV_BHVR_SHOWLOC:				// @showloc=n|y						- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_SHOWNAMES:			// @shownames=n|y					- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_EMOTE:				// @emote=n|y						- Checked: 2010-03-26 (RLVa-1.2.0b)
+		case RLV_BHVR_SENDCHAT:				// @sendchat=n|y					- Checked: 2010-03-26 (RLVa-1.2.0b)
+		case RLV_BHVR_CHATWHISPER:			// @chatwhisper=n|y					- Checked: 2010-03-26 (RLVa-1.2.0b)
+		case RLV_BHVR_CHATNORMAL:			// @chatnormal=n|y					- Checked: 2010-03-26 (RLVa-1.2.0b)
+		case RLV_BHVR_CHATSHOUT:			// @chatshout=n|y					- Checked: 2010-03-26 (RLVa-1.2.0b)
+		case RLV_BHVR_PERMISSIVE:			// @permissive=n|y					- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_SHOWINV:				// @showinv=n|y						- Checked: 2010-03-01 (RLVa-1.2.0a)
+		case RLV_BHVR_SHOWMINIMAP:			// @showminimap=n|y					- Checked: 2010-02-28 (RLVa-1.2.0a)
+		case RLV_BHVR_SHOWWORLDMAP:			// @showworldmap=n|y				- Checked: 2010-02-28 (RLVa-1.2.0a)
+		case RLV_BHVR_SHOWHOVERTEXTHUD:		// @showhovertexthud=n|y			- Checked: 2010-03-27 (RLVa-1.2.0b)
+		case RLV_BHVR_SHOWHOVERTEXTWORLD:	// @showhovertextworld=n|y			- Checked: 2010-03-27 (RLVa-1.2.0b)
+		case RLV_BHVR_SHOWHOVERTEXTALL:		// @showhovertextall=n|y			- Checked: 2010-03-27 (RLVa-1.2.0b)
+		case RLV_BHVR_STANDTP:				// @standtp=n|y						- Checked: 2010-08-29 (RLVa-1.2.1c)
+		case RLV_BHVR_TPLM:					// @tplm=n|y						- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_TPLOC:				// @tploc=n|y						- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_VIEWNOTE:				// @viewnote=n|y					- Checked: 2010-03-27 (RLVa-1.2.0b)
+		case RLV_BHVR_VIEWSCRIPT:			// @viewscript=n|y					- Checked: 2010-03-27 (RLVa-1.2.0b)
+		case RLV_BHVR_VIEWTEXTURE:			// @viewtexture=n|y					- Checked: 2010-03-27 (RLVa-1.2.0b)
+		case RLV_BHVR_ACCEPTPERMISSION:		// @acceptpermission=n|y			- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+#ifdef RLV_EXTENSION_CMD_ALLOWIDLE
+		case RLV_BHVR_ALLOWIDLE:			// @allowidle=n|y					- Checked: 2010-05-03 (RLVa-1.2.0g) | Modified: RLVa-1.1.0h
+#endif // RLV_EXTENSION_CMD_ALLOWIDLE
+		case RLV_BHVR_EDIT:					// @edit=n|y						- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_REZ:					// @rez=n|y							- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_FARTOUCH:				// @fartouch=n|y					- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+#ifdef RLV_EXTENSION_CMD_INTERACT
+		case RLV_BHVR_INTERACT:				// @interact=n|y					- Checked: 2010-01-01 (RLVa-1.1.0l) | Added: RLVa-1.1.0l
+#endif // RLV_EXTENSION_CMD_INTERACT
+		case RLV_BHVR_FLY:					// @fly=n|y							- Checked: 2010-03-02 (RLVa-1.2.0a)
+		case RLV_BHVR_UNSIT:				// @unsit=n|y						- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_SIT:					// @sit=n|y							- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_SITTP:				// @sittp=n|y						- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_SETDEBUG:				// @setdebug=n|y					- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+			VERIFY_OPTION_REF(strOption.empty());
+			break;
+		// The following block is only valid if there's no option (= restriction) or if it specifies a valid UUID (= behaviour exception)
+		case RLV_BHVR_RECVCHAT:				// @recvchat[:<uuid>]=n|y			- Checked: 2010-03-26 (RLVa-1.2.0b)
+		case RLV_BHVR_RECVEMOTE:			// @recvemote[:<uuid>]=n|y			- Checked: 2010-03-26 (RLVa-1.2.0b)
+		case RLV_BHVR_SENDIM:				// @sendim[:<uuid>]=n|y				- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_RECVIM:				// @recvim[:<uuid>]=n|y				- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_TPLURE:				// @tplure[:<uuid>]=n|y				- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+		case RLV_BHVR_ACCEPTTP:				// @accepttp[:<uuid>]=n|y			- Checked: 2009-12-05 (RLVa-1.1.0h) | Modified: RLVa-1.1.0h
+#ifdef RLV_EXTENSION_CMD_TOUCHXXX
+		case RLV_BHVR_TOUCHWORLD:			// @touchworld[:<uuid>=n|y			- Checked: 2010-01-01 (RLVa-1.1.0l) | Added: RLVa-1.1.0l
+		case RLV_BHVR_TOUCHATTACH:			// @touchattach[:<uuid>=n|y			- Checked: 2010-01-01 (RLVa-1.1.0l) | Added: RLVa-1.1.0l
+		case RLV_BHVR_TOUCHHUD:				// @touchhud[:<uuid>=n|y			- Checked: 2010-01-01 (RLVa-1.1.0l) | Added: RLVa-1.1.0l
+#endif // RLV_EXTENSION_CMD_TOUCHXXX
+			{
+				LLUUID idException(strOption);
+				if (idException.notNull())		// If there's an option then it should specify a valid UUID
+				{
+					if (RLV_TYPE_ADD == eType)
+						addException(rlvCmd.getObjectID(), eBhvr, idException);
+					else
+						removeException(rlvCmd.getObjectID(), eBhvr, idException);
+					break;
+				}
+				VERIFY_OPTION_REF(strOption.empty());
+			}
+			break;
+		case RLV_BHVR_UNKNOWN:
+			// Pass unknown commands on to registered command handlers
+			return (notifyCommandHandlers(&RlvCommandHandler::onAddRemCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN;
+		default:
+			// Fail with "Invalid param" if none of the above handled it
+			eRet = RLV_RET_FAILED_PARAM;
+			break;
+	}
+
+	// If this command represents a behaviour restriction that's been added/removed then we need to do some additional processing
+	if ( (RLV_RET_SUCCESS == eRet) && (fRefCount) )
+	{
+		if (RLV_TYPE_ADD == eType)
+		{
+			if (rlvCmd.isStrict())
+				addException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr);
+			m_Behaviours[eBhvr]++;
+		}
+		else
+		{
+			if (rlvCmd.isStrict())
+				removeException(rlvCmd.getObjectID(), RLV_BHVR_PERMISSIVE, eBhvr);
+			m_Behaviours[eBhvr]--;
+		}
+
+		m_OnBehaviour(eBhvr, eType);
+
+		// Show an - optional - notification on every global behaviour change
+		#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR
+/*
+		if ( ((RLV_TYPE_ADD == eType) && (1 == m_Behaviours[eBhvr])) || (0 == m_Behaviours[eBhvr]) )
+		{
+			RlvNotifications::notifyBehaviour(eBhvr, eType);
+		}
+*/
+		#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR
+	}
+
+	return eRet;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+ERlvCmdRet RlvHandler::onAddRemAttach(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	RLV_ASSERT( (RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType()) );
+	RLV_ASSERT( (RLV_BHVR_ADDATTACH == rlvCmd.getBehaviourType()) || (RLV_BHVR_REMATTACH == rlvCmd.getBehaviourType()) );
+
+	// Sanity check - if there's an option it should specify a valid attachment point name
+	S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption());
+	if ( (!idxAttachPt) && (!rlvCmd.getOption().empty())  )
+		return RLV_RET_FAILED_OPTION;
+
+	if (!isAgentAvatarValid())
+		return RLV_RET_FAILED;
+
+	ERlvLockMask eLock = (RLV_BHVR_REMATTACH == rlvCmd.getBehaviourType()) ? RLV_LOCK_REMOVE : RLV_LOCK_ADD;
+	for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); 
+			itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach)
+	{
+		if ( (0 == idxAttachPt) || (itAttach->first == idxAttachPt) )
+		{
+			if (RLV_TYPE_ADD == rlvCmd.getParamType())
+				gRlvAttachmentLocks.addAttachmentPointLock(itAttach->first, rlvCmd.getObjectID(), eLock);
+			else
+				gRlvAttachmentLocks.removeAttachmentPointLock(itAttach->first, rlvCmd.getObjectID(), eLock);
+		}
+	}
+
+	fRefCount = rlvCmd.getOption().empty();	// Only reference count global locks
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+ERlvCmdRet RlvHandler::onAddRemDetach(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	RLV_ASSERT( (RLV_TYPE_ADD == rlvCmd.getParamType()) || (RLV_TYPE_REMOVE == rlvCmd.getParamType()) );
+	RLV_ASSERT(RLV_BHVR_DETACH == rlvCmd.getBehaviourType());
+
+	if (rlvCmd.getOption().empty())	// @detach=n|y - RLV_LOCK_REMOVE locks an attachment *object*
+	{
+		// The object may or may not exist (it may not have rezzed yet, or it may have already been killed):
+		//   * @detach=n: - if it has rezzed then we'll already have looked up what we need (see next line if it's not an attachment)
+		//                - if it hasn't rezzed yet then it's a @detach=n from a non-attachment and RlvHandler::onAttach() takes care of it
+		//   * @detach=y: - if it ever rezzed as an attachment we'll have cached the UUID of its root
+		//                - if it never rezzed as an attachment there won't be a lock to remove
+		rlv_object_map_t::const_iterator itObj = m_Objects.find(rlvCmd.getObjectID());
+		if ( (itObj != m_Objects.end()) && (itObj->second.m_fLookup) && (itObj->second.m_idxAttachPt) )
+		{
+			if (RLV_TYPE_ADD == rlvCmd.getParamType())
+				gRlvAttachmentLocks.addAttachmentLock(itObj->second.m_idRoot, itObj->first);
+			else
+				gRlvAttachmentLocks.removeAttachmentLock(itObj->second.m_idRoot, itObj->first);
+		}
+	}
+	else							// @detach:<attachpt>=n|y - RLV_LOCK_ADD and RLV_LOCK_REMOVE locks an attachment *point*
+	{
+		// The attachment point index should always be non-zero for @detach:<attachpt>=n|y
+		S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption());
+		if (0 == idxAttachPt)
+			return RLV_RET_FAILED_OPTION;
+
+		if (RLV_TYPE_ADD == rlvCmd.getParamType())
+			gRlvAttachmentLocks.addAttachmentPointLock(idxAttachPt, rlvCmd.getObjectID(), (ERlvLockMask)(RLV_LOCK_ADD | RLV_LOCK_REMOVE));
+		else
+			gRlvAttachmentLocks.removeAttachmentPointLock(idxAttachPt, rlvCmd.getObjectID(), (ERlvLockMask)(RLV_LOCK_ADD | RLV_LOCK_REMOVE));
+	}
+
+	fRefCount = false;	// Don't reference count @detach[:<option>]=n
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-03-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0a
+ERlvCmdRet RlvHandler::onAddRemSetEnv(const RlvCommand& rlvCmd, bool& fRefCount)
+{
+	// Sanity check - there shouldn't be an option
+	if (!rlvCmd.getOption().empty())
+		return RLV_RET_FAILED_OPTION;
+	if (RlvSettings::getNoSetEnv())
+		return RLV_RET_FAILED_DISABLED;
+
+	if (RLV_TYPE_ADD == rlvCmd.getParamType())
+	{
+		// Save the current WindLight params so we can restore them on @setenv=y
+		RLV_ASSERT(!m_pWLSnapshot);
+		if (m_pWLSnapshot)
+			delete m_pWLSnapshot;
+		m_pWLSnapshot = RlvWLSnapshot::takeSnapshot();
+	}
+	else
+	{
+		// Restore WindLight parameters to what they were before @setenv=n was issued
+		RlvWLSnapshot::restoreSnapshot(m_pWLSnapshot);
+		delete m_pWLSnapshot;
+		m_pWLSnapshot = NULL;
+	}
+	fRefCount = true;
+
+	return RLV_RET_SUCCESS;
+}
+
+// ============================================================================
+// Command handlers (RLV_TYPE_FORCE)
+//
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0j
+ERlvCmdRet RlvHandler::processForceCommand(const RlvCommand& rlvCmd) const
+{
+	RLV_ASSERT(RLV_TYPE_FORCE == rlvCmd.getParamType());
+
+	ERlvCmdRet eRet = RLV_RET_SUCCESS;
+	switch (rlvCmd.getBehaviourType())
+	{
+		case RLV_BHVR_DETACH:		// @detach[:<option>]=force				- Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+			{
+				RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption());
+				if (rlvCmdOption.isSharedFolder())
+					eRet = onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourType());
+				else
+					eRet = onForceRemAttach(rlvCmd);
+			}
+			break;
+		case RLV_BHVR_REMATTACH:	// @remattach[:<option>]=force
+			eRet = onForceRemAttach(rlvCmd);
+			break;
+		case RLV_BHVR_REMOUTFIT:	// @remoutfit[:<option>]=force
+			eRet = onForceRemOutfit(rlvCmd);
+			break;
+		case RLV_BHVR_UNSIT:		// @unsit=force							- Checked: 2010-03-18 (RLVa-1.2.0c) | Modified: RLVa-0.2.0g
+			{
+				VERIFY_OPTION(rlvCmd.getOption().empty());
+				if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (!hasBehaviourExcept(RLV_BHVR_UNSIT, rlvCmd.getObjectID())) )
+				{
+					gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
+					send_agent_update(TRUE, TRUE);	// See behaviour notes on why we have to force an agent update here
+				}
+			}
+			break;
+		case RLV_BHVR_SIT:			// @sit:<option>=force
+			eRet = onForceSit(rlvCmd);
+			break;
+		case RLV_BHVR_TPTO:			// @tpto:<option>=force					- Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0h
+			{
+				eRet = RLV_RET_FAILED_OPTION;
+				if ( (!rlvCmd.getOption().empty()) && (std::string::npos == rlvCmd.getOption().find_first_not_of("0123456789/.")) )
+				{
+					LLVector3d posGlobal;
+
+					boost_tokenizer tokens(rlvCmd.getOption(), boost::char_separator<char>("/", "", boost::keep_empty_tokens)); int idx = 0;
+					for (boost_tokenizer::const_iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken)
+					{
+						if (idx < 3)
+							LLStringUtil::convertToF64(*itToken, posGlobal[idx++]);
+					}
+
+					if (idx == 3)
+					{
+						gAgent.teleportViaLocation(posGlobal);
+						eRet = RLV_RET_SUCCESS;
+					}
+				}
+			}
+			break;
+		case RLV_BHVR_ATTACH:
+		case RLV_BHVR_ATTACHOVER:
+		case RLV_BHVR_ATTACHALL:
+		case RLV_BHVR_ATTACHALLOVER:
+		case RLV_BHVR_DETACHALL:
+			{
+				RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption());
+				VERIFY_OPTION(rlvCmdOption.isSharedFolder());
+
+				eRet = onForceWear(rlvCmdOption.getSharedFolder(), rlvCmd.getBehaviourType());
+			}
+			break;
+		case RLV_BHVR_ATTACHTHIS:
+		case RLV_BHVR_ATTACHTHISOVER:
+		case RLV_BHVR_DETACHTHIS:
+		case RLV_BHVR_ATTACHALLTHIS:
+		case RLV_BHVR_ATTACHALLTHISOVER:
+		case RLV_BHVR_DETACHALLTHIS:
+			{
+				RlvCommandOptionGetPath rlvGetPathOption(rlvCmd);
+				VERIFY_OPTION(rlvGetPathOption.isValid());
+
+				LLInventoryModel::cat_array_t folders;
+				if (RlvInventory::instance().getPath(rlvGetPathOption.getItemIDs(), folders))
+				{
+					for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++)
+						onForceWear(folders.get(idxFolder), rlvCmd.getBehaviourType());
+				}
+			}
+			break;
+		case RLV_BHVR_DETACHME:		// @detachme=force						- Checked: 2010-04-04 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c
+			{
+				VERIFY_OPTION(rlvCmd.getOption().empty());
+				// NOTE: @detachme should respect locks but shouldn't respect things like nostrip
+				const LLViewerObject* pAttachObj = gObjectList.findObject(rlvCmd.getObjectID());
+				if ( (pAttachObj) && (pAttachObj->isAttachment()) && (!gRlvAttachmentLocks.isLockedAttachment(pAttachObj)) )
+				{
+					gMessageSystem->newMessage("ObjectDetach");
+					gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+					gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+					gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+					gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+					gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, pAttachObj->getLocalID());
+					gMessageSystem->sendReliable( gAgent.getRegionHost() );
+				}
+			}
+			break;
+		case RLV_BHVR_UNKNOWN:
+			// Pass unknown commands on to registered command handlers
+			return (notifyCommandHandlers(&RlvCommandHandler::onForceCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN;
+		default:
+			// Fail with "Invalid param" if none of the above handled it
+			eRet = RLV_RET_FAILED_PARAM;
+			break;
+	}
+	return eRet;
+}
+
+// Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+ERlvCmdRet RlvHandler::onForceRemAttach(const RlvCommand& rlvCmd) const
+{
+	RLV_ASSERT(RLV_TYPE_FORCE == rlvCmd.getParamType());
+	RLV_ASSERT( (RLV_BHVR_REMATTACH == rlvCmd.getBehaviourType()) || (RLV_BHVR_DETACH == rlvCmd.getBehaviourType()) );
+
+	if (!isAgentAvatarValid())
+		return RLV_RET_FAILED;
+
+	RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption());
+	// @remattach:<attachpt>=force - force detach single attachment point
+	if (rlvCmdOption.isAttachmentPoint())
+	{
+		RlvForceWear::instance().forceDetach(rlvCmdOption.getAttachmentPoint());
+		return RLV_RET_SUCCESS;
+	}
+	// @remattach:<group>=force - force detach attachments points belonging to <group>
+	// @remattach=force         - force detach all attachments points
+	else if ( (rlvCmdOption.isAttachmentPointGroup()) || (rlvCmdOption.isEmpty()) )
+	{
+		for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); 
+				itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach)
+		{
+			const LLViewerJointAttachment* pAttachPt = itAttach->second;
+			if ( (pAttachPt) && (pAttachPt->getNumObjects()) &&
+				 ((rlvCmdOption.isEmpty()) || (rlvAttachGroupFromIndex(pAttachPt->getGroup()) == rlvCmdOption.getAttachmentPointGroup())) )
+			{
+				RlvForceWear::instance().forceDetach(pAttachPt);
+			}
+		}
+		return RLV_RET_SUCCESS;
+	}
+	return RLV_RET_FAILED_OPTION;
+}
+
+// Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+ERlvCmdRet RlvHandler::onForceRemOutfit(const RlvCommand& rlvCmd) const
+{
+	RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption());
+	if ( (!rlvCmdOption.isWearableType()) && (!rlvCmdOption.isEmpty()) )
+		return RLV_RET_FAILED_OPTION;
+
+	for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++)
+	{
+		if ( (rlvCmdOption.isEmpty()) || ((LLWearableType::EType)idxType == rlvCmdOption.getWearableType()))
+			RlvForceWear::instance().forceRemove((LLWearableType::EType)idxType);
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-03-18 (RLVa-1.2.0c) | Modified: RLVa-1.1.0j
+ERlvCmdRet RlvHandler::onForceSit(const RlvCommand& rlvCmd) const
+{
+	LLViewerObject* pObj = NULL; LLUUID idTarget(rlvCmd.getOption());
+	// Sanity checking - we need to know about the object and it should identify a prim/linkset
+	if ( (idTarget.isNull()) || ((pObj = gObjectList.findObject(idTarget)) == NULL) || (LL_PCODE_VOLUME != pObj->getPCode()) )
+		return RLV_RET_FAILED_OPTION;
+
+	if (!canSit(pObj))
+		return RLV_RET_FAILED_LOCK;
+	else if ( (hasBehaviour(RLV_BHVR_STANDTP)) && (isAgentAvatarValid()) )
+	{
+		if (gAgentAvatarp->isSitting())
+			return RLV_RET_FAILED_LOCK;
+		m_posSitSource = gAgent.getPositionGlobal();
+	}
+
+	// Copy/paste from handle_sit_or_stand() [see http://wiki.secondlife.com/wiki/AgentRequestSit]
+	gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
+	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	gMessageSystem->nextBlockFast(_PREHASH_TargetObject);
+	gMessageSystem->addUUIDFast(_PREHASH_TargetID, pObj->mID);
+	// Offset: "a rough position in local coordinates for the edge to sit on"
+	// (we might not even be looking at the object so I don't think we can supply the offset to an edge)
+	gMessageSystem->addVector3Fast(_PREHASH_Offset, LLVector3::zero);
+	pObj->getRegion()->sendReliableMessage();
+
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+ERlvCmdRet RlvHandler::onForceWear(const LLViewerInventoryCategory* pFolder, ERlvBehaviour eBhvr) const
+{
+	if ( (pFolder) && (!RlvInventory::instance().isSharedFolder(pFolder->getUUID())) )
+		return RLV_RET_FAILED_OPTION;
+
+	RlvForceWear::EWearAction eAction = RlvForceWear::ACTION_WEAR_REPLACE;
+	if ( (RLV_BHVR_ATTACHOVER == eBhvr) || (RLV_BHVR_ATTACHTHISOVER == eBhvr) || 
+		 (RLV_BHVR_ATTACHALLOVER == eBhvr) || (RLV_BHVR_ATTACHALLTHISOVER == eBhvr) )
+	{
+		eAction = RlvForceWear::ACTION_WEAR_ADD;
+	}
+	else if ( (RLV_BHVR_DETACH == eBhvr) || (RLV_BHVR_DETACHTHIS == eBhvr) || 
+		      (RLV_BHVR_DETACHALL == eBhvr) || (RLV_BHVR_DETACHALLTHIS == eBhvr) )
+	{
+		eAction = RlvForceWear::ACTION_REMOVE;
+	}
+
+	RlvForceWear::EWearFlags eFlags = RlvForceWear::FLAG_DEFAULT;
+	if ( (RLV_BHVR_ATTACHALL == eBhvr) || (RLV_BHVR_ATTACHALLOVER == eBhvr) || (RLV_BHVR_DETACHALL == eBhvr) ||
+		 (RLV_BHVR_ATTACHALLTHIS == eBhvr) || (RLV_BHVR_ATTACHALLTHISOVER == eBhvr) || (RLV_BHVR_DETACHALLTHIS == eBhvr) )
+	{
+		eFlags = (RlvForceWear::EWearFlags)(eFlags | RlvForceWear::FLAG_MATCHALL);
+	}
+
+	RlvForceWear::instance().forceFolder(pFolder, eAction, eFlags);
+	return RLV_RET_SUCCESS;
+}
+
+// ============================================================================
+// Command handlers (RLV_TYPE_REPLY)
+//
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+ERlvCmdRet RlvHandler::processReplyCommand(const RlvCommand& rlvCmd) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+
+	// Sanity check - <param> should specify a - valid - reply channel
+	S32 nChannel;
+	if ( (!LLStringUtil::convertToS32(rlvCmd.getParam(), nChannel)) || (!RlvUtil::isValidReplyChannel(nChannel)) )
+		return RLV_RET_FAILED_PARAM;
+
+	ERlvCmdRet eRet = RLV_RET_SUCCESS; std::string strReply;
+	switch (rlvCmd.getBehaviourType())
+	{
+		case RLV_BHVR_VERSION:			// @version=<channel>					- Checked: 2010-03-27 (RLVa-1.2.0b)
+		case RLV_BHVR_VERSIONNEW:		// @versionnew=<channel>				- Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.2.0b
+			// NOTE: RLV will respond even if there's an option
+			strReply = RlvStrings::getVersion(RLV_BHVR_VERSION == rlvCmd.getBehaviourType());
+			break;
+		case RLV_BHVR_VERSIONNUM:		// @versionnum=<channel>				- Checked: 2010-03-27 (RLVa-1.2.0b) | Added: RLVa-1.0.4b
+			// NOTE: RLV will respond even if there's an option
+			strReply = RlvStrings::getVersionNum();
+			break;
+		case RLV_BHVR_GETATTACH:		// @getattach[:<layer>]=<channel>
+			eRet = onGetAttach(rlvCmd, strReply);
+			break;
+#ifdef RLV_EXTENSION_CMD_GETXXXNAMES
+		case RLV_BHVR_GETATTACHNAMES:	// @getattachnames[:<grp>]=<channel>
+		case RLV_BHVR_GETADDATTACHNAMES:// @getaddattachnames[:<grp>]=<channel>
+		case RLV_BHVR_GETREMATTACHNAMES:// @getremattachnames[:<grp>]=<channel>
+			eRet = onGetAttachNames(idObj, rlvCmd, strReply);
+			break;
+#endif // RLV_EXTENSION_CMD_GETXXXNAMES
+		case RLV_BHVR_GETOUTFIT:		// @getoutfit[:<layer>]=<channel>
+			eRet = onGetOutfit(rlvCmd, strReply);
+			break;
+#ifdef RLV_EXTENSION_CMD_GETXXXNAMES
+		case RLV_BHVR_GETOUTFITNAMES:	// @getoutfitnames=<channel>
+		case RLV_BHVR_GETADDOUTFITNAMES:// @getaddoutfitnames=<channel>
+		case RLV_BHVR_GETREMOUTFITNAMES:// @getremoutfitnames=<channel>
+			eRet = onGetOutfitNames(idObj, rlvCmd, strReply);
+			break;
+#endif // RLV_EXTENSION_CMD_GETXXXNAMES
+		case RLV_BHVR_FINDFOLDER:		// @findfolder:<criteria>=<channel>
+#ifdef RLV_EXTENSION_CMD_FINDFOLDERS
+		case RLV_BHVR_FINDFOLDERS:		// @findfolders:<criteria>=<channel>
+#endif // RLV_EXTENSION_CMD_FINDFOLDERS
+			eRet = onFindFolder(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_GETPATH:			// @getpath[:<option>]=<channel>
+		case RLV_BHVR_GETPATHNEW:		// @getpathnew[:<option>]=<channel>
+			eRet = onGetPath(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_GETINV:			// @getinv[:<path>]=<channel>
+			eRet = onGetInv(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_GETINVWORN:		// @getinvworn[:<path>]=<channel>
+			eRet = onGetInvWorn(rlvCmd, strReply);
+			break;
+		case RLV_BHVR_GETSITID:			// @getsitid=<channel>					- Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+			{
+				// NOTE: RLV-1.16.1 returns a NULL UUID if we're not sitting
+				LLUUID idSitObj;
+				if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) )
+				{
+					const LLViewerObject* pSeatObj = dynamic_cast<LLViewerObject*>(gAgentAvatarp->getRoot());
+					if (pSeatObj)
+						idSitObj = pSeatObj->getID();
+				}
+				strReply = idSitObj.asString();
+			}
+			break;
+		case RLV_BHVR_GETSTATUS:		// @getstatus[:<option>]=<channel>		- Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+			{
+				// NOTE: specification says response should start with '/' but RLV-1.16.1 returns an empty string when no rules are set
+				rlv_object_map_t::const_iterator itObj = m_Objects.find(rlvCmd.getObjectID());
+				if (itObj != m_Objects.end())
+					strReply = itObj->second.getStatusString(rlvCmd.getOption());
+			}
+			break;
+		case RLV_BHVR_GETSTATUSALL:		// @getstatusall[:<option>]=<channel>	- Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+			{
+				// NOTE: specification says response should start with '/' but RLV-1.16.1 returns an empty string when no rules are set
+				for (rlv_object_map_t::const_iterator itObj = m_Objects.begin(); itObj != m_Objects.end(); ++itObj)
+					strReply += itObj->second.getStatusString(rlvCmd.getOption());
+			}
+			break;
+		case RLV_BHVR_UNKNOWN:
+			// Pass unknown commands on to registered command handlers
+			return (notifyCommandHandlers(&RlvCommandHandler::onReplyCommand, rlvCmd, eRet, false)) ? eRet : RLV_RET_FAILED_UNKNOWN;
+		default:
+			// Fail with "Invalid param" if none of the above handled it
+			return RLV_RET_FAILED_PARAM;
+	}
+
+	// If we made it this far then:
+	//   - the command was handled successfully so we send off the response
+	//   - the command failed but we still send off an - empty - response to keep the issuing script from blocking
+	RlvUtil::sendChatReply(nChannel, strReply);
+
+	return eRet;
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+ERlvCmdRet RlvHandler::onFindFolder(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT( (RLV_BHVR_FINDFOLDER == rlvCmd.getBehaviourType()) || (RLV_BHVR_FINDFOLDERS == rlvCmd.getBehaviourType()) ); 
+
+	// (Compatibility: RLV 1.16.1 returns the first random folder it finds while we return a blank on no option)
+	if (rlvCmd.getOption().empty())
+		return RLV_RET_FAILED_OPTION;
+
+	LLInventoryModel::cat_array_t folders;
+	if (RlvInventory::instance().findSharedFolders(rlvCmd.getOption(), folders))
+	{
+		if (RLV_BHVR_FINDFOLDER == rlvCmd.getBehaviourType())
+		{
+			// We need to return an "in depth" result so whoever has the most '/' is our lucky winner
+			// (maxSlashes needs to be initialized to -1 since children of the #RLV folder won't have '/' in their shared path)
+			int maxSlashes = -1, curSlashes; std::string strFolderName;
+			for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++)
+			{
+				strFolderName = RlvInventory::instance().getSharedPath(folders.get(idxFolder));
+
+				curSlashes = std::count(strFolderName.begin(), strFolderName.end(), '/');
+				if (curSlashes > maxSlashes)
+				{
+					maxSlashes = curSlashes;
+					strReply = strFolderName;
+				}
+			}
+		}
+		else if (RLV_BHVR_FINDFOLDERS == rlvCmd.getBehaviourType())
+		{
+			for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++)
+			{
+				if (!strReply.empty())
+					strReply.push_back(',');
+				strReply += RlvInventory::instance().getSharedPath(folders.get(idxFolder));
+			}
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.1.0e
+ERlvCmdRet RlvHandler::onGetAttach(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT(RLV_BHVR_GETATTACH == rlvCmd.getBehaviourType());
+
+	if (!isAgentAvatarValid())
+		return RLV_RET_FAILED;
+
+	// Sanity check - <option> should specify an attachment point or be empty
+	S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(rlvCmd.getOption());
+	if ( (idxAttachPt == 0) && (!rlvCmd.getOption().empty()) )
+		return RLV_RET_FAILED_OPTION;
+
+	// If we're fetching all worn attachments then the reply should start with 0
+	if (0 == idxAttachPt)
+		strReply.push_back('0');
+
+	for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); 
+			itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach)
+	{
+		const LLViewerJointAttachment* pAttachPt = itAttach->second;
+		if ( (0 == idxAttachPt) || (itAttach->first == idxAttachPt) )
+		{
+			bool fWorn = (pAttachPt->getNumObjects()) && 
+				( (!RlvSettings::getHideLockedAttach()) || (RlvForceWear::isForceDetachable(pAttachPt, true, rlvCmd.getObjectID())) );
+			strReply.push_back( (fWorn) ? '1' : '0' );
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.1.0e
+ERlvCmdRet RlvHandler::onGetAttachNames(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT( (RLV_BHVR_GETATTACHNAMES == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETADDATTACHNAMES == rlvCmd.getBehaviourType()) || 
+		        (RLV_BHVR_GETREMATTACHNAMES == rlvCmd.getBehaviourType()) );
+
+	if (!isAgentAvatarValid())
+		return RLV_RET_FAILED;
+
+	ERlvAttachGroupType eAttachGroup = rlvAttachGroupFromString(rlvCmd.getOption());
+	for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); 
+			itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach)
+	{
+		const LLViewerJointAttachment* pAttachPt = itAttach->second;
+		if ( (RLV_ATTACHGROUP_INVALID == eAttachGroup) || (rlvAttachGroupFromIndex(pAttachPt->getGroup()) == eAttachGroup) )
+		{
+			bool fAdd = false;
+			switch (rlvCmd.getBehaviourType())
+			{
+				case RLV_BHVR_GETATTACHNAMES:		// Every attachment point that has an attached object (locked or unlocked)
+					fAdd = (pAttachPt->getNumObjects());
+					break;
+/*
+				case RLV_BHVR_GETADDATTACHNAMES:	// Every attachment point that can be worn on (but ignore any locks set by the issuer)
+					fAdd = (!isLockedAttachmentExcept(itAttach->first, RLV_LOCK_ADD, gObjectList.findObject(idObj))) &&
+						   ( (pAttachPt->getObject() == NULL) || 
+						     (!isLockedAttachmentExcept(itAttach->first, RLV_LOCK_REMOVE, gObjectList.findObject(idObj))) );
+					break;
+*/
+				case RLV_BHVR_GETREMATTACHNAMES:	// Every attachment point that can be detached (but ignore any locks set by the issuer)
+					fAdd = RlvForceWear::isForceDetachable(pAttachPt, true, rlvCmd.getObjectID());
+					break;
+				default:
+					break;
+			}
+
+			if (fAdd)
+			{
+				if (!strReply.empty())
+					strReply.push_back(',');
+				strReply.append(pAttachPt->getName());
+			}
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-03-09 (RLVa-1.2.0a) | Modified: RLVa-1.1.0f
+ERlvCmdRet RlvHandler::onGetInv(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT(RLV_BHVR_GETINV == rlvCmd.getBehaviourType());
+
+	const LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(rlvCmd.getOption());
+	if (!pFolder)
+		return (RlvInventory::instance().getSharedRoot() != NULL) ? RLV_RET_FAILED_OPTION : RLV_RET_FAILED_NOSHAREDROOT;
+
+	LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems;
+	gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems);
+	if (!pFolders)
+		return RLV_RET_FAILED;
+
+	for (S32 idxFolder = 0, cntFolder = pFolders->count(); idxFolder < cntFolder; idxFolder++)
+	{
+		// Return all folders that:
+		//   - aren't hidden
+		//   - aren't a folded folder (only really matters when "Enable Legacy Naming" is enabled - see related blog post)
+		//     (we can skip checking for .<composite> folders since the ones we'll want to hide start with '.' anyway)
+		const std::string& strFolder = pFolders->get(idxFolder)->getName();
+		if ( (!strFolder.empty()) && (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && 
+			 (!RlvInventory::isFoldedFolder(pFolders->get(idxFolder).get(), false)) )
+		{
+			if (!strReply.empty())
+				strReply.push_back(',');
+			strReply += strFolder;
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+struct rlv_wear_info { U32 cntWorn, cntTotal, cntChildWorn, cntChildTotal; };
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.1.0f
+ERlvCmdRet RlvHandler::onGetInvWorn(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	// Sanity check - gAgentAvatarp can't be NULL [see RlvForceWear::isWearingItem()]
+	if (!isAgentAvatarValid())
+		return RLV_RET_FAILED;
+	// Sanity check - folder should exist and not be hidden
+	LLViewerInventoryCategory* pFolder = RlvInventory::instance().getSharedFolder(rlvCmd.getOption());
+	if ( (!pFolder) || (pFolder->getName().empty()) || (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName()[0]) )
+		return (RlvInventory::instance().getSharedRoot() != NULL) ? RLV_RET_FAILED_OPTION : RLV_RET_FAILED_NOSHAREDROOT;
+
+	// Collect everything @attachall would be attaching
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+	RlvWearableItemCollector f(pFolder->getUUID(), true, true);
+	gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f);
+
+	rlv_wear_info wi = {0};
+
+	// Add all the folders to a lookup map 
+	std::map<LLUUID, rlv_wear_info> mapFolders;
+	mapFolders.insert(std::pair<LLUUID, rlv_wear_info>(pFolder->getUUID(), wi));
+	for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++)
+		mapFolders.insert(std::pair<LLUUID, rlv_wear_info>(folders.get(idxFolder)->getUUID(), wi));
+
+	// Iterate over all the found items
+	LLViewerInventoryItem* pItem; std::map<LLUUID, rlv_wear_info>::iterator itFolder;
+	for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++)
+	{
+		pItem = items.get(idxItem);
+		if (!RlvForceWear::isWearableItem(pItem))
+			continue;
+
+		// The "folded parent" is the folder this item should be considered a direct descendent of (may or may not match actual parent)
+		const LLUUID& idParent = f.getFoldedParent(pItem->getParentUUID());
+
+		// Walk up the tree: sooner or later one of the parents will be a folder in the map
+		LLViewerInventoryCategory* pParent = gInventory.getCategory(idParent);
+		while ( (itFolder = mapFolders.find(pParent->getUUID())) == mapFolders.end() )
+			pParent = gInventory.getCategory(pParent->getParentUUID());
+
+		U32 &cntWorn  = (idParent == pParent->getUUID()) ? itFolder->second.cntWorn : itFolder->second.cntChildWorn, 
+			&cntTotal = (idParent == pParent->getUUID()) ? itFolder->second.cntTotal : itFolder->second.cntChildTotal;
+
+		if (RlvForceWear::isWearingItem(pItem))
+			cntWorn++;
+		cntTotal++;
+	}
+
+	// Extract the result for the main folder
+	itFolder = mapFolders.find(pFolder->getUUID());
+	wi.cntWorn = itFolder->second.cntWorn;
+	wi.cntTotal = itFolder->second.cntTotal;
+	mapFolders.erase(itFolder);
+
+	// Build the result for each child folder
+	for (itFolder = mapFolders.begin(); itFolder != mapFolders.end(); ++itFolder)
+	{
+		rlv_wear_info& wiFolder = itFolder->second;
+
+		wi.cntChildWorn += wiFolder.cntWorn + wiFolder.cntChildWorn;
+		wi.cntChildTotal += wiFolder.cntTotal + wiFolder.cntChildTotal;
+
+		strReply += llformat(",%s|%d%d", gInventory.getCategory(itFolder->first)->getName().c_str(),
+		 (0 == wiFolder.cntTotal) ? 0 : (0 == wiFolder.cntWorn) ? 1 : (wiFolder.cntWorn != wiFolder.cntTotal) ? 2 : 3,
+		 (0 == wiFolder.cntChildTotal) ? 0 : (0 == wiFolder.cntChildWorn) ? 1 : (wiFolder.cntChildWorn != wiFolder.cntChildTotal) ? 2 : 3
+		);
+	}
+
+	// Now just prepend the root and done
+	strReply = llformat("|%d%d", (0 == wi.cntTotal) ? 0 : (0 == wi.cntWorn) ? 1 : (wi.cntWorn != wi.cntTotal) ? 2 : 3,
+		(0 == wi.cntChildTotal) ? 0 : (0 == wi.cntChildWorn) ? 1 : (wi.cntChildWorn != wi.cntChildTotal) ? 2: 3) + strReply;
+
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+ERlvCmdRet RlvHandler::onGetOutfit(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT(RLV_BHVR_GETOUTFIT == rlvCmd.getBehaviourType());
+
+	// (Compatibility: RLV-1.16.1 will execute @getoutfit=<channel> if <layer> is invalid while we just return failure)
+	LLWearableType::EType wtType = LLWearableType::typeNameToType(rlvCmd.getOption());
+	if ( (LLWearableType::WT_INVALID == wtType) && (!rlvCmd.getOption().empty()) )
+		return RLV_RET_FAILED_OPTION;
+
+	const LLWearableType::EType wtRlvTypes[] =
+		{ 
+			LLWearableType::WT_GLOVES, LLWearableType::WT_JACKET, LLWearableType::WT_PANTS, LLWearableType::WT_SHIRT, 
+			LLWearableType::WT_SHOES, LLWearableType::WT_SKIRT, LLWearableType::WT_SOCKS, LLWearableType::WT_UNDERPANTS, 
+			LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_SKIN, LLWearableType::WT_EYES, LLWearableType::WT_HAIR, 
+			LLWearableType::WT_SHAPE, LLWearableType::WT_ALPHA, LLWearableType::WT_TATTOO
+		};
+
+	for (int idxType = 0, cntType = sizeof(wtRlvTypes) / sizeof(LLWearableType::EType); idxType < cntType; idxType++)
+	{
+		if ( (LLWearableType::WT_INVALID == wtType) || (wtRlvTypes[idxType] == wtType) )
+		{
+			// We never hide body parts, even if they're "locked" and we're hiding locked layers
+			// (nor do we hide a layer if the issuing object is the only one that has this layer locked)
+			bool fWorn = (gAgentWearables.getWearableCount(wtRlvTypes[idxType]) > 0) && 
+				( (!RlvSettings::getHideLockedLayers()) || 
+				  (LLAssetType::AT_BODYPART == LLWearableType::getAssetType(wtRlvTypes[idxType])) ||
+				  (RlvForceWear::isForceRemovable(wtRlvTypes[idxType], true, rlvCmd.getObjectID())) );
+			strReply.push_back( (fWorn) ? '1' : '0' );
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2009-11-21 (RLVa-1.1.0f) | Added: RLVa-1.1.0e
+ERlvCmdRet RlvHandler::onGetOutfitNames(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT( (RLV_BHVR_GETOUTFITNAMES == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETADDOUTFITNAMES == rlvCmd.getBehaviourType()) || 
+		        (RLV_BHVR_GETREMOUTFITNAMES == rlvCmd.getBehaviourType()) );
+
+	// Sanity check - all these commands are optionless
+	if (!rlvCmd.getOption().empty())
+		return RLV_RET_FAILED_OPTION;
+
+	// RELEASE-RLVa: [SL-2.0.0] Needs revisiting/rewriting once 'LLAgentWearables::MAX_WEARABLES_PER_TYPE > 1'
+	for (int idxType = 0; idxType < LLWearableType::WT_COUNT; idxType++)
+	{
+		bool fAdd = false; LLWearableType::EType wtType = (LLWearableType::EType)idxType;
+		switch (rlvCmd.getBehaviourType())
+		{
+			case RLV_BHVR_GETOUTFITNAMES:		// Every layer that's worn
+				fAdd = (gAgentWearables.getWearableCount(wtType) > 0);
+				break;
+/*
+			case RLV_BHVR_GETADDOUTFITNAMES:	// Every layer that can be worn on (but ignore any locks set by the issuer)
+				fAdd = (isWearable(wtType)) && ( (gAgent.getWearable(wtType) == NULL) || (isRemovableExcept(wtType, idObj)) );
+				break;
+*/
+			case RLV_BHVR_GETREMOUTFITNAMES:	// Every layer that can be removed (but ignore any locks set by the issuer)
+				fAdd = RlvForceWear::isForceRemovable(wtType);
+				break;
+			default:
+				break;
+		}
+
+		if (fAdd)
+		{
+			if (!strReply.empty())
+				strReply.push_back(',');
+			strReply.append(LLWearableType::getTypeName((LLWearableType::EType)idxType));
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+ERlvCmdRet RlvHandler::onGetPath(const RlvCommand& rlvCmd, std::string& strReply) const
+{
+	RLV_ASSERT(RLV_TYPE_REPLY == rlvCmd.getParamType());
+	RLV_ASSERT( (RLV_BHVR_GETPATH == rlvCmd.getBehaviourType()) || (RLV_BHVR_GETPATHNEW == rlvCmd.getBehaviourType()) ); 
+
+	RlvCommandOptionGetPath rlvGetPathOption(rlvCmd);
+	if (!rlvGetPathOption.isValid())
+		return RLV_RET_FAILED_OPTION;
+
+	LLInventoryModel::cat_array_t folders;
+	if (RlvInventory::instance().getPath(rlvGetPathOption.getItemIDs(), folders))
+	{
+		if (RLV_BHVR_GETPATH == rlvCmd.getBehaviourType())
+		{
+			strReply = RlvInventory::instance().getSharedPath(folders.get(0));
+		}
+		else if (RLV_BHVR_GETPATHNEW == rlvCmd.getBehaviourType())
+		{
+			for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++)
+			{
+				if (!strReply.empty())
+					strReply.push_back(',');
+				strReply += RlvInventory::instance().getSharedPath(folders.get(idxFolder));
+			}
+		}
+	}
+	return RLV_RET_SUCCESS;
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvhandler.h b/indra/newview/rlvhandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..306c8ba39e89339745cb58fa975c58ed55099ae5
--- /dev/null
+++ b/indra/newview/rlvhandler.h
@@ -0,0 +1,356 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_HANDLER_H
+#define RLV_HANDLER_H
+
+#include <stack>
+#include "llagentconstants.h"
+#include "llstartup.h"
+#include "llviewerjointattachment.h"
+#include "llviewerobject.h"
+
+#include "rlvcommon.h"
+#include "rlvhelper.h"
+#include "rlvlocks.h"
+
+// ============================================================================
+
+class RlvHandler
+{
+public:
+	RlvHandler();
+	~RlvHandler();
+
+	// --------------------------------
+
+	/*
+	 * Rule checking functions
+	 */
+	// NOTE: - to check @detach=n    -> (see RlvAttachmentLocks)
+	//       - to check @addattach=n -> (see RlvAttachmentLocks)
+	//       - to check @remattach=n -> (see RlvAttachmentLocks)
+	//       - to check @addoutfit=n -> (see RlvWearableLocks)
+	//       - to check @remoutfit=n -> (see RlvWearableLocks)
+	//       - to check exceptions   -> isException()
+public:
+	// Returns TRUE is at least one object contains the specified behaviour (and optional option)
+	bool hasBehaviour(ERlvBehaviour eBehaviour) const { return (eBehaviour < RLV_BHVR_COUNT) ? (0 != m_Behaviours[eBehaviour]) : false; }
+	bool hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption) const;
+	// Returns TRUE if at least one object (except the specified one) contains the specified behaviour (and optional option)
+	bool hasBehaviourExcept(ERlvBehaviour eBehaviour, const LLUUID& idObj) const;
+	bool hasBehaviourExcept(ERlvBehaviour eBehaviour, const std::string& strOption, const LLUUID& idObj) const;
+
+	// Adds or removes an exception for the specified behaviour
+	void addException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption);
+	void removeException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption);
+	// Returns TRUE if the specified option was added as an exception for the specified behaviour
+	bool isException(ERlvBehaviour eBhvr, const RlvExceptionOption& varOption, ERlvExceptionCheck typeCheck = RLV_CHECK_DEFAULT) const;
+	// Returns TRUE if the specified behaviour should behave "permissive" (rather than "strict"/"secure")
+	bool isPermissive(ERlvBehaviour eBhvr) const;
+
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	// Returns TRUE if the composite folder doesn't contain any "locked" items
+	bool canTakeOffComposite(const LLInventoryCategory* pFolder) const;
+	// Returns TRUE if the composite folder doesn't replace any "locked" items
+	bool canWearComposite(const LLInventoryCategory* pFolder) const;
+	// Returns TRUE if the folder is a composite folder and optionally returns the name
+	bool getCompositeInfo(const LLInventoryCategory* pFolder, std::string* pstrName) const;
+	// Returns TRUE if the inventory item belongs to a composite folder and optionally returns the name and composite folder
+	bool getCompositeInfo(const LLUUID& idItem, std::string* pstrName, LLViewerInventoryCategory** ppFolder) const;
+	// Returns TRUE if the folder is a composite folder
+	bool isCompositeFolder(const LLInventoryCategory* pFolder) const { return getCompositeInfo(pFolder, NULL); }
+	// Returns TRUE if the inventory item belongs to a composite folder
+	bool isCompositeDescendent(const LLUUID& idItem) const { return getCompositeInfo(idItem, NULL, NULL); }
+	// Returns TRUE if the inventory item is part of a folded composite folder and should be hidden from @getoufit or @getattach
+	bool isHiddenCompositeItem(const LLUUID& idItem, const std::string& strItemType) const;
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+	// --------------------------------
+
+	/*
+	 * Helper functions 
+	 */
+public:
+	// Accessors
+	bool              getCanCancelTp() const		{ return m_fCanCancelTp; }					// @accepttp and @tpto
+	void              setCanCancelTp(bool fAllow)	{ m_fCanCancelTp = fAllow; }				// @accepttp and @tpto
+	const LLVector3d& getSitSource() const						{ return m_posSitSource; }		// @standtp
+	void              setSitSource(const LLVector3d& posSource)	{ m_posSitSource = posSource; }	// @standtp
+
+	// Command specific helper functions
+	bool canShowHoverText(LLViewerObject* pObj) const;											// @showhovertext* command family
+	bool canSit(LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero) const;
+	bool canStand() const;
+	bool canTouch(LLViewerObject* pObj, const LLVector3& posOffset = LLVector3::zero) const;	// @touch
+	void filterChat(std::string& strUTF8Text, bool fFilterEmote) const;							// @sendchat, @recvchat and @redirchat
+	bool redirectChatOrEmote(const std::string& strUTF8Test) const;								// @redirchat and @rediremote
+
+	// Command processing helper functions
+	ERlvCmdRet processCommand(const LLUUID& idObj, const std::string& strCommand, bool fFromObj);
+	void       processRetainedCommands(ERlvBehaviour eBhvrFilter = RLV_BHVR_UNKNOWN, ERlvParamType eTypeFilter = RLV_TYPE_UNKNOWN);
+
+	// Returns a pointer to the currently executing command (do *not* save this pointer)
+	const RlvCommand* getCurrentCommand() const { return (!m_CurCommandStack.empty()) ? m_CurCommandStack.top() : NULL; }
+	// Returns the UUID of the object we're currently executing a command for
+	const LLUUID&     getCurrentObject() const	{ return (!m_CurObjectStack.empty()) ? m_CurObjectStack.top() : LLUUID::null; }
+
+	// Initialization
+	static BOOL canDisable();
+	static BOOL isEnabled()	{ return m_fEnabled; }
+	static BOOL setEnabled(BOOL fEnable);
+protected:
+	void clearState();
+
+	// --------------------------------
+
+	/*
+	 * Event handling
+	 */
+public:
+	// The behaviour signal is triggered whenever a command is successfully processed and resulted in adding or removing a behaviour
+	typedef boost::signals2::signal<void (ERlvBehaviour, ERlvParamType)> rlv_behaviour_signal_t;
+	boost::signals2::connection setBehaviourCallback(const rlv_behaviour_signal_t::slot_type& cb ) { return m_OnBehaviour.connect(cb); }
+	// The command signal is triggered whenever a command is processed
+	typedef boost::signals2::signal<void (const RlvCommand&, ERlvCmdRet, bool)> rlv_command_signal_t;
+	boost::signals2::connection setCommandCallback(const rlv_command_signal_t::slot_type& cb ) { return m_OnCommand.connect(cb); }
+
+	void addCommandHandler(RlvCommandHandler* pHandler);
+	void removeCommandHandler(RlvCommandHandler* pHandler);
+protected:
+	void clearCommandHandlers();
+	bool notifyCommandHandlers(rlvCommandHandler f, const RlvCommand& rlvCmd, ERlvCmdRet& eRet, bool fNotifyAll) const;
+
+	// Externally invoked event handlers
+public:
+	void onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt);
+	void onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt);
+	bool onGC();
+	void onLoginComplete();
+	void onSitOrStand(bool fSitting);
+	void onTeleportFailed();
+	void onTeleportFinished(const LLVector3d& posArrival);
+	static void onIdleStartup(void* pParam);
+
+	/*
+	 * Command processing
+	 */
+protected:
+	ERlvCmdRet processCommand(const RlvCommand& rlvCmd, bool fFromObj);
+	ERlvCmdRet processClearCommand(const RlvCommand& rlvCmd);
+
+	// Command handlers (RLV_TYPE_ADD and RLV_TYPE_CLEAR)
+	ERlvCmdRet processAddRemCommand(const RlvCommand& rlvCmd);
+	ERlvCmdRet onAddRemAttach(const RlvCommand& rlvCmd, bool& fRefCount);
+	ERlvCmdRet onAddRemDetach(const RlvCommand& rlvCmd, bool& fRefCount);
+	ERlvCmdRet onAddRemSetEnv(const RlvCommand& rlvCmd, bool& fRefCount);
+	// Command handlers (RLV_TYPE_FORCE)
+	ERlvCmdRet processForceCommand(const RlvCommand& rlvCmd) const;
+	ERlvCmdRet onForceRemAttach(const RlvCommand& rlvCmd) const;
+	ERlvCmdRet onForceRemOutfit(const RlvCommand& rlvCmd) const;
+	ERlvCmdRet onForceSit(const RlvCommand& rlvCmd) const;
+	ERlvCmdRet onForceWear(const LLViewerInventoryCategory* pFolder, ERlvBehaviour eBhvr) const;
+	// Command handlers (RLV_TYPE_REPLY)
+	ERlvCmdRet processReplyCommand(const RlvCommand& rlvCmd) const;
+	ERlvCmdRet onFindFolder(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetAttach(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetAttachNames(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetInv(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetInvWorn(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetOutfit(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetOutfitNames(const RlvCommand& rlvCmd, std::string& strReply) const;
+	ERlvCmdRet onGetPath(const RlvCommand& rlvCmd, std::string& strReply) const;
+
+	// --------------------------------
+
+	/*
+	 * Member variables
+	 */
+public:
+	typedef std::map<LLUUID, RlvObject> rlv_object_map_t;
+	typedef std::multimap<ERlvBehaviour, RlvException> rlv_exception_map_t;
+protected:
+	rlv_object_map_t      m_Objects;				// Map of objects that have active restrictions (idObj -> RlvObject)
+	rlv_exception_map_t   m_Exceptions;				// Map of currently active restriction exceptions (ERlvBehaviour -> RlvException)
+	S16                   m_Behaviours[RLV_BHVR_COUNT];
+
+	rlv_command_list_t    m_Retained;
+	RlvGCTimer*           m_pGCTimer;
+	RlvWLSnapshot*        m_pWLSnapshot;
+
+	std::stack<const RlvCommand*> m_CurCommandStack;// Convenience (see @tpto)
+	std::stack<LLUUID>    m_CurObjectStack;			// Convenience (see @tpto)
+
+	rlv_behaviour_signal_t m_OnBehaviour;
+	rlv_command_signal_t   m_OnCommand;
+	mutable std::list<RlvCommandHandler*> m_CommandHandlers;
+
+	static BOOL			  m_fEnabled;				// Use setEnabled() to toggle this
+
+	bool                  m_fCanCancelTp;			// @accepttp and @tpto
+	mutable LLVector3d    m_posSitSource;			// @standtp (mutable because onForceXXX handles are all declared as const)
+
+	friend class RlvSharedRootFetcher;				// Fetcher needs access to m_fFetchComplete
+	friend class RlvGCTimer;						// Timer clear its own point at destruction
+
+	// --------------------------------
+
+	/*
+	 * Internal access functions used by unit tests
+	 */
+public:
+	const rlv_object_map_t*    getObjectMap() const		{ return &m_Objects; }
+	//const rlv_exception_map_t* getExceptionMap() const	{ return &m_Exceptions; }
+};
+
+typedef RlvHandler rlv_handler_t;
+extern rlv_handler_t gRlvHandler;
+
+// ============================================================================
+// Inlined member functions
+//
+
+// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a
+inline void RlvHandler::addException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption)
+{
+	m_Exceptions.insert(std::pair<ERlvBehaviour, RlvException>(eBhvr, RlvException(idObj, eBhvr, varOption)));
+}
+
+// Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.0.0f
+inline bool RlvHandler::canShowHoverText(LLViewerObject *pObj) const
+{
+	return ( (!pObj) || (LL_PCODE_VOLUME != pObj->getPCode()) ||
+		    !( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTALL)) ||
+			   ( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTWORLD)) && (!pObj->isHUDAttachment()) ) ||
+			   ( (hasBehaviour(RLV_BHVR_SHOWHOVERTEXTHUD)) && (pObj->isHUDAttachment()) ) ||
+			   (isException(RLV_BHVR_SHOWHOVERTEXT, pObj->getID(), RLV_CHECK_PERMISSIVE)) ) );
+}
+
+// Checked: 2010-03-06 (RLVa-1.2.0c) | Added: RLVa-1.1.0j
+inline bool RlvHandler::canSit(LLViewerObject* pObj, const LLVector3& posOffset /*= LLVector3::zero*/) const
+{
+	// The user can sit on the specified object if:
+	//   - not prevented from sitting
+	//   - not prevented from standing up or not currently sitting
+	//   - not standtp restricted or not currently sitting (if the user is sitting and tried to sit elsewhere the tp would just kick in)
+	//   - [regular sit] not @sittp=n or @fartouch=n restricted or if they clicked on a point within 1.5m of the avie's current position
+	//   - [force sit] not @sittp=n restricted by a *different* object than the one that issued the command or the object is within 1.5m
+	return
+		( (pObj) && (LL_PCODE_VOLUME == pObj->getPCode()) ) &&
+		(!hasBehaviour(RLV_BHVR_SIT)) && 
+		( ((!hasBehaviour(RLV_BHVR_UNSIT)) && (!hasBehaviour(RLV_BHVR_STANDTP))) || 
+		  ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting())) ) &&
+		( ((NULL == getCurrentCommand() || (RLV_BHVR_SIT != getCurrentCommand()->getBehaviourType()))
+			? ((!hasBehaviour(RLV_BHVR_SITTP)) && (!hasBehaviour(RLV_BHVR_FARTOUCH)))	// [regular sit]
+			: (!hasBehaviourExcept(RLV_BHVR_SITTP, getCurrentObject()))) ||				// [force sit]
+		  (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) < 1.5f * 1.5f) );
+}
+
+// Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+inline bool RlvHandler::canStand() const
+{
+	// NOTE: return FALSE only if we're @unsit=n restricted and the avie is currently sitting on something and TRUE for everything else
+	return (!hasBehaviour(RLV_BHVR_UNSIT)) || ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting()));
+}
+
+// Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l
+inline bool RlvHandler::canTouch(LLViewerObject* pObj, const LLVector3& posOffset /*=LLVector3::zero*/) const
+{
+#ifdef RLV_EXTENSION_CMD_TOUCHXXX
+	bool fCanTouch = (pObj) && 
+		( (!hasBehaviour(RLV_BHVR_TOUCH)) || (!isException(RLV_BHVR_TOUCH, pObj->getRootEdit()->getID(), RLV_CHECK_PERMISSIVE)) );
+
+	if (fCanTouch)
+	{
+		if ( (!pObj->isAttachment()) || (!pObj->permYouOwner()) )
+		{
+			// Rezzed prim or attachment worn by another avie
+			fCanTouch = 
+				( (!hasBehaviour(RLV_BHVR_TOUCHWORLD)) ||
+				  (isException(RLV_BHVR_TOUCHWORLD, pObj->getRootEdit()->getID(), RLV_CHECK_PERMISSIVE)) ) &&
+				( (!hasBehaviour(RLV_BHVR_FARTOUCH)) || 
+				  (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) <= 1.5f * 1.5f) );
+		}
+		else if (pObj->isHUDAttachment())
+		{
+			// HUD attachment
+			fCanTouch = (!hasBehaviour(RLV_BHVR_TOUCHHUD)) || 
+				(isException(RLV_BHVR_TOUCHHUD, pObj->getRootEdit()->getID(), RLV_CHECK_PERMISSIVE));
+		}
+		else
+		{
+			// Regular attachment worn by this avie
+			fCanTouch = 
+				( (!hasBehaviour(RLV_BHVR_TOUCHATTACH)) || 
+				  (isException(RLV_BHVR_TOUCHATTACH, pObj->getRootEdit()->getID(), RLV_CHECK_PERMISSIVE)) );
+		}
+	}
+	return fCanTouch;
+#else
+	return (pObj) &&
+	  (
+		((pObj->isAttachment()) && (pObj->permYouOwner())) ||
+		( (!hasBehaviour(RLV_BHVR_FARTOUCH)) || 
+		  (dist_vec_squared(gAgent.getPositionGlobal(), pObj->getPositionGlobal() + LLVector3d(posOffset)) <= 1.5f * 1.5f) )
+	  );
+#endif // RLV_EXTENSION_CMD_TOUCHXXX
+}
+
+inline bool RlvHandler::hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption) const
+{
+	return hasBehaviourExcept(eBehaviour, strOption, LLUUID::null);
+}
+
+inline bool RlvHandler::hasBehaviourExcept(ERlvBehaviour eBehaviour, const LLUUID& idObj) const
+{
+	return hasBehaviourExcept(eBehaviour, std::string(), idObj);
+}
+
+inline bool RlvHandler::isPermissive(ERlvBehaviour eBhvr) const
+{
+	return (RlvCommand::hasStrictVariant(eBhvr)) 
+		? !((hasBehaviour(RLV_BHVR_PERMISSIVE)) || (isException(RLV_BHVR_PERMISSIVE, eBhvr, RLV_CHECK_PERMISSIVE)))
+		: true;
+}
+
+// Checked: 2009-10-04 (RLVa-1.0.4a) | Modified: RLVa-1.0.4a
+inline void RlvHandler::removeException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& varOption)
+{
+	for (rlv_exception_map_t::iterator itException = m_Exceptions.lower_bound(eBhvr), 
+			endException = m_Exceptions.upper_bound(eBhvr); itException != endException; ++itException)
+	{
+		if ( (itException->second.idObject == idObj) && (itException->second.varOption == varOption) )
+		{
+			m_Exceptions.erase(itException);
+			break;
+		}
+	}
+}
+
+// Checked: 2009-11-25 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+inline ERlvCmdRet RlvHandler::processCommand(const LLUUID& idObj, const std::string& strCommand, bool fFromObj)
+{
+	if (STATE_STARTED != LLStartUp::getStartupState())
+	{
+		m_Retained.push_back(RlvCommand(idObj, strCommand));
+		return RLV_RET_RETAINED;
+	}
+	return processCommand(RlvCommand(idObj, strCommand), fFromObj);
+}
+
+// ============================================================================
+
+#endif // RLV_HANDLER_H
diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8073e4378476c950f5de292832b5e25ba3fc0b0b
--- /dev/null
+++ b/indra/newview/rlvhelper.cpp
@@ -0,0 +1,1122 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llagentwearables.h"
+#include "llappearancemgr.h"
+#include "llgesturemgr.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llwlparammanager.h"
+
+#include "rlvhelper.h"
+#include "rlvhandler.h"
+#include "rlvinventory.h"
+
+// ============================================================================
+// RlvCommmand
+//
+
+RlvCommand::RlvBhvrTable RlvCommand::m_BhvrMap;
+
+// Checked: 2009-12-27 (RLVa-1.1.0k) | Modified: RLVa-1.1.0k
+RlvCommand::RlvCommand(const LLUUID& idObj, const std::string& strCommand)
+	: m_idObj(idObj), m_eBehaviour(RLV_BHVR_UNKNOWN), m_fStrict(false), m_eParamType(RLV_TYPE_UNKNOWN)
+{
+	if ((m_fValid = parseCommand(strCommand, m_strBehaviour, m_strOption, m_strParam)))
+	{
+		S32 nTemp = 0;
+		if ( ("n" == m_strParam) || ("add" == m_strParam) )
+			m_eParamType = RLV_TYPE_ADD;
+		else if ( ("y" == m_strParam) || ("rem" == m_strParam) )
+			m_eParamType = RLV_TYPE_REMOVE;
+		else if (m_strBehaviour == "clear")						// clear is the odd one out so just make it its own type
+			m_eParamType = RLV_TYPE_CLEAR;
+		else if ("force" == m_strParam)
+			m_eParamType = RLV_TYPE_FORCE;
+		else if (LLStringUtil::convertToS32(m_strParam, nTemp))	// Assume it's a reply command if we can convert <param> to an S32
+			m_eParamType = RLV_TYPE_REPLY;
+		else
+		{
+			m_eParamType = RLV_TYPE_UNKNOWN;
+			m_fValid = false;
+		}
+	}
+
+	if (!m_fValid)
+	{
+		m_strBehaviour = m_strOption = m_strParam = "";
+		return;
+	}
+
+	// HACK: all those @addoutfit* synonyms are rather tedious (and error-prone) to deal with so replace them their @attach* equivalent
+	if ( (RLV_TYPE_FORCE == m_eParamType) && (0 == m_strBehaviour.find("addoutfit")) )
+		m_strBehaviour.replace(0, 9, "attach");
+	m_eBehaviour = getBehaviourFromString(m_strBehaviour, &m_fStrict);
+}
+
+
+bool RlvCommand::parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption, std::string& strParam)
+{
+	// (See behaviour notes for the command parsing truth table)
+
+	// Format: <behaviour>[:<option>]=<param>
+	int idxParam  = strCommand.find('=');
+	int idxOption = (idxParam > 0) ? strCommand.find(':') : -1;
+	if (idxOption > idxParam - 1)
+		idxOption = -1;
+
+	// If <behaviour> is missing it's always an improperly formatted command
+	if ( (0 == idxOption) || (0 == idxParam) )
+		return false;
+
+	strBehaviour = strCommand.substr(0, (-1 != idxOption) ? idxOption : idxParam);
+	strOption = strParam = "";
+
+	// If <param> is missing it's an improperly formatted command
+	if ( (-1 == idxParam) || ((int)strCommand.length() - 1 == idxParam) )
+	{
+		// Unless "<behaviour> == "clear" AND (idxOption == 0)" 
+		// OR <behaviour> == "clear" AND (idxParam != 0) [see table above]
+		if ( ("clear" == strBehaviour) && ( (!idxOption) || (idxParam) ) )
+			return true;
+		return false;
+	}
+
+	if ( (-1 != idxOption) && (idxOption + 1 != idxParam) )
+		strOption = strCommand.substr(idxOption + 1, idxParam - idxOption - 1);
+	strParam = strCommand.substr(idxParam + 1);
+
+	return true;
+}
+
+// Checked: 2009-12-05 (RLVa-1.1.0h) | Added: RLVa-1.1.0h
+ERlvBehaviour RlvCommand::getBehaviourFromString(const std::string& strBhvr, bool* pfStrict /*=NULL*/)
+{
+	std::string::size_type idxStrict = strBhvr.find("_sec");
+	bool fStrict = (std::string::npos != idxStrict) && (idxStrict + 4 == strBhvr.length());
+	if (pfStrict)
+		*pfStrict = fStrict;
+
+	RLV_ASSERT(m_BhvrMap.size() > 0);
+	RlvBhvrTable::const_iterator itBhvr = m_BhvrMap.find( (!fStrict) ? strBhvr : strBhvr.substr(0, idxStrict));
+	if ( (itBhvr != m_BhvrMap.end()) && ((!fStrict) || (hasStrictVariant(itBhvr->second))) )
+		return itBhvr->second;
+	return RLV_BHVR_UNKNOWN;
+}
+
+// Checked: 2010-02-27 (RLVa-1.2.0a) | Modified: RLVa-1.1.0h
+void RlvCommand::initLookupTable()
+{
+	static bool fInitialized = false;
+	if (!fInitialized)
+	{
+		// NOTE: keep this matched with the enumeration at all times
+		std::string arBehaviours[RLV_BHVR_COUNT] =
+			{
+				"detach", "attach", "addattach", "remattach", "addoutfit", "remoutfit", "emote", "sendchat", "recvchat", "recvemote",
+				"redirchat", "rediremote", "chatwhisper", "chatnormal", "chatshout", "sendchannel", "sendim", "recvim", "permissive",
+				"notify", "showinv", "showminimap", "showworldmap", "showloc", "shownames", "showhovertext", "showhovertexthud",
+				"showhovertextworld", "showhovertextall", "tplm", "tploc", "tplure", "viewnote", "viewscript", "viewtexture", 
+				"acceptpermission", "accepttp", "allowidle", "edit", "rez", "fartouch", "interact", "touch", "touchattach", "touchhud", 
+				"touchworld", "fly", "unsit", "sit", "sittp", "standtp", "setdebug", "setenv", "detachme", "attachover", "attachthis",
+				"attachthisover", "detachthis", "attachall", "attachallover", "detachall", "attachallthis", "attachallthisover",
+				"detachallthis", "tpto", "version", "versionnew", "versionnum", "getattach", "getattachnames", 	"getaddattachnames", 
+				"getremattachnames", "getoutfit", "getoutfitnames", "getaddoutfitnames", "getremoutfitnames", "findfolder", "findfolders", 
+				"getpath", "getpathnew", "getinv", "getinvworn", "getsitid", "getstatus", "getstatusall"
+			};
+
+		for (int idxBvhr = 0; idxBvhr < RLV_BHVR_COUNT; idxBvhr++)
+			m_BhvrMap.insert(std::pair<std::string, ERlvBehaviour>(arBehaviours[idxBvhr], (ERlvBehaviour)idxBvhr));
+
+		fInitialized = true;
+	}
+}
+
+// ============================================================================
+// RlvCommandOption
+//
+
+// Checked: 2010-09-28 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+RlvCommandOptionGeneric::RlvCommandOptionGeneric(const std::string& strOption)
+{
+	LLWearableType::EType wtType(LLWearableType::WT_INVALID); LLUUID idOption; ERlvAttachGroupType eAttachGroup(RLV_ATTACHGROUP_INVALID);
+	LLViewerJointAttachment* pAttachPt = NULL; LLViewerInventoryCategory* pFolder = NULL;
+
+	if (!(m_fEmpty = strOption.empty()))														// <option> could be an empty string
+	{
+		if ((wtType = LLWearableType::typeNameToType(strOption)) != LLWearableType::WT_INVALID)
+			m_varOption = wtType;																// ... or specify a clothing layer
+		else if ((pAttachPt = RlvAttachPtLookup::getAttachPoint(strOption)) != NULL)
+			m_varOption = pAttachPt;															// ... or specify an attachment point
+		else if (idOption.set(strOption))
+			m_varOption = idOption;																// ... or specify an UUID
+		else if ((pFolder = RlvInventory::instance().getSharedFolder(strOption)) != NULL)
+			m_varOption = pFolder;																// ... or specify a shared folder path
+		else if ((eAttachGroup = rlvAttachGroupFromString(strOption)) != RLV_ATTACHGROUP_INVALID)
+			m_varOption = eAttachGroup;															// ... or specify an attachment point group
+		else
+			m_varOption = strOption;															// ... or it might just be a string
+	}
+}
+
+// Checked: 2010-09-28 (RLVa-1.2.1c) | Added: RLVa-1.2.1c
+RlvCommandOptionGetPath::RlvCommandOptionGetPath(const RlvCommand& rlvCmd)
+	: m_fValid(true)							// Assume the option will be a valid one until we find out otherwise
+{
+	// @getpath[:<option>]=<channel> => <option> is transformed to a list of inventory item UUIDs to get the path of
+
+	RlvCommandOptionGeneric rlvCmdOption(rlvCmd.getOption());
+	if (rlvCmdOption.isWearableType())			// <option> can be a clothing layer
+	{
+		LLWearableType::EType wtType = rlvCmdOption.getWearableType();
+		for (S32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(wtType); idxWearable < cntWearable; idxWearable++)
+			m_idItems.push_back(gAgentWearables.getWearableItemID(wtType, idxWearable));
+	}
+	else if (rlvCmdOption.isAttachmentPoint())	// ... or it can specify an attachment point
+	{
+		const LLViewerJointAttachment* pAttachPt = rlvCmdOption.getAttachmentPoint();
+		for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+				itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+		{
+			m_idItems.push_back((*itAttachObj)->getAttachmentItemID());
+		}
+	}
+	else if (rlvCmdOption.isEmpty())			// ... or it can be empty (in which case we act on the object that issued the command)
+	{
+		const LLViewerObject* pObj = gObjectList.findObject(rlvCmd.getObjectID());
+		if ( (pObj) || (pObj->isAttachment()) )
+			m_idItems.push_back(pObj->getAttachmentItemID());
+	}
+	else										// ... but anything else isn't a valid option
+	{
+		m_fValid = false;
+	}
+}
+
+// =========================================================================
+// RlvObject
+//
+
+RlvObject::RlvObject(const LLUUID& idObj) : m_UUID(idObj), m_nLookupMisses(0)
+{ 
+	LLViewerObject* pObj = gObjectList.findObject(idObj);
+	m_fLookup = (NULL != pObj);
+	m_idxAttachPt = (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getState()) : 0;
+	m_idRoot = (pObj) ? pObj->getRootEdit()->getID() : LLUUID::null;
+}
+
+bool RlvObject::addCommand(const RlvCommand& rlvCmd)
+{
+	RLV_ASSERT(RLV_TYPE_ADD == rlvCmd.getParamType());
+
+	// Don't add duplicate commands for this object (ie @detach=n followed by another @detach=n later on)
+	for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
+	{
+		if ( (itCmd->getBehaviour() == rlvCmd.getBehaviour()) && (itCmd->getOption() == rlvCmd.getOption()) && 
+			 (itCmd->isStrict() == rlvCmd.isStrict() ) )
+		{
+			return false;
+		}
+	}
+
+	// Now that we know it's not a duplicate, add it to the end of the list
+	m_Commands.push_back(rlvCmd);
+
+	return true;
+}
+
+bool RlvObject::removeCommand(const RlvCommand& rlvCmd)
+{
+	RLV_ASSERT(RLV_TYPE_REMOVE == rlvCmd.getParamType());
+
+	for (rlv_command_list_t::iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
+	{
+		//if (*itCmd == rlvCmd) <- commands will never be equal since one is an add and the other is a remove *rolls eyes*
+		if ( (itCmd->getBehaviour() == rlvCmd.getBehaviour()) && (itCmd->getOption() == rlvCmd.getOption()) && 
+			 (itCmd->isStrict() == rlvCmd.isStrict() ) )
+		{
+			m_Commands.erase(itCmd);
+			return true;
+		}
+	}
+	return false;	// Command was never added so nothing to remove now
+}
+
+bool RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, bool fStrictOnly) const
+{
+	for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
+		if ( (itCmd->getBehaviourType() == eBehaviour) && (itCmd->getOption().empty()) && ((!fStrictOnly) || (itCmd->isStrict())) )
+			return true;
+	return false;
+}
+
+bool RlvObject::hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption, bool fStrictOnly) const
+{
+	for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
+		if ( (itCmd->getBehaviourType() == eBehaviour) && (itCmd->getOption() == strOption) && ((!fStrictOnly) || (itCmd->isStrict())) )
+			return true;
+	return false;
+}
+
+// Checked: 2009-11-27 (RLVa-1.1.0f) | Modified: RLVa-1.1.0f
+std::string RlvObject::getStatusString(const std::string& strMatch) const
+{
+	std::string strStatus, strCmd;
+
+	for (rlv_command_list_t::const_iterator itCmd = m_Commands.begin(); itCmd != m_Commands.end(); ++itCmd)
+	{
+		strCmd = itCmd->asString();
+		if ( (strMatch.empty()) || (std::string::npos != strCmd.find(strMatch)) )
+		{
+			strStatus.push_back('/');
+			strStatus += strCmd;
+		}
+	}
+
+	return strStatus;
+}
+
+// ============================================================================
+// RlvForceWear
+//
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+bool RlvForceWear::isWearingItem(const LLInventoryItem* pItem)
+{
+	if (pItem)
+	{
+		switch (pItem->getActualType())
+		{
+			case LLAssetType::AT_BODYPART:
+			case LLAssetType::AT_CLOTHING:
+				return gAgentWearables.isWearingItem(pItem->getUUID());
+			case LLAssetType::AT_OBJECT:
+				return (isAgentAvatarValid()) && (gAgentAvatarp->isWearingAttachment(pItem->getUUID()));
+			case LLAssetType::AT_GESTURE:
+				return LLGestureMgr::instance().isGestureActive(pItem->getUUID());
+			case LLAssetType::AT_LINK:
+				return isWearingItem(gInventory.getItem(pItem->getLinkedUUID()));
+			default:
+				break;
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-03-21 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvForceWear::forceFolder(const LLViewerInventoryCategory* pFolder, EWearAction eAction, EWearFlags eFlags)
+{
+	// [See LLWearableBridge::wearOnAvatar(): don't wear anything until initial wearables are loaded, can destroy clothing items]
+	if (!gAgentWearables.areWearablesLoaded())
+	{
+		LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded");
+		return;
+	}
+	if (!isAgentAvatarValid())
+		return;
+
+	// Grab a list of all the items we'll be wearing/attaching
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+	RlvWearableItemCollector f(pFolder->getUUID(), isWearAction(eAction), (eFlags & FLAG_MATCHALL));
+	gInventory.collectDescendentsIf(pFolder->getUUID(), folders, items, FALSE, f);
+
+	for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++)
+	{
+		LLViewerInventoryItem* pRlvItem = items.get(idxItem);
+		LLViewerInventoryItem* pItem = (LLAssetType::AT_LINK == pRlvItem->getActualType()) ? pRlvItem->getLinkedItem() : pRlvItem;
+
+		// If it's wearable it should be worn on detach
+//		if ( (ACTION_DETACH == eAction) && (isWearableItem(pItem)) && (!isWearingItem(pItem)) )
+//			continue;
+
+		//  NOTES: * if there are composite items then RlvWearableItemCollector made sure they can be worn (or taken off depending)
+		//         * some scripts issue @remattach=force,attach:worn-items=force so we need to attach items even if they're currently worn
+		switch (pItem->getType())
+		{
+			case LLAssetType::AT_BODYPART:
+				RLV_ASSERT(isWearAction(eAction));	// RlvWearableItemCollector shouldn't be supplying us with body parts on detach
+			case LLAssetType::AT_CLOTHING:
+				if (isWearAction(eAction))
+				{
+					// The check for whether we're replacing a currently worn composite item happens in onWearableArrived()
+					if (!isAddWearable(pItem))
+						addWearable(pRlvItem, eAction);
+				}
+				else
+				{
+					const LLWearable* pWearable = gAgentWearables.getWearableFromItemID(pItem->getUUID());
+					if ( (pWearable) && (isForceRemovable(pWearable, false)) )
+						remWearable(pWearable);
+				}
+				break;
+
+			case LLAssetType::AT_OBJECT:
+				if (isWearAction(eAction))
+				{
+					if ( (gRlvAttachmentLocks.canAttach(pRlvItem)) || (RlvSettings::getEnableSharedWear()) )
+					{
+						if (!isAddAttachment(pRlvItem))
+						{
+							#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+							// We still need to check whether we're about to replace a currently worn composite item
+							// (which we're not if we're just reattaching an attachment we're already wearing)
+							LLViewerInventoryCategory* pCompositeFolder = NULL;
+							if ( (pAttachPt->getObject()) && (RlvSettings::getEnableComposites()) && 
+								 (pAttachPt->getItemID() != pItem->getUUID()) &&
+								 (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pCompositeFolder)) )
+							{
+								// If we can't take off the composite folder this item would replace then don't allow it to get attached
+								if (gRlvHandler.canTakeOffComposite(pCompositeFolder))
+								{
+									forceFolder(pCompositeFolder, ACTION_DETACH, FLAG_DEFAULT);
+									addAttachment(pRlvItem);
+								}
+							}
+							else
+							#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+							{
+								addAttachment(pRlvItem, eAction);
+							}
+						}
+					}
+				}
+				else
+				{
+					const LLViewerObject* pAttachObj = gAgentAvatarp->getWornAttachment(pItem->getUUID());
+					if ( (pAttachObj) && (isForceDetachable(pAttachObj, false)) )
+						remAttachment(pAttachObj);
+				}
+				break;
+
+			#ifdef RLV_EXTENSION_FORCEWEAR_GESTURES
+			case LLAssetType::AT_GESTURE:
+				if (isWearAction(eAction))
+				{
+					if (std::find_if(m_addGestures.begin(), m_addGestures.end(), RlvPredIsEqualOrLinkedItem(pRlvItem)) == m_addGestures.end())
+						m_addGestures.push_back(pRlvItem);
+				}
+				else
+				{
+					if (std::find_if(m_remGestures.begin(), m_remGestures.end(), RlvPredIsEqualOrLinkedItem(pRlvItem)) == m_remGestures.end())
+						m_remGestures.push_back(pRlvItem);
+				}
+				break;
+			#endif // RLV_EXTENSION_FORCEWEAR_GESTURES
+
+			default:
+				break;
+		}
+	}
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+bool RlvForceWear::isForceDetachable(const LLViewerObject* pAttachObj, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/)
+{
+	// Attachment can be detached by an RLV command if:
+	//   - it's not "remove locked" by anything (or anything except the object specified by pExceptObj)
+	//   - it's strippable
+	//   - composite folders are disabled *or* it isn't part of a composite folder that has at least one item locked
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	LLViewerInventoryCategory* pFolder = NULL;
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	return 
+	  (
+	    (pAttachObj) && (pAttachObj->isAttachment())
+		&& ( (idExcept.isNull()) ? (!gRlvAttachmentLocks.isLockedAttachment(pAttachObj))
+								 : (!gRlvAttachmentLocks.isLockedAttachmentExcept(pAttachObj, idExcept)) )
+		#ifdef RLV_EXTENSION_FLAG_NOSTRIP
+		&& (isStrippable(pAttachObj->getAttachmentItemID()))
+		#endif // RLV_EXTENSION_FLAG_NOSTRIP
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		&& ( (!fCheckComposite) || (!RlvSettings::getEnableComposites()) || 
+		     (!gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) || (gRlvHandler.canTakeOffComposite(pFolder)) )
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	  );
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+bool RlvForceWear::isForceDetachable(const LLViewerJointAttachment* pAttachPt, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/)
+{
+	// Attachment point can be detached by an RLV command if there's at least one attachment that can be removed
+	for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+			itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+	{
+		if (isForceDetachable(*itAttachObj, fCheckComposite, idExcept))
+			return true;
+	}
+	return false;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.1.0i
+void RlvForceWear::forceDetach(const LLViewerObject* pAttachObj)
+{
+	// Sanity check - no need to process duplicate removes
+	if ( (!pAttachObj) || (isRemAttachment(pAttachObj)) )
+		return;
+
+	if (isForceDetachable(pAttachObj))
+	{
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		LLViewerInventoryCategory* pFolder = NULL;
+		if ( (RlvSettings::getEnableComposites()) && 
+			 (gRlvHandler.getCompositeInfo(pAttachPt->getItemID(), NULL, &pFolder)) )
+		{
+			// Attachment belongs to a composite folder so detach the entire folder (if we can take it off)
+			if (gRlvHandler.canTakeOffComposite(pFolder))
+				forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT);
+		}
+		else
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		{
+			remAttachment(pAttachObj);
+		}
+	}
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvForceWear::forceDetach(const LLViewerJointAttachment* pAttachPt)
+{
+	for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+			itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+	{
+		forceDetach(*itAttachObj);
+	}
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+bool RlvForceWear::isForceRemovable(const LLWearable* pWearable, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/)
+{
+	// Wearable can be removed by an RLV command if:
+	//   - its asset type is AT_CLOTHING
+	//   - it's not "remove locked" by anything (or anything except the object specified by idExcept)
+	//   - it's strippable
+	//   - composite folders are disabled *or* it isn't part of a composite folder that has at least one item locked
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	LLViewerInventoryCategory* pFolder = NULL;
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	return 
+	  (
+		(pWearable) && (LLAssetType::AT_CLOTHING == pWearable->getAssetType()) 
+		&& ( (idExcept.isNull()) ? !gRlvWearableLocks.isLockedWearable(pWearable)
+		                         : !gRlvWearableLocks.isLockedWearableExcept(pWearable, idExcept) )
+		#ifdef RLV_EXTENSION_FLAG_NOSTRIP
+		&& (isStrippable(pWearable->getItemID()))
+		#endif // RLV_EXTENSION_FLAG_NOSTRIP
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		&& ( (!fCheckComposite) || (!RlvSettings::getEnableComposites()) || 
+		     (!gRlvHandler.getCompositeInfo(pWearable->getItemID(), NULL, &pFolder)) || (gRlvHandler.canTakeOffComposite(pFolder)) )
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	  );
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+bool RlvForceWear::isForceRemovable(LLWearableType::EType wtType, bool fCheckComposite /*=true*/, const LLUUID& idExcept /*=LLUUID::null*/)
+{
+	// Wearable type can be removed by an RLV command if there's at least one currently worn wearable that can be removed
+	for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(wtType); idxWearable < cntWearable; idxWearable++)
+		if (isForceRemovable(gAgentWearables.getWearable(wtType, idxWearable), fCheckComposite, idExcept))
+			return true;
+	return false;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvForceWear::forceRemove(const LLWearable* pWearable)
+{
+	// Sanity check - no need to process duplicate removes
+	if ( (!pWearable) || (isRemWearable(pWearable)) )
+		return;
+
+	if (isForceRemovable(pWearable))
+	{
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		LLViewerInventoryCategory* pFolder = NULL;
+		if ( (RlvSettings::getEnableComposites()) && 
+			 (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(wtType), NULL, &pFolder)) )
+		{
+			// Wearable belongs to a composite folder so detach the entire folder (if we can take it off)
+			if (gRlvHandler.canTakeOffComposite(pFolder))
+				forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT);
+		}
+		else
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		{
+			remWearable(pWearable);
+		}
+	}
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvForceWear::forceRemove(LLWearableType::EType wtType)
+{
+	for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(wtType); idxWearable < cntWearable; idxWearable++)
+		forceRemove(gAgentWearables.getWearable(wtType, idxWearable));
+}
+
+#ifdef RLV_EXTENSION_FLAG_NOSTRIP
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+bool RlvForceWear::isStrippable(const LLInventoryItem* pItem)
+{
+	// An item is exempt from @detach or @remoutfit if:
+	//   - its name contains "nostrip" (anywhere in the name)
+	//   - its parent folder contains "nostrip" (anywhere in the name)
+	if (pItem)
+	{
+		// If the item is an inventory link then we first examine its target before examining the link itself (and never its name)
+		if (LLAssetType::AT_LINK == pItem->getActualType())
+		{
+			if (!isStrippable(pItem->getLinkedUUID()))
+				return false;
+		}
+		else
+		{
+			if (std::string::npos != pItem->getName().find(RLV_FOLDER_FLAG_NOSTRIP))
+				return false;
+		}
+
+		LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID());
+		while ( (pFolder) && (gInventory.getRootFolderID() != pFolder->getParentUUID()) )
+		{
+			if (std::string::npos != pFolder->getName().find(RLV_FOLDER_FLAG_NOSTRIP))
+				return false;
+			// If the item's parent is a folded folder then we need to check its parent as well
+			pFolder = 
+				(RlvInventory::isFoldedFolder(pFolder, true)) ? gInventory.getCategory(pFolder->getParentUUID()) : NULL;
+		}
+	}
+	return true;
+}
+#endif // RLV_EXTENSION_FLAG_NOSTRIP
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvForceWear::addAttachment(const LLViewerInventoryItem* pItem, EWearAction eAction)
+{
+	// Remove it from 'm_remAttachments' if it's queued for detaching
+	const LLViewerObject* pAttachObj = (isAgentAvatarValid()) ? gAgentAvatarp->getWornAttachment(pItem->getLinkedUUID()) : NULL;
+	if ( (pAttachObj) && (isRemAttachment(pAttachObj)) )
+		m_remAttachments.erase(std::remove(m_remAttachments.begin(), m_remAttachments.end(), pAttachObj), m_remAttachments.end());
+
+	S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pItem, true);
+	if (ACTION_WEAR_ADD == eAction)
+	{
+		// Insert it at the back if it's not already there
+		idxAttachPt |= ATTACHMENT_ADD;
+		if (!isAddAttachment(pItem))
+		{
+			addattachments_map_t::iterator itAddAttachments = m_addAttachments.find(idxAttachPt);
+			if (itAddAttachments == m_addAttachments.end())
+			{
+				m_addAttachments.insert(addattachment_pair_t(idxAttachPt, LLInventoryModel::item_array_t()));
+				itAddAttachments = m_addAttachments.find(idxAttachPt);
+			}
+			itAddAttachments->second.push_back((LLViewerInventoryItem*)pItem);
+		}
+	}
+	else if (ACTION_WEAR_REPLACE == eAction)
+	{
+		// Replace all pending attachments on this attachment point with the specified item (don't clear if it's the default attach point)
+		addattachments_map_t::iterator itAddAttachments = m_addAttachments.find(idxAttachPt | ATTACHMENT_ADD);
+		if ( (0 != idxAttachPt) && (itAddAttachments != m_addAttachments.end()) )
+			itAddAttachments->second.clear();
+
+		itAddAttachments = m_addAttachments.find(idxAttachPt);
+		if (itAddAttachments == m_addAttachments.end())
+		{
+			m_addAttachments.insert(addattachment_pair_t(idxAttachPt, LLInventoryModel::item_array_t()));
+			itAddAttachments = m_addAttachments.find(idxAttachPt);
+		}
+
+		if (0 != idxAttachPt)
+			itAddAttachments->second.clear();
+		itAddAttachments->second.push_back((LLViewerInventoryItem*)pItem);
+	}
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvForceWear::remAttachment(const LLViewerObject* pAttachObj)
+{
+	// Remove it from 'm_addAttachments' if it's queued for attaching
+	const LLViewerInventoryItem* pItem = (pAttachObj->isAttachment()) ? gInventory.getItem(pAttachObj->getAttachmentItemID()) : NULL;
+	if (pItem)
+	{
+		addattachments_map_t::iterator itAddAttachments = m_addAttachments.begin();
+		while (itAddAttachments != m_addAttachments.end())
+		{
+			LLInventoryModel::item_array_t& wearItems = itAddAttachments->second;
+			if (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end())
+				wearItems.erase(std::remove_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), wearItems.end());
+
+			if (wearItems.empty())
+				m_addAttachments.erase(itAddAttachments++);
+			else
+				++itAddAttachments;
+		}
+	}
+
+	// Add it to 'm_remAttachments' if it's not already there
+	if (!isRemAttachment(pAttachObj))
+		m_remAttachments.push_back(pAttachObj);
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvForceWear::addWearable(const LLViewerInventoryItem* pItem, EWearAction eAction)
+{
+	const LLWearable* pWearable = gAgentWearables.getWearableFromItemID(pItem->getLinkedUUID());
+	// When replacing remove all currently worn wearables of this type *unless* the item is currently worn
+	if ( (ACTION_WEAR_REPLACE == eAction) && (!pWearable) )
+		forceRemove(pItem->getWearableType());
+	// Remove it from 'm_remWearables' if it's pending removal
+	if ( (pWearable) && (isRemWearable(pWearable)) )
+		m_remWearables.erase(std::remove(m_remWearables.begin(), m_remWearables.end(), pWearable), m_remWearables.end());
+
+	addwearables_map_t::iterator itAddWearables = m_addWearables.find(pItem->getWearableType());
+	if (itAddWearables == m_addWearables.end())
+	{
+		m_addWearables.insert(addwearable_pair_t(pItem->getWearableType(), LLInventoryModel::item_array_t()));
+		itAddWearables = m_addWearables.find(pItem->getWearableType());
+	}
+
+	if (ACTION_WEAR_ADD == eAction)				// Add it at the back if it's not already there
+	{
+		if (!isAddWearable(pItem))
+			itAddWearables->second.push_back((LLViewerInventoryItem*)pItem);
+	}
+	else if (ACTION_WEAR_REPLACE == eAction)	// Replace all pending wearables of this type with the specified item
+	{
+		itAddWearables->second.clear();
+		itAddWearables->second.push_back((LLViewerInventoryItem*)pItem);
+	}
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+void RlvForceWear::remWearable(const LLWearable* pWearable)
+{
+	// Remove it from 'm_addWearables' if it's queued for wearing
+	const LLViewerInventoryItem* pItem = gInventory.getItem(pWearable->getItemID());
+	if ( (pItem) && (isAddWearable(pItem)) )
+	{
+		addwearables_map_t::iterator itAddWearables = m_addWearables.find(pItem->getWearableType());
+
+		LLInventoryModel::item_array_t& wearItems = itAddWearables->second;
+		wearItems.erase(std::remove_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), wearItems.end());
+		if (wearItems.empty())
+			m_addWearables.erase(itAddWearables);
+	}
+
+	// Add it to 'm_remWearables' if it's not already there
+	if (!isRemWearable(pWearable))
+		m_remWearables.push_back(pWearable);
+}
+
+// Checked: 2010-03-22 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvForceWear::done()
+{
+	// Sanity check - don't go through all the motions below only to find out there's nothing to actually do
+	if ( (m_remWearables.empty()) && (m_remAttachments.empty()) && (m_remGestures.empty()) &&
+		 (m_addWearables.empty()) && (m_addAttachments.empty()) && (m_addGestures.empty()) )
+	{
+		return;
+	}
+
+	LLAppearanceMgr* pAppearanceMgr = LLAppearanceMgr::getInstance();
+	bool fUpdateAppearance = false;
+	
+	//
+	// Process removals
+	//
+
+	// Wearables
+	if (m_remWearables.size())
+	{
+		for (std::list<const LLWearable*>::const_iterator itWearable = m_remWearables.begin(); itWearable != m_remWearables.end(); ++itWearable)
+			pAppearanceMgr->removeCOFItemLinks((*itWearable)->getItemID(), false);
+		m_remWearables.clear();
+		fUpdateAppearance = true;
+	}
+
+	// Gestures
+	if (m_remGestures.size())
+	{
+		for (S32 idxItem = 0, cntItem = m_remGestures.count(); idxItem < cntItem; idxItem++)
+			pAppearanceMgr->removeCOFItemLinks(m_remGestures.get(idxItem)->getUUID(), false);
+		m_remGestures.clear();
+		fUpdateAppearance = true;
+	}
+
+	// Attachments
+	if (m_remAttachments.size())
+	{
+		// Don't bother with COF if all we're doing is detaching some attachments (keeps people from rebaking on every @remattach=force)
+		fUpdateAppearance = (fUpdateAppearance) || (!m_addWearables.empty()) || (!m_addAttachments.empty()) || (!m_addGestures.empty());
+		if (!fUpdateAppearance)
+		{
+			gMessageSystem->newMessage("ObjectDetach");
+			gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+			gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+			gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+			for (std::list<const LLViewerObject*>::const_iterator itAttachObj = m_remAttachments.begin(); 
+					itAttachObj != m_remAttachments.end(); ++itAttachObj)
+			{
+				gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+				gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, (*itAttachObj)->getLocalID());
+			}
+
+			gMessageSystem->sendReliable(gAgent.getRegionHost());
+		}
+
+		for (std::list<const LLViewerObject*>::const_iterator itAttachObj = m_remAttachments.begin(); 
+				itAttachObj != m_remAttachments.end(); ++itAttachObj)
+		{
+			pAppearanceMgr->removeCOFItemLinks((*itAttachObj)->getAttachmentItemID(), false);
+		}
+
+		m_remAttachments.clear();
+	}
+
+	//
+	// Process additions
+	//
+
+	// Wearables need to be split into AT_BODYPART and AT_CLOTHING for COF
+	LLInventoryModel::item_array_t addBodyParts, addClothing;
+	for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.begin(); itAddWearables != m_addWearables.end(); ++itAddWearables)
+	{
+		const LLInventoryModel::item_array_t& wearItems = itAddWearables->second;
+		for (S32 idxItem = 0, cntItem = wearItems.count(); idxItem < cntItem; idxItem++)
+		{
+			LLViewerInventoryItem* pItem = wearItems.get(idxItem);
+			if (!pAppearanceMgr->isLinkInCOF(pItem->getUUID()))		// It's important to examine COF here and *not* gAgentWearables
+			{
+				if (LLAssetType::AT_BODYPART == pItem->getType())
+					addBodyParts.push_back(pItem);
+				else
+					addClothing.push_back(pItem);
+			}
+		}
+	}
+	m_addWearables.clear();
+
+	// Until LL provides a way for updateCOF to selectively attach add/replace we have to deal with attachments ourselves
+	if (m_addAttachments.size())
+	{
+		for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.begin(); 
+				itAddAttachments != m_addAttachments.end(); ++itAddAttachments)
+		{
+			const LLInventoryModel::item_array_t& wearItems = itAddAttachments->second;
+			for (S32 idxItem = 0, cntItem = wearItems.count(); idxItem < cntItem; idxItem++)
+			{
+				const LLUUID& idItem = wearItems.get(idxItem)->getLinkedUUID();
+				if (gAgentAvatarp->attachmentWasRequested(idItem))
+					continue;
+				gAgentAvatarp->addAttachmentRequest(idItem);
+
+				LLSD payload;
+				payload["item_id"] = idItem;
+				payload["attachment_point"] = itAddAttachments->first;
+				LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/);
+			}
+		}
+		m_addAttachments.clear();
+	}
+
+	// If there are additions we need to call LLAppearanceManager::updateCOF(), otherwise LLAppearanceManager::updateAppearanceFromCOF()
+	if ( (!addBodyParts.empty()) || (!addClothing.empty()) || (!m_addGestures.empty()) )
+	{
+		pAppearanceMgr->updateCOF(addBodyParts, addClothing, LLInventoryModel::item_array_t(), m_addGestures, true);
+
+		m_addGestures.clear();
+	}
+	else if (fUpdateAppearance)
+	{
+		pAppearanceMgr->updateAppearanceFromCOF();
+	}
+
+	// Since RlvForceWear is a singleton now we want to be sure there aren't any leftovers
+	RLV_ASSERT( (m_remWearables.empty()) && (m_remAttachments.empty()) && (m_remGestures.empty()) );
+	RLV_ASSERT( (m_addWearables.empty()) && (m_addAttachments.empty()) && (m_addGestures.empty()) );
+}
+
+// Checked: 2010-02-17 (RLVa-1.1.0o) | Modified: RLVa-1.1.0o
+/*
+void RlvForceWear::onWearableArrived(LLWearable* pWearable, void* pParam)
+{
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	// If this wearable will end up replacing a currently worn one that belongs to a composite folder then we need to detach the composite
+	LLViewerInventoryCategory* pFolder = NULL;
+	if ( (RlvSettings::getEnableComposites()) && (pWearable) && (gAgent.getWearable(pWearable->getType())) )
+	{
+		// If we're just rewearing the same item we're already wearing then we're not replacing a composite folder
+		LLWearableHoldingPattern* pWearData = (LLWearableHoldingPattern*)pParam; LLUUID idItem;
+		for (LLWearableHoldingPattern::found_list_t::const_iterator itWearable = pWearData->mFoundList.begin();
+				itWearable != pWearData->mFoundList.end(); ++itWearable)
+		{
+			LLFoundData* pFound = *itWearable;
+			if (pWearable->getID() == pFound->mAssetID)
+			{
+				idItem = pFound->mItemID;
+				break;
+			}
+		}
+		if ( (idItem.notNull()) && (idItem != gAgent.getWearableItem(pWearable->getType())) && 
+			 (gRlvHandler.getCompositeInfo(gAgent.getWearableItem(pWearable->getType()), NULL, &pFolder)) )
+		{
+			RlvForceWear rlvWear;
+			rlvWear.forceFolder(pFolder, ACTION_DETACH, FLAG_DEFAULT);
+			rlvWear.done();
+		}
+	}
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+	wear_inventory_category_on_avatar_loop(pWearable, pParam);
+}
+*/
+
+// ============================================================================
+// RlvBehaviourNotifyObserver
+//
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+RlvBehaviourNotifyHandler::RlvBehaviourNotifyHandler()
+{
+	// NOTE: the reason we use rlv_command_signal_t instead of the better-suited rlv_behaviour_signal_t is because
+	//       RLV will notify scripts about "invalid" commands so we need to as well
+	m_ConnCommand = gRlvHandler.setCommandCallback(boost::bind(&RlvBehaviourNotifyHandler::onCommand, this, _1, _2, _3));
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvBehaviourNotifyHandler::onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet, bool fInternal)
+{
+	if (fInternal)
+		return;
+
+	std::string strCmd = rlvCmd.asString(), strNotify; ERlvParamType eCmdType = rlvCmd.getParamType();
+	if ( (RLV_TYPE_ADD == eCmdType) || (RLV_TYPE_REMOVE == eCmdType) )
+		strNotify = llformat("/%s=%s", strCmd.c_str(), rlvCmd.getParam().c_str());
+	else if (RLV_TYPE_CLEAR == eCmdType)
+		strNotify = llformat("/%s", strCmd.c_str());
+	else
+		return;
+
+	for (std::multimap<LLUUID, notifyData>::const_iterator itNotify = m_Notifications.begin(); 
+			itNotify != m_Notifications.end(); ++itNotify)
+	{
+		if ( (itNotify->second.strFilter.empty()) || (std::string::npos != strCmd.find(itNotify->second.strFilter)) )
+			RlvUtil::sendChatReply(itNotify->second.nChannel, strNotify);
+	}
+}
+
+// ============================================================================
+// RlvWLSnapshot
+//
+
+// Checked: 2010-03-18 (RLVa-1.2.0e) | Added: RLVa-0.2.0h
+void RlvWLSnapshot::restoreSnapshot(const RlvWLSnapshot* pWLSnapshot)
+{
+	LLWLParamManager* pWLParams = LLWLParamManager::instance();
+	if ( (pWLSnapshot) && (pWLParams) )
+	{
+		pWLParams->mAnimator.mIsRunning = pWLSnapshot->fIsRunning;
+		pWLParams->mAnimator.mUseLindenTime = pWLSnapshot->fUseLindenTime;
+		pWLParams->mCurParams = pWLSnapshot->WLParams;
+		pWLParams->propagateParameters();
+	}
+}
+
+// Checked: 2010-03-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+RlvWLSnapshot* RlvWLSnapshot::takeSnapshot()
+{
+	RlvWLSnapshot* pWLSnapshot = NULL;
+	LLWLParamManager* pWLParams = LLWLParamManager::instance();
+	if (pWLParams)
+	{
+		pWLSnapshot = new RlvWLSnapshot();
+		pWLSnapshot->fIsRunning = pWLParams->mAnimator.mIsRunning;
+		pWLSnapshot->fUseLindenTime = pWLParams->mAnimator.mUseLindenTime;
+		pWLSnapshot->WLParams = pWLParams->mCurParams;
+	}
+	return pWLSnapshot;
+}
+
+// =========================================================================
+// Various helper classes/timers/functors
+//
+
+// Checked: 2010-03-13 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+BOOL RlvGCTimer::tick()
+{
+	bool fContinue = gRlvHandler.onGC();
+	if (!fContinue)
+		gRlvHandler.m_pGCTimer = NULL;
+	return !fContinue;
+}
+
+// ============================================================================
+// Various helper functions
+//
+
+// Checked: 2010-04-11 (RLVa-1.2.0b) | Modified: RLVa-0.2.0g
+bool rlvCanDeleteOrReturn()
+{
+	bool fIsAllowed = true;
+
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ))
+	{
+		// We'll allow if none of the prims are owned by the avie or group owned
+		LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection();
+		RlvSelectIsOwnedByOrGroupOwned f(gAgent.getID());
+		if ( (handleSel.notNull()) && ((0 == handleSel->getRootObjectCount()) || (NULL != handleSel->getFirstRootNode(&f, FALSE))) )
+			fIsAllowed = false;
+	}
+	
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) && (isAgentAvatarValid()) )
+	{
+		// We'll allow if the avie isn't sitting on any of the selected objects
+		LLObjectSelectionHandle handleSel = LLSelectMgr::getInstance()->getSelection();
+		RlvSelectIsSittingOn f(gAgentAvatarp->getRoot());
+		if ( (handleSel.notNull()) && (handleSel->getFirstRootNode(&f, TRUE)) )
+			fIsAllowed = false;
+	}
+
+	return fIsAllowed;
+}
+
+// ============================================================================
+// Attachment group helper functions
+//
+
+// Has to match the order of ERlvAttachGroupType
+const std::string cstrAttachGroups[RLV_ATTACHGROUP_COUNT] = { "head", "torso", "arms", "legs", "hud" };
+
+// Checked: 2009-10-19 (RLVa-1.1.0e) | Added: RLVa-1.1.0e
+ERlvAttachGroupType rlvAttachGroupFromIndex(S32 idxGroup)
+{
+	switch (idxGroup)
+	{
+		case 0: // Right Hand
+		case 1: // Right Arm
+		case 3: // Left Arm
+		case 4: // Left Hand
+			return RLV_ATTACHGROUP_ARMS;
+		case 2: // Head
+			return RLV_ATTACHGROUP_HEAD;
+		case 5: // Left Leg
+		case 7: // Right Leg
+			return RLV_ATTACHGROUP_LEGS;
+		case 6: // Torso
+			return RLV_ATTACHGROUP_TORSO;
+		case 8: // HUD
+			return RLV_ATTACHGROUP_HUD;
+		default:
+			return RLV_ATTACHGROUP_INVALID;
+	}
+}
+
+// Checked: 2009-10-19 (RLVa-1.1.0e) | Added: RLVa-1.1.0e
+ERlvAttachGroupType rlvAttachGroupFromString(const std::string& strGroup)
+{
+	for (int idx = 0; idx < RLV_ATTACHGROUP_COUNT; idx++)
+		if (cstrAttachGroups[idx] == strGroup)
+			return (ERlvAttachGroupType)idx;
+	return RLV_ATTACHGROUP_INVALID;
+}
+
+// =========================================================================
+// String helper functions
+//
+
+// Checked: 2009-07-04 (RLVa-1.0.0a)
+void rlvStringReplace(std::string& strText, std::string strFrom, const std::string& strTo)
+{
+	if (strFrom.empty())
+		return;
+
+	size_t lenFrom = strFrom.length();
+	size_t lenTo = strTo.length();
+
+	std::string strTemp(strText);
+	LLStringUtil::toLower(strTemp);
+	LLStringUtil::toLower(strFrom);
+
+	std::string::size_type idxCur, idxStart = 0, idxOffset = 0;
+	while ( (idxCur = strTemp.find(strFrom, idxStart)) != std::string::npos)
+	{
+		strText.replace(idxCur + idxOffset, lenFrom, strTo);
+		idxStart = idxCur + lenFrom;
+		idxOffset += lenTo - lenFrom;
+	}
+}
+
+// Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b
+std::string rlvGetFirstParenthesisedText(const std::string& strText, std::string::size_type* pidxMatch /*=NULL*/)
+{
+	if (pidxMatch)
+		*pidxMatch = std::string::npos;	// Assume we won't find anything
+
+	std::string::size_type idxIt, idxStart; int cntLevel = 1;
+	if ((idxStart = strText.find_first_of('(')) == std::string::npos)
+		return std::string();
+
+	const char* pstrText = strText.c_str(); idxIt = idxStart;
+	while ( (cntLevel > 0) && (idxIt < strText.length()) )
+	{
+		if ('(' == pstrText[++idxIt])
+			cntLevel++;
+		else if (')' == pstrText[idxIt])
+			cntLevel--;
+	}
+
+	if (idxIt < strText.length())
+	{
+		if (pidxMatch)
+			*pidxMatch = idxStart;	// Return the character index of the starting '('
+		return strText.substr(idxStart + 1, idxIt - idxStart - 1);
+	}
+	return std::string();
+}
+
+// Checked: 2009-07-29 (RLVa-1.0.1b) | Added: RLVa-1.0.1b
+std::string rlvGetLastParenthesisedText(const std::string& strText, std::string::size_type* pidxStart /*=NULL*/)
+{
+	if (pidxStart)
+		*pidxStart = std::string::npos;	// Assume we won't find anything
+
+	// Extracts the last - matched - parenthesised text from the input string
+	std::string::size_type idxIt, idxEnd; int cntLevel = 1;
+	if ((idxEnd = strText.find_last_of(')')) == std::string::npos)
+		return std::string();
+
+	const char* pstrText = strText.c_str(); idxIt = idxEnd;
+	while ( (cntLevel > 0) && (idxIt >= 0) )
+	{
+		if (')' == pstrText[--idxIt])
+			cntLevel++;
+		else if ('(' == pstrText[idxIt])
+			cntLevel--;
+	}
+
+	if ( (idxIt >= 0) && (idxIt < strText.length()) )	// NOTE: allow for std::string::size_type to be signed or unsigned
+	{
+		if (pidxStart)
+			*pidxStart = idxIt;		// Return the character index of the starting '('
+		return strText.substr(idxIt + 1, idxEnd - idxIt - 1);
+	}
+	return std::string();
+}
+
+// =========================================================================
diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h
new file mode 100644
index 0000000000000000000000000000000000000000..ade4b58b161e00647910a0e7af8e9bbed13c003b
--- /dev/null
+++ b/indra/newview/rlvhelper.h
@@ -0,0 +1,453 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_HELPER_H
+#define RLV_HELPER_H
+
+#include "lleventtimer.h"
+#include "llwlparamset.h"
+
+#include "rlvdefines.h"
+#include "rlvcommon.h"
+
+#ifdef LL_WINDOWS
+	#pragma warning (push)
+	#pragma warning (disable : 4702) // warning C4702: unreachable code
+#endif
+#include <boost/variant.hpp>
+#ifdef LL_WINDOWS
+	#pragma warning (pop)
+#endif
+
+// ============================================================================
+// RlvCommand
+//
+
+class RlvCommand
+{
+public:
+	explicit RlvCommand(const LLUUID& idObj, const std::string& strCommand);
+
+	/*
+	 * Member functions
+	 */
+public:
+	std::string        asString() const;
+	const std::string& getBehaviour() const		{ return m_strBehaviour; }
+	ERlvBehaviour      getBehaviourType() const	{ return m_eBehaviour; }
+	const LLUUID&      getObjectID() const		{ return m_idObj; }
+	const std::string& getOption() const		{ return m_strOption; }
+	const std::string& getParam() const			{ return m_strParam; }
+	ERlvParamType      getParamType() const		{ return m_eParamType; }
+	bool               isStrict() const			{ return m_fStrict; }
+	bool               isValid() const			{ return m_fValid; }
+
+	static ERlvBehaviour      getBehaviourFromString(const std::string& strBhvr, bool* pfStrict = NULL);
+	static const std::string& getStringFromBehaviour(ERlvBehaviour eBhvr);
+	static bool               hasStrictVariant(ERlvBehaviour eBhvr);
+
+	static void initLookupTable();
+protected:
+	static bool parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption,  std::string& strParam);
+
+	/*
+	 * Operators
+	 */
+public:
+	bool operator ==(const RlvCommand&) const;
+
+	/*
+	 * Member variables
+	 */
+protected:
+	bool          m_fValid;
+	LLUUID        m_idObj;
+	std::string   m_strBehaviour;
+	ERlvBehaviour m_eBehaviour;
+	bool          m_fStrict;
+	std::string   m_strOption;
+	std::string   m_strParam;
+	ERlvParamType m_eParamType;
+
+	typedef std::map<std::string, ERlvBehaviour> RlvBhvrTable;
+	static RlvBhvrTable m_BhvrMap;
+
+	friend class RlvHandler;
+};
+typedef std::list<RlvCommand> rlv_command_list_t;
+
+// ============================================================================
+// RlvCommandOption (and derived classed)
+//
+
+class RlvCommandOption
+{
+protected:
+	RlvCommandOption() {}
+public:
+	virtual ~RlvCommandOption() {}
+
+public:
+	virtual bool isAttachmentPoint() const		{ return false; }
+	virtual bool isAttachmentPointGroup() const	{ return false; }
+	virtual bool isEmpty() const = 0;
+	virtual bool isSharedFolder() const			{ return false; }
+	virtual bool isString() const				{ return false; }
+	virtual bool isUUID() const					{ return false; }
+	virtual bool isValid() const = 0;
+	virtual bool isWearableType() const			{ return false; }
+
+	virtual LLViewerJointAttachment*   getAttachmentPoint() const		{ return NULL; }
+	virtual ERlvAttachGroupType        getAttachmentPointGroup() const	{ return RLV_ATTACHGROUP_INVALID; }
+	virtual LLViewerInventoryCategory* getSharedFolder() const			{ return NULL; }
+	virtual const std::string&         getString() const				{ return LLStringUtil::null; }
+	virtual const LLUUID&              getUUID() const					{ return LLUUID::null; }
+	virtual LLWearableType::EType      getWearableType() const			{ return LLWearableType::WT_INVALID; }
+};
+
+class RlvCommandOptionGeneric : public RlvCommandOption
+{
+public:
+	explicit RlvCommandOptionGeneric(const std::string& strOption);
+	RlvCommandOptionGeneric(LLViewerJointAttachment* pAttachPt) : m_fEmpty(false)	{ m_varOption = pAttachPt; }
+	RlvCommandOptionGeneric(LLViewerInventoryCategory* pFolder) : m_fEmpty(false)	{ m_varOption = pFolder; }
+	RlvCommandOptionGeneric(const LLUUID& idOption) : m_fEmpty(false)				{ m_varOption = idOption; }
+	RlvCommandOptionGeneric(LLWearableType::EType wtType) : m_fEmpty(false)			{ m_varOption = wtType; }
+	/*virtual*/ ~RlvCommandOptionGeneric() {}
+
+public:
+	/*virtual*/ bool isAttachmentPoint() const		{ return typeid(LLViewerJointAttachment*) == m_varOption.type(); }
+	/*virtual*/ bool isAttachmentPointGroup() const	{ return typeid(ERlvAttachGroupType) == m_varOption.type(); }
+	/*virtual*/ bool isEmpty() const				{ return m_fEmpty; }
+	/*virtual*/ bool isSharedFolder() const			{ return typeid(LLViewerInventoryCategory*) == m_varOption.type(); }
+	/*virtual*/ bool isString() const				{ return typeid(std::string) == m_varOption.type(); }
+	/*virtual*/ bool isUUID() const					{ return typeid(LLUUID) == m_varOption.type(); }
+	/*virtual*/ bool isValid() const				{ return true; } // This doesn't really have any significance for the generic class
+	/*virtual*/ bool isWearableType() const			{ return typeid(LLWearableType::EType) == m_varOption.type(); }
+
+	/*virtual*/ LLViewerJointAttachment*   getAttachmentPoint() const
+		{ return (isAttachmentPoint()) ? boost::get<LLViewerJointAttachment*>(m_varOption) : RlvCommandOption::getAttachmentPoint(); }
+	/*virtual*/ ERlvAttachGroupType        getAttachmentPointGroup() const
+		{ return (isAttachmentPointGroup()) ? boost::get<ERlvAttachGroupType>(m_varOption) : RlvCommandOption::getAttachmentPointGroup(); }
+	/*virtual*/ LLViewerInventoryCategory* getSharedFolder() const
+		{ return (isSharedFolder()) ? boost::get<LLViewerInventoryCategory*>(m_varOption) : RlvCommandOption::getSharedFolder(); }
+	/*virtual*/ const std::string&         getString() const
+		{ return (isString()) ? boost::get<std::string>(m_varOption) : RlvCommandOption::getString(); }
+	/*virtual*/ const LLUUID&              getUUID() const
+		{ return (isUUID()) ? boost::get<LLUUID>(m_varOption) : RlvCommandOption::getUUID(); }
+	/*virtual*/ LLWearableType::EType      getWearableType() const
+		{ return (isWearableType()) ? boost::get<LLWearableType::EType>(m_varOption) : RlvCommandOption::getWearableType(); }
+
+protected:
+	bool m_fEmpty;
+	boost::variant<LLViewerJointAttachment*, ERlvAttachGroupType, LLViewerInventoryCategory*, std::string, LLUUID, LLWearableType::EType> m_varOption;
+};
+
+class RlvCommandOptionGetPath : public RlvCommandOption
+{
+public:
+	RlvCommandOptionGetPath(const RlvCommand& rlvCmd);
+	/*virtual*/ ~RlvCommandOptionGetPath() {}
+
+	/*virtual*/ bool  isEmpty() const	 { return m_idItems.empty(); }
+	/*virtual*/ bool  isValid() const	 { return m_fValid; }
+	const uuid_vec_t& getItemIDs() const { return m_idItems; }
+
+protected:
+	bool       m_fValid;
+	uuid_vec_t m_idItems;
+};
+
+// ============================================================================
+// RlvObject
+//
+
+class RlvObject
+{
+public:
+	RlvObject(const LLUUID& idObj);
+
+	/*
+	 * Member functions
+	 */
+public:
+	bool addCommand(const RlvCommand& rlvCmd);
+	bool removeCommand(const RlvCommand& rlvCmd);
+
+	std::string getStatusString(const std::string& strMatch) const;
+	bool        hasBehaviour(ERlvBehaviour eBehaviour, bool fStrictOnly) const;
+	bool        hasBehaviour(ERlvBehaviour eBehaviour, const std::string& strOption, bool fStrictOnly) const;
+
+	const rlv_command_list_t* getCommandList() const { return &m_Commands; }
+
+	/*
+	 * Member variables
+	 */
+protected:
+	LLUUID             m_UUID;				// The object's UUID
+	S32                m_idxAttachPt;		// The object's attachment point (or 0 if it's not an attachment)
+	LLUUID             m_idRoot;			// The UUID of the object's root (may or may not be different from m_UUID)
+	bool               m_fLookup;			// TRUE if the object existed in gObjectList at one point in time
+	S16                m_nLookupMisses;		// Count of unsuccessful lookups in gObjectList by the GC
+	rlv_command_list_t m_Commands;			// List of behaviours held by this object (in the order they were received)
+
+	friend class RlvHandler;
+};
+
+// ============================================================================
+// RlvForceWear
+//
+
+class RlvForceWear : public LLSingleton<RlvForceWear>
+{
+protected:
+	RlvForceWear() {}
+
+public:
+	// Folders
+	enum EWearAction { ACTION_WEAR_REPLACE, ACTION_WEAR_ADD, ACTION_REMOVE };
+	enum EWearFlags { FLAG_NONE = 0x00, FLAG_MATCHALL = 0x01, FLAG_DEFAULT = FLAG_NONE };
+	void forceFolder(const LLViewerInventoryCategory* pFolder, EWearAction eAction, EWearFlags eFlags);
+
+	// Generic
+	static bool isWearAction(EWearAction eAction) { return (ACTION_WEAR_REPLACE == eAction) || (ACTION_WEAR_ADD == eAction); }
+	static bool isWearableItem(const LLInventoryItem* pItem);
+	static bool isWearingItem(const LLInventoryItem* pItem);
+
+	// Nostrip
+	static bool isStrippable(const LLUUID& idItem) { return isStrippable(gInventory.getItem(idItem)); }
+	static bool isStrippable(const LLInventoryItem* pItem);
+
+	// Attachments
+	static bool isForceDetachable(const LLViewerObject* pAttachObj, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null);
+	static bool isForceDetachable(const LLViewerJointAttachment* pAttachPt, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null);
+	void forceDetach(const LLViewerObject* pAttachObj);
+	void forceDetach(const LLViewerJointAttachment* ptAttachPt);
+
+	// Wearables
+	static bool isForceRemovable(const LLWearable* pWearable, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null);
+	static bool isForceRemovable(LLWearableType::EType wtType, bool fCheckComposite = true, const LLUUID& idExcept = LLUUID::null);
+	void forceRemove(const LLWearable* pWearable);
+	void forceRemove(LLWearableType::EType wtType);
+
+public:
+	void done();
+protected:
+	void addAttachment(const LLViewerInventoryItem* pItem, EWearAction eAction);
+	void remAttachment(const LLViewerObject* pAttachObj);
+	void addWearable(const LLViewerInventoryItem* pItem, EWearAction eAction);
+	void remWearable(const LLWearable* pWearable);
+
+	// Convenience (prevents long lines that run off the screen elsewhere)
+	bool isAddAttachment(const LLViewerInventoryItem* pItem) const
+	{
+		bool fFound = false;
+		for (addattachments_map_t::const_iterator itAddAttachments = m_addAttachments.begin(); 
+				(!fFound) && (itAddAttachments != m_addAttachments.end()); ++itAddAttachments)
+		{
+			const LLInventoryModel::item_array_t& wearItems = itAddAttachments->second;
+			fFound = (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end());
+		}
+		return fFound;
+	}
+	bool isRemAttachment(const LLViewerObject* pAttachObj) const
+	{
+		return std::find(m_remAttachments.begin(), m_remAttachments.end(), pAttachObj) != m_remAttachments.end();
+	}
+	bool isAddWearable(const LLViewerInventoryItem* pItem) const
+	{
+		bool fFound = false;
+		for (addwearables_map_t::const_iterator itAddWearables = m_addWearables.begin(); 
+				(!fFound) && (itAddWearables != m_addWearables.end()); ++itAddWearables)
+		{
+			const LLInventoryModel::item_array_t& wearItems = itAddWearables->second;
+			fFound = (std::find_if(wearItems.begin(), wearItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) != wearItems.end());
+		}
+		return fFound;
+	}
+	bool isRemWearable(const LLWearable* pWearable) const
+	{
+		return std::find(m_remWearables.begin(), m_remWearables.end(), pWearable) != m_remWearables.end();
+	}
+
+protected:
+	typedef std::pair<LLWearableType::EType, LLInventoryModel::item_array_t> addwearable_pair_t;
+	typedef std::map<LLWearableType::EType, LLInventoryModel::item_array_t> addwearables_map_t;
+	addwearables_map_t               m_addWearables;
+	typedef std::pair<S32, LLInventoryModel::item_array_t> addattachment_pair_t;
+	typedef std::map<S32, LLInventoryModel::item_array_t> addattachments_map_t;
+	addattachments_map_t             m_addAttachments;
+	LLInventoryModel::item_array_t   m_addGestures;
+	std::list<const LLViewerObject*> m_remAttachments;
+	std::list<const LLWearable*>     m_remWearables;
+	LLInventoryModel::item_array_t   m_remGestures;
+
+private:
+	friend class LLSingleton<RlvForceWear>;
+};
+
+// ============================================================================
+// RlvBehaviourNotifyObserver
+//
+
+// TODO-RLVa: [RLVa-1.2.1] See about just reintegrating this back into RlvHandler
+class RlvBehaviourNotifyHandler : public LLSingleton<RlvBehaviourNotifyHandler>
+{
+	friend class LLSingleton<RlvBehaviourNotifyHandler>;
+protected:
+	RlvBehaviourNotifyHandler();
+	virtual ~RlvBehaviourNotifyHandler() { if (m_ConnCommand.connected()) m_ConnCommand.disconnect(); }
+
+public:
+	void addNotify(const LLUUID& idObj, S32 nChannel, const std::string& strFilter)
+	{
+		m_Notifications.insert(std::pair<LLUUID, notifyData>(idObj, notifyData(nChannel, strFilter)));
+	}
+	void removeNotify(const LLUUID& idObj, S32 nChannel, const std::string& strFilter)
+	{
+		for (std::multimap<LLUUID, notifyData>::iterator itNotify = m_Notifications.lower_bound(idObj), 
+				endNotify = m_Notifications.upper_bound(idObj); itNotify != endNotify; ++itNotify)
+		{
+			if ( (itNotify->second.nChannel == nChannel) && (itNotify->second.strFilter == strFilter) )
+			{
+				m_Notifications.erase(itNotify);
+				break;
+			}
+		}
+		if (m_Notifications.empty())
+			delete this;	// Delete ourself if we have nothing to do
+	}
+protected:
+	void onCommand(const RlvCommand& rlvCmd, ERlvCmdRet eRet, bool fInternal);
+
+protected:
+	struct notifyData
+	{
+		S32         nChannel;
+		std::string strFilter;
+		notifyData(S32 channel, const std::string& filter) : nChannel(channel), strFilter(filter) {}
+	};
+	std::multimap<LLUUID, notifyData> m_Notifications;
+	boost::signals2::connection m_ConnCommand;
+};
+
+// ============================================================================
+// RlvException
+//
+
+typedef boost::variant<std::string, LLUUID, S32, ERlvBehaviour> RlvExceptionOption;
+
+struct RlvException
+{
+public:
+	LLUUID				idObject;    // UUID of the object that added the exception
+	ERlvBehaviour		eBehaviour;  // Behaviour the exception applies to
+	RlvExceptionOption	varOption;   // Exception data (type is dependent on eBehaviour)
+
+	RlvException(const LLUUID& idObj, ERlvBehaviour eBhvr, const RlvExceptionOption& option) : idObject(idObj), eBehaviour(eBhvr), varOption(option) {}
+private:
+	RlvException();
+};
+
+// ============================================================================
+// RlvWLSnapshot
+//
+
+struct RlvWLSnapshot
+{
+public:
+	static void           restoreSnapshot(const RlvWLSnapshot* pWLSnapshot);
+	static RlvWLSnapshot* takeSnapshot();
+private:
+	RlvWLSnapshot() {}
+
+	bool		 fIsRunning;
+	bool		 fUseLindenTime;
+	LLWLParamSet WLParams;
+};
+
+// ============================================================================
+// Various helper classes/timers/functors
+//
+
+class RlvGCTimer : public LLEventTimer
+{
+public:
+	RlvGCTimer() : LLEventTimer(30.0) {}
+	virtual BOOL tick();
+};
+
+// ============================================================================
+// Various helper functions
+//
+
+bool rlvCanDeleteOrReturn();
+
+ERlvAttachGroupType rlvAttachGroupFromIndex(S32 idxGroup);
+ERlvAttachGroupType rlvAttachGroupFromString(const std::string& strGroup);
+
+std::string rlvGetFirstParenthesisedText(const std::string& strText, std::string::size_type* pidxMatch = NULL);
+std::string rlvGetLastParenthesisedText(const std::string& strText, std::string::size_type* pidxStart = NULL);
+void        rlvStringReplace(std::string& strText, std::string strFrom, const std::string& strTo);
+
+// ============================================================================
+// Inlined class member functions
+//
+
+// Checked: 2009-09-19 (RLVa-1.0.3d)
+inline std::string RlvCommand::asString() const
+{
+	// NOTE: @clear=<param> should be represented as clear:<param>
+	return (m_eParamType != RLV_TYPE_CLEAR)
+		? (!m_strOption.empty()) ? (std::string(m_strBehaviour)).append(":").append(m_strOption) : (std::string(m_strBehaviour))
+	    : (!m_strParam.empty())  ? (std::string(m_strBehaviour)).append(":").append(m_strParam)  : (std::string(m_strBehaviour));
+}
+
+inline bool RlvCommand::operator ==(const RlvCommand& rhs) const
+{
+	// The specification notes that "@detach=n" is semantically identical to "@detach=add" (same for "y" and "rem"
+	return (m_strBehaviour == rhs.m_strBehaviour) && (m_strOption == rhs.m_strOption) &&
+		( (RLV_TYPE_UNKNOWN != m_eParamType) ? (m_eParamType == rhs.m_eParamType) : (m_strParam == rhs.m_strParam) );
+}
+
+inline bool RlvCommand::hasStrictVariant(ERlvBehaviour eBhvr)
+{
+	switch (eBhvr)
+	{
+		case RLV_BHVR_RECVCHAT:
+		case RLV_BHVR_RECVEMOTE:
+		case RLV_BHVR_RECVIM:
+		case RLV_BHVR_SENDIM:
+		case RLV_BHVR_TPLURE:
+		case RLV_BHVR_SENDCHANNEL:
+			return true;
+		default:
+			return false;
+	}
+}
+
+// Checked: 2010-04-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+inline bool RlvForceWear::isWearableItem(const LLInventoryItem* pItem)
+{
+	LLAssetType::EType assetType = pItem->getType();
+	return 
+		(LLAssetType::AT_BODYPART == assetType) || (LLAssetType::AT_CLOTHING == assetType) ||
+		(LLAssetType::AT_OBJECT == assetType) || (LLAssetType::AT_GESTURE == assetType);
+}
+
+// ============================================================================
+
+#endif // RLV_HELPER_H
diff --git a/indra/newview/rlvinventory.cpp b/indra/newview/rlvinventory.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b2a29e4c116f9689a41e0e9258d1be03e6a24ca0
--- /dev/null
+++ b/indra/newview/rlvinventory.cpp
@@ -0,0 +1,654 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
+#include "llappearancemgr.h"
+#include "llinventoryobserver.h"
+#include "llstartup.h"
+#include "llviewerfoldertype.h"
+#include "llviewerobject.h"
+#include "llvoavatarself.h"
+
+#include "rlvdefines.h"
+#include "rlvcommon.h"
+#include "rlvlocks.h"
+#include "rlvinventory.h"
+#include "rlvhandler.h"
+
+// ============================================================================
+// Static variable initialization
+//
+
+const std::string RlvInventory::cstrSharedRoot = RLV_ROOT_FOLDER;
+
+// ============================================================================
+// Helper classes
+//
+
+// TODO-RLVa: [RLVa-1.2.1] This class really shouldn't be calling "fetchSharedLinks" directly so find a better way
+class RlvSharedInventoryFetcher : public LLInventoryFetchDescendentsObserver
+{
+public:
+	RlvSharedInventoryFetcher(const uuid_vec_t& idFolders): LLInventoryFetchDescendentsObserver(idFolders) {}
+	virtual ~RlvSharedInventoryFetcher() {}
+
+	virtual void done()
+	{
+		RLV_INFOS << "Shared folders fetch completed" << LL_ENDL;
+		RlvInventory::instance().m_fFetchComplete = true;
+		RlvInventory::instance().fetchSharedLinks();
+
+		gInventory.removeObserver(this);
+		delete this;
+	}
+};
+
+// ============================================================================
+// RlvInventory member functions
+//
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h
+void RlvInventory::fetchSharedInventory()
+{
+	// Sanity check - don't fetch if we're already fetching, or if we don't have a shared root
+	const LLViewerInventoryCategory* pRlvRoot = getSharedRoot();
+	if ( (m_fFetchStarted) || (!pRlvRoot) )
+		return;
+
+	// Grab all the folders under the shared root
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items;
+	gInventory.collectDescendents(pRlvRoot->getUUID(), folders, items, FALSE);
+
+	// Add them to the "to fetch" list
+	uuid_vec_t idFolders;
+	idFolders.push_back(pRlvRoot->getUUID());
+	for (S32 idxFolder = 0, cntFolder = folders.count(); idxFolder < cntFolder; idxFolder++)
+		idFolders.push_back(folders.get(idxFolder)->getUUID());
+
+	// Now fetch them all in one go
+	RlvSharedInventoryFetcher* pFetcher = new RlvSharedInventoryFetcher(idFolders);
+
+	RLV_INFOS << "Starting fetch of " << idFolders.size() << " shared folders" << RLV_ENDL;
+	pFetcher->startFetch();
+	m_fFetchStarted = true;
+
+	if (pFetcher->isFinished())
+		pFetcher->done();
+	else
+		gInventory.addObserver(pFetcher);
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h
+void RlvInventory::fetchSharedLinks()
+{
+	// TOFIX-RLVa: [RLVa-1.2.1] Finish adding support for AT_LINK_FOLDER
+	const LLViewerInventoryCategory* pRlvRoot = getSharedRoot();
+	if (!pRlvRoot)
+		return;
+
+	// Grab all the inventory links under the shared root
+	LLInventoryModel::cat_array_t folders; LLInventoryModel::item_array_t items; RlvIsLinkType f;
+	gInventory.collectDescendentsIf(pRlvRoot->getUUID(), folders, items, FALSE, f, FALSE);
+
+	// Add them to the "to fetch" list based on link type
+	uuid_vec_t idFolders, idItems;
+	for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++)
+	{
+		const LLViewerInventoryItem* pItem = items.get(idxItem);
+		switch (pItem->getActualType())
+		{
+			case LLAssetType::AT_LINK:
+				idItems.push_back(pItem->getLinkedUUID());
+				break;
+			case LLAssetType::AT_LINK_FOLDER:
+				idFolders.push_back(pItem->getLinkedUUID());
+				break;
+			default:
+				break;;
+		}
+	}
+
+	RLV_INFOS << "Starting link target fetch of " << idItems.size() << " items and " << idFolders.size() << " folders" << RLV_ENDL;
+
+	// Fetch all the link item targets
+	LLInventoryFetchItemsObserver itemFetcher(idItems);
+	itemFetcher.startFetch();
+
+	// Fetch all the link folder targets
+	// TODO!
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvInventory::fetchWornItems()
+{
+	uuid_vec_t idItems;
+
+	// Fetch all currently worn clothing layers and body parts
+	for (int type = 0; type < LLWearableType::WT_COUNT; type++)
+	{
+		// RELEASE-RLVa: [SL-2.0.0] Needs rewriting once 'LLAgentWearables::MAX_WEARABLES_PER_TYPE > 1'
+		const LLUUID& idItem = gAgentWearables.getWearableItemID((LLWearableType::EType)type, 0);
+		if (idItem.notNull())
+			idItems.push_back(idItem);
+	}
+
+	// Fetch all currently worn attachments
+	if (isAgentAvatarValid())
+	{
+		for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); 
+				itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt)
+		{
+			const LLViewerJointAttachment* pAttachPt = itAttachPt->second;
+			if (pAttachPt)
+			{
+				for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+					 itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+				{
+					const LLViewerObject* pAttachObj = (*itAttachObj);
+					if ( (pAttachObj) && (pAttachObj->getAttachmentItemID().notNull()) )
+						idItems.push_back(pAttachObj->getAttachmentItemID());
+				}
+			}
+		}
+	}
+
+	LLInventoryFetchItemsObserver itemFetcher(idItems);
+	itemFetcher.startFetch();
+}
+
+// Checked: 2010-04-07 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h
+bool RlvInventory::findSharedFolders(const std::string& strCriteria, LLInventoryModel::cat_array_t& folders) const
+{
+	// Sanity check - can't do anything without a shared root
+	const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot();
+	if (!pRlvRoot)
+		return false;
+
+	folders.clear();
+	LLInventoryModel::item_array_t items;
+	RlvCriteriaCategoryCollector f(strCriteria);
+	gInventory.collectDescendentsIf(pRlvRoot->getUUID(), folders, items, FALSE, f);
+
+	return (folders.count() != 0);
+}
+
+// Checked: 2010-08-30 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c
+bool RlvInventory::getPath(const uuid_vec_t& idItems, LLInventoryModel::cat_array_t& folders) const
+{
+	// Sanity check - can't do anything without a shared root
+	const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot();
+	if (!pRlvRoot)
+		return false;
+
+	folders.clear();
+	for (uuid_vec_t::const_iterator itItem = idItems.begin(); itItem != idItems.end(); ++itItem)
+	{
+		const LLInventoryItem* pItem = gInventory.getItem(*itItem);
+		if ( (pItem) && (gInventory.isObjectDescendentOf(pItem->getUUID(), pRlvRoot->getUUID())) )
+		{
+			// If the containing folder is a folded folder we need its parent
+			LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID());
+			if (RlvInventory::instance().isFoldedFolder(pFolder, true))
+				pFolder = gInventory.getCategory(pFolder->getParentUUID());
+			folders.push_back(pFolder);
+		}
+	}
+
+	return (folders.count() != 0);
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.0h
+LLViewerInventoryCategory* RlvInventory::getSharedRoot() const
+{
+	if (gInventory.isInventoryUsable())
+	{
+		LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems;
+		gInventory.getDirectDescendentsOf(gInventory.getRootFolderID(), pFolders, pItems);
+		if (pFolders)
+		{
+			// NOTE: we might have multiple #RLV folders so we'll just go with the first one we come across
+			LLViewerInventoryCategory* pFolder;
+			for (S32 idxFolder = 0, cntFolder = pFolders->count(); idxFolder < cntFolder; idxFolder++)
+			{
+				if ( ((pFolder = pFolders->get(idxFolder)) != NULL) && (RlvInventory::cstrSharedRoot == pFolder->getName()) )
+					return pFolder;
+			}
+		}
+	}
+	return NULL;
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.0.1a
+LLViewerInventoryCategory* RlvInventory::getSharedFolder(const LLUUID& idParent, const std::string& strFolderName) const
+{
+	LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems;
+	gInventory.getDirectDescendentsOf(idParent, pFolders, pItems);
+	if ( (!pFolders) || (strFolderName.empty()) )
+		return NULL;
+
+	// If we can't find an exact match then we'll settle for a "contains" match
+	LLViewerInventoryCategory* pPartial = NULL;
+
+	//LLStringUtil::toLower(strFolderName); <- everything was already converted to lower case before
+
+	std::string strName;
+	for (S32 idxFolder = 0, cntFolder = pFolders->count(); idxFolder < cntFolder; idxFolder++)
+	{
+		LLViewerInventoryCategory* pFolder = pFolders->get(idxFolder);
+
+		strName = pFolder->getName();
+		if (strName.empty())
+			continue;
+		LLStringUtil::toLower(strName);
+
+		if (strFolderName == strName)
+			return pFolder;		// Found an exact match, no need to keep on going
+		else if ( (!pPartial) && (RLV_FOLDER_PREFIX_HIDDEN != strName[0]) && (std::string::npos != strName.find(strFolderName)) )
+			pPartial = pFolder;	// Found a partial (non-hidden) match, but we might still find an exact one (first partial match wins)
+	}
+
+	return pPartial;
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-0.2.0e
+LLViewerInventoryCategory* RlvInventory::getSharedFolder(const std::string& strPath) const
+{
+	// Sanity check - no shared root => no shared folder
+	LLViewerInventoryCategory* pRlvRoot = getSharedRoot(), *pFolder = pRlvRoot;
+	if (!pRlvRoot)
+		return NULL;
+
+	// Walk the path (starting at the root)
+	boost_tokenizer tokens(strPath, boost::char_separator<char>("/", "", boost::drop_empty_tokens));
+	for (boost_tokenizer::const_iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken)
+	{
+		pFolder = getSharedFolder(pFolder->getUUID(), *itToken);
+		if (!pFolder)
+			return NULL;	// No such folder
+	}
+
+	return pFolder;			// If strPath was empty or just a bunch of //// then: pFolder == pRlvRoot
+}
+
+// Checked: 2010-03-02 (RLVa-1.2.0a) | Modified: RLVa-0.2.0g
+std::string RlvInventory::getSharedPath(const LLViewerInventoryCategory* pFolder) const
+{
+	// Sanity check - no shared root or no folder => no path
+	const LLViewerInventoryCategory* pRlvRoot = getSharedRoot();
+	if ( (!pRlvRoot) || (!pFolder) || (pRlvRoot->getUUID() == pFolder->getUUID()) )
+		return std::string();
+
+	const LLUUID& idRLV  = pRlvRoot->getUUID();
+	const LLUUID& idRoot = gInventory.getRootFolderID();
+	std::string strPath;
+
+	// Walk up the tree until we reach the top
+	RLV_ASSERT(gInventory.isObjectDescendentOf(pFolder->getUUID(), pRlvRoot->getUUID()));
+	while (pFolder)
+	{
+		strPath = "/" + pFolder->getName() + strPath;
+
+		const LLUUID& idParent = pFolder->getParentUUID();
+		if (idRLV == idParent)			// Reached the shared root, we're done
+			break;
+		else if (idRoot == idParent)	// We reached the agent's inventory root (indicative of a logic error elsewhere)
+			return std::string();
+
+		pFolder = gInventory.getCategory(idParent);
+	}
+
+	return strPath.erase(0, 1);
+}
+
+// Checked: 2009-05-26 (RLVa-0.2.0d) | Modified: RLVa-0.2.0d
+S32 RlvInventory::getDirectDescendentsCount(const LLInventoryCategory* pFolder, LLAssetType::EType filterType)
+{
+	S32 cntType = 0;
+	if (pFolder)
+	{
+		LLInventoryModel::cat_array_t* pFolders; LLInventoryModel::item_array_t* pItems;
+		gInventory.getDirectDescendentsOf(pFolder->getUUID(), pFolders, pItems);
+
+		if (pItems)
+		{
+			for (S32 idxItem = 0, cntItem = pItems->count(); idxItem < cntItem; idxItem++)
+				if (pItems->get(idxItem)->getType() == filterType)
+					cntType++;
+		}
+	}
+	return cntType;
+}
+
+// ============================================================================
+// RlvRenameOnWearObserver member functions
+//
+
+// Checked: 2010-03-14 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvRenameOnWearObserver::done()
+{
+	gInventory.removeObserver(this);
+
+	// We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers()
+	doOnIdleOneTime(boost::bind(&RlvRenameOnWearObserver::doneIdle, this));
+}
+
+// Checked: 2010-03-14 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvRenameOnWearObserver::doneIdle()
+{
+	const LLViewerInventoryCategory* pRlvRoot = NULL;
+	if ( (RlvSettings::getEnableSharedWear()) || (!RlvSettings::getSharedInvAutoRename()) || (LLStartUp::getStartupState() < STATE_STARTED) || 
+		 (!isAgentAvatarValid()) || ((pRlvRoot = RlvInventory::instance().getSharedRoot()) == NULL) )
+	{
+		delete this;
+		return;
+	}
+
+	const LLViewerJointAttachment* pAttachPt = NULL; S32 idxAttachPt = 0;
+	RLV_ASSERT(mComplete.size() > 0);	// Catch instances where we forgot to call startFetch()
+	for (uuid_vec_t::const_iterator itItem = mComplete.begin(); itItem != mComplete.end(); ++itItem)
+	{
+		const LLUUID& idAttachItem = *itItem;
+
+		// If the item resides under #RLV we'll rename it directly; otherwise settle for "renaming" all of its links residing under #RLV
+		LLInventoryModel::item_array_t items;
+		if (gInventory.isObjectDescendentOf(idAttachItem, pRlvRoot->getUUID()))
+			items.push_back(gInventory.getItem(idAttachItem));
+		else
+			items = gInventory.collectLinkedItems(idAttachItem, pRlvRoot->getUUID());
+		if (items.empty())
+			continue;
+
+		if ( ((pAttachPt = gAgentAvatarp->getWornAttachmentPoint(idAttachItem)) == NULL) ||
+			 ((idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt)) == 0) )
+		{
+			RLV_ASSERT(false);
+			continue;
+		}
+
+		for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++)
+		{
+			LLViewerInventoryItem* pItem = items.get(idxItem);
+			if (!pItem)
+				continue;
+
+			S32 idxAttachPtItem = RlvAttachPtLookup::getAttachPointIndex(pItem);
+			if ( (idxAttachPt == idxAttachPtItem) || (idxAttachPtItem) )
+				continue;
+
+			std::string strAttachPt = pAttachPt->getName();
+			LLStringUtil::toLower(strAttachPt);
+
+			// If we can modify the item then we rename it directly, otherwise we create a new folder and move it
+			if (pItem->getPermissions().allowModifyBy(gAgent.getID()))
+			{
+				std::string strName = pItem->getName();
+				LLStringUtil::truncate(strName, DB_INV_ITEM_NAME_STR_LEN - strAttachPt.length() - 3);
+
+				strName += " (" + strAttachPt + ")";
+
+				pItem->rename(strName);
+				pItem->updateServer(FALSE);
+				gInventory.addChangedMask(LLInventoryObserver::LABEL, pItem->getUUID());
+			}
+			else
+			{
+				// Don't do anything if the item is a direct descendant of the shared root, or a folded folder
+				LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID());
+				if ( (pFolder) && (pFolder->getUUID() != pRlvRoot->getUUID()) && (!RlvInventory::isFoldedFolder(pFolder, false)) )
+				{
+					std::string strFolderName = ".(" + strAttachPt + ")";
+
+					// Rename the item's parent folder if it's called "New Folder", isn't directly under #RLV and contains exactly 1 object
+					if ( (LLViewerFolderType::lookupNewCategoryName(LLFolderType::FT_NONE) == pFolder->getName()) && 
+						 (pFolder->getParentUUID() != pRlvRoot->getUUID()) && 
+						 (1 == RlvInventory::getDirectDescendentsCount(pFolder, LLAssetType::AT_OBJECT)) )
+					{
+						pFolder->rename(strFolderName);
+						pFolder->updateServer(FALSE);
+						gInventory.addChangedMask(LLInventoryObserver::LABEL, pFolder->getUUID());
+					}
+					else
+					{
+						// "No modify" item with a non-renameable parent: create a new folder named and move the item into it
+						LLUUID idAttachFolder = gInventory.createNewCategory(pFolder->getUUID(), LLFolderType::FT_NONE, strFolderName);
+						move_inventory_item(gAgent.getID(), gAgent.getSessionID(), pItem->getUUID(), idAttachFolder, std::string(), NULL);
+					}
+				}
+			}
+		}
+	}
+	gInventory.notifyObservers();
+
+	delete this;
+}
+
+// ============================================================================
+// "Give to #RLV" helper classes
+//
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+void RlvGiveToRLVTaskOffer::changed(U32 mask)
+{
+	if (mask & LLInventoryObserver::ADD)
+	{
+		LLMessageSystem* pMsg = gMessageSystem;
+		if ( (pMsg->getMessageName()) && (0 == strcmp(pMsg->getMessageName(), "BulkUpdateInventory")) )
+		{
+			LLUUID idTransaction;
+			pMsg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, idTransaction);
+			if(m_idTransaction == idTransaction)
+			{
+				LLUUID idInvObject;
+				for(S32 idxBlock = 0, cntBlock = pMsg->getNumberOfBlocksFast(_PREHASH_FolderData); idxBlock < cntBlock; idxBlock++)
+				{
+					pMsg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, idInvObject, idxBlock);
+					if ( (idInvObject.notNull()) && (std::find(m_Folders.begin(), m_Folders.end(), idInvObject) == m_Folders.end()) )
+						m_Folders.push_back(idInvObject);
+				}
+
+				done();
+			}
+		}
+	}
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+void RlvGiveToRLVTaskOffer::done()
+{
+	gInventory.removeObserver(this);
+
+	// We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers()
+	doOnIdleOneTime(boost::bind(&RlvGiveToRLVTaskOffer::doneIdle, this));
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e
+void RlvGiveToRLVTaskOffer::doneIdle()
+{
+	const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot();
+	if (pRlvRoot)
+	{
+		for (folder_ref_t::const_iterator itFolder = m_Folders.begin(); itFolder != m_Folders.end(); ++itFolder)
+		{
+			const LLViewerInventoryCategory* pFolder = gInventory.getCategory(*itFolder);
+			if (!pFolder)
+				continue;
+
+			std::string strFolder = pFolder->getName();
+			if ( (pRlvRoot->getUUID() == pFolder->getParentUUID() ) && (strFolder.find(RLV_PUTINV_PREFIX) == 0))
+			{
+				LLPointer<LLViewerInventoryCategory> pNewFolder = new LLViewerInventoryCategory(pFolder);
+				pNewFolder->rename(strFolder.erase(0, strFolder.find(RLV_FOLDER_PREFIX_PUTINV)));
+				pNewFolder->updateServer(FALSE);
+				gInventory.updateCategory(pNewFolder);
+
+				gInventory.notifyObservers();
+				break;
+			}
+		}
+	}
+	delete this;
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+void RlvGiveToRLVAgentOffer::done()
+{
+	gInventory.removeObserver(this);
+
+	// We shouldn't be messing with inventory items during LLInventoryModel::notifyObservers()
+	doOnIdleOneTime(boost::bind(&RlvGiveToRLVAgentOffer::doneIdle, this));
+}
+
+// Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e
+void RlvGiveToRLVAgentOffer::doneIdle()
+{
+	const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot();
+	const LLViewerInventoryCategory* pFolder = (mComplete.size()) ? gInventory.getCategory(mComplete[0]) : NULL;
+	if ( (pRlvRoot) && (pFolder) )
+	{
+		std::string strName = pFolder->getName();
+		if (strName.find(RLV_PUTINV_PREFIX) == 0)
+		{
+			LLInventoryModel::update_list_t update;
+			LLInventoryModel::LLCategoryUpdate updOldParent(pFolder->getParentUUID(), -1);
+			update.push_back(updOldParent);
+			LLInventoryModel::LLCategoryUpdate updNewParent(pRlvRoot->getUUID(), 1);
+			update.push_back(updNewParent);
+			gInventory.accountForUpdate(update);
+
+			LLPointer<LLViewerInventoryCategory> pNewFolder = new LLViewerInventoryCategory(pFolder);
+			pNewFolder->setParent(pRlvRoot->getUUID());
+			pNewFolder->updateParentOnServer(FALSE);
+			pNewFolder->rename(strName.erase(0, strName.find(RLV_FOLDER_PREFIX_PUTINV)));
+			pNewFolder->updateServer(FALSE);
+			gInventory.updateCategory(pNewFolder);
+
+			gInventory.notifyObservers();
+		}
+	}
+	delete this;
+}
+
+// ============================================================================
+// RlvWearableItemCollector
+//
+
+// Checked: 2010-04-07 (RLVa-1.2.0d) | Added: RLVa-0.2.0e
+const LLUUID& RlvWearableItemCollector::getFoldedParent(const LLUUID& idFolder) const
+{
+	std::map<LLUUID, LLUUID>::const_iterator itFolder = m_FoldingMap.end(), itCur = m_FoldingMap.find(idFolder);
+	while (itCur != m_FoldingMap.end())
+	{
+		itFolder = itCur;
+		itCur = m_FoldingMap.find(itFolder->second);
+	}
+	return (m_FoldingMap.end() == itFolder) ? idFolder : itFolder->second;
+}
+
+// Checked: 2010-03-20 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+bool RlvWearableItemCollector::onCollectFolder(const LLInventoryCategory* pFolder)
+{
+	const LLUUID& idParent = pFolder->getParentUUID();
+	if (m_Wearable.end() == std::find(m_Wearable.begin(), m_Wearable.end(), idParent))
+		return false;															// Not the child of a wearable folder == skip
+
+	const std::string& strFolder = pFolder->getName();
+	if (strFolder.empty())														// Shouldn't happen but does... naughty Lindens
+		return false;
+
+	if (RlvInventory::isFoldedFolder(pFolder, false))							// Check for folder that should get folded under its parent
+	{
+		if ( (!m_fAttach) || (1 == RlvInventory::getDirectDescendentsCount(pFolder, LLAssetType::AT_OBJECT)) )
+		{																		// When attaching there should only be 1 attachment in it
+			m_Folded.push_front(pFolder->getUUID());
+			m_FoldingMap.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), idParent));
+		}
+	}
+	else if ( (RLV_FOLDER_PREFIX_HIDDEN != strFolder[0]) && (m_fMatchAll) )		// Collect from any non-hidden child folder for *all
+	{
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		if ( (!RlvSettings::getEnableComposites()) ||							// ... if we're not checking composite folders
+			 (!gRlvHandler.isCompositeFolder(pFolder)) ||						// ... or if it's not a composite folder
+		     ((m_fAttach) && (gRlvHandler.canWearComposite(pFolder))) ||		// ... or if we're attaching and can attach it OR
+			 (!m_fAttach) && (gRlvHandler.canTakeOffComposite(pFolder)) )		// ... or if we're detaching and can detach it
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		{
+			m_Wearable.push_front(pFolder->getUUID());
+		}
+		return (idParent == m_idFolder);										// (Convenience for @getinvworn)
+	}
+	#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	else if ( (RlvSettings::getEnableComposites()) &&
+			  (RLV_FOLDER_PREFIX_HIDDEN == strFolder[0]) &&						// Hidden folder that's a... 
+			  (gRlvHandler.isCompositeFolder(pFolder)) &&						// ... composite folder which we...
+		      ( ((m_fAttach) && (gRlvHandler.canWearComposite(pFolder))) ||		// ... are attaching and can attach OR
+			    (!m_fAttach) && (gRlvHandler.canTakeOffComposite(pFolder)) ) )	// ... are detaching and can detach
+	{
+		m_Wearable.push_front(pFolder->getUUID());
+		m_FoldingMap.insert(std::pair<LLUUID, LLUUID>(pFolder->getUUID(), idParent));
+	}
+	#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+
+	return false;
+}
+
+// Checked: 2010-03-20 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+bool RlvWearableItemCollector::onCollectItem(const LLInventoryItem* pItem)
+{
+	#ifdef RLV_EXTENSION_FLAG_NOSTRIP
+	if ( (!m_fAttach) && (!RlvForceWear::isStrippable(pItem)) )						// Don't process "nostrip" items on detach
+		return false;
+	#endif // RLV_EXTENSION_FLAG_NOSTRIP
+
+	const LLUUID& idParent = pItem->getParentUUID(); bool fRet = false;
+	switch (pItem->getType())
+	{
+		case LLAssetType::AT_BODYPART:
+			if (!m_fAttach)
+				break;																	// Don't process body parts on detach
+		case LLAssetType::AT_CLOTHING:
+			#ifdef RLV_EXTENSION_FLAG_NOSTRIP
+				fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) ||
+						 ( (m_fAttach) && (m_Folded.end() != std::find(m_Folded.begin(), m_Folded.end(), idParent)) &&
+						   (RlvForceWear::isStrippable(pItem)) ) );
+			#else
+				fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent));
+			#endif // RLV_EXTENSION_FLAG_NOSTRIP
+			break;
+		case LLAssetType::AT_OBJECT:
+			fRet = ( (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent)) || 
+				     (m_Folded.end() != std::find(m_Folded.begin(), m_Folded.end(), idParent)) ) &&
+				   ( (!m_fAttach) || (RlvAttachPtLookup::hasAttachPointName(pItem)) || (RlvSettings::getEnableSharedWear()) );
+			break;
+		#ifdef RLV_EXTENSION_FORCEWEAR_GESTURES
+		case LLAssetType::AT_GESTURE:
+			fRet = (m_Wearable.end() != std::find(m_Wearable.begin(), m_Wearable.end(), idParent));
+			break;
+		#endif // RLV_EXTENSION_FORCEWEAR_GESTURES
+		default:
+			break;
+	}
+	return fRet;
+}
+
+// Checked: 2010-03-20 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d
+bool RlvWearableItemCollector::operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem)
+{
+	// NOTE: this is used for more than was originally intended so only modify if you're sure it won't break something obscure
+	return (pFolder) ? onCollectFolder(pFolder) : ( (pItem) ? onCollectItem(pItem) : false );
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvinventory.h b/indra/newview/rlvinventory.h
new file mode 100644
index 0000000000000000000000000000000000000000..22e451bcfb93c034a39b1534cf294c3f9d9d0ecf
--- /dev/null
+++ b/indra/newview/rlvinventory.h
@@ -0,0 +1,256 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_INVENTORY_H
+#define RLV_INVENTORY_H
+
+#include "llinventoryfunctions.h"
+#include "llinventoryobserver.h"
+#include "llsingleton.h"
+#include "llviewerinventory.h"
+
+#include "rlvhelper.h"
+#include "rlvlocks.h"
+
+// ============================================================================
+// RlvInventory class declaration
+//
+
+// TODO-RLVa: [RLVa-1.2.0] Make all of this static rather than a singleton?
+class RlvInventory : public LLSingleton<RlvInventory>
+{
+protected:
+	RlvInventory() : m_fFetchStarted(false), m_fFetchComplete(false) {}
+
+	/*
+	 * #RLV Shared inventory
+	 */
+public:
+	// Find all folders that match a supplied criteria (clears the output array)
+	bool                       findSharedFolders(const std::string& strCriteria, LLInventoryModel::cat_array_t& folders) const;
+	// Gets the shared path for any shared items present in idItems (clears the output array)
+	bool                       getPath(const uuid_vec_t& idItems, LLInventoryModel::cat_array_t& folders) const;
+	// Returns a pointer to the shared root folder (if there is one)
+	LLViewerInventoryCategory* getSharedRoot() const;
+	// Returns a subfolder of idParent that starts with strFolderName (exact match > partial match)
+	LLViewerInventoryCategory* getSharedFolder(const LLUUID& idParent, const std::string& strFolderName) const;
+	// Looks up a folder from a path (relative to the shared root)
+	LLViewerInventoryCategory* getSharedFolder(const std::string& strPath) const;
+	// Returns the path of the supplied folder (relative to the shared root)
+	std::string                getSharedPath(const LLViewerInventoryCategory* pFolder) const;
+	// Returns TRUE if the supplied folder is a descendent of the #RLV folder
+	bool                       isSharedFolder(const LLUUID& idFolder);
+
+	/*
+	 * Inventory fetching
+	 */
+public:
+	void fetchSharedInventory();
+	void fetchWornItems();
+protected:
+	void fetchSharedLinks();
+
+	/*
+	 * General purpose helper functions
+	 */
+public:
+	// Returns the number of direct descendents of pFolder that have the specified type asset type
+	static S32 getDirectDescendentsCount(const LLInventoryCategory* pFolder, LLAssetType::EType filterType);
+	// A "folded folder" is a folder whose items logically belong to the grandparent rather than the parent
+	static bool isFoldedFolder(const LLInventoryCategory* pFolder, bool fCheckComposite);
+
+	/*
+	 * Member variables
+	 */
+protected:
+	bool m_fFetchStarted;			// TRUE if we fired off an inventory fetch
+	bool m_fFetchComplete;			// TRUE if everything was fetched
+
+private:
+	static const std::string cstrSharedRoot;
+	friend class RlvSharedInventoryFetcher;
+	friend class LLSingleton<RlvInventory>;
+};
+
+// ============================================================================
+// RlvRenameOnWearObserver - Handles "auto-rename-on-wear" for (linked) items living under #RLV
+//
+
+class RlvRenameOnWearObserver : public LLInventoryFetchItemsObserver
+{
+public:
+	RlvRenameOnWearObserver(const LLUUID& idItem) : LLInventoryFetchItemsObserver(idItem) {}
+	virtual ~RlvRenameOnWearObserver() {}
+	virtual void done();
+protected:
+	void doneIdle();
+};
+
+// ============================================================================
+// "Give to #RLV" helper classes
+//
+
+// [See LLInventoryTransactionObserver which says it's not entirely complete?]
+// NOTE: the offer may span mulitple BulkUpdateInventory messages so if we're no longer around then (ie due to "delete this") then
+//       we'll miss those; in this specific case we only care about the *folder* though and that will be in the very first message
+class RlvGiveToRLVTaskOffer : public LLInventoryObserver
+{
+public:
+	RlvGiveToRLVTaskOffer(const LLUUID& idTransaction) : m_idTransaction(idTransaction) {}
+	/*virtual*/ void changed(U32 mask);
+protected:
+	/*virtual*/ void done();
+	void doneIdle();
+
+	typedef std::vector<LLUUID> folder_ref_t;
+	folder_ref_t m_Folders;
+	LLUUID       m_idTransaction;
+};
+
+class RlvGiveToRLVAgentOffer : public LLInventoryFetchDescendentsObserver
+{
+public:
+	RlvGiveToRLVAgentOffer(const LLUUID& idFolder) : LLInventoryFetchDescendentsObserver(idFolder) {}
+	/*virtual*/ void done();
+protected:
+	void doneIdle();
+};
+
+// ============================================================================
+// RlvCriteriaCategoryCollector - Criteria based folder matching filter used by @findfolder and @findfolders
+//
+
+class RlvCriteriaCategoryCollector : public LLInventoryCollectFunctor
+{
+public:
+	RlvCriteriaCategoryCollector(const std::string& strCriteria)
+	{
+		std::string::size_type idxIt, idxLast = 0;
+		while (idxLast < strCriteria.length())
+		{
+			idxIt = strCriteria.find("&&", idxLast);
+			if (std::string::npos == idxIt)
+				idxIt = strCriteria.length();
+			if (idxIt != idxLast)
+				m_Criteria.push_back(strCriteria.substr(idxLast, idxIt - idxLast));
+			idxLast = idxIt + 2;
+		}
+	}
+	virtual ~RlvCriteriaCategoryCollector() {}
+
+	virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem)
+	{
+		if ( (!pFolder) || (m_Criteria.empty()) )	// We're only interested in matching folders, we don't care about items
+			return false;							// (if there are no criteria then we don't want to return a match)
+
+		std::string strFolderName = pFolder->getName();
+		LLStringUtil::toLower(strFolderName);
+
+		// NOTE: hidden or "give to #RLV" folders can never be a match
+		if ( (strFolderName.empty()) ||	
+			 (RLV_FOLDER_PREFIX_HIDDEN == strFolderName[0]) || (RLV_FOLDER_PREFIX_PUTINV == strFolderName[0]) )
+		{
+			return false;
+		}
+
+		for (std::list<std::string>::const_iterator itCrit = m_Criteria.begin(); itCrit != m_Criteria.end(); ++itCrit)
+			if (std::string::npos == strFolderName.find(*itCrit))
+				return false;
+		return true;
+	}
+
+protected:
+	std::list<std::string> m_Criteria;
+};
+
+// ============================================================================
+// RlvWearableItemCollector - Inventory item filter used by attach/detach/attachall/detachall/getinvworn
+//
+
+class RlvWearableItemCollector : public LLInventoryCollectFunctor
+{
+public:
+	RlvWearableItemCollector(const LLUUID& idFolder, bool fAttach, bool fMatchAll)
+		: m_idFolder(idFolder), m_fAttach(fAttach), m_fMatchAll(fMatchAll)
+	{
+		m_Wearable.push_back(idFolder);
+	}
+	virtual ~RlvWearableItemCollector() {}
+
+	virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem);
+
+	const LLUUID& getFoldedParent(const LLUUID& idFolder) const;
+protected:
+	bool         m_fAttach;
+	bool         m_fMatchAll;
+	const LLUUID m_idFolder;
+
+	bool onCollectFolder(const LLInventoryCategory* pFolder);
+	bool onCollectItem(const LLInventoryItem* pItem);
+
+	std::list<LLUUID> m_Folded;
+	std::list<LLUUID> m_Wearable;
+
+	std::map<LLUUID, LLUUID> m_FoldingMap;
+};
+
+// ============================================================================
+// General purpose inventory helper classes
+//
+
+class RlvIsLinkType : public LLInventoryCollectFunctor
+{
+public:
+	RlvIsLinkType() {}
+	virtual ~RlvIsLinkType() {}
+	virtual bool operator()(LLInventoryCategory* pFolder, LLInventoryItem* pItem) { return (pItem) && (pItem->getIsLinkType()); }
+};
+
+// ============================================================================
+// RlvInventory inlined member functions
+//
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+inline bool RlvInventory::isFoldedFolder(const LLInventoryCategory* pFolder, bool fCheckComposite)
+{
+	return
+	  // If legacy naming isn't enabled we can return early if the folder name doesn't start with a '.' (= the most common case)
+	  (pFolder) && ( (RlvSettings::getEnableLegacyNaming()) || (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) &&
+	  (
+		// .(<attachpt>) type folder
+		(0 != RlvAttachPtLookup::getAttachPointIndex(pFolder))
+		#ifdef RLV_EXTENSION_FLAG_NOSTRIP
+		// .(nostrip) folder
+		|| ( (pFolder) && (".("RLV_FOLDER_FLAG_NOSTRIP")" == pFolder->getName()) )
+		#endif // RLV_EXTENSION_FLAG_NOSTRIP
+		// Composite folder (if composite folders are enabled and we're asked to look for them)
+		#ifdef RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+		|| ( (fCheckComposite) && (RlvSettings::getEnableComposites()) &&
+		     (pFolder) && (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) && (isCompositeFolder(pFolder)) )
+		#endif // RLV_EXPERIMENTAL_COMPOSITEFOLDERS
+	  );
+}
+
+// Checked: 2010-08-29 (RLVa-1.2.0c) | Added: RLVa-1.2.0c
+inline bool RlvInventory::isSharedFolder(const LLUUID& idFolder)
+{
+	const LLViewerInventoryCategory* pRlvRoot = getSharedRoot();
+	return (pRlvRoot) ? (pRlvRoot->getUUID() != idFolder) && (gInventory.isObjectDescendentOf(idFolder, pRlvRoot->getUUID())) : false;
+}
+
+// ============================================================================
+
+#endif // RLV_INVENTORY_H
diff --git a/indra/newview/rlvlocks.cpp b/indra/newview/rlvlocks.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6001a926459f4d87a2fe0abdafa0a863e4cbdba2
--- /dev/null
+++ b/indra/newview/rlvlocks.cpp
@@ -0,0 +1,869 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llnotifications.h"
+#include "llviewerobjectlist.h"
+#include "pipeline.h"
+
+#include "rlvhelper.h"
+#include "rlvlocks.h"
+
+// ============================================================================
+// RlvAttachPtLookup member functions
+//
+
+std::map<std::string, S32> RlvAttachPtLookup::m_AttachPtLookupMap;
+
+// Checked: 2010-03-02 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvAttachPtLookup::initLookupTable()
+{
+	static bool fInitialized = false;
+	if (!fInitialized)
+	{
+		if (isAgentAvatarValid())
+		{
+			std::string strAttachPtName;
+			for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); 
+					 itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach)
+			{
+				const LLViewerJointAttachment* pAttachPt = itAttach->second;
+				if (pAttachPt)
+				{
+					strAttachPtName = pAttachPt->getName();
+					LLStringUtil::toLower(strAttachPtName);
+					m_AttachPtLookupMap.insert(std::pair<std::string, S32>(strAttachPtName, itAttach->first));
+				}
+			}
+			fInitialized = true;
+		}
+	}
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-0.2.2a
+S32 RlvAttachPtLookup::getAttachPointIndex(const LLViewerJointAttachment* pAttachPt)
+{
+	if (isAgentAvatarValid())
+	{
+		for (LLVOAvatar::attachment_map_t::const_iterator itAttach = gAgentAvatarp->mAttachmentPoints.begin(); 
+				itAttach != gAgentAvatarp->mAttachmentPoints.end(); ++itAttach)
+		{
+			if (itAttach->second == pAttachPt)
+				return itAttach->first;
+		}
+	}
+	return 0;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.0.1b
+S32 RlvAttachPtLookup::getAttachPointIndex(const LLInventoryCategory* pFolder)
+{
+	if (!pFolder)
+		return 0;
+
+	// RLVa-1.0.1 added support for legacy matching (See http://rlva.catznip.com/blog/2009/07/attachment-point-naming-convention/)
+	if (RlvSettings::getEnableLegacyNaming())
+		return getAttachPointIndexLegacy(pFolder);
+
+	// Otherwise the only valid way to specify an attachment point in a folder name is: ^\.\(\s+attachpt\s+\)
+	std::string::size_type idxMatch;
+	std::string strAttachPt = rlvGetFirstParenthesisedText(pFolder->getName(), &idxMatch);
+	LLStringUtil::trim(strAttachPt);
+
+	return ( (1 == idxMatch) && (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) ? getAttachPointIndex(strAttachPt) : 0;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+S32 RlvAttachPtLookup::getAttachPointIndex(const LLInventoryItem* pItem, bool fFollowLinks /*=true*/)
+{
+	// Sanity check - if it's not an object then it can't have an attachment point
+	if ( (!pItem) || (LLAssetType::AT_OBJECT != pItem->getType()) )
+		return 0;
+
+	// If the item is an inventory link then we first examine its target before examining the link itself
+	if ( (LLAssetType::AT_LINK == pItem->getActualType()) && (fFollowLinks) )
+	{
+		S32 idxAttachPt = getAttachPointIndex(gInventory.getItem(pItem->getLinkedUUID()), false);
+		if (idxAttachPt)
+			return idxAttachPt;
+	}
+
+	// The attachment point should be placed at the end of the item's name, surrounded by parenthesis
+	// (if there is no such text then strAttachPt will be an empty string which is fine since it means we'll look at the item's parent)
+	// (if the item is an inventory link then we only look at its containing folder and never examine its name)
+	std::string strAttachPt = 
+		(LLAssetType::AT_LINK != pItem->getActualType()) ? rlvGetLastParenthesisedText(pItem->getName()) : LLStringUtil::null;
+	LLStringUtil::trim(strAttachPt);
+
+	// If the item is modify   : we look at the item's name first and only then at the containing folder
+	// If the item is no modify: we look at the containing folder's name first and only then at the item itself
+	S32 idxAttachPt = 0;
+	if (pItem->getPermissions().allowModifyBy(gAgent.getID()))
+	{
+		idxAttachPt = (!strAttachPt.empty()) ? getAttachPointIndex(strAttachPt) : 0;
+		if (!idxAttachPt)
+			idxAttachPt = getAttachPointIndex(gInventory.getCategory(pItem->getParentUUID()));
+	}
+	else
+	{
+		idxAttachPt = getAttachPointIndex(gInventory.getCategory(pItem->getParentUUID()));
+		if ( (!idxAttachPt) && (!strAttachPt.empty()) )
+			idxAttachPt = getAttachPointIndex(strAttachPt);
+	}
+	return idxAttachPt;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.0.1b
+S32 RlvAttachPtLookup::getAttachPointIndexLegacy(const LLInventoryCategory* pFolder)
+{
+	// Hopefully some day this can just be deprecated (see http://rlva.catznip.com/blog/2009/07/attachment-point-naming-convention/)
+	if ( (!pFolder) || (pFolder->getName().empty()) )
+		return 0;
+
+	// Check for a (...) block *somewhere* in the name
+	std::string::size_type idxMatch;
+	std::string strAttachPt = rlvGetFirstParenthesisedText(pFolder->getName(), &idxMatch);
+	if (!strAttachPt.empty())
+	{
+		// Could be "(attachpt)", ".(attachpt)" or "Folder name (attachpt)"
+		if ( (0 != idxMatch) && ((1 != idxMatch) || (RLV_FOLDER_PREFIX_HIDDEN == pFolder->getName().at(0)) ) &&	// No '(' or '.(' start
+			 (idxMatch + strAttachPt.length() + 1 != pFolder->getName().length()) )								// or there's extra text
+		{
+			// It's definitely not one of the first two so assume it's the last form (in which case we need the last paranthesised block)
+			strAttachPt = rlvGetLastParenthesisedText(pFolder->getName());
+		}
+	}
+	else
+	{
+		// There's no paranthesised block, but it could still be "attachpt" or ".attachpt" (just strip away the '.' from the last one)
+		strAttachPt = pFolder->getName();
+		if (RLV_FOLDER_PREFIX_HIDDEN == strAttachPt[0])
+			strAttachPt.erase(0, 1);
+	}
+	return getAttachPointIndex(strAttachPt);
+}
+
+// ============================================================================
+// RlvAttachmentLocks member functions
+//
+
+RlvAttachmentLocks gRlvAttachmentLocks;
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvAttachmentLocks::addAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+#ifndef RLV_RELEASE
+	LLViewerObject* pDbgObj = gObjectList.findObject(idAttachObj);
+	// Assertion: the object specified by idAttachObj exists/is rezzed, is an attachment and always specifies the root
+	RLV_VERIFY( (pDbgObj) && (pDbgObj->isAttachment()) && (pDbgObj == pDbgObj->getRootEdit()) );
+#endif // RLV_RELEASE
+
+	m_AttachObjRem.insert(std::pair<LLUUID, LLUUID>(idAttachObj, idRlvObj));
+	updateLockedHUD();
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvAttachmentLocks::addAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+	// NOTE: m_AttachPtXXX can contain duplicate <idxAttachPt, idRlvObj> pairs (ie @detach:spine=n,detach=n from an attachment on spine)
+	if (eLock & RLV_LOCK_REMOVE)
+	{
+		m_AttachPtRem.insert(std::pair<S32, LLUUID>(idxAttachPt, idRlvObj));
+		updateLockedHUD();
+	}
+	if (eLock & RLV_LOCK_ADD)
+		m_AttachPtAdd.insert(std::pair<S32, LLUUID>(idxAttachPt, idRlvObj));
+}
+
+// Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+bool RlvAttachmentLocks::canDetach(const LLViewerJointAttachment* pAttachPt, bool fDetachAll /*=false*/) const
+{
+	//   (fDetachAll) | (isLockedAttachment)
+	//   ===================================
+	//        F       |         F             => unlocked attachment => return true
+	//        F       |         T             => locked attachment   => keep going
+	//        T       |         F             => unlocked attachment => keep going
+	//        T       |         T             => locked attachment   => return false
+	//  -> inside the loop : (A xor (not B)) condition and return !fDetachAll
+	//  -> outside the loop: return fDetachAll
+	//       fDetachAll == false : return false => all attachments are locked
+	//       fDetachAll == true  : return true  => all attachments are unlocked
+	if (pAttachPt)
+	{
+		for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+				itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+		{
+			if ( (fDetachAll) ^ (!isLockedAttachment(*itAttachObj)) )
+				return !fDetachAll;
+		}
+	}
+	return (pAttachPt) && (fDetachAll);
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+bool RlvAttachmentLocks::hasLockedAttachment(const LLViewerJointAttachment* pAttachPt) const
+{
+	if (pAttachPt)
+	{
+		for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+				itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+		{
+			if (isLockedAttachment(*itAttachObj))
+				return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+bool RlvAttachmentLocks::isLockedAttachmentExcept(const LLViewerObject* pObj, const LLUUID& idRlvObj) const
+{
+	if (idRlvObj.isNull())
+		return isLockedAttachment(pObj);
+
+	// If pObj is valid then it should always specify a root since we store root UUIDs in m_AttachObjRem
+	RLV_ASSERT( (!pObj) || (pObj == pObj->getRootEdit()) );
+
+	// Loop over every object that has the specified attachment locked (but ignore any locks owned by idRlvObj)
+	for (rlv_attachobjlock_map_t::const_iterator itAttachObj = m_AttachObjRem.lower_bound(pObj->getID()), 
+			endAttachObj = m_AttachObjRem.upper_bound(pObj->getID()); itAttachObj != endAttachObj; ++itAttachObj)
+	{
+		if (itAttachObj->second != idRlvObj)
+			return true;
+	}
+	return isLockedAttachmentPointExcept(RlvAttachPtLookup::getAttachPointIndex(pObj), RLV_LOCK_REMOVE, idRlvObj);
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.0.5b
+bool RlvAttachmentLocks::isLockedAttachmentPointExcept(S32 idxAttachPt, ERlvLockMask eLock, const LLUUID& idRlvObj) const
+{
+	if (idRlvObj.isNull())
+		return isLockedAttachmentPoint(idxAttachPt, eLock);
+
+	// Loop over every object that has the specified attachment point locked (but ignore any locks owned by idRlvObj)
+	if (eLock & RLV_LOCK_REMOVE)
+	{
+		for (rlv_attachptlock_map_t::const_iterator itAttachPt = m_AttachPtRem.lower_bound(idxAttachPt), 
+				endAttachPt = m_AttachPtRem.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt)
+		{
+			if (itAttachPt->second != idRlvObj)
+				return true;
+		}
+	}
+	if (eLock & RLV_LOCK_ADD)
+	{
+		for (rlv_attachptlock_map_t::const_iterator itAttachPt = m_AttachPtAdd.lower_bound(idxAttachPt), 
+				endAttachPt = m_AttachPtAdd.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt)
+		{
+			if (itAttachPt->second != idRlvObj)
+				return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvAttachmentLocks::removeAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+#ifndef RLV_RELEASE
+	// NOTE: pObj *can* be NULL [see comments for @detach=n in RlvHandler::onAddRemDetach()]
+	const LLViewerObject* pDbgObj = gObjectList.findObject(idAttachObj);
+	// Assertion: if the object exists then it's an attachment and always specifies the root
+	RLV_VERIFY( (!pDbgObj) || ((pDbgObj->isAttachment()) && (pDbgObj == pDbgObj->getRootEdit())) );
+#endif // RLV_RELEASE
+
+	// NOTE: try to remove the lock even if pObj isn't an attachment (ie in case the user was able to "Drop" it)
+	RLV_ASSERT( m_AttachObjRem.lower_bound(idAttachObj) != m_AttachObjRem.upper_bound(idAttachObj) ); // The lock should always exist
+	for (rlv_attachobjlock_map_t::iterator itAttachObj = m_AttachObjRem.lower_bound(idAttachObj), 
+			endAttachObj = m_AttachObjRem.upper_bound(idAttachObj); itAttachObj != endAttachObj; ++itAttachObj)
+	{
+		if (idRlvObj == itAttachObj->second)
+		{
+			m_AttachObjRem.erase(itAttachObj);
+			updateLockedHUD();
+			break;
+		}
+	}
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+void RlvAttachmentLocks::removeAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+	if (eLock & RLV_LOCK_REMOVE)
+	{
+		RLV_ASSERT( m_AttachPtRem.lower_bound(idxAttachPt) != m_AttachPtRem.upper_bound(idxAttachPt) ); // The lock should always exist
+		for (rlv_attachptlock_map_t::iterator itAttachPt = m_AttachPtRem.lower_bound(idxAttachPt), 
+				endAttachPt = m_AttachPtRem.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt)
+		{
+			if (idRlvObj == itAttachPt->second)
+			{
+				m_AttachPtRem.erase(itAttachPt);
+				updateLockedHUD();
+				break;
+			}
+		}
+	}
+	if (eLock & RLV_LOCK_ADD)
+	{
+		RLV_ASSERT( m_AttachPtAdd.lower_bound(idxAttachPt) != m_AttachPtAdd.upper_bound(idxAttachPt) ); // The lock should always exist
+		for (rlv_attachptlock_map_t::iterator itAttachPt = m_AttachPtAdd.lower_bound(idxAttachPt), 
+				endAttachPt = m_AttachPtAdd.upper_bound(idxAttachPt); itAttachPt != endAttachPt; ++itAttachPt)
+		{
+			if (idRlvObj == itAttachPt->second)
+			{
+				m_AttachPtAdd.erase(itAttachPt);
+				break;
+			}
+		}
+	}
+}
+
+// Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a
+void RlvAttachmentLocks::updateLockedHUD()
+{
+	if (!isAgentAvatarValid())
+		return;
+
+	m_fHasLockedHUD = false;
+	for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); 
+			itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt)
+	{
+		const LLViewerJointAttachment* pAttachPt = itAttachPt->second;
+		if ( (pAttachPt) && (pAttachPt->getIsHUDAttachment()) && (hasLockedAttachment(pAttachPt)) )
+		{
+			m_fHasLockedHUD = true;
+			break;
+		}
+	}
+
+	// Reset HUD visibility and wireframe options if at least one HUD attachment is locked
+	if (m_fHasLockedHUD)
+	{
+		LLPipeline::sShowHUDAttachments = TRUE;
+		gUseWireframe = FALSE;
+	}
+}
+
+// Checked: 2010-03-11 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+bool RlvAttachmentLocks::verifyAttachmentLocks()
+{
+	bool fSuccess = true;
+
+	// Verify attachment locks
+	rlv_attachobjlock_map_t::iterator itAttachObj = m_AttachObjRem.begin(), itCurrentObj;
+	while (itAttachObj != m_AttachObjRem.end())
+	{
+		itCurrentObj = itAttachObj++;
+
+		// If the attachment no longer exists (or is no longer attached) then we shouldn't be holding a lock to it
+		const LLViewerObject* pAttachObj = gObjectList.findObject(itCurrentObj->first);
+		if ( (!pAttachObj) || (!pAttachObj->isAttachment()) )
+		{
+			m_AttachObjRem.erase(itCurrentObj);
+			fSuccess = false;
+		}
+	}
+
+	return fSuccess;
+}
+
+// ============================================================================
+// RlvAttachmentLockWatchdog member functions
+//
+
+// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+void RlvAttachmentLockWatchdog::attach(S32 idxAttachPt, const LLUUID& idItem)
+{
+	// RELEASE-RLVa: [SL-2.0.0] This will need rewriting for "ENABLE_MULTIATTACHMENTS"
+	LLSD payload;
+	payload["item_id"] = idItem;
+	payload["attachment_point"] = idxAttachPt | ATTACHMENT_ADD;
+	payload["rlv_force"] = true;
+	LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0);
+}
+
+// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+void RlvAttachmentLockWatchdog::detach(const LLViewerObject* pAttachObj)
+{
+	if (pAttachObj)
+	{
+		gMessageSystem->newMessage("ObjectDetach");
+		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+		gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+		gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+		gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+		gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, pAttachObj->getLocalID());
+		if (std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID()) == m_PendingDetach.end())
+			m_PendingDetach.push_back(pAttachObj->getAttachmentItemID());
+
+		gMessageSystem->sendReliable(gAgent.getRegionHost() );
+
+		// HACK-RLVa: force the region to send out an ObjectUpdate for the old attachment so obsolete viewers will remember it exists
+		S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachObj);
+		const LLViewerJointAttachment* pAttachPt = 
+			(isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, (S32)idxAttachPt, (LLViewerJointAttachment*)NULL) : NULL;
+		if ( (pAttachPt) && (!pAttachPt->getIsHUDAttachment()) && (pAttachPt->mAttachedObjects.size() > 1) )
+		{
+			for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+					itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+			{
+				if (pAttachObj != *itAttachObj)
+				{
+					LLSelectMgr::instance().deselectAll();
+					LLSelectMgr::instance().selectObjectAndFamily(*itAttachObj);
+					LLSelectMgr::instance().deselectAll();
+					break;
+				}
+			}
+		}
+	}
+}
+
+// Checked: 2010-07-28 (RLVa-1.2.0i) | Added: RLVa-1.2.0i
+void RlvAttachmentLockWatchdog::detach(S32 idxAttachPt, const LLViewerObject* pAttachObjExcept /*=NULL*/)
+{
+	const LLViewerJointAttachment* pAttachPt = 
+		(isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, (S32)idxAttachPt, (LLViewerJointAttachment*)NULL) : NULL;
+	if (!pAttachPt)
+		return;
+
+	std::list<const LLViewerObject*> attachObjs;
+	for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+			itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+	{
+		const LLViewerObject* pAttachObj = *itAttachObj;
+		if (pAttachObj != pAttachObjExcept)
+			attachObjs.push_back(pAttachObj);
+	}
+
+	if (!attachObjs.empty())
+	{
+		gMessageSystem->newMessage("ObjectDetach");
+		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+		gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+		gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+		
+		for (std::list<const LLViewerObject*>::const_iterator itAttachObj = attachObjs.begin(); 
+				itAttachObj != attachObjs.end(); ++itAttachObj)
+		{
+			const LLViewerObject* pAttachObj = *itAttachObj;
+			gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+			gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, pAttachObj->getLocalID());
+			if (std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID()) == m_PendingDetach.end())
+				m_PendingDetach.push_back(pAttachObj->getAttachmentItemID());
+		}
+
+		gMessageSystem->sendReliable(gAgent.getRegionHost());
+
+		// HACK-RLVa: force the region to send out an ObjectUpdate for the old attachment so obsolete viewers will remember it exists
+		if ( (!pAttachPt->getIsHUDAttachment()) && (pAttachPt->mAttachedObjects.size() > attachObjs.size()) )
+		{
+			for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+					itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+			{
+				if (std::find(attachObjs.begin(), attachObjs.end(), *itAttachObj) == attachObjs.end())
+				{
+					LLSelectMgr::instance().deselectAll();
+					LLSelectMgr::instance().selectObjectAndFamily(*itAttachObj);
+					LLSelectMgr::instance().deselectAll();
+					break;
+				}
+			}
+		}
+	}
+}
+
+// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+void RlvAttachmentLockWatchdog::onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt)
+{
+	S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachObj);
+	const LLUUID& idAttachItem = (pAttachObj) ? pAttachObj->getAttachmentItemID() : LLUUID::null;
+	RLV_ASSERT( (!isAgentAvatarValid()) || ((idxAttachPt) && (idAttachItem.notNull())) );
+	if ( (!idxAttachPt) || (idAttachItem.isNull()) )
+		return;
+
+	// Check if the attachment point has a pending "reattach"
+	rlv_attach_map_t::iterator itAttach = m_PendingAttach.lower_bound(idxAttachPt), itAttachEnd = m_PendingAttach.upper_bound(idxAttachPt);
+	if (itAttach != itAttachEnd)
+	{
+		bool fPendingReattach = false;
+		for (; itAttach != itAttachEnd; ++itAttach)
+		{
+			if (idAttachItem == itAttach->second.idItem)
+			{
+				fPendingReattach = true;
+				m_PendingAttach.erase(itAttach);
+				break;
+			}
+		}
+		if (!fPendingReattach)
+			detach(pAttachObj);
+		return;
+	}
+
+	// Check if the attach is the result of a user action (="Wear")
+	rlv_wear_map_t::iterator itWear = m_PendingWear.find(idAttachItem);
+	if (itWear != m_PendingWear.end())
+	{
+		// We need to return the attachment point to its previous state if an attachment was added to a non-attachable attachment point
+		if (gRlvAttachmentLocks.isLockedAttachmentPoint(idxAttachPt, RLV_LOCK_ADD))
+		{
+			// Get the state of the attachment point at the time the user picked "Wear" (but do nothing if the item itself was worn then)
+			std::map<S32, std::list<LLUUID> >::iterator itAttachPrev = itWear->second.attachPts.find(idxAttachPt);
+			RLV_ASSERT(itAttachPrev != itWear->second.attachPts.end());
+			if ( (itAttachPrev != itWear->second.attachPts.end()) &&
+				 (std::find(itAttachPrev->second.begin(), itAttachPrev->second.end(), idAttachItem)) == itAttachPrev->second.end())
+			{
+				// If it was empty we need to detach everything on the attachment point; if it wasn't we need to restore it to what it was
+				if (itAttachPrev->second.empty())
+				{
+					detach(idxAttachPt);
+				}
+				else
+				{
+					// Iterate over all the current attachments and force detach any that shouldn't be there
+					std::list<const LLViewerObject*> attachObjs;
+					for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+							itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+					{
+						const LLViewerObject* pAttachObj = *itAttachObj;
+
+						std::list<LLUUID>::iterator itAttach = 
+							std::find(itAttachPrev->second.begin(), itAttachPrev->second.end(), pAttachObj->getAttachmentItemID());
+						if (itAttach == itAttachPrev->second.end())
+							detach(pAttachObj);
+						else
+							itAttachPrev->second.erase(itAttach);
+					}
+
+					// Whatever is left is something that needs to be reattached
+					for (std::list<LLUUID>::iterator itAttach = itAttachPrev->second.begin(); 
+							itAttach != itAttachPrev->second.end(); ++itAttach)
+					{
+						m_PendingAttach.insert(std::pair<S32, RlvReattachInfo>(idxAttachPt, RlvReattachInfo(*itAttach)));
+					}
+				}
+			}
+		}
+		else if (RLV_WEAR_REPLACE == itWear->second.eWearAction)
+		{
+			// Now that we know where this attaches to check if we can actually perform a "replace"
+			bool fCanReplace = true;
+			for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+					((itAttachObj != pAttachPt->mAttachedObjects.end()) && (fCanReplace)); ++itAttachObj)
+			{
+				if (pAttachObj != *itAttachObj)
+					fCanReplace &= !gRlvAttachmentLocks.isLockedAttachment(*itAttachObj);
+			}
+
+			if (fCanReplace)
+				detach(idxAttachPt, pAttachObj);	// Replace == allowed: detach everything except the new attachment
+			else
+				detach(pAttachObj);					// Replace != allowed: detach the new attachment
+		}
+		m_PendingWear.erase(itWear); // No need to start the timer since it should be running already if '!m_PendingWear.empty()'
+	}
+}
+
+// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+void RlvAttachmentLockWatchdog::onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt)
+{
+	S32 idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt);
+	const LLUUID& idAttachItem = (pAttachObj) ? pAttachObj->getAttachmentItemID() : LLUUID::null;
+	RLV_ASSERT( (!isAgentAvatarValid()) || ((idxAttachPt) && (idAttachItem.notNull())) );
+	if ( (!idxAttachPt) || (idAttachItem.isNull()) )
+		return;
+
+	// If it's an attachment that's pending force-detach then we don't want to do anything (even if it's currently "remove locked")
+	rlv_detach_map_t::iterator itDetach = std::find(m_PendingDetach.begin(), m_PendingDetach.end(), idAttachItem);
+	if (itDetach != m_PendingDetach.end())
+	{
+		m_PendingDetach.erase(itDetach);
+		return;
+	}
+
+	// If the attachment is currently "remove locked" then we should reattach it (unless it's already pending reattach)
+	if (gRlvAttachmentLocks.isLockedAttachment(pAttachObj))
+	{
+		bool fPendingAttach = false;
+		for (rlv_attach_map_t::const_iterator itReattach = m_PendingAttach.lower_bound(idxAttachPt), 
+				itReattachEnd = m_PendingAttach.upper_bound(idxAttachPt); itReattach != itReattachEnd; ++itReattach)
+		{
+			if (itReattach->second.idItem == idAttachItem)
+			{
+				fPendingAttach = true;
+				break;
+			}
+		}
+
+		// TODO-RLVa: [RLVa-1.2.1] we should re-add the item to COF as well to make sure it'll reattach when the user relogs
+		//		-> check the call order in LLVOAvatarSelf::detachObject() since COF removal happens *after* we're called
+		if (!fPendingAttach)
+		{
+			m_PendingAttach.insert(std::pair<S32, RlvReattachInfo>(idxAttachPt, RlvReattachInfo(idAttachItem)));
+			startTimer();
+		}
+	}
+}
+
+// Checked: 2010-03-05 (RLVa-1.2.0a) | Modified: RLVa-1.0.5b
+void RlvAttachmentLockWatchdog::onSavedAssetIntoInventory(const LLUUID& idItem)
+{
+	for (rlv_attach_map_t::iterator itAttach = m_PendingAttach.begin(); itAttach != m_PendingAttach.end(); ++itAttach)
+	{
+		if ( (!itAttach->second.fAssetSaved) && (idItem == itAttach->second.idItem) )
+		{
+			attach(itAttach->first, itAttach->second.idItem);
+			itAttach->second.tsAttach = LLFrameTimer::getElapsedSeconds();
+		}
+	}
+}
+
+// Checked: 2010-03-05 (RLVa-1.2.0a) | Modified: RLVa-1.0.5b
+BOOL RlvAttachmentLockWatchdog::onTimer()
+{
+	// RELEASE-RLVa: [SL-2.0.0] This will need rewriting for "ENABLE_MULTIATTACHMENTS"
+	F64 tsCurrent = LLFrameTimer::getElapsedSeconds();
+
+	// Garbage collect (failed) wear requests older than 60 seconds
+	rlv_wear_map_t::iterator itWear = m_PendingWear.begin();
+	while (itWear != m_PendingWear.end())
+	{
+		if (itWear->second.tsWear + 60 < tsCurrent)
+			m_PendingWear.erase(itWear++);
+		else
+			++itWear;
+	}
+
+	// Walk over the pending reattach list
+	rlv_attach_map_t::iterator itAttach = m_PendingAttach.begin();
+	while (itAttach != m_PendingAttach.end())
+	{
+		// Sanity check - make sure the item is still in the user's inventory
+		if (gInventory.getItem(itAttach->second.idItem) == NULL)
+		{
+			m_PendingAttach.erase(itAttach++);
+			continue;
+		}
+
+		// Force an attach if we haven't gotten a SavedAssetIntoInventory message after 15 seconds
+		// (or if it's been 30 seconds since we last tried to reattach the item)
+		bool fAttach = false;
+		if ( (!itAttach->second.fAssetSaved) && (itAttach->second.tsDetach + 15 < tsCurrent) )
+		{
+			itAttach->second.fAssetSaved = true;
+			fAttach = true;
+		}
+		else if ( (itAttach->second.fAssetSaved) && (itAttach->second.tsAttach + 30 < tsCurrent) )
+		{
+			fAttach = true;
+		}
+
+		if (fAttach)
+		{
+			attach(itAttach->first, itAttach->second.idItem);
+			itAttach->second.tsAttach = tsCurrent;
+		}
+
+		++itAttach;
+	}
+
+	return ( (m_PendingAttach.empty()) && (m_PendingDetach.empty()) && (m_PendingWear.empty()) );
+}
+
+// Checked: 2010-07-28 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+void RlvAttachmentLockWatchdog::onWearAttachment(const LLUUID& idItem, ERlvWearMask eWearAction)
+{
+	// We only need to keep track of user wears if there's actually anything locked
+	RLV_ASSERT(idItem.notNull());
+	if ( (idItem.isNull()) || (!isAgentAvatarValid()) || (!gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) )
+		return;
+
+	// If the attachment point this will end up being attached to is:
+	//   - unlocked    : nothing should happen (from RLVa's point of view)
+	//   - RLV_LOCK_ADD: the new attachment should get detached and the current one(s) reattached (unless it's currently empty)
+	//   - RLV_LOCK_REM:
+	//       o eWearAction == RLV_WEAR_ADD     : nothing should happen (from RLVa's point of view)
+	//       o eWearAction == RLV_WEAR_REPLACE : examine whether the new attachment can indeed replace/detach the old one
+	RlvWearInfo infoWear(idItem, eWearAction);
+	RLV_ASSERT( (RLV_WEAR_ADD == eWearAction) || (RLV_WEAR_REPLACE == eWearAction) ); // One of the two, but never both
+	for (LLVOAvatar::attachment_map_t::const_iterator itAttachPt = gAgentAvatarp->mAttachmentPoints.begin(); 
+			itAttachPt != gAgentAvatarp->mAttachmentPoints.end(); ++itAttachPt)
+	{
+		const LLViewerJointAttachment* pAttachPt = itAttachPt->second;
+		// We only need to know which attachments were present for RLV_LOCK_ADD locked attachment points (and not RLV_LOCK_REM locked ones)
+		if (gRlvAttachmentLocks.isLockedAttachmentPoint(pAttachPt, RLV_LOCK_ADD))
+		{
+			std::list<LLUUID> attachObjs;
+			for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator itAttachObj = pAttachPt->mAttachedObjects.begin();
+					itAttachObj != pAttachPt->mAttachedObjects.end(); ++itAttachObj)
+			{
+				const LLViewerObject* pAttachObj = *itAttachObj;
+				if (std::find(m_PendingDetach.begin(), m_PendingDetach.end(), pAttachObj->getAttachmentItemID()) != m_PendingDetach.end())
+					continue;	// Exclude attachments that are pending a force-detach
+				attachObjs.push_back(pAttachObj->getAttachmentItemID());
+			}
+			infoWear.attachPts.insert(std::pair<S32, std::list<LLUUID> >(itAttachPt->first, attachObjs));
+		}
+	}
+
+	m_PendingWear.insert(std::pair<LLUUID, RlvWearInfo>(idItem, infoWear));
+	startTimer();
+}
+
+// ============================================================================
+// RlvWearableLocks member functions
+//
+
+RlvWearableLocks gRlvWearableLocks;
+
+// Checked: 2010-03-18 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+void RlvWearableLocks::addWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+	// NOTE: m_WearableTypeXXX can contain duplicate <eType, idRlvObj> pairs (ie @remoutfit:shirt=n,remoutfit=n from the same object)
+	if (eLock & RLV_LOCK_REMOVE)
+		m_WearableTypeRem.insert(std::pair<LLWearableType::EType, LLUUID>(eType, idRlvObj));
+	if (eLock & RLV_LOCK_ADD)
+		m_WearableTypeAdd.insert(std::pair<LLWearableType::EType, LLUUID>(eType, idRlvObj));
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+bool RlvWearableLocks::canRemove(LLWearableType::EType eType) const
+{
+	// NOTE: we return TRUE if the wearable type has at least one wearable that can be removed by the user
+	for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(eType); idxWearable < cntWearable; idxWearable++)
+		if (!isLockedWearable(gAgentWearables.getWearable(eType, idxWearable)))
+			return true;
+	return false;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+bool RlvWearableLocks::hasLockedWearable(LLWearableType::EType eType) const
+{
+	// NOTE: we return TRUE if there is at least 1 non-removable wearable currently worn on this wearable type
+	for (U32 idxWearable = 0, cntWearable = gAgentWearables.getWearableCount(eType); idxWearable < cntWearable; idxWearable++)
+		if (isLockedWearable(gAgentWearables.getWearable(eType, idxWearable)))
+			return true;
+	return false;
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+bool RlvWearableLocks::isLockedWearableExcept(const LLWearable* pWearable, const LLUUID& idRlvObj) const
+{
+	if (idRlvObj.isNull())
+		return isLockedWearable(pWearable);
+
+	// TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do
+	return (pWearable) && (isLockedWearableTypeExcept(pWearable->getType(), RLV_LOCK_REMOVE, idRlvObj));
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+bool RlvWearableLocks::isLockedWearableTypeExcept(LLWearableType::EType eType, ERlvLockMask eLock, const LLUUID& idRlvObj) const
+{
+	if (idRlvObj.isNull())
+		return isLockedWearableType(eType, eLock);
+
+	// Loop over every object that marked the specified wearable type eLock type locked and skip over anything owned by idRlvObj
+	if (eLock & RLV_LOCK_REMOVE)
+	{
+		for (rlv_wearabletypelock_map_t::const_iterator itWearableType = m_WearableTypeRem.lower_bound(eType), 
+				endWearableType = m_WearableTypeRem.upper_bound(eType); itWearableType != endWearableType; ++itWearableType)
+		{
+			if (itWearableType->second != idRlvObj)
+				return true;
+		}
+	}
+	if (eLock & RLV_LOCK_ADD)
+	{
+		for (rlv_wearabletypelock_map_t::const_iterator itWearableType = m_WearableTypeAdd.lower_bound(eType), 
+				endWearableType = m_WearableTypeAdd.upper_bound(eType); itWearableType != endWearableType; ++itWearableType)
+		{
+			if (itWearableType->second != idRlvObj)
+				return true;
+		}
+	}
+	return false;
+}
+
+// Checked: 2010-03-18 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+void RlvWearableLocks::removeWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock)
+{
+/*
+	// Sanity check - make sure it's an object we know about
+	if ( (m_Objects.find(idRlvObj) == m_Objects.end()) || (!idxAttachPt) )
+		return;	// If (idxAttachPt) == 0 then: (pObj == NULL) || (pObj->isAttachment() == FALSE)
+*/
+
+	if (eLock & RLV_LOCK_REMOVE)
+	{
+		RLV_ASSERT( m_WearableTypeRem.lower_bound(eType) != m_WearableTypeRem.upper_bound(eType) ); // The lock should always exist
+		for (rlv_wearabletypelock_map_t::iterator itWearableType = m_WearableTypeRem.lower_bound(eType), 
+				endWearableType = m_WearableTypeRem.upper_bound(eType); itWearableType != endWearableType; ++itWearableType)
+		{
+			if (idRlvObj == itWearableType->second)
+			{
+				m_WearableTypeRem.erase(itWearableType);
+				break;
+			}
+		}
+	}
+	if (eLock & RLV_LOCK_ADD)
+	{
+		RLV_ASSERT( m_WearableTypeAdd.lower_bound(eType) != m_WearableTypeAdd.upper_bound(eType) ); // The lock should always exist
+		for (rlv_wearabletypelock_map_t::iterator itWearableType = m_WearableTypeAdd.lower_bound(eType), 
+				endWearableType = m_WearableTypeAdd.upper_bound(eType); itWearableType != endWearableType; ++itWearableType)
+		{
+			if (idRlvObj == itWearableType->second)
+			{
+				m_WearableTypeAdd.erase(itWearableType);
+				break;
+			}
+		}
+	}
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvlocks.h b/indra/newview/rlvlocks.h
new file mode 100644
index 0000000000000000000000000000000000000000..262570a7ada99fa2a5da145aad7c309d7dc4bd76
--- /dev/null
+++ b/indra/newview/rlvlocks.h
@@ -0,0 +1,459 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_LOCKS_H
+#define RLV_LOCKS_H
+
+#include "llagentwearables.h"
+#include "lleventtimer.h"
+
+#include "rlvdefines.h"
+#include "rlvcommon.h"
+
+// ============================================================================
+// RlvAttachPtLookup class declaration
+//
+
+#include "llagent.h"
+#include "llviewerjointattachment.h"
+#include "llviewerobject.h"
+#include "llvoavatarself.h"
+
+#include "rlvdefines.h"
+
+class RlvAttachPtLookup
+{
+public:
+	static LLViewerJointAttachment* getAttachPoint(const std::string& strText);
+	static LLViewerJointAttachment* getAttachPoint(const LLInventoryItem* pItem);
+
+	static S32 getAttachPointIndex(std::string strText);
+	static S32 getAttachPointIndex(const LLViewerObject* pObj);
+	static S32 getAttachPointIndex(const LLViewerJointAttachment* pObj);
+	static S32 getAttachPointIndex(const LLInventoryCategory* pFolder);
+	static S32 getAttachPointIndex(const LLInventoryItem* pItem, bool fFollowLinks = true);
+
+	static bool hasAttachPointName(const LLInventoryItem* pItem) { return (0 != getAttachPointIndex(pItem)); }
+private:
+	static S32 getAttachPointIndexLegacy(const LLInventoryCategory* pFolder);
+
+public:
+	static void initLookupTable();
+private:
+	static std::map<std::string, S32> m_AttachPtLookupMap;
+};
+
+// ============================================================================
+// RlvAttachmentLocks class declaration
+//
+
+// TODO-RLVa: [RLVa-1.2.1] Once everything is working for SL-2.0 thin out the member functions since a few of them are duplicates/unneeded
+class RlvAttachmentLocks
+{
+public:
+	RlvAttachmentLocks() : m_fHasLockedHUD(false) {}
+
+public:
+	// Adds an RLV_LOCK_REMOVE lock (held by idRlvObj) for the attachment
+	void addAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj);
+	// Adds an eLock type lock (held by idRlvObj) for the attachment point
+	void addAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock);
+
+	// Returns TRUE if there is at least 1 non-detachable attachment currently attached to the attachment point
+	bool hasLockedAttachment(const LLViewerJointAttachment* pAttachPt) const;
+	// Returns TRUE if there is at least 1 eLock type locked attachment point (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE)
+	//   - RLV_LOCK_REMOVE: specific attachment locked *or* any attachment point locked (regardless of whether it currently has attachments)
+	bool hasLockedAttachmentPoint(ERlvLockMask eLock) const;
+	// Returns TRUE if there is at least 1 non-detachable HUD attachment
+	bool hasLockedHUD() const { return m_fHasLockedHUD; }
+
+	// Returns TRUE if the attachment is RLV_LOCK_REMOVE locked
+	bool isLockedAttachment(const LLViewerObject* pObj) const;
+	bool isLockedAttachment(const LLInventoryItem* pItem) const;
+	// Returns TRUE if the attachment point is RLV_LOCK_REMOVE locked by anything other than idRlvObj
+	bool isLockedAttachmentExcept(const LLViewerObject* pObj, const LLUUID& idRlvObj) const;
+	// Returns TRUE if the attachment point is eLock type locked (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE)
+	bool isLockedAttachmentPoint(S32 idxAttachPt, ERlvLockMask eLock) const;
+	bool isLockedAttachmentPoint(const LLViewerJointAttachment* pAttachPt, ERlvLockMask eLock) const;
+
+	// Removes an RLV_LOCK_REMOVE lock (held by idRlvObj) for the attachment
+	void removeAttachmentLock(const LLUUID& idAttachObj, const LLUUID& idRlvObj);
+	// Removes an eLock type lock (held by idRlvObj) for the attachment point
+	void removeAttachmentPointLock(S32 idxAttachPt, const LLUUID& idRlvObj, ERlvLockMask eLock);
+
+	// Refreshes locked HUD attachment state
+	void updateLockedHUD();
+	// Iterates over all current attachment and attachment point locks and verifies their status (returns TRUE if verification succeeded)
+	bool verifyAttachmentLocks();
+
+protected:
+	// Returns TRUE if the attachment point is eLock type locked by anything other than idRlvObj
+	bool isLockedAttachmentPointExcept(S32 idxAttachPt, ERlvLockMask eLock, const LLUUID& idRlvObj) const;
+
+	/*
+	 * canAttach/canDetach trivial helper functions (note that a more approriate name might be userCanAttach/userCanDetach)
+	 */
+public:
+	// Returns TRUE if the inventory item can be attached by the user (and optionally provides the attachment point - which may be NULL)
+	ERlvWearMask canAttach(const LLInventoryItem* pItem, LLViewerJointAttachment** ppAttachPtOut = NULL) const;
+	// Returns TRUE if the attachment point can be attached to by the user
+	ERlvWearMask canAttach(const LLViewerJointAttachment* pAttachPt) const;
+
+	// Returns TRUE if the inventory item can be detached by the user
+	bool canDetach(const LLInventoryItem* pItem) const { return !isLockedAttachment(pItem); }
+	// Returns TRUE if the attachment point has at least one attachment that can be detached by the user
+	bool canDetach(const LLViewerJointAttachment* pAttachPt, bool fDetachAll = false) const;
+
+	/*
+	 * Member variables
+	 */
+public:
+	typedef std::multimap<LLUUID, LLUUID> rlv_attachobjlock_map_t;
+	typedef std::multimap<S32, LLUUID> rlv_attachptlock_map_t;
+	// Accessors for RlvFloaterLocks
+	const rlv_attachptlock_map_t& getAttachPtLocks(ERlvLockMask eLock) { return (RLV_LOCK_ADD == eLock) ? m_AttachPtAdd : m_AttachPtRem; }
+	const rlv_attachobjlock_map_t& getAttachObjLocks() { return m_AttachObjRem; }
+private:
+	rlv_attachptlock_map_t	m_AttachPtAdd;		// Map of attachment points that can't be attached to (idxAttachPt -> idObj)
+	rlv_attachptlock_map_t	m_AttachPtRem;		// Map of attachment points whose attachments can't be detached (idxAttachPt -> idObj)
+	rlv_attachobjlock_map_t	m_AttachObjRem;		// Map of attachments that can't be detached (idAttachObj -> idObj)
+
+	bool m_fHasLockedHUD;
+};
+
+extern RlvAttachmentLocks gRlvAttachmentLocks;
+
+// ============================================================================
+// RlvAttachmentLockWatchdog - Self contained class that automagically takes care of enforcing attachment locks (ie reattach-on-detach)
+//
+
+// TODO-RLVa: [RLVa-1.2.1] This class really looks rather cluttered so look into cleaning it up/simplifying it a bit
+class RlvAttachmentLockWatchdog : public LLSingleton<RlvAttachmentLockWatchdog>
+{
+	friend class LLSingleton<RlvAttachmentLockWatchdog>;
+protected:
+	RlvAttachmentLockWatchdog() : m_pTimer(NULL) {}
+	~RlvAttachmentLockWatchdog() { delete m_pTimer; }
+
+	/*
+	 * Member functions
+	 */
+protected:
+	// NOTE: attach/detach do *not* respect attachment locks so use with care
+	void attach(S32 idxAttachPt, const LLUUID& idItem);
+	void detach(const LLViewerObject* pAttachObj);
+	void detach(S32 idxAttachPt, const LLViewerObject* pAttachObjExcept = NULL);
+
+	void startTimer() { if (!m_pTimer) m_pTimer = new RlvAttachmentLockWatchdogTimer(this); }
+
+	/*
+	 * Event handlers
+	 */
+public:
+	void onAttach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt);
+	void onDetach(const LLViewerObject* pAttachObj, const LLViewerJointAttachment* pAttachPt);
+	void onSavedAssetIntoInventory(const LLUUID& idItem);
+	BOOL onTimer();
+	void onWearAttachment(const LLInventoryItem* pItem, ERlvWearMask eWearAction);
+	void onWearAttachment(const LLUUID& idItem, ERlvWearMask eWearAction);
+
+	/*
+	 * Member variables
+	 */
+protected:
+	typedef std::list<LLUUID> rlv_detach_map_t;
+	rlv_detach_map_t m_PendingDetach;
+
+	struct RlvReattachInfo
+	{
+		RlvReattachInfo(const LLUUID& itemid) : idItem(itemid), fAssetSaved(false), tsAttach(0) 
+			{ tsDetach = LLFrameTimer::getElapsedSeconds(); }
+
+		LLUUID idItem;
+		bool   fAssetSaved;
+		F64    tsDetach;
+		F64    tsAttach;
+	protected:
+		RlvReattachInfo();
+	};
+	typedef std::multimap<S32, RlvReattachInfo> rlv_attach_map_t;
+	rlv_attach_map_t m_PendingAttach;
+
+	struct RlvWearInfo
+	{
+		RlvWearInfo(const LLUUID& itemid, ERlvWearMask wearaction) : idItem(itemid), eWearAction(wearaction)
+			{ tsWear = LLFrameTimer::getElapsedSeconds(); }
+
+		LLUUID       idItem;
+		ERlvWearMask eWearAction;
+		F64          tsWear;
+		std::map<S32, std::list<LLUUID> > attachPts;
+	protected:
+		RlvWearInfo();
+	};
+	typedef std::map<LLUUID, RlvWearInfo> rlv_wear_map_t;
+	rlv_wear_map_t   m_PendingWear;
+
+	class RlvAttachmentLockWatchdogTimer : public LLEventTimer
+	{
+	public:
+		RlvAttachmentLockWatchdogTimer(RlvAttachmentLockWatchdog* pWatchdog) : LLEventTimer(10), m_pWatchdog(pWatchdog) {}
+		virtual ~RlvAttachmentLockWatchdogTimer() { m_pWatchdog->m_pTimer = NULL; }
+		virtual BOOL tick() { return m_pWatchdog->onTimer(); }
+		RlvAttachmentLockWatchdog* m_pWatchdog;
+	} *m_pTimer;
+};
+
+// ============================================================================
+// RlvWearableLocks class declaration - modelled on RlvAttachmentLocks (attach pt = wearable type - attachment = wearable)
+//
+
+class RlvWearableLocks
+{
+public:
+	// Adds an eLock type lock (held by idRlvObj) for the wearable type
+	void addWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock);
+
+	// Returns TRUE if there is at least 1 non-removable wearable currently worn on this wearable type
+	bool hasLockedWearable(LLWearableType::EType eType) const;
+	// Returns TRUE if there is at least 1 eLock type locked wearable type (RLV_LOCK_ANY = RLV_LOCK_ADD *or* RLV_LOCK_REMOVE)
+	//   - RLV_LOCK_REMOVE: specific wearable locked *or* any wearable type locked (regardless of whether it currently has wearables)
+	bool hasLockedWearableType(ERlvLockMask eLock) const;
+
+	// Removes an eLock type lock (held by idRlvObj) for the wearable type
+	void removeWearableTypeLock(LLWearableType::EType eType, const LLUUID& idRlvObj, ERlvLockMask eLock);
+
+	// Returns TRUE if the wearable is RLV_LOCK_REMOVE locked
+	bool isLockedWearable(const LLWearable* pWearable) const;
+	bool isLockedWearable(const LLInventoryItem* pItem) const;
+	// Returns TRUE if the wearable is RLV_LOCK_REMOVE locked by anything other than idRlvObj
+	bool isLockedWearableExcept(const LLWearable* pWearable, const LLUUID& idRlvObj) const;
+
+	// NOTE: isLockedWearableType doesn't check if a worn wearable is a specific wearable lock so don't let these be called by the outside
+protected:
+	// Returns TRUE if the wearable type is eLock type locked
+	bool isLockedWearableType(LLWearableType::EType eType, ERlvLockMask eLock) const;
+	// Returns TRUE if the wearable type is eLock type locked by anything other than idRlvObj
+	bool isLockedWearableTypeExcept(LLWearableType::EType eType, ERlvLockMask eLock, const LLUUID& idRlvObj) const;
+
+	/*
+	 * canWear/canRemove trivial helper functions (note that a more approriate name might be userCanWear/userCanRemove)
+	 */
+public:
+	// Returns whether the inventory item can be worn by the user
+	ERlvWearMask canWear(const LLViewerInventoryItem* pItem) const;
+	// Returns whether the wearable type can be worn to by the user
+	ERlvWearMask canWear(LLWearableType::EType eType) const;
+
+	// Returns TRUE if the inventory item can be removed by the user
+	bool canRemove(const LLInventoryItem* pItem) const;
+	// Returns TRUE if the wearable type has at least one wearable that can be removed by the user
+	bool canRemove(LLWearableType::EType eType) const;
+
+	/*
+	 * Member variables
+	 */
+public:
+	typedef std::multimap<LLWearableType::EType, LLUUID> rlv_wearabletypelock_map_t;
+	// Accessors for RlvFloaterLocks
+	const rlv_wearabletypelock_map_t& getWearableTypeLocks(ERlvLockMask eLock) { return (RLV_LOCK_ADD == eLock) ? m_WearableTypeAdd : m_WearableTypeRem; }
+protected:
+	rlv_wearabletypelock_map_t m_WearableTypeAdd;
+	rlv_wearabletypelock_map_t m_WearableTypeRem;
+};
+
+extern RlvWearableLocks gRlvWearableLocks;
+
+// ============================================================================
+// RlvAttachPtLookup inlined member functions
+//
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d
+inline LLViewerJointAttachment* RlvAttachPtLookup::getAttachPoint(const std::string& strText)
+{
+	return (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, getAttachPointIndex(strText), (LLViewerJointAttachment*)NULL) : NULL;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.0.1b
+inline LLViewerJointAttachment* RlvAttachPtLookup::getAttachPoint(const LLInventoryItem* pItem)
+{
+	return (isAgentAvatarValid()) ? get_if_there(gAgentAvatarp->mAttachmentPoints, getAttachPointIndex(pItem), (LLViewerJointAttachment*)NULL) : NULL;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+inline S32 RlvAttachPtLookup::getAttachPointIndex(std::string strText)
+{
+	LLStringUtil::toLower(strText);
+	RLV_ASSERT(m_AttachPtLookupMap.size() > 0);
+	std::map<std::string, S32>::const_iterator itAttachPt = m_AttachPtLookupMap.find(strText);
+	return (itAttachPt != m_AttachPtLookupMap.end()) ? itAttachPt->second : 0;
+}
+
+// Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d
+inline S32 RlvAttachPtLookup::getAttachPointIndex(const LLViewerObject* pObj)
+{
+	return (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getState()) : 0;
+}
+
+// ============================================================================
+// RlvAttachmentLocks inlined member functions
+//
+
+// Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+inline ERlvWearMask RlvAttachmentLocks::canAttach(const LLInventoryItem* pItem, LLViewerJointAttachment** ppAttachPtOut /*=NULL*/) const
+{
+	// The specified item can be attached if:
+	//   - it doesn't specify an attachment point
+	//   - the attachment point it specifies can be attached to
+	LLViewerJointAttachment* pAttachPt = RlvAttachPtLookup::getAttachPoint(pItem);
+	if (ppAttachPtOut)
+		*ppAttachPtOut = pAttachPt;
+	return (!pAttachPt) ? (ERlvWearMask)(RLV_WEAR_REPLACE | RLV_WEAR_ADD) : canAttach(pAttachPt);
+}
+
+// Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i
+inline ERlvWearMask RlvAttachmentLocks::canAttach(const LLViewerJointAttachment* pAttachPt) const
+{
+	// Non-attachable attachment point  => RLV_WEAR_LOCKED
+	// One or more locked attachment(s) => RLV_WEAR_LOCKED  (or RLV_WEAR_ADD)
+	// Unlocked attachment(s)           => RLV_WEAR_REPLACE (or RLV_WEAR_ADD | RLV_WEAR_REPLACE)
+	// Empty attachment point           => RLV_WEAR_REPLACE (or RLV_WEAR_ADD | RLV_WEAR_REPLACE)
+	RLV_ASSERT(pAttachPt);	// TODO-RLVa: [RLVa-1.2.1] Maybe it's better to just return something similar like above?
+	return 
+		(ERlvWearMask)(((pAttachPt) && (!isLockedAttachmentPoint(pAttachPt, RLV_LOCK_ADD))) 
+			? ((canDetach(pAttachPt, true)) ? RLV_WEAR_REPLACE : 0) | RLV_WEAR_ADD
+			: RLV_WEAR_LOCKED);
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+inline bool RlvAttachmentLocks::hasLockedAttachmentPoint(ERlvLockMask eLock) const
+{
+	// Remove locks are more common so check those first
+	return
+		( (eLock & RLV_LOCK_REMOVE) && ((!m_AttachPtRem.empty()) || (!m_AttachObjRem.empty())) ) || 
+		( (eLock & RLV_LOCK_ADD) && (!m_AttachPtAdd.empty()) );
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+inline bool RlvAttachmentLocks::isLockedAttachment(const LLViewerObject* pObj) const
+{
+	// If pObj is valid then it should always specify a root since we store root UUIDs in m_AttachObjRem
+	RLV_ASSERT( (!pObj) || (pObj == pObj->getRootEdit()) );
+
+	// Object is locked if:
+	//   - it's specifically marked as non-detachable (ie @detach=n)
+	//   - it's attached to an attachment point that is RLV_LOCK_REMOVE locked (ie @remattach:<attachpt>=n)
+	return 
+		(pObj) && (pObj->isAttachment()) &&
+		( (m_AttachObjRem.find(pObj->getID()) != m_AttachObjRem.end()) || 
+		  (isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pObj), RLV_LOCK_REMOVE)) );
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Added: RLVa-1.0.5a
+inline bool RlvAttachmentLocks::isLockedAttachment(const LLInventoryItem* pItem) const
+{
+	return (pItem) && (isAgentAvatarValid()) && (isLockedAttachment(gAgentAvatarp->getWornAttachment(pItem->getLinkedUUID())));
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Added: RLVa-1.0.5a
+inline bool RlvAttachmentLocks::isLockedAttachmentPoint(S32 idxAttachPt, ERlvLockMask eLock) const
+{
+	return
+		( (eLock & RLV_LOCK_REMOVE) && (m_AttachPtRem.find(idxAttachPt) != m_AttachPtRem.end()) ) ||
+		( (eLock & RLV_LOCK_ADD) && (m_AttachPtAdd.find(idxAttachPt) != m_AttachPtAdd.end()) );
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Modified: RLVa-1.2.0a
+inline bool RlvAttachmentLocks::isLockedAttachmentPoint(const LLViewerJointAttachment* pAttachPt, ERlvLockMask eLock) const
+{
+	return (pAttachPt) && (isLockedAttachmentPoint(RlvAttachPtLookup::getAttachPointIndex(pAttachPt), eLock));
+}
+
+// ============================================================================
+// RlvWearableLocks inlined member functions
+//
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+inline bool RlvWearableLocks::canRemove(const LLInventoryItem* pItem) const
+{
+	// The specified item can be removed if its wearable can be removed
+	RLV_ASSERT( (pItem) && (LLInventoryType::IT_WEARABLE == pItem->getInventoryType()) );
+	return (pItem) ? !isLockedWearable(gAgentWearables.getWearableFromItemID(pItem->getLinkedUUID())) : false;
+}
+
+// Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+inline ERlvWearMask RlvWearableLocks::canWear(const LLViewerInventoryItem* pItem) const
+{
+	// The specified item can be worn if the wearable type it specifies can be worn on
+	RLV_ASSERT( (pItem) && (LLInventoryType::IT_WEARABLE == pItem->getInventoryType()) );
+	return (pItem) ? canWear(pItem->getWearableType()) : RLV_WEAR_LOCKED;
+}
+
+// Checked: 2010-05-14 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g
+inline ERlvWearMask RlvWearableLocks::canWear(LLWearableType::EType eType) const
+{
+	// The specified wearable type can be worn on if:
+	//   - the wearable type itself isn't RLV_LOCK_ADD locked => RLV_WEAR_ADD
+	//     (and there are less than the maximum amount currently worn)
+	//   - it doesn't have any non-removable wearables        => RLV_WEAR_REPLACE | RLV_WEAR_ADD = RLV_WEAR
+	// TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do
+	return (!isLockedWearableType(eType, RLV_LOCK_ADD))
+	  ? ((!hasLockedWearable(eType)) 
+			? RLV_WEAR 
+			: (gAgentWearables.getWearableCount(eType) < LLAgentWearables::MAX_CLOTHING_PER_TYPE) ? RLV_WEAR_ADD : RLV_WEAR_LOCKED)
+	  : RLV_WEAR_LOCKED;
+}
+
+// Checked: 2010-03-18 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a
+inline bool RlvWearableLocks::hasLockedWearableType(ERlvLockMask eLock) const
+{
+	// Remove locks are more common so check those first
+	// TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do
+	return ( (eLock & RLV_LOCK_REMOVE) && (!m_WearableTypeRem.empty()) ) || ( (eLock & RLV_LOCK_ADD) && (!m_WearableTypeAdd.empty()) );
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+inline bool RlvWearableLocks::isLockedWearable(const LLWearable* pWearable) const
+{
+	// Wearable is locked if:
+	//   - it's specifically marked as non-removable
+	//   - it's worn on a wearable type that is RLV_LOCK_REMOVE locked
+	// TODO-RLVa: [RLVa-1.2.1] We don't have the ability to lock a specific wearable yet so rewrite this when we do
+	RLV_ASSERT(pWearable);
+	return (pWearable) && (isLockedWearableType(pWearable->getType(), RLV_LOCK_REMOVE));
+}
+
+// Checked: 2010-03-19 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+inline bool RlvWearableLocks::isLockedWearableType(LLWearableType::EType eType, ERlvLockMask eLock) const
+{
+	return
+		( (eLock & RLV_LOCK_REMOVE) && (m_WearableTypeRem.find(eType) != m_WearableTypeRem.end()) ) ||
+		( (eLock & RLV_LOCK_ADD) && (m_WearableTypeAdd.find(eType) != m_WearableTypeAdd.end()) );
+}
+
+// ============================================================================
+// RlvAttachmentLockWatchdog inlined member functions
+//
+
+// Checked: 2010-08-07 (RLVa-1.2.0i) | Added: RLVa-1.2.0i
+inline void RlvAttachmentLockWatchdog::onWearAttachment(const LLInventoryItem* pItem, ERlvWearMask eWearAction)
+{
+	onWearAttachment(pItem->getLinkedUUID(), eWearAction);
+}
+
+// ============================================================================
+
+#endif // RLV_LOCKS_H
diff --git a/indra/newview/rlvui.cpp b/indra/newview/rlvui.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5b5eb9ef6de1fc8845585e0be04d8949a44ab49c
--- /dev/null
+++ b/indra/newview/rlvui.cpp
@@ -0,0 +1,550 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llavatarlist.h"				// Avatar list control used by the "Nearby" tab in the "People" sidebar panel
+#include "llbottomtray.h"
+#include "llbutton.h"
+#include "llcallfloater.h"
+#include "llinventorypanel.h"
+#include "llimview.h"					// LLIMMgr
+#include "llmoveview.h"					// Movement panel (contains "Stand" and "Stop Flying" buttons)
+#include "llnavigationbar.h"			// Navigation bar
+#include "llnotificationsutil.h"
+#include "lloutfitslist.h"				// "My Outfits" sidebar panel
+#include "llpaneloutfitsinventory.h"	// "My Appearance" sidebar panel
+#include "llpanelpeople.h"				// "People" sidebar panel
+#include "llpanelprofile.h"				// "Profile" sidebar panel
+#include "llpanelwearing.h"				// "Current Outfit" sidebar panel
+#include "llparcel.h"
+#include "llsidetray.h"
+#include "llsidetraypanelcontainer.h"
+#include "lltabcontainer.h"
+#include "lltoolmgr.h"
+#include "llviewerparcelmgr.h"
+#include "roles_constants.h"			// Group "powers"
+
+#include "rlvui.h"
+#include "rlvhandler.h"
+
+// ============================================================================
+
+// Checked: 2010-02-28 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+RlvUIEnabler::RlvUIEnabler()
+{
+	// Connect us to the behaviour toggle signal
+	gRlvHandler.setBehaviourCallback(boost::bind(&RlvUIEnabler::onBehaviour, this, _1, _2));
+
+	// onRefreshHoverText()
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWLOC, boost::bind(&RlvUIEnabler::onRefreshHoverText, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWNAMES, boost::bind(&RlvUIEnabler::onRefreshHoverText, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTALL, boost::bind(&RlvUIEnabler::onRefreshHoverText, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTWORLD, boost::bind(&RlvUIEnabler::onRefreshHoverText, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWHOVERTEXTHUD, boost::bind(&RlvUIEnabler::onRefreshHoverText, this)));
+
+	// onToggleViewXXX
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWNOTE, boost::bind(&RlvUIEnabler::onToggleViewXXX, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWSCRIPT, boost::bind(&RlvUIEnabler::onToggleViewXXX, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_VIEWTEXTURE, boost::bind(&RlvUIEnabler::onToggleViewXXX, this)));
+
+	// onToggleXXX
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_EDIT, boost::bind(&RlvUIEnabler::onToggleEdit, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_FLY, boost::bind(&RlvUIEnabler::onToggleFly, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SETENV, boost::bind(&RlvUIEnabler::onToggleSetEnv, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWINV, boost::bind(&RlvUIEnabler::onToggleShowInv, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWLOC, boost::bind(&RlvUIEnabler::onToggleShowLoc, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWMINIMAP, boost::bind(&RlvUIEnabler::onToggleShowMinimap, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWNAMES, boost::bind(&RlvUIEnabler::onToggleShowNames, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_SHOWWORLDMAP, boost::bind(&RlvUIEnabler::onToggleShowWorldMap, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_UNSIT, boost::bind(&RlvUIEnabler::onToggleUnsit, this)));
+
+	// onToggleTp
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLOC, boost::bind(&RlvUIEnabler::onToggleTp, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLM, boost::bind(&RlvUIEnabler::onToggleTp, this)));
+
+	// onUpdateLoginLastLocation
+	#ifdef RLV_EXTENSION_STARTLOCATION
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_TPLOC, boost::bind(&RlvUIEnabler::onUpdateLoginLastLocation, this)));
+	m_Handlers.insert(std::pair<ERlvBehaviour, behaviour_handler_t>(RLV_BHVR_UNSIT, boost::bind(&RlvUIEnabler::onUpdateLoginLastLocation, this)));
+	#endif // RLV_EXTENSION_STARTLOCATION
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onBehaviour(ERlvBehaviour eBhvr, ERlvParamType eType)
+{
+	// We're only interested in behaviour toggles (ie on->off or off->on)
+	if ( ((RLV_TYPE_ADD == eType) && (1 == gRlvHandler.hasBehaviour(eBhvr))) ||
+		 ((RLV_TYPE_REMOVE == eType) && (0 == gRlvHandler.hasBehaviour(eBhvr))) )
+	{
+		for (behaviour_handler_map_t::const_iterator itHandler = m_Handlers.lower_bound(eBhvr), endHandler = m_Handlers.upper_bound(eBhvr);
+				itHandler != endHandler; ++itHandler)
+		{
+			itHandler->second();
+		}
+	}
+}
+
+// ============================================================================
+
+// Checked: 2010-03-02 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onRefreshHoverText()
+{
+	// Refresh all hover text each time any of the monitored behaviours get set or unset
+	LLHUDText::refreshAllObjectText();
+}
+
+// Checked: 2010-03-17 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onToggleEdit()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_EDIT);
+
+	if (!fEnable)
+	{
+		// Turn off "View / Highlight Transparent"
+		LLDrawPoolAlpha::sShowDebugAlpha = FALSE;
+
+		// Hide the beacons floater if it's currently visible
+		if (LLFloaterReg::floaterInstanceVisible("beacons"))
+			LLFloaterReg::hideInstance("beacons");
+
+		// Hide the build floater if it's currently visible
+		if (LLToolMgr::instance().inBuildMode())
+			LLToolMgr::instance().toggleBuildMode();
+	}
+
+	// Start or stop filtering opening the beacons floater
+	if (!fEnable)
+		addGenericFloaterFilter("beacons");
+	else
+		removeGenericFloaterFilter("beacons");
+}
+
+// Checked: 2010-03-02 (RLVa-1.2.0d) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onToggleFly()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_FLY);
+
+	// Drop the avie out of the sky if currently flying and restricted
+	if ( (!fEnable) && (gAgent.getFlying()) )
+		gAgent.setFlying(FALSE);
+
+	// Force an update since the status only updates when the current parcel changes [see LLFloaterMove::postBuild()]
+	LLFloaterMove::sUpdateFlyingStatus();
+}
+
+// Checked: 2010-03-17 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onToggleSetEnv()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SETENV);
+
+	const std::string strEnvFloaters[] = { "env_day_cycle", /*"env_post_process",*/ "env_settings", "env_water", "env_windlight" };
+	for (int idxFloater = 0, cntFloater = sizeof(strEnvFloaters) / sizeof(std::string); idxFloater < cntFloater; idxFloater++)
+	{
+		if (!fEnable)
+		{
+			// Hide the floater if it's currently visible
+			if (LLFloaterReg::floaterInstanceVisible(strEnvFloaters[idxFloater]))
+				LLFloaterReg::hideInstance(strEnvFloaters[idxFloater]);
+
+			addGenericFloaterFilter(strEnvFloaters[idxFloater]);
+		}
+		else
+		{
+			removeGenericFloaterFilter(strEnvFloaters[idxFloater]);
+		}
+	}
+}
+
+// Checked: 2010-08-24 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a
+void RlvUIEnabler::onToggleShowInv()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWINV);
+
+	//
+	// Enable/disable the "My Inventory" button on the sidebar button panel
+	//
+	LLSideTray* pSideTray = LLSideTray::getInstance(); 
+	RLV_ASSERT(pSideTray);
+	if (pSideTray)
+	{
+		LLButton* pInvBtn = pSideTray->getButtonFromName("sidebar_inventory");
+		RLV_ASSERT(pInvBtn);
+		if (pInvBtn) 
+			pInvBtn->setEnabled(fEnable);
+
+		// When disabling, switch to the "Home" sidebar tab if "My Inventory" is currently active
+		// NOTE: when collapsed 'isPanelActive' will return FALSE even if the panel is currently active so we have to sidestep that
+		const LLPanel* pActiveTab = pSideTray->getActiveTab();
+		if ( (!fEnable) && (pActiveTab) && ("sidebar_inventory" == pActiveTab->getName()) )
+		{
+			pSideTray->selectTabByName("sidebar_home");	// Using selectTabByName() instead of showPanel() will prevent it from expanding
+			if (pSideTray->getCollapsed())
+				pSideTray->collapseSideBar();			// Fixes a button highlighting glitch when changing the active tab while collapsed
+		}
+
+		// Start or stop filtering opening the inventory sidebar tab
+		RLV_ASSERT_DBG( (fEnable) || (!m_ConnSidePanelInventory.connected()) );
+		if (!fEnable)
+			m_ConnSidePanelInventory = pSideTray->setValidateCallback(boost::bind(&RlvUIEnabler::canOpenSidebarTab, this, RLV_BHVR_SHOWINV, "sidebar_inventory", _1, _2));
+		else
+			m_ConnSidePanelInventory.disconnect();
+	}
+
+	//
+	// Enable/disable the "My Outfits" panel on the "My Appearance" sidebar tab
+	//
+	LLPanelOutfitsInventory* pAppearancePanel = LLPanelOutfitsInventory::findInstance();
+	if (pAppearancePanel)
+	{
+		LLTabContainer* pAppearanceTabs = pAppearancePanel->getAppearanceTabs();
+		LLOutfitsList* pMyOutfitsPanel = pAppearancePanel->getMyOutfitsPanel();
+		if ( (pAppearanceTabs) && (pMyOutfitsPanel) )
+		{
+			S32 idxTab = pAppearanceTabs->getIndexForPanel(pMyOutfitsPanel);
+			RLV_ASSERT(-1 != idxTab);
+			pAppearanceTabs->enableTabButton(idxTab, fEnable);
+
+			// When disabling, switch to the COF tab if "My Outfits" is currently active
+			if ( (!fEnable) && (pAppearanceTabs->getCurrentPanelIndex() == idxTab) )
+				pAppearanceTabs->selectTabPanel(pAppearancePanel->getCurrentOutfitPanel());
+		}
+	}
+
+	//
+	// When disabling, hide any old style inventory floaters that may be open
+	//
+	if (!fEnable)
+	{
+		LLFloaterReg::const_instance_list_t lFloaters = LLFloaterReg::getFloaterList("inventory");
+		for (LLFloaterReg::const_instance_list_t::const_iterator itFloater = lFloaters.begin(); itFloater != lFloaters.end(); ++itFloater)
+			(*itFloater)->closeFloater();
+	}
+
+	// Filter out (or stop filtering) newly spawned old style inventory floaters
+	if (!fEnable)
+		addGenericFloaterFilter("inventory");
+	else
+		removeGenericFloaterFilter("inventory");
+}
+
+// Checked: 2010-04-22 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+void RlvUIEnabler::onToggleShowLoc()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC);
+
+	// RELEASE-RLVa: [SL-2.0.1] Check that the code below still evaluates to *only* LLNavigationBar::instance().mCmbLocation->refresh()
+	LLNavigationBar::instance().handleLoginComplete();
+
+	if (!fEnable)
+	{
+		// Hide the "About Land" floater if it's currently visible
+		if (LLFloaterReg::floaterInstanceVisible("about_land"))
+			LLFloaterReg::hideInstance("about_land");
+		// Hide the "Region / Estate" floater if it's currently visible
+		if (LLFloaterReg::floaterInstanceVisible("region_info"))
+			LLFloaterReg::hideInstance("region_info");
+		// Hide the "God Tools" floater if it's currently visible
+		if (LLFloaterReg::floaterInstanceVisible("god_tools"))
+			LLFloaterReg::hideInstance("god_tools");
+	}
+
+	// Start or stop filtering the "About Land" and "Region / Estate" floaters
+	if ( (!fEnable) && (!m_ConnFloaterShowLoc.connected()) )
+		m_ConnFloaterShowLoc = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterShowLoc, this, _1, _2));
+	else if ( (fEnable) && (m_ConnFloaterShowLoc.connected()) )
+		m_ConnFloaterShowLoc.disconnect();
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onToggleShowMinimap()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWMINIMAP);
+
+	// Hide the mini-map if it's currently visible
+	if ( (!fEnable) && (LLFloaterReg::floaterInstanceVisible("mini_map")) )
+		LLFloaterReg::hideFloaterInstance("mini_map");
+
+	// Enable/disable the "Mini-Map" bottom tray button
+	const LLBottomTray* pTray = LLBottomTray::getInstance();
+	LLView* pBtnView = (pTray) ? pTray->getChildView("mini_map_btn") : NULL;
+	if (pBtnView)
+		pBtnView->setEnabled(fEnable);
+
+	// Start or stop filtering opening the mini-map
+	if (!fEnable)
+		addGenericFloaterFilter("mini_map");
+	else
+		removeGenericFloaterFilter("mini_map");
+}
+
+// Checked: 2010-06-05 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d
+void RlvUIEnabler::onToggleShowNames()
+{
+	// Refresh the nearby people list
+	LLPanelPeople* pPeoplePanel = dynamic_cast<LLPanelPeople*>(LLSideTray::getInstance()->getPanel("panel_people"));
+	RLV_ASSERT( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) );
+	if ( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) )
+		pPeoplePanel->getNearbyList()->refreshNames();
+
+	// Refresh the speaker list
+	LLCallFloater* pCallFloater = LLFloaterReg::findTypedInstance<LLCallFloater>("voice_controls");
+	if (pCallFloater)
+		pCallFloater->getAvatarCallerList()->refreshNames();
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onToggleShowWorldMap()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP);
+
+	// Hide the world map if it's currently visible
+	if ( (!fEnable) && (LLFloaterReg::floaterInstanceVisible("world_map")) )
+		LLFloaterReg::hideFloaterInstance("world_map");
+
+	// Enable/disable the "Map" bottom tray button
+	const LLBottomTray* pTray = LLBottomTray::getInstance();
+	LLView* pBtnView = (pTray) ? pTray->getChildView("world_map_btn") : NULL;
+	if (pBtnView)
+		pBtnView->setEnabled(fEnable);
+
+	// Start or stop filtering opening the world map
+	if (!fEnable)
+		addGenericFloaterFilter("world_map");
+	else
+		removeGenericFloaterFilter("world_map");
+}
+
+// Checked: 2010-08-22 (RLVa-1.2.1a) | Added: RLVa-1.2.1a
+void RlvUIEnabler::onToggleTp()
+{
+	// Disable the navigation bar "Home" button if both @tplm=n *and* @tploc=n restricted
+	LLButton* pNavBarHomeBtn = LLNavigationBar::getInstance()->getChild<LLButton>("home_btn");
+	RLV_ASSERT(pNavBarHomeBtn);
+	if (pNavBarHomeBtn)
+		pNavBarHomeBtn->setEnabled(!(gRlvHandler.hasBehaviour(RLV_BHVR_TPLM) && gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)));
+}
+
+// Checked: 2010-03-01 (RLVa-1.2.0c) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onToggleUnsit()
+{
+	bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT);
+
+	LLPanelStandStopFlying* pPanelStand = LLPanelStandStopFlying::getInstance();
+	RLV_ASSERT(pPanelStand);
+	if (pPanelStand)
+	{
+		LLButton* pBtnStand = pPanelStand->getChild<LLButton>("stand_btn");
+		RLV_ASSERT(pBtnStand);
+		if (pBtnStand)
+			pBtnStand->setEnabled(fEnable);
+	}
+}
+
+// Checked: 2010-03-01 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+void RlvUIEnabler::onToggleViewXXX()
+{
+	// If any of the three are still active then we keep filtering
+	bool fEnable = (!gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) && 
+		(!gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE));
+
+	// Start or stop filtering opening the preview floaters
+	if ( (!fEnable) && (!m_ConnFloaterViewXXX.connected()) )
+		m_ConnFloaterViewXXX = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterViewXXX, this, _1, _2));
+	else if ( (fEnable) && (m_ConnFloaterViewXXX.connected()) )
+		m_ConnFloaterViewXXX.disconnect();
+}
+
+// Checked: 2010-04-01 (RLVa-1.2.0c) | Added: RLVa-1.2.0c
+void RlvUIEnabler::onUpdateLoginLastLocation()
+{
+	RlvSettings::updateLoginLastLocation();
+}
+
+// ============================================================================
+
+// Checked: 2010-02-28 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+inline void RlvUIEnabler::addGenericFloaterFilter(const std::string& strFloaterName)
+{
+	m_FilteredFloaters.insert(strFloaterName);
+
+	if (!m_ConnFloaterGeneric.connected())
+		m_ConnFloaterGeneric = LLFloaterReg::setValidateCallback(boost::bind(&RlvUIEnabler::filterFloaterGeneric, this, _1, _2));
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+inline void RlvUIEnabler::removeGenericFloaterFilter(const std::string& strFloaterName)
+{
+	std::multiset<std::string>::iterator itFloater = m_FilteredFloaters.find(strFloaterName);
+	RLV_ASSERT_DBG(itFloater != m_FilteredFloaters.end());
+	m_FilteredFloaters.erase(itFloater);
+
+	RLV_ASSERT_DBG(m_ConnFloaterGeneric.connected());
+	if (m_FilteredFloaters.empty())
+		m_ConnFloaterGeneric.disconnect();
+}
+
+// Checked: 2010-02-28 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+bool RlvUIEnabler::filterFloaterGeneric(const std::string& strName, const LLSD&)
+{
+	return m_FilteredFloaters.find(strName) == m_FilteredFloaters.end();
+}
+
+// Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+bool RlvUIEnabler::filterFloaterShowLoc(const std::string& strName, const LLSD&)
+{
+	if ("about_land" == strName)
+		return canViewParcelProperties();
+	else if ("region_info" == strName)
+		return canViewRegionProperties();
+	else if ("god_tools" == strName)
+		return false;
+	return true;
+}
+
+// Checked: 2010-03-01 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+bool RlvUIEnabler::filterFloaterViewXXX(const std::string& strName, const LLSD&)
+{
+	if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWNOTE)) && ("preview_notecard" == strName) )
+	{
+		notifyBlockedViewXXX(LLAssetType::AT_NOTECARD);
+		return false;
+	}
+	else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWSCRIPT)) && (("preview_script" == strName) || ("preview_scriptedit" == strName)) )
+	{
+		notifyBlockedViewXXX(LLAssetType::AT_SCRIPT);
+		return false;
+	}
+	else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_VIEWTEXTURE)) && ("preview_texture" == strName) )
+	{
+		notifyBlockedViewXXX(LLAssetType::AT_TEXTURE);
+		return false;
+	}
+	return true;
+}
+
+// ============================================================================
+
+// Checked: 2010-03-01 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
+bool RlvUIEnabler::canOpenSidebarTab(ERlvBehaviour eBhvrFilter, const std::string& strNameFilter, LLUICtrl* pCtrl, const LLSD& sdParam)
+{
+	return (!gRlvHandler.hasBehaviour(eBhvrFilter)) || (strNameFilter != sdParam.asString());
+}
+
+// ============================================================================
+
+// Checked: 2010-03-01 (RLVa-1.2.0b) | Added: RLVa-1.2.0a
+void RlvUIEnabler::notifyBlockedViewXXX(LLAssetType::EType assetType)
+{
+	LLStringUtil::format_map_t argsMsg; std::string strMsg = RlvStrings::getString(RLV_STRING_BLOCKED_VIEWXXX);
+	argsMsg["[TYPE]"] = LLAssetType::lookup(assetType);
+	LLStringUtil::format(strMsg, argsMsg);
+
+	LLSD argsNotify;
+	argsNotify["MESSAGE"] = strMsg;
+	LLNotificationsUtil::add("SystemMessageTip", argsNotify);
+}
+
+// ============================================================================
+
+// Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+bool RlvUIEnabler::canViewParcelProperties()
+{
+	// We'll allow "About Land" as long as the user has the ability to return prims (through ownership or through group powers)
+	bool fShow = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC);
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+	{
+		// RELEASE-RLVa: [SL-2.0.0] Check that ôpening the "About Land" floater still sets focus to the current parcel is none is selected
+		LLParcelSelection* pParcelSel = LLViewerParcelMgr::getInstance()->getFloatingParcelSelection();
+		LLParcel* pParcel = (pParcelSel) ? pParcelSel->getParcel() : LLViewerParcelMgr::getInstance()->getAgentParcel();
+		if ( ((pParcelSel) && (pParcelSel->hasOthersSelected())) || (!pParcel) )
+			return false;
+
+		// Ideally we could just use LLViewerParcelMgr::isParcelOwnedByAgent(), but that has that sneaky exemption for "god-like"
+		// RELEASE-RLVa: [SL-2.0.0] Check that the "inlining" of "isParcelOwnedByAgent" and "LLAgent::hasPowerInGroup()" still matches
+		const LLUUID& idOwner = pParcel->getOwnerID();
+		if ( (idOwner != gAgent.getID()) )
+		{
+			// LLAgent::hasPowerInGroup() has it too so copy/paste from there
+			S32 count = gAgent.mGroups.count();
+			for (S32 i = 0; i < count; ++i)
+			{
+				if (gAgent.mGroups.get(i).mID == idOwner)
+				{
+					fShow |= ((gAgent.mGroups.get(i).mPowers & GP_LAND_RETURN) > 0);
+					break;
+				}
+			}
+		}
+		else
+		{
+			fShow = true;
+		}
+	}
+	return fShow;
+}
+
+// Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f
+bool RlvUIEnabler::canViewRegionProperties()
+{
+	// We'll allow "Region / Estate" if the user is either the sim owner or an estate manager
+	bool fShow = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC);
+	if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
+	{
+		// [See LLRegion::canManageEstate() but without the "god-like" exception]
+		const LLViewerRegion* pRegion = gAgent.getRegion();
+		if (pRegion)
+			fShow = (pRegion->isEstateManager()) || (pRegion->getOwner() == gAgent.getID());
+	}
+	return fShow;
+}
+
+// Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RLVa-1.2.0f
+bool RlvUIEnabler::hasOpenIM(const LLUUID& idAgent)
+{
+	LLUUID idSession = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, idAgent);
+	return (NULL != LLFloaterReg::findInstance("impanel", idSession));
+}
+
+// Checked: 2010-04-20 (RLVa-1.2.0h) | Added: RLVa-1.2.0f
+bool RlvUIEnabler::hasOpenProfile(const LLUUID& idAgent)
+{
+	// NOTE: despite its name this function is used to determine whether or not we'll obfuscate names for inventory drops on nearby agents
+	//   -> SL-2.1.0 added the ability to "share" inventory by dropping it on the avatar picker floater so we should check for that
+	//   -> we can drag/drop inventory onto calling cards but probably noone knows about it and it would be too involved to check for that
+	// TODO-RLVa: [RLVa-1.2.1] Check the avatar picker as well
+
+	// Check if the user has the specified agent's profile open
+	LLSideTray* pSideTray = LLSideTray::getInstance(); 
+	RLV_ASSERT(pSideTray);
+	if ( (pSideTray) && (!pSideTray->getCollapsed()) )
+	{
+		/*const*/ LLSideTrayPanelContainer* pPanelContainer = dynamic_cast</*const*/ LLSideTrayPanelContainer*>(pSideTray->getActivePanel());
+		if (pPanelContainer)
+		{
+			const LLPanel* pActivePanel = pPanelContainer->getCurrentPanel();
+			if ( (pActivePanel) && ("panel_profile_view" == pActivePanel->getName()) )
+			{
+				const LLPanelProfile* pProfilePanel = dynamic_cast<const LLPanelProfile*>(pActivePanel);
+				RLV_ASSERT(pProfilePanel);
+				if (pProfilePanel)
+					return (idAgent == pProfilePanel->getAvatarId());
+			}
+		}
+	}
+	return false;
+}
+
+// ============================================================================
diff --git a/indra/newview/rlvui.h b/indra/newview/rlvui.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c6a6a40eb2ebdba22854c7fccd143502d3e8891
--- /dev/null
+++ b/indra/newview/rlvui.h
@@ -0,0 +1,109 @@
+/** 
+ *
+ * Copyright (c) 2009-2010, Kitty Barnett
+ * 
+ * The source code in this file is provided to you under the terms of the 
+ * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+ * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt 
+ * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt
+ * 
+ * By copying, modifying or distributing this software, you acknowledge that
+ * you have read and understood your obligations described above, and agree to 
+ * abide by those obligations.
+ * 
+ */
+
+#ifndef RLV_UI_H
+#define RLV_UI_H
+
+#include "llfloaterreg.h"
+#include "llsingleton.h"
+
+#include "rlvdefines.h"
+
+// ============================================================================
+// RlvUIEnabler - self-contained class that handles disabling or reenabling certain aspects of the viewer's UI
+//
+
+class RlvUIEnabler : public LLSingleton<RlvUIEnabler>
+{
+protected:
+	RlvUIEnabler();
+	friend class LLSingleton<RlvUIEnabler>;
+	friend class RlvHandler;
+
+	/*
+	 * Signal callbacks
+	 */
+public:
+	void onBehaviour(ERlvBehaviour eBhvr, ERlvParamType eType);			// RlvHandler::rlv_behaviour_signal_t
+
+	/*
+	 * Behaviour handlers
+	 */
+protected:
+	void onRefreshHoverText();											// showloc, shownames, showhovertext(all|world|hud)
+	void onToggleEdit();												// edit
+	void onToggleFly();													// fly
+	void onToggleSetEnv();												// setenv
+	void onToggleShowInv();												// showinv
+	void onToggleShowLoc();												// showloc
+	void onToggleShowMinimap();											// showminimap
+	void onToggleShowNames();											// shownames
+	void onToggleShowWorldMap();										// showworldmap
+	void onToggleTp();													// tploc and tplm
+	void onToggleUnsit();												// unsit
+	void onToggleViewXXX();												// viewnote, viewscript, viewtexture
+	void onUpdateLoginLastLocation();									// tploc and unsit
+
+	/*
+	 * Floater validation callbacks
+	 */
+protected:
+	void addGenericFloaterFilter(const std::string& strFloaterName);
+	void removeGenericFloaterFilter(const std::string& strFloaterName);
+	bool filterFloaterGeneric(const std::string&, const LLSD&);
+	boost::signals2::connection m_ConnFloaterGeneric;
+
+	bool filterFloaterShowLoc(const std::string&, const LLSD& );
+	boost::signals2::connection m_ConnFloaterShowLoc;					// showloc
+	bool filterFloaterViewXXX(const std::string&, const LLSD&);
+	boost::signals2::connection m_ConnFloaterViewXXX;					// viewnote, viewscript, viewtexture
+
+	/*
+	 * Sidebar panel change validation
+	 */
+protected:
+	bool canOpenSidebarTab(ERlvBehaviour, const std::string&, LLUICtrl*, const LLSD&);
+	boost::signals2::connection m_ConnSidePanelInventory;				// showinv
+
+	/*
+	 * User feedback functions
+	 */
+public:
+	static void notifyBlockedViewXXX(LLAssetType::EType assetType); 
+
+	/*
+	 * Helper functions
+	 */
+public:
+	static bool canViewParcelProperties();								// showloc
+	static bool canViewRegionProperties();								// showloc
+	static bool hasOpenIM(const LLUUID& idAgent);						// shownames
+	static bool hasOpenProfile(const LLUUID& idAgent);					// shownames
+
+	/*
+	 * Member variables
+	 */
+protected:
+	typedef boost::function<void()> behaviour_handler_t;
+	typedef std::multimap<ERlvBehaviour, behaviour_handler_t> behaviour_handler_map_t;
+	behaviour_handler_map_t m_Handlers;
+
+	std::multiset<std::string> m_FilteredFloaters;
+};
+
+// ============================================================================
+
+#endif // RLV_UI_H
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index f4d65bdb3aadde2659ca38cbef70cc067f394cb0..4c8f9210c554220600dd7f40c97ce214ebed2cbf 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -45,6 +45,7 @@ Windows Graphics Driver Version: [GRAPHICS_DRIVER_VERSION]
      name="AboutLibs">
 OpenGL Version: [OPENGL_VERSION]
 
+RestrainedLove API: [RLV_VERSION]
 libcurl Version: [LIBCURL_VERSION]
 J2C Decoder Version: [J2C_VERSION]
 Audio Driver Version: [AUDIO_DRIVER_VERSION]
diff --git a/indra/newview/skins/default/xui/en/floater_map.xml b/indra/newview/skins/default/xui/en/floater_map.xml
index 6370ff92438cf701c45dc4bcd88d2a704098dbaf..e2f60cec2303b640f5b1f9acb64f5b14d5fcd398 100644
--- a/indra/newview/skins/default/xui/en/floater_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_map.xml
@@ -18,9 +18,10 @@
  left="0"
  top="0"
  width="200">
+    <!-- RLVa shows the anonimized name on the regular tooltip when @shownames=n restricted (rather than show the avatar inspector) --> 
     <floater.string
      name="ToolTipMsg">
-        [REGION](Double-click to open Map, shift-drag to pan)
+        [AGENT][REGION](Double-click to open Map, shift-drag to pan)
     </floater.string>
     <floater.string name="mini_map_caption">
 	MINIMAP
diff --git a/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml b/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml
new file mode 100644
index 0000000000000000000000000000000000000000..becdbd2bd38cdd0cfa3f20f7d94ff3464e1daf7f
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_rlv_behaviours.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater can_close="true" can_drag_on_left="false" can_minimize="true" can_resize="true"
+         height="425" min_height="200" min_width="375" name="rlv_behaviours" title="Active RLV Restrictions" width="350"
+         save_rect="true" save_visibility="true" single_instance="true">
+  <scroll_list top="0" draw_border="false" follows="top|left|bottom|right" height="400" multi_select="false"
+               name="behaviour_list" draw_heading="true" draw_stripes="true" layout="topleft">
+    <scroll_list.columns label="Restriction" name="behaviour" width="170" />
+    <scroll_list.columns label="Object Name" name="name" width="170" />
+  </scroll_list>
+</floater>
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/floater_rlv_locks.xml b/indra/newview/skins/default/xui/en/floater_rlv_locks.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9472da598191bda8021f3de21348c366c5461643
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_rlv_locks.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater can_close="true" can_drag_on_left="false" can_minimize="true" can_resize="true"
+         height="425" min_height="200" min_width="375" name="rlvLocks" title="Active RLV Locks" width="350"
+         save_rect="true" save_visibility="true" single_instance="true">
+  <scroll_list top="0" draw_border="false" follows="top|left|bottom|right" height="400" multi_select="false"
+               name="lock_list" draw_heading="true" draw_stripes="true" layout="topleft">
+    <scroll_list.columns label="Lock Type" name="lock_type" width="110" />
+    <scroll_list.columns label="Add / Rem" name="lock_addrem" width="75" />
+    <scroll_list.columns label="Lock Target" name="lock_target" width="150" />
+    <scroll_list.columns label="Held By" name="lock_origin" width="150" />
+  </scroll_list>
+</floater>
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml
index b46b62ec4d18e69f5a174b883953467977d8fd87..f7f1bf3c5f9cd75e778224e9a06bc134520c1537 100644
--- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml
+++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml
@@ -9,6 +9,9 @@
         <menu_item_call.on_click
          function="ShowAgentProfile"
          parameter="hit object" />
+        <menu_item_call.on_enable
+         function="RLV.EnableIfNot"
+         parameter="shownames" />
     </menu_item_call>
    <menu_item_call
      enabled="false"
@@ -24,6 +27,9 @@
      name="Send IM...">
         <menu_item_call.on_click
          function="Avatar.SendIM" />
+        <menu_item_call.on_enable
+         function="RLV.EnableIfNot"
+         parameter="shownames" />
     </menu_item_call>
     <menu_item_call
      label="Call"
@@ -36,8 +42,11 @@
       <menu_item_call
          label="Invite to Group"
          name="Invite...">
-      <menu_item_call.on_click
+        <menu_item_call.on_click
          function="Avatar.InviteToGroup" />
+        <menu_item_call.on_enable
+         function="RLV.EnableIfNot"
+         parameter="shownames" />
       </menu_item_call>
    <menu_item_separator />
     <menu_item_call
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_other.xml b/indra/newview/skins/default/xui/en/menu_avatar_other.xml
index 276b5f106f785799b6b829be611030b47b3e65c3..e344d873e5cb98b427079602c6c5b5589daac778 100644
--- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_other.xml
@@ -9,6 +9,9 @@
         <menu_item_call.on_click
          function="ShowAgentProfile"
          parameter="hit object" />
+        <menu_item_call.on_enable
+         function="RLV.EnableIfNot"
+         parameter="shownames" />
     </menu_item_call>
    <menu_item_call
      enabled="false"
@@ -24,6 +27,9 @@
      name="Send IM...">
         <menu_item_call.on_click
          function="Avatar.SendIM" />
+        <menu_item_call.on_enable
+         function="RLV.EnableIfNot"
+         parameter="shownames" />
     </menu_item_call>
     <menu_item_call
      label="Call"
@@ -36,8 +42,11 @@
       <menu_item_call
          label="Invite to Group"
          name="Invite...">
-      <menu_item_call.on_click
+        <menu_item_call.on_click
          function="Avatar.InviteToGroup" />
+        <menu_item_call.on_enable
+         function="RLV.EnableIfNot"
+         parameter="shownames" />
       </menu_item_call>
    <menu_item_separator />
     <menu_item_call
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index c79a484ef63d5b46f00b71bfe17a8dd3433f152d..c1a3548fd1f4a18abfb01afb522abd161283f38e 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1426,6 +1426,112 @@
                  parameter="flexible" />
             </menu_item_check>
         </menu>        
+		<menu
+		 label="RLVa"
+		 name="RLVa"
+		 tear_off="true"
+		 visible="false">
+			<menu
+			 label="Debug"
+			 name="Debug"
+			 tear_off="true">
+				<menu_item_check
+				 label="Show Debug Messages"
+				 name="Show Debug Messages">
+					<menu_item_check.on_check
+					 function="CheckControl"
+					 parameter="RestrainedLoveDebug" />
+					<menu_item_check.on_click
+					 function="ToggleControl"
+					 parameter="RestrainedLoveDebug" />
+				</menu_item_check>
+				<menu_item_separator/>
+				<menu_item_check
+				 label="Enable Legacy Naming"
+				 name="Enable Legacy Naming">
+					<menu_item_check.on_check
+					 function="CheckControl"
+					 parameter="RLVaEnableLegacyNaming" />
+					<menu_item_check.on_click
+					 function="ToggleControl"
+					 parameter="RLVaEnableLegacyNaming" />
+				</menu_item_check>
+				<menu_item_check
+				 label="Rename Shared Items on Wear"
+				 name="Rename Shared Items on Wear">
+					<menu_item_check.on_check
+					 function="CheckControl"
+					 parameter="RLVaSharedInvAutoRename" />
+					<menu_item_check.on_click
+					 function="ToggleControl"
+					 parameter="RLVaSharedInvAutoRename" />
+				</menu_item_check>
+				<menu_item_separator/>
+				<menu_item_check
+				 label="Locks..."
+				 name="Locks">
+					<menu_item_check.on_check
+					 function="Floater.Visible"
+					 parameter="rlv_locks" />
+					<menu_item_check.on_click
+					 function="Floater.Toggle"
+					 parameter="rlv_locks" />
+				</menu_item_check>
+			</menu>
+			<menu_item_separator/>
+			<menu_item_check
+			 label="Hide Locked Layers"
+			 name="Hide Locked Layers">
+				<menu_item_check.on_check
+				 function="CheckControl"
+				 parameter="RLVaHideLockedLayers" />
+				<menu_item_check.on_click
+				 function="ToggleControl"
+				 parameter="RLVaHideLockedLayers" />
+			</menu_item_check>
+			<menu_item_check
+			 label="Hide Locked Attachments"
+			 name="Hide Locked Attachments">
+				<menu_item_check.on_check
+				 function="CheckControl"
+				 parameter="RLVaHideLockedAttachments" />
+				<menu_item_check.on_click
+				 function="ToggleControl"
+				 parameter="RLVaHideLockedAttachments" />
+			</menu_item_check>
+			<menu_item_separator/>
+			<menu_item_check
+			 label="Forbid Give to #RLV"
+			 name="Forbid Give to #RLV">
+				<menu_item_check.on_check
+				 function="CheckControl"
+				 parameter="RestrainedLoveForbidGiveToRLV" />
+				<menu_item_check.on_click
+				 function="ToggleControl"
+				 parameter="RestrainedLoveForbidGiveToRLV" />
+			</menu_item_check>
+			<menu_item_check
+			 label="Show Name Tags"
+			 name="Show Name Tags">
+				<menu_item_check.on_check
+				 function="CheckControl"
+				 parameter="RLVaShowNameTags" />
+				<menu_item_check.on_click
+				 function="ToggleControl"
+				 parameter="RLVaShowNameTags" />
+			</menu_item_check>
+			<menu_item_separator/>
+			<menu_item_check
+			 label="Restrictions..."
+			 name="Restrictions">
+				<menu_item_check.on_check
+				 function="Floater.Visible"
+				 parameter="rlv_behaviours" />
+				<menu_item_check.on_click
+				 function="Floater.Toggle"
+				 parameter="rlv_behaviours" />
+			</menu_item_check>
+		</menu>
         <menu_item_check
          label="Use Plugin Read Thread"
          name="Use Plugin Read Thread">
@@ -1687,7 +1793,14 @@
         </menu> <!--Shortcuts-->
 
         <menu_item_separator/>
-
+        <menu_item_check
+           label="RestrainedLove API"
+           name="RLV API">
+              <menu_item_check.on_check
+               function="RLV.CheckEnabled" />
+              <menu_item_check.on_click
+               function="RLV.ToggleEnabled" />
+        </menu_item_check>
         <menu_item_call
          label="Show Debug Settings"
          name="Debug Settings">
diff --git a/indra/newview/skins/default/xui/en/rlva_strings.xml b/indra/newview/skins/default/xui/en/rlva_strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..aba11e6645bdef6704b7ad881c85a29d50bcaf1d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/rlva_strings.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<rlva_strings>
+
+  <strings>
+    <!-- Primarily used when @showloc restricted -->
+    <string name="hidden_generic">(Hidden)</string>
+    <string name="hidden_parcel">(Hidden parcel)</string>
+    <string name="hidden_region">(Hidden region)</string>
+
+    <!-- Received/sent IMs will be replaced by the matching string when @recvim/sendim restricted -->
+    <string name="blocked_recvim">*** IM blocked by your viewer</string>
+    <string name="blocked_sendim">*** IM blocked by sender's viewer</string>
+
+    <!-- Shown as notifications -->
+    <string name="blocked_viewxxx">Unable to open [TYPE] due to RLV restrictions</string>
+
+    <!-- Sent as "Busy" messages to the remote party -->
+    <string name="blocked_recvim_remote">
+      The Resident you messaged is prevented from reading your instant messages at the moment, please try again later.
+    </string>
+    <string name="blocked_tplure_remote">
+      The Resident you invited is prevented from accepting teleport offers. Please try again later.
+    </string>
+
+    <!-- Shown in local chat when dropping inventory onto a nearby agent (moved to strings.xml since it needs to be accesible by LLTrans) -->
+    <!--
+    <string name="inventory_item_offered_rlv">
+      Inventory item offered to [NAME]
+    </string>
+    -->
+  </strings>
+
+  <!-- Generic names used to replace resident names when @shownames restricted -->
+  <anonyms>
+    <anonym>A resident</anonym>
+    <anonym>This resident</anonym>
+    <anonym>That resident</anonym>
+    <anonym>An individual</anonym>
+    <anonym>This individual</anonym>
+    <anonym>That individual</anonym>
+    <anonym>A person</anonym>
+    <anonym>This person</anonym>
+    <anonym>That person</anonym>
+    <anonym>A stranger</anonym>
+    <anonym>This stranger</anonym>
+    <anonym>That stranger</anonym>
+    <anonym>A being</anonym>
+    <anonym>This being</anonym>
+    <anonym>That being</anonym>
+    <anonym>An agent</anonym>
+    <anonym>This agent</anonym>
+    <anonym>That agent</anonym>
+    <anonym>A soul</anonym>
+    <anonym>This soul</anonym>
+    <anonym>That soul</anonym>
+    <anonym>Somebody</anonym>
+    <anonym>Some people</anonym>
+    <anonym>Someone</anonym>
+    <anonym>Mysterious one</anonym>
+    <anonym>An unknown being</anonym>
+    <anonym>Unidentified one</anonym>
+    <anonym>An unknown person</anonym>
+  </anonyms>
+
+  <behaviour-notifications>
+    <!-- 
+    <notification behaviour="defaultwear" type="add">Text goes here</notification>
+    <notification behaviour="defaultwear" type="rem">Text goes here</notification>
+    -->
+  </behaviour-notifications>
+
+</rlva_strings>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index cf040b10c7a5add2a8bfc9759c51e6a53d5a6da1..0e813549d9b261b47bf31deb0231022da8cae348 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -3034,6 +3034,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE].
   <string name="inventory_item_offered-im">
     Inventory item offered
   </string>
+  <string name="inventory_item_offered_rlv">
+    Inventory item offered to [NAME]
+  </string>
   <string name="share_alert">
     Drag items from inventory here
   </string>