diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 219fae84be8dd529457cbe5ad8fed338a0d1b075..b51709e2086fcdbbe5a13eeb9a9e81642b37db94 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -34,6 +34,7 @@
 #include "linden_common.h"
 #include "llurlentry.h"
 #include "lluri.h"
+
 #include "llcachename.h"
 #include "lltrans.h"
 #include "lluicolortable.h"
@@ -383,6 +384,38 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa
 	}
 }
 
+//
+// LLUrlEntryInventory Describes a Second Life inventory Url, e.g.,
+// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select
+//
+LLUrlEntryInventory::LLUrlEntryInventory()
+{
+	mPattern = boost::regex("secondlife:///app/inventory/[\\da-f-]+/\\w+",
+							boost::regex::perl|boost::regex::icase);
+	mMenuName = "menu_url_inventory.xml";
+}
+
+std::string LLUrlEntryInventory::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
+{
+	return unescapeUrl(url);
+	// TODO: Figure out if we can somehow access the inventory from here to get the actual item name
+	/*  
+	std::string inventory_id_string = getIDStringFromUrl(url);
+	if (inventory_id_string.empty())
+	{
+		// something went wrong, give raw url
+		return unescapeUrl(url);
+	}
+	LLUUID inventory_id(inventory_id_string);
+	LLInventoryItem* item = gInventory.getItem(inventory_id);
+	if(!item)
+	{
+		return unescapeUrl(url);
+	}
+	return item->getName(); */
+}
+
+
 ///
 /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
 /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 7970b48eb5a7445148cdd7e97f2ea9a5cbaa5853..b3fb333fdd80f91c25fffdb9931a154c3bb6bbc6 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -173,6 +173,19 @@ class LLUrlEntryGroup : public LLUrlEntryBase
 							 const std::string& last, BOOL is_group);
 };
 
+///
+/// LLUrlEntryInventory Describes a Second Life inventory Url, e.g.,
+/// secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select
+///
+class LLUrlEntryInventory : public LLUrlEntryBase
+{
+public:
+	LLUrlEntryInventory();
+	/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
+private:
+};
+
+
 ///
 /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
 /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about
diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp
index a6922b019b52cd2f88999935943086905b5b042c..b2f084e5acb80756f445573bee037d51d50364bd 100644
--- a/indra/llui/llurlregistry.cpp
+++ b/indra/llui/llurlregistry.cpp
@@ -55,6 +55,7 @@ LLUrlRegistry::LLUrlRegistry()
 	registerUrl(new LLUrlEntryPlace());
 	registerUrl(new LLUrlEntrySL());
 	registerUrl(new LLUrlEntrySLLabel());
+	registerUrl(new LLUrlEntryInventory());
 }
 
 LLUrlRegistry::~LLUrlRegistry()
diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h
index 384e6292e8a6aad73f8e0c74d0faac1d9dc2fdc1..e908506b337ef5d1454c94aa6c2f8ccb2af077d8 100644
--- a/indra/newview/llinventoryobserver.h
+++ b/indra/newview/llinventoryobserver.h
@@ -113,7 +113,7 @@ class LLInventoryFetchObserver : public LLInventoryObserver
 
 	bool isEverythingComplete() const;
 	void fetchItems(const item_ref_t& ids);
-	virtual void done() = 0;
+	virtual void done() {};
 
 protected:
 	item_ref_t mComplete;
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 87d256b60a94f1231928d90d7ff6d5466c160b57..c6ec25c1cb307a39d64ff64d324680b1e5322e0e 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -56,11 +56,43 @@
 #include "lltrans.h"
 #include "llappearancemgr.h"
 #include "llfloatercustomize.h"
+#include "llcommandhandler.h"
+#include "llviewermessage.h"
 
 ///----------------------------------------------------------------------------
 /// Local function declarations, constants, enums, and typedefs
 ///----------------------------------------------------------------------------
 
+class LLInventoryHandler : public LLCommandHandler
+{
+public:
+	// requires trusted browser to trigger
+	LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_THROTTLE) { }
+	
+	bool handle(const LLSD& params, const LLSD& query_map,
+				LLMediaCtrl* web)
+	{
+		if (params.size() < 2) return false;
+		LLUUID inventory_id;
+		if (!inventory_id.set(params[0], FALSE))
+		{
+			return false;
+		}
+		
+		const std::string verb = params[1].asString();
+		if (verb == "select")
+		{
+			std::vector<LLUUID> items_to_open;
+			items_to_open.push_back(inventory_id);
+			open_inventory_offer(items_to_open, "");
+			return true;
+		}
+		
+		return false;
+	}
+};
+LLInventoryHandler gInventoryHandler;
+
 ///----------------------------------------------------------------------------
 /// Class LLViewerInventoryItem
 ///----------------------------------------------------------------------------
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 4d7d3ee8ac7c60724382b2d6c98cfeb748a64175..adad06dc6f1b52e5b260ff2ce4dffe4b71765a13 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -170,7 +170,6 @@ static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL	= 10.0f; // seconds
 extern BOOL gDebugClicks;
 
 // function prototypes
-void open_offer(const std::vector<LLUUID>& items, const std::string& from_name);
 bool check_offer_throttle(const std::string& from_name, bool check_only);
 
 //inventory offer throttle globals
@@ -727,7 +726,7 @@ class LLOpenAgentOffer : public LLInventoryFetchObserver
 	LLOpenAgentOffer(const std::string& from_name) : mFromName(from_name) {}
 	/*virtual*/ void done()
 	{
-		open_offer(mComplete, mFromName);
+		open_inventory_offer(mComplete, mFromName);
 		gInventory.removeObserver(this);
 		delete this;
 	}
@@ -745,7 +744,7 @@ class LLOpenTaskOffer : public LLInventoryAddedObserver
 protected:
 	/*virtual*/ void done()
 	{
-		open_offer(mAdded, "");
+		open_inventory_offer(mAdded, "");
 		mAdded.clear();
 	}
  };
@@ -876,7 +875,7 @@ bool check_offer_throttle(const std::string& from_name, bool check_only)
 	}
 }
  
-void open_offer(const std::vector<LLUUID>& items, const std::string& from_name)
+void open_inventory_offer(const std::vector<LLUUID>& items, const std::string& from_name)
 {
 	std::vector<LLUUID>::const_iterator it = items.begin();
 	std::vector<LLUUID>::const_iterator end = items.end();
@@ -1066,12 +1065,60 @@ LLSD LLOfferInfo::asLLSD()
 	return sd;
 }
 
+void LLOfferInfo::send_auto_receive_response(void)
+{	
+	LLMessageSystem* msg = gMessageSystem;
+	msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
+	msg->nextBlockFast(_PREHASH_AgentData);
+	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	msg->nextBlockFast(_PREHASH_MessageBlock);
+	msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
+	msg->addUUIDFast(_PREHASH_ToAgentID, mFromID);
+	msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
+	msg->addUUIDFast(_PREHASH_ID, mTransactionID);
+	msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
+	std::string name;
+	LLAgentUI::buildFullname(name);
+	msg->addStringFast(_PREHASH_FromAgentName, name);
+	msg->addStringFast(_PREHASH_Message, ""); 
+	msg->addU32Fast(_PREHASH_ParentEstateID, 0);
+	msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
+	msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
+	
+	// Auto Receive Message. 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.
+	// Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, 
+	// or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
+	msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
+	msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
+						   sizeof(mFolderID.mData));
+	// send the message
+	msg->sendReliable(mHost);
+	
+	if(IM_INVENTORY_OFFERED == mIM)
+	{
+		// add buddy to recent people list
+		LLRecentPeople::instance().add(mFromID);
+	}
+}
+
 bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response)
- {
+{
 	LLChat chat;
 	std::string log_message;
 	S32 button = LLNotification::getSelectedOption(notification, response);
-
+	
+	LLInventoryObserver* opener = NULL;
+	LLViewerInventoryCategory* catp = NULL;
+	catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID);
+	LLViewerInventoryItem* itemp = NULL;
+	if(!catp)
+	{
+		itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID);
+	}
+	 
 	// For muting, we need to add the mute, then decline the offer.
 	// This must be done here because:
 	// * callback may be called immediately,
@@ -1082,6 +1129,136 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
 		gCacheName->get(mFromID, mFromGroup, &inventory_offer_mute_callback);
 	}
 
+	std::string from_string; // Used in the pop-up.
+	std::string chatHistory_string;  // Used in chat history.
+	
+	// TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here:
+	from_string = chatHistory_string = mFromName;
+	
+	bool busy=FALSE;
+	
+	switch(button)
+	{
+	case IOR_SHOW:
+		// we will want to open this item when it comes back.
+		LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
+				 << LL_ENDL;
+		switch (mIM)
+		{
+		case IM_INVENTORY_OFFERED:
+			{
+				// 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.
+				LLInventoryFetchObserver::item_ref_t items;
+				items.push_back(mObjectID);
+				LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(from_string);
+				open_agent_offer->fetchItems(items);
+				if(catp || (itemp && itemp->isComplete()))
+				{
+					open_agent_offer->done();
+				}
+				else
+				{
+					opener = open_agent_offer;
+				}
+			}
+			break;
+		case IM_TASK_INVENTORY_OFFERED:
+		case IM_GROUP_NOTICE:
+		case IM_GROUP_NOTICE_REQUESTED:
+			// This is an offer from a task or group.
+			// We don't use a new instance of an opener
+			// We instead use the singular observer gOpenTaskOffer
+			// Since it already exists, we don't need to actually do anything
+			break;
+		default:
+			LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
+			break;
+		}	// end switch (mIM)
+			
+		// Show falls through to accept.
+			
+	case IOR_ACCEPT:
+		//don't spam them if they are getting flooded
+		if (check_offer_throttle(mFromName, true))
+		{
+			log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
+			chat.mText = log_message;
+			LLFloaterChat::addChatHistory(chat);
+		}
+		break;
+
+	case IOR_BUSY:
+		//Busy falls through to decline.  Says to make busy message.
+		busy=TRUE;
+	case IOR_MUTE:
+		// MUTE falls through to decline
+	case IOR_DECLINE:
+		{
+			log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +".";
+			chat.mText = log_message;
+			if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) )  // muting for SL-42269
+			{
+				chat.mMuted = TRUE;
+			}
+			LLFloaterChat::addChatHistory(chat);
+			
+			LLInventoryFetchComboObserver::folder_ref_t folders;
+			LLInventoryFetchComboObserver::item_ref_t items;
+			items.push_back(mObjectID);
+			LLDiscardAgentOffer* discard_agent_offer;
+			discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID);
+			discard_agent_offer->fetch(folders, items);
+			if(catp || (itemp && itemp->isComplete()))
+			{
+				discard_agent_offer->done();
+			}
+			else
+			{
+				opener = discard_agent_offer;
+			}
+			
+			
+			if (busy &&	(!mFromGroup && !mFromObject))
+			{
+				busy_message(gMessageSystem, mFromID);
+			}
+			break;
+		}
+	default:
+		// close button probably
+		// The item has already been fetched and is in your inventory, we simply won't highlight it
+		// OR delete it if the notification gets killed, since we don't want that to be a vector for 
+		// losing inventory offers.
+		break;
+	}
+
+	if(opener)
+	{
+		gInventory.addObserver(opener);
+	}
+
+	delete this;
+	return false;
+}
+
+bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const LLSD& response)
+{
+	LLChat chat;
+	std::string log_message;
+	S32 button = LLNotification::getSelectedOption(notification, response);
+	
+	// For muting, we need to add the mute, then decline the offer.
+	// This must be done here because:
+	// * callback may be called immediately,
+	// * adding the mute sends a message,
+	// * we can't build two messages at once.
+	if (2 == button)
+	{
+		gCacheName->get(mFromID, mFromGroup, &inventory_offer_mute_callback);
+	}
+	
 	LLMessageSystem* msg = gMessageSystem;
 	msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
 	msg->nextBlockFast(_PREHASH_AgentData);
@@ -1108,7 +1285,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
 	{
 		itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID);
 	}
-
+	
 	std::string from_string; // Used in the pop-up.
 	std::string chatHistory_string;  // Used in chat history.
 	if (mFromObject == TRUE)
@@ -1119,16 +1296,16 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
 			if (gCacheName->getGroupName(mFromID, group_name))
 			{
 				from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" 
-							+ mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup") 
-				            + " "+ "'" + group_name + "'";
+				+ mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup") 
+				+ " "+ "'" + group_name + "'";
 				
 				chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup") 
-								   + " " + group_name + "'";
+				+ " " + group_name + "'";
 			}
 			else
 			{
 				from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'"
-				            + mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup");
+				+ mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup");
 				chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup");
 			}
 		}
@@ -1138,13 +1315,13 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
 			if (gCacheName->getName(mFromID, first_name, last_name))
 			{
 				from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName 
-							+ LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + first_name + " " + last_name;
+				+ LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + first_name + " " + last_name;
 				chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + first_name + " " + last_name;
 			}
 			else
 			{
 				from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+LLTrans::getString("'") 
-				            + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser");
+				+ mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser");
 				chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser");
 			}
 		}
@@ -1158,137 +1335,90 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
 	
 	switch(button)
 	{
-	case IOR_ACCEPT:
-		// 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.
-		// Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, 
-		// or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
-		msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
-		msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
-					 sizeof(mFolderID.mData));
-		// send the message
-		msg->sendReliable(mHost);
-
-		//don't spam them if they are getting flooded
-		if (check_offer_throttle(mFromName, true))
-		{
-			log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
- 			chat.mText = log_message;
- 			LLFloaterChat::addChatHistory(chat);
-		}
-
-		// we will want to open this item when it comes back.
-		LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
-				 << LL_ENDL;
-		switch (mIM)
-		{
-		case IM_INVENTORY_OFFERED:
-		{
-			// 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.
-			LLInventoryFetchObserver::item_ref_t items;
-			items.push_back(mObjectID);
-			LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(from_string);
-			open_agent_offer->fetchItems(items);
-			if(catp || (itemp && itemp->isComplete()))
+		case IOR_ACCEPT:
+			// 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.
+			// Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, 
+			// or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
+			msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
+			msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
+								   sizeof(mFolderID.mData));
+			// send the message
+			msg->sendReliable(mHost);
+			
+			//don't spam them if they are getting flooded
+			if (check_offer_throttle(mFromName, true))
 			{
-				open_agent_offer->done();
+				log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
+				chat.mText = log_message;
+				LLFloaterChat::addChatHistory(chat);
 			}
-			else
+			
+			// we will want to open this item when it comes back.
+			LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
+			<< LL_ENDL;
+			switch (mIM)
+		{
+			case IM_TASK_INVENTORY_OFFERED:
+			case IM_GROUP_NOTICE:
+			case IM_GROUP_NOTICE_REQUESTED:
 			{
-				opener = open_agent_offer;
+				// This is an offer from a task or group.
+				// We don't use a new instance of an opener
+				// We instead use the singular observer gOpenTaskOffer
+				// Since it already exists, we don't need to actually do anything
 			}
-		}
+				break;
+			default:
+				LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
+				break;
+		}	// end switch (mIM)
 			break;
-		case IM_TASK_INVENTORY_OFFERED:
-		case IM_GROUP_NOTICE:
-		case IM_GROUP_NOTICE_REQUESTED:
-		{
-			// This is an offer from a task or group.
-			// We don't use a new instance of an opener
-			// We instead use the singular observer gOpenTaskOffer
-			// Since it already exists, we don't need to actually do anything
-		}
-		break;
+			
+		case IOR_BUSY:
+			//Busy falls through to decline.  Says to make busy message.
+			busy=TRUE;
+		case IOR_MUTE:
+			// MUTE falls through to decline
+		case IOR_DECLINE:
+			// DECLINE. The math for the dialog works, because the decline
+			// for inventory_offered, task_inventory_offer or
+			// group_notice_inventory is 2 greater than the offer integer value.
+			// Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED,
+			// or IM_GROUP_NOTICE_INVENTORY_DECLINED
 		default:
-			LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
-			break;
-		}	// end switch (mIM)
-		break;
-
-	case IOR_BUSY:
-		//Busy falls through to decline.  Says to make busy message.
-		busy=TRUE;
-	case IOR_MUTE:
-		// MUTE falls through to decline
-	case IOR_DECLINE:
-		// DECLINE. The math for the dialog works, because the decline
-		// for inventory_offered, task_inventory_offer or
-		// group_notice_inventory is 2 greater than the offer integer value.
-		// Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED,
-		// or IM_GROUP_NOTICE_INVENTORY_DECLINED
-	default:
-		// close button probably (or any of the fall-throughs from above)
-		msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 2));
-		msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
-		// send the message
-		msg->sendReliable(mHost);
-
-		log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +".";
-		chat.mText = log_message;
-		if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) )  // muting for SL-42269
-		{
-			chat.mMuted = TRUE;
-		}
-		LLFloaterChat::addChatHistory(chat);
-
-		// If it's from an agent, we have to fetch the item to throw
-		// it away. If it's from a task or group, just denying the 
-		// request will suffice to discard the item.
-		if(IM_INVENTORY_OFFERED == mIM)
-		{
-			LLInventoryFetchComboObserver::folder_ref_t folders;
-			LLInventoryFetchComboObserver::item_ref_t items;
-			items.push_back(mObjectID);
-			LLDiscardAgentOffer* discard_agent_offer;
-			discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID);
-			discard_agent_offer->fetch(folders, items);
-			if(catp || (itemp && itemp->isComplete()))
+			// close button probably (or any of the fall-throughs from above)
+			msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 2));
+			msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
+			// send the message
+			msg->sendReliable(mHost);
+			
+			log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +".";
+			chat.mText = log_message;
+			if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) )  // muting for SL-42269
 			{
-				discard_agent_offer->done();
+				chat.mMuted = TRUE;
 			}
-			else
+			LLFloaterChat::addChatHistory(chat);
+			
+			if (busy &&	(!mFromGroup && !mFromObject))
 			{
-				opener = discard_agent_offer;
+				busy_message(msg,mFromID);
 			}
-			
-		}
-		if (busy &&	(!mFromGroup && !mFromObject))
-		{
-			busy_message(msg,mFromID);
-		}
-		break;
-	}
-
-	if(IM_INVENTORY_OFFERED == mIM)
-	{
-		// add buddy to recent people list
-		LLRecentPeople::instance().add(mFromID);
+			break;
 	}
-
+	
 	if(opener)
 	{
 		gInventory.addObserver(opener);
 	}
-
+	
 	delete this;
 	return false;
 }
 
-
-void inventory_offer_handler(LLOfferInfo* info, BOOL from_task)
+void inventory_offer_handler(LLOfferInfo* info)
 {
 	//Until throttling is implmented, busy mode should reject inventory instead of silently
 	//accepting it.  SEE SL-39554
@@ -1375,21 +1505,45 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task)
 	args["OBJECTFROMNAME"] = info->mFromName;
 	args["NAME"] = info->mFromName;
 	args["NAME_SLURL"] = LLSLURL::buildCommand("agent", info->mFromID, "about");
-	std::string verb = "highlight?name=" + msg;
+	std::string verb = "select?name=" + msg;
 	args["ITEM_SLURL"] = LLSLURL::buildCommand("inventory", info->mObjectID, verb.c_str());
 
 	LLNotification::Params p("ObjectGiveItem");
-	p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2));
 
-	if (from_task)
+	// Object -> Agent Inventory Offer
+	if (info->mFromObject)
 	{
+		// 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
+		p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_task_offer_callback, info, _1, _2));
 		p.name = name_found ? "ObjectGiveItem" : "ObjectGiveItemUnknownUser";
 	}
-	else
+	else // Agent -> Agent Inventory Offer
 	{
+		// Note: sets inventory_offer_callback as the callback
+		p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2));
 		p.name = "UserGiveItem";
+		
+		// Prefetch the item into your local inventory.
+		LLInventoryFetchObserver::item_ref_t items;
+		items.push_back(info->mObjectID);
+		LLInventoryFetchObserver* fetch_item = new LLInventoryFetchObserver();
+		fetch_item->fetchItems(items);
+		if(fetch_item->isEverythingComplete())
+		{
+			fetch_item->done();
+		}
+		else
+		{
+			gInventory.addObserver(fetch_item);
+		}
+		
+		// In viewer 2 we're now auto receiving inventory offers and messaging as such (not sending reject messages).
+		info->send_auto_receive_response();
 	}
-
+	
+	// Pop up inv offer notification and let the user accept (keep), or reject (and silently delete) the inventory.
 	LLNotifications::instance().add(p);
 }
 
@@ -1885,7 +2039,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 			}
 			else
 			{
-				inventory_offer_handler(info, dialog == IM_TASK_INVENTORY_OFFERED);
+				inventory_offer_handler(info);
 			}
 		}
 		break;
diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h
index e24da2013d19c6b4189413230c96248258468065..1a98828010f8e1ac2f0bb6e7b32589139cc29a0f 100644
--- a/indra/newview/llviewermessage.h
+++ b/indra/newview/llviewermessage.h
@@ -59,7 +59,8 @@ enum InventoryOfferResponse
 	IOR_ACCEPT,
 	IOR_DECLINE,
 	IOR_MUTE,
-	IOR_BUSY
+	IOR_BUSY,
+	IOR_SHOW
 };
 
 BOOL can_afford_transaction(S32 cost);
@@ -197,6 +198,7 @@ void invalid_message_callback(LLMessageSystem*, void*, EMessageException);
 
 void process_initiate_download(LLMessageSystem* msg, void**);
 void start_new_inventory_observer();
+void open_inventory_offer(const std::vector<LLUUID>& items, const std::string& from_name);
 
 struct LLOfferInfo
 {
@@ -218,7 +220,9 @@ struct LLOfferInfo
 	LLHost mHost;
 
 	LLSD asLLSD();
+	void send_auto_receive_response(void);
 	bool inventory_offer_callback(const LLSD& notification, const LLSD& response);
+	bool inventory_task_offer_callback(const LLSD& notification, const LLSD& response);
 
 };
 
diff --git a/indra/newview/skins/default/xui/en/menu_url_inventory.xml b/indra/newview/skins/default/xui/en/menu_url_inventory.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cf9d1d58817e39a1b8633d3080cd8f1f2b5c2f9d
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_url_inventory.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Url Popup">
+    <menu_item_call
+     label="Show Inventory Item"
+     layout="topleft"
+     name="show_item">
+        <menu_item_call.on_click
+         function="Url.Execute" />
+    </menu_item_call>
+    <menu_item_separator
+     layout="topleft" />
+    <menu_item_call
+     label="Copy Name to clipboard"
+     layout="topleft"
+     name="url_copy_label">
+        <menu_item_call.on_click
+         function="Url.CopyLabel" />
+    </menu_item_call>
+    <menu_item_call
+     label="Copy SLurl to clipboard"
+     layout="topleft"
+     name="url_copy">
+        <menu_item_call.on_click
+         function="Url.CopyUrl" />
+    </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 9d1bcb8f60b640b882ea0decac4c267dacd31b5b..a87f05cbcc0ec342e06e95ed22e742d730696afc 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -4494,7 +4494,7 @@ You don&apos;t have permission to copy this.
    icon="notifytip.tga"
    name="InventoryAccepted"
    type="notifytip">
-[NAME] accepted your inventory offer.
+[NAME] received your inventory offer.
   </notification>
 
   <notification
@@ -4966,17 +4966,17 @@ No valid parcel could be found.
    icon="notify.tga"
    name="ObjectGiveItem"
    type="offer">
-An object named [OBJECTFROMNAME] owned by [NAME_SLURL] has offered you [OBJECTTYPE]:
+An object named [OBJECTFROMNAME] owned by [NAME_SLURL] has given you [OBJECTTYPE]:
 [ITEM_SLURL]
     <form name="form">
       <button
        index="0"
        name="Keep"
-       text="OK"/>
+       text="Keep"/>
       <button
        index="1"
        name="Discard"
-       text="Cancel"/>
+       text="Discard"/>
       <button
        index="2"
        name="Mute"
@@ -4988,17 +4988,17 @@ An object named [OBJECTFROMNAME] owned by [NAME_SLURL] has offered you [OBJECTTY
    icon="notify.tga"
    name="ObjectGiveItemUnknownUser"
    type="offer">
-An object named [OBJECTFROMNAME] owned by (an unknown Resident) has offered you [OBJECTTYPE]:
+An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you [OBJECTTYPE]:
 [ITEM_SLURL]
     <form name="form">
       <button
        index="0"
        name="Keep"
-       text="OK"/>
+       text="Keep"/>
       <button
        index="1"
        name="Discard"
-       text="Cancel"/>
+       text="Discard"/>
       <button
        index="2"
        name="Mute"
@@ -5010,17 +5010,21 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has offered you
    icon="notify.tga"
    name="UserGiveItem"
    type="offer">
-[NAME_SLURL] has offered you [OBJECTTYPE]:
+[NAME_SLURL] has given you [OBJECTTYPE]:
 [ITEM_SLURL]
     <form name="form">
       <button
        index="0"
        name="Keep"
-       text="Accept"/>
+       text="Keep"/>
+      <button
+       index="4"
+       name="Show"
+       text="Show"/> 
       <button
        index="1"
        name="Discard"
-       text="No, thanks"/>
+       text="Discard"/>
     </form>
   </notification>