summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llui/llurlentry.cpp33
-rw-r--r--indra/llui/llurlentry.h13
-rw-r--r--indra/llui/llurlregistry.cpp1
-rw-r--r--indra/newview/llinventoryobserver.h2
-rw-r--r--indra/newview/llviewerinventory.cpp32
-rw-r--r--indra/newview/llviewermessage.cpp196
-rw-r--r--indra/newview/llviewermessage.h5
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_inventory.xml28
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml30
9 files changed, 238 insertions, 102 deletions
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index 219fae84be..b51709e208 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 7970b48eb5..b3fb333fdd 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -174,6 +174,19 @@ private:
};
///
+/// 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 a6922b019b..b2f084e5ac 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 384e6292e8..e908506b33 100644
--- a/indra/newview/llinventoryobserver.h
+++ b/indra/newview/llinventoryobserver.h
@@ -113,7 +113,7 @@ public:
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 089535dfab..9da96cb605 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 11b2f07f1b..fa84debdf9 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -726,7 +726,7 @@ public:
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;
}
@@ -875,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();
@@ -1065,22 +1065,8 @@ LLSD LLOfferInfo::asLLSD()
return sd;
}
-bool LLOfferInfo::inventory_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);
- }
-
+void LLOfferInfo::send_auto_receive_response(void)
+{
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
msg->nextBlockFast(_PREHASH_AgentData);
@@ -1099,6 +1085,31 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
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);
@@ -1107,6 +1118,16 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
{
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,
+ // * 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);
+ }
std::string from_string; // Used in the pop-up.
std::string chatHistory_string; // Used in chat history.
@@ -1157,64 +1178,54 @@ 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);
- }
-
+ 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;
+ // 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;
+ 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:
@@ -1223,31 +1234,15 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
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)
{
+ 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);
@@ -1263,20 +1258,21 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
opener = discard_agent_offer;
}
+
+ if (busy && (!mFromGroup && !mFromObject))
+ {
+ busy_message(gMessageSystem, mFromID);
+ }
+ break;
}
- if (busy && (!mFromGroup && !mFromObject))
- {
- busy_message(msg,mFromID);
- }
+ 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(IM_INVENTORY_OFFERED == mIM)
- {
- // add buddy to recent people list
- LLRecentPeople::instance().add(mFromID);
- }
-
if(opener)
{
gInventory.addObserver(opener);
@@ -1387,7 +1383,25 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task)
{
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);
}
diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h
index e24da2013d..2d8930d2fe 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,6 +220,7 @@ struct LLOfferInfo
LLHost mHost;
LLSD asLLSD();
+ void send_auto_receive_response(void);
bool inventory_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 0000000000..cf9d1d5881
--- /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 d955e875a7..ff777a762f 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,21 @@ No valid parcel could be found.
icon="notify.tga"
name="ObjectGiveItem"
type="offer">
-An object named [OBJECTFROMNAME] owned by [NAME] has offered you [OBJECTTYPE]:
+An object named [OBJECTFROMNAME] owned by [NAME] has given you [OBJECTTYPE]:
[ITEM_SLURL]
<form name="form">
<button
index="0"
name="Keep"
- text="OK"/>
+ text="Keep"/>
+ <button
+ index="4"
+ name="Show"
+ text="Show"/>
<button
index="1"
name="Discard"
- text="Cancel"/>
+ text="Discard"/>
<button
index="2"
name="Mute"
@@ -4993,11 +4997,15 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you a
<button
index="0"
name="Keep"
- text="OK"/>
+ text="Keep"/>
+ <button
+ index="4"
+ name="Show"
+ text="Show"/>
<button
index="1"
name="Discard"
- text="Cancel"/>
+ text="Discard"/>
<button
index="2"
name="Mute"
@@ -5009,17 +5017,21 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you a
icon="notify.tga"
name="UserGiveItem"
type="offer">
-[NAME] has offered you [OBJECTTYPE]:
+[NAME] 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>