diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llui/llurlentry.cpp | 33 | ||||
-rw-r--r-- | indra/llui/llurlentry.h | 13 | ||||
-rw-r--r-- | indra/llui/llurlregistry.cpp | 1 | ||||
-rw-r--r-- | indra/newview/llinventoryobserver.h | 2 | ||||
-rw-r--r-- | indra/newview/llviewerinventory.cpp | 32 | ||||
-rw-r--r-- | indra/newview/llviewermessage.cpp | 416 | ||||
-rw-r--r-- | indra/newview/llviewermessage.h | 6 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/menu_url_inventory.xml | 28 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/notifications.xml | 24 |
9 files changed, 412 insertions, 143 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 87d256b60a..c6ec25c1cb 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 4d7d3ee8ac..adad06dc6f 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 @@ 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; } @@ -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 e24da2013d..1a98828010 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 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 9d1bcb8f60..a87f05cbcc 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'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> |