diff options
Diffstat (limited to 'indra/newview/llviewermessage.cpp')
-rw-r--r-- | indra/newview/llviewermessage.cpp | 1553 |
1 files changed, 1002 insertions, 551 deletions
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index f16465acba..cde78e1cc8 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -31,76 +31,48 @@ */ #include "llviewerprecompiledheaders.h" - #include "llviewermessage.h" -#include <deque> - +#include "llanimationstates.h" #include "llaudioengine.h" -#include "indra_constants.h" +#include "llavataractions.h" #include "lscript_byteformat.h" -#include "mean_collision_data.h" -#include "llfloaterbump.h" -#include "llassetstorage.h" -#include "llcachename.h" -#include "llchat.h" -#include "lldbstrings.h" #include "lleconomy.h" -#include "llfilepicker.h" +#include "lleventtimer.h" #include "llfloaterreg.h" -#include "llfocusmgr.h" #include "llfollowcamparams.h" -#include "llinstantmessage.h" -#include "llquantize.h" -#include "llregionflags.h" #include "llregionhandle.h" #include "llsdserialize.h" -#include "llstring.h" #include "llteleportflags.h" -#include "lltracker.h" #include "lltransactionflags.h" +#include "llvfile.h" +#include "llvfs.h" #include "llxfermanager.h" -#include "message.h" -#include "sound_ids.h" -#include "lltimer.h" -#include "llmd5.h" +#include "mean_collision_data.h" #include "llagent.h" +#include "llagentcamera.h" #include "llcallingcard.h" -#include "llconsole.h" -#include "llvieweraudio.h" -#include "llviewercontrol.h" -#include "lldrawpool.h" -#include "llfirstuse.h" -#include "llfloateractivespeakers.h" -#include "llfloateranimpreview.h" +//#include "llfirstuse.h" #include "llfloaterbuycurrency.h" #include "llfloaterbuyland.h" -#include "llfloaterchat.h" -#include "llfloaterimagepreview.h" #include "llfloaterland.h" #include "llfloaterregioninfo.h" #include "llfloaterlandholdings.h" -#include "llurldispatcher.h" #include "llfloaterpostcard.h" #include "llfloaterpreference.h" -#include "llfollowcam.h" -#include "llgroupnotify.h" -#include "llhudeffect.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" -#include "llimpanel.h" -#include "llinventorymodel.h" -#include "llfloaterinventory.h" -#include "llmenugl.h" -#include "llmoveview.h" -#include "llmutelist.h" +#include "llinventoryfunctions.h" +#include "llinventoryobserver.h" +#include "llinventorypanel.h" #include "llnearbychat.h" #include "llnotifications.h" -#include "llnotify.h" +#include "llnotificationsutil.h" #include "llpanelgrouplandmoney.h" #include "llpanelplaces.h" #include "llrecentpeople.h" +#include "llscriptfloater.h" #include "llselectmgr.h" #include "llsidetray.h" #include "llstartup.h" @@ -109,21 +81,14 @@ #include "llstatenums.h" #include "llstatusbar.h" #include "llimview.h" -#include "lltool.h" -#include "lltoolbar.h" -#include "lltoolmgr.h" +#include "llspeakers.h" #include "lltrans.h" -#include "llui.h" // for make_ui_sound -#include "lluploaddialog.h" -#include "llviewercamera.h" +#include "llviewerfoldertype.h" +#include "lluri.h" #include "llviewergenericmessage.h" -#include "llviewerinventory.h" #include "llviewermenu.h" -#include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" -#include "llviewerpartsource.h" -#include "llviewerregion.h" #include "llviewerstats.h" #include "llviewertexteditor.h" #include "llviewerthrottle.h" @@ -131,27 +96,24 @@ #include "llvlmanager.h" #include "llvoavatarself.h" #include "llvotextbubble.h" -#include "llweb.h" #include "llworld.h" #include "pipeline.h" -#include "llappviewer.h" #include "llfloaterworldmap.h" #include "llviewerdisplay.h" #include "llkeythrottle.h" #include "llgroupactions.h" #include "llagentui.h" #include "llpanelblockedlist.h" -#include "llpanelplaceinfo.h" +#include "llpanelplaceprofile.h" -#include <boost/tokenizer.hpp> -#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/split.hpp> // +#include <boost/regex.hpp> #if LL_WINDOWS // For Windows specific error handler #include "llwindebug.h" // For the invalid message handler #endif -//#include "llnearbychathistory.h" -#include "llnotificationmanager.h" +#include "llnotificationmanager.h" // // // Constants @@ -168,7 +130,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 @@ -209,8 +170,7 @@ const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); - LLUUID fid; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLMessageSystem* msg = gMessageSystem; const LLSD& payload = notification["payload"]; @@ -220,10 +180,11 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) switch(option) { case 0: + { // accept LLAvatarTracker::formFriendship(payload["from_id"]); - fid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); + const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); // This will also trigger an onlinenotification if the user is online msg->newMessageFast(_PREHASH_AcceptFriendship); @@ -235,19 +196,40 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) msg->nextBlockFast(_PREHASH_FolderData); msg->addUUIDFast(_PREHASH_FolderID, fid); msg->sendReliable(LLHost(payload["sender"].asString())); + + LLSD payload = notification["payload"]; + payload["SUPPRESS_TOAST"] = true; + LLNotificationsUtil::add("FriendshipAcceptedByMe", + notification["substitutions"], payload); break; - case 1: - // decline - // We no longer notify other viewers, but we DO still send - // the rejection to the simulator to delete the pending userop. - msg->newMessageFast(_PREHASH_DeclineFriendship); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); - msg->sendReliable(LLHost(payload["sender"].asString())); - break; + } + case 1: // Decline + { + LLSD payload = notification["payload"]; + payload["SUPPRESS_TOAST"] = true; + LLNotificationsUtil::add("FriendshipDeclinedByMe", + notification["substitutions"], payload); + } + // fall-through + case 2: // Send IM - decline and start IM session + { + // decline + // We no longer notify other viewers, but we DO still send + // the rejection to the simulator to delete the pending userop. + msg->newMessageFast(_PREHASH_DeclineFriendship); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); + msg->sendReliable(LLHost(payload["sender"].asString())); + + // start IM session + if(2 == option) + { + LLAvatarActions::startIM(payload["from_id"].asUUID()); + } + } default: // close button probably, possibly timed out break; @@ -293,7 +275,9 @@ void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_ } else { - LLFloaterBuyCurrency::buyCurrency("Giving", amount); + LLStringUtil::format_map_t args; + args["AMOUNT"] = llformat("%d", amount); + LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("giving", args), amount); } } @@ -631,7 +615,7 @@ void send_sound_trigger(const LLUUID& sound_id, F32 gain) bool join_group_response(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); BOOL delete_context_data = TRUE; bool accept_invite = false; @@ -646,7 +630,7 @@ bool join_group_response(const LLSD& notification, const LLSD& response) LLGroupActions::show(group_id); LLSD args; args["MESSAGE"] = message; - LLNotifications::instance().add("JoinGroup", args, notification["payload"]); + LLNotificationsUtil::add("JoinGroup", args, notification["payload"]); return false; } if(option == 0 && !group_id.isNull()) @@ -664,8 +648,7 @@ bool join_group_response(const LLSD& notification, const LLSD& response) delete_context_data = FALSE; LLSD args; args["NAME"] = name; - args["INVITE"] = message; - LLNotifications::instance().add("JoinedTooManyGroupsMember", args, notification["payload"]); + LLNotificationsUtil::add("JoinedTooManyGroupsMember", args, notification["payload"]); } } @@ -682,7 +665,7 @@ bool join_group_response(const LLSD& notification, const LLSD& response) // asking about a fee. LLSD next_payload = notification["payload"]; next_payload["fee"] = 0; - LLNotifications::instance().add("JoinGroupCanAfford", + LLNotificationsUtil::add("JoinGroupCanAfford", args, next_payload); } @@ -722,7 +705,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; } @@ -740,11 +723,23 @@ class LLOpenTaskOffer : public LLInventoryAddedObserver protected: /*virtual*/ void done() { - open_offer(mAdded, ""); + open_inventory_offer(mAdded, ""); mAdded.clear(); } }; +class LLOpenTaskGroupOffer : public LLInventoryAddedObserver +{ +protected: + /*virtual*/ void done() + { + open_inventory_offer(mAdded, "group_offer"); + mAdded.clear(); + gInventory.removeObserver(this); + delete this; + } +}; + //one global instance to bind them LLOpenTaskOffer* gNewInventoryObserver=NULL; @@ -760,6 +755,7 @@ void start_new_inventory_observer() class LLDiscardAgentOffer : public LLInventoryFetchComboObserver { + LOG_CLASS(LLDiscardAgentOffer); public: LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : mFolderID(folder_id), @@ -768,8 +764,7 @@ public: virtual void done() { LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL; - LLUUID trash_id; - trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); bool notify = false; if(trash_id.notNull() && mObjectID.notNull()) { @@ -857,9 +852,13 @@ bool check_offer_throttle(const std::string& from_name, bool check_only) } message << ", automatic preview disabled for " << OFFER_THROTTLE_TIME << " seconds."; - chat.mText = message.str(); + //this is kinda important, so actually put it on screen - LLFloaterChat::addChat(chat, FALSE, FALSE); + std::string log_msg = message.str(); + LLSD args; + args["MESSAGE"] = log_msg; + LLNotificationsUtil::add("SystemMessage", args); + throttle_logged=true; } return false; @@ -872,145 +871,189 @@ 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 uuid_vec_t& items, const std::string& from_name) { - std::vector<LLUUID>::const_iterator it = items.begin(); - std::vector<LLUUID>::const_iterator end = items.end(); - LLUUID trash_id(gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH)); - LLInventoryItem* item; - for(; it != end; ++it) + for (uuid_vec_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) { - const LLUUID& id = *it; - item = gInventory.getItem(id); - if(!item) + const LLUUID& item_id = (*item_iter); + if(!highlight_offered_item(item_id)) { - LL_WARNS("Messaging") << "Unable to show inventory item: " << id << LL_ENDL; continue; } - if(gInventory.isObjectDescendentOf(id, trash_id)) - { + + LLInventoryItem* item = gInventory.getItem(item_id); + llassert(item); + if (!item) { continue; } - LLAssetType::EType asset_type = item->getType(); - //if we are throttled, don't display them - if (check_offer_throttle(from_name, false)) + //////////////////////////////////////////////////////////////////////////////// + // Special handling for various types. + const LLAssetType::EType asset_type = item->getType(); + if (check_offer_throttle(from_name, false)) // If we are throttled, don't display { + LL_DEBUGS("Messaging") << "Highlighting inventory item: " << item->getUUID() << LL_ENDL; // If we opened this ourselves, focus it - BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO; + const BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO; switch(asset_type) { case LLAssetType::AT_NOTECARD: - LLFloaterReg::showInstance("preview_notecard", LLSD(id), take_focus); - break; + { + LLFloaterReg::showInstance("preview_notecard", LLSD(item_id), take_focus); + break; + } case LLAssetType::AT_LANDMARK: { LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID()); - LLSD args; - args["LANDMARK_NAME"] = item->getName(); - args["FOLDER_NAME"] = std::string(parent_folder ? parent_folder->getName() : "unknown"); - LLNotifications::instance().add("LandmarkCreated", args); - - // Created landmark is passed to Places panel to allow its editing. - LLPanelPlaces *panel = dynamic_cast<LLPanelPlaces*>(LLSideTray::getInstance()->showPanel("panel_places", LLSD())); - if (panel) + if ("inventory_handler" == from_name) + { + //we have to filter inventory_handler messages to avoid notification displaying + LLSideTray::getInstance()->showPanel("panel_places", + LLSD().with("type", "landmark").with("id", item->getUUID())); + } + else if("group_offer" == from_name) + { + // do not open inventory when we open group notice attachment because + // we already opened landmark info panel + // "group_offer" is passed by LLOpenTaskGroupOffer + + continue; + } + else if(from_name.empty()) { - panel->setItem(item); + // we receive a message from LLOpenTaskOffer, it mean that new landmark has been added. + LLSD args; + args["LANDMARK_NAME"] = item->getName(); + args["FOLDER_NAME"] = std::string(parent_folder ? parent_folder->getName() : "unknown"); + LLNotificationsUtil::add("LandmarkCreated", args); + // Created landmark is passed to Places panel to allow its editing. In fact panel should be already displayed. + // If the panel is closed we don't reopen it until created landmark is loaded. + //TODO*:: dserduk(7/12/09) remove LLPanelPlaces dependency from here + LLPanelPlaces *places_panel = dynamic_cast<LLPanelPlaces*>(LLSideTray::getInstance()->getPanel("panel_places")); + if (places_panel) + { + // Landmark creation handling is moved to LLPanelPlaces::showAddedLandmarkInfo() + // TODO* LLPanelPlaces dependency is going to be removed. See EXT-4347. + //if("create_landmark" == places_panel->getPlaceInfoType() && !places_panel->getItem()) + //{ + // places_panel->setItem(item); + //} + //else + // we are opening a group notice attachment + if("create_landmark" != places_panel->getPlaceInfoType()) + { + LLSD args; + args["type"] = "landmark"; + args["id"] = item_id; + LLSideTray::getInstance()->showPanel("panel_places", args); + } + } } - } + } break; case LLAssetType::AT_TEXTURE: - LLFloaterReg::showInstance("preview_texture", LLSD(id), take_focus); - break; + { + LLFloaterReg::showInstance("preview_texture", LLSD(item_id), take_focus); + break; + } + case LLAssetType::AT_ANIMATION: + LLFloaterReg::showInstance("preview_anim", LLSD(item_id), take_focus); + break; + case LLAssetType::AT_SCRIPT: + LLFloaterReg::showInstance("preview_script", LLSD(item_id), take_focus); + break; + case LLAssetType::AT_SOUND: + LLFloaterReg::showInstance("preview_sound", LLSD(item_id), take_focus); + break; default: break; } } - //highlight item, if it's not in the trash or lost+found - // Don't auto-open the inventory floater - LLFloaterInventory* view = NULL; - if(gSavedSettings.getBOOL("ShowInInventory") && - asset_type != LLAssetType::AT_CALLINGCARD && - item->getInventoryType() != LLInventoryType::IT_ATTACHMENT && - !from_name.empty()) - { - view = LLFloaterInventory::showAgentInventory(); - } - else - { - view = LLFloaterInventory::getActiveInventory(); - } - if(!view) - { - return; - } - - //Trash Check - LLUUID trash_id; - trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH); - if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id)) - { - return; - } - LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND); - //BOOL inventory_has_focus = gFocusMgr.childHasKeyboardFocus(view); - BOOL user_is_away = gAwayTimer.getStarted(); - - // don't select lost and found items if the user is active - if (gInventory.isObjectDescendentOf(item->getUUID(), lost_and_found_id) - && !user_is_away) - { - return; + //////////////////////////////////////////////////////////////////////////////// + // Highlight item if it's not in the trash, lost+found, or COF + const BOOL auto_open = gSavedSettings.getBOOL("ShowInInventory") && + (asset_type != LLAssetType::AT_CALLINGCARD) && + (item->getInventoryType() != LLInventoryType::IT_ATTACHMENT) && + !from_name.empty(); + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open); + if(active_panel) + { + LL_DEBUGS("Messaging") << "Highlighting" << item_id << LL_ENDL; + LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); + active_panel->setSelection(item_id, TAKE_FOCUS_NO); + gFocusMgr.setKeyboardFocus(focus_ctrl); } + } +} - //Not sure about this check. Could make it easy to miss incoming items. - //don't dick with highlight while the user is working - //if(inventory_has_focus && !user_is_away) - // break; - LL_DEBUGS("Messaging") << "Highlighting" << item->getUUID() << LL_ENDL; - //highlight item +bool highlight_offered_item(const LLUUID& item_id) +{ + LLInventoryItem* item = gInventory.getItem(item_id); + if(!item) + { + LL_WARNS("Messaging") << "Unable to show inventory item: " << item_id << LL_ENDL; + return false; + } - if (view->getPanel()) + //////////////////////////////////////////////////////////////////////////////// + // Don't highlight if it's in certain "quiet" folders which don't need UI + // notification (e.g. trash, cof, lost-and-found). + if(!gAgent.getAFK()) + { + const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(item_id); + if (parent) { - LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); - view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO); - gFocusMgr.setKeyboardFocus(focus_ctrl); + const LLFolderType::EType parent_type = parent->getPreferredType(); + if (LLViewerFolderType::lookupIsQuietType(parent_type)) + { + return false; + } } } + + return true; } void inventory_offer_mute_callback(const LLUUID& blocked_id, const std::string& first_name, const std::string& last_name, - BOOL is_group) + BOOL is_group, LLOfferInfo* offer = NULL) { std::string from_name; LLMute::EType type; - if (is_group) { type = LLMute::GROUP; from_name = first_name; } + else if(offer && offer->mFromObject) + { + //we have to block object by name because blocked_id is an id of owner + type = LLMute::BY_NAME; + from_name = offer->mFromName; + } else { type = LLMute::AGENT; from_name = first_name + " " + last_name; } - LLMute mute(blocked_id, from_name, type); + // id should be null for BY_NAME mute, see LLMuteList::add for details + LLMute mute(type == LLMute::BY_NAME ? LLUUID::null : blocked_id, from_name, type); if (LLMuteList::getInstance()->add(mute)) { LLPanelBlockedList::showPanelAndSelect(blocked_id); } // purge the message queue of any previously queued inventory offers from the same source. - class OfferMatcher : public LLNotifyBoxView::Matcher + class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher { public: OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - BOOL matches(const LLNotificationPtr notification) const + bool matches(const LLNotificationPtr notification) const { if(notification->getName() == "ObjectGiveItem" || notification->getName() == "ObjectGiveItemUnknownUser" @@ -1023,7 +1066,9 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, private: const LLUUID& blocked_id; }; - gNotifyBoxView->purgeMessagesMatching(OfferMatcher(blocked_id)); + + LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID( + gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id)); } LLOfferInfo::LLOfferInfo(const LLSD& sd) @@ -1041,6 +1086,21 @@ LLOfferInfo::LLOfferInfo(const LLSD& sd) mHost = LLHost(sd["sender"].asString()); } +LLOfferInfo::LLOfferInfo(const LLOfferInfo& info) +{ + mIM = info.mIM; + mFromID = info.mFromID; + mFromGroup = info.mFromGroup; + mFromObject = info.mFromObject; + mTransactionID = info.mTransactionID; + mFolderID = info.mFolderID; + mObjectID = info.mObjectID; + mType = info.mType; + mFromName = info.mFromName; + mDesc = info.mDesc; + mHost = info.mHost; +} + LLSD LLOfferInfo::asLLSD() { LLSD sd; @@ -1058,12 +1118,197 @@ 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); + S32 button = LLNotificationsUtil::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, + // * adding the mute sends a message, + // * we can't build two messages at once. + if (2 == button) // Block + { + gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,_4,this)); + } + + 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_GROUP_NOTICE: + opener = new LLOpenTaskGroupOffer; + send_auto_receive_response(); + break; + case IM_TASK_INVENTORY_OFFERED: + 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; + } + break; + // end switch (mIM) + + 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("."); + LLSD args; + args["MESSAGE"] = log_message; + LLNotificationsUtil::add("SystemMessage", args); + } + 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; + } + + // *NOTE dzaporozhan + // Disabled logging to old chat floater to fix crash in group notices - EXT-4149 + // LLFloaterChat::addChatHistory(chat); + + uuid_vec_t folders; + uuid_vec_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, @@ -1071,9 +1316,9 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // * we can't build two messages at once. if (2 == button) { - gCacheName->get(mFromID, mFromGroup, &inventory_offer_mute_callback); + gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,_4,this)); } - + LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ImprovedInstantMessage); msg->nextBlockFast(_PREHASH_AgentData); @@ -1093,14 +1338,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); LLInventoryObserver* opener = NULL; - LLViewerInventoryCategory* catp = NULL; - catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID); - LLViewerInventoryItem* itemp = NULL; - if(!catp) - { - 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) @@ -1111,16 +1349,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"); } } @@ -1130,13 +1368,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"); } } @@ -1150,126 +1388,78 @@ 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("."); + LLSD args; + args["MESSAGE"] = log_message; + LLNotificationsUtil::add("SystemMessage", args); } - 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())) - { - discard_agent_offer->done(); - } - else + // 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 +"."; + LLSD args; + args["MESSAGE"] = log_message; + LLNotificationsUtil::add("SystemMessage", args); + + 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); @@ -1279,8 +1469,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& 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 @@ -1312,11 +1501,16 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) // Strip any SLURL from the message display. (DEV-2754) std::string msg = info->mDesc; int indx = msg.find(" ( http://slurl.com/secondlife/"); + if(indx == std::string::npos) + { + // try to find new slurl host + indx = msg.find(" ( http://maps.secondlife.com/secondlife/"); + } if(indx >= 0) { LLStringUtil::truncate(msg, indx); } - + LLSD args; args["[OBJECTNAME]"] = msg; @@ -1326,7 +1520,9 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType)); if (!typestr.empty()) { - args["OBJECTTYPE"] = typestr; + // human readable matches string name from strings.xml + // lets get asset type localized name + args["OBJECTTYPE"] = LLTrans::getString(typestr); } else { @@ -1363,23 +1559,70 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) } } + // If mObjectID is null then generate the object_id based on msg to prevent + // multiple creation of chiclets for same object. + LLUUID object_id = info->mObjectID; + if (object_id.isNull()) + object_id.generate(msg); + payload["from_id"] = info->mFromID; + // Needed by LLScriptFloaterManager to bind original notification with + // faked for toast one. + payload["object_id"] = object_id; + // Flag indicating that this notification is faked for toast. + payload["give_inventory_notification"] = FALSE; args["OBJECTFROMNAME"] = info->mFromName; args["NAME"] = info->mFromName; + args["NAME_SLURL"] = LLSLURL::buildCommand("agent", info->mFromID, "about"); + std::string verb = "select?name=" + LLURI::escape(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"; + // Pop up inv offer chiclet and let the user accept (keep), or reject (and silently delete) the inventory. + LLNotifications::instance().add(p); } - else + else // Agent -> Agent Inventory Offer { + p.responder = info; + // Note: sets inventory_offer_callback as the callback + // *TODO fix memory leak + // inventory_offer_callback() is not invoked if user received notification and + // closes viewer(without responding the notification) + 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(); - LLNotifications::instance().add(p); + // Inform user that there is a script floater via toast system + { + payload["give_inventory_notification"] = TRUE; + LLNotificationPtr notification = LLNotifications::instance().add(p.payload(payload)); + } + } } bool lure_callback(const LLSD& notification, const LLSD& response) @@ -1391,7 +1634,7 @@ bool lure_callback(const LLSD& notification, const LLSD& response) } else { - option = LLNotification::getSelectedOption(notification, response); + option = LLNotificationsUtil::getSelectedOption(notification, response); } LLUUID from_id = notification["payload"]["from_id"].asUUID(); @@ -1422,7 +1665,7 @@ static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lu bool goto_url_callback(const LLSD& notification, const LLSD& response) { std::string url = notification["payload"]["url"].asString(); - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if(1 == option) { LLWeb::loadURL(url); @@ -1431,6 +1674,29 @@ bool goto_url_callback(const LLSD& notification, const LLSD& response) } static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback); +bool inspect_remote_object_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LLFloaterReg::showInstance("inspect_remote_object", notification["payload"]); + } + return false; +} +static LLNotificationFunctorRegistration inspect_remote_object_callback_reg("ServerObjectMessage", inspect_remote_object_callback); + +class LLPostponedServerObjectNotification: public LLPostponedNotification +{ +protected: + /* virtual */ + void modifyNotificationParams() + { + LLSD payload = mParams.payload; + payload["SESSION_NAME"] = mName; + mParams.payload = payload; + } +}; + void process_improved_im(LLMessageSystem *msg, void **user_data) { if (gNoRender) @@ -1498,28 +1764,17 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } std::string separator_string(": "); - int message_offset = 0; - - //Handle IRC styled /me messages. - std::string prefix = message.substr(0, 4); - if (prefix == "/me " || prefix == "/me'") - { - separator_string = ""; - message_offset = 3; - } LLSD args; + LLSD payload; switch(dialog) { case IM_CONSOLE_AND_CHAT_HISTORY: - // These are used for system messages, hence don't need the name, - // as it is always "Second Life". // *TODO: Translate args["MESSAGE"] = message; - - // Note: don't put the message in the IM history, even though was sent - // via the IM mechanism. - LLNotifications::instance().add("SystemMessageTip",args); + payload["SESSION_NAME"] = name; + payload["from_id"] = from_id; + LLNotificationsUtil::add("IMSystemMessageTip",args, payload); break; case IM_NOTHING_SPECIAL: @@ -1558,7 +1813,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // now store incoming IM in chat history - buffer = message.substr(message_offset); + buffer = message; LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; @@ -1574,31 +1829,30 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) region_id, position, true); - - // pretend this is chat generated by self, so it does not show up on screen - chat.mText = std::string("IM: ") + name + separator_string + message.substr(message_offset); - LLFloaterChat::addChat( chat, TRUE, TRUE ); } else if (from_id.isNull()) { - // Messages from "Second Life" ID don't go to IM history - // messages which should be routed to IM window come from a user ID with name=SYSTEM_NAME - chat.mText = name + ": " + message; - LLFloaterChat::addChat(chat, FALSE, FALSE); + LLSD args; + args["MESSAGE"] = message; + LLNotificationsUtil::add("SystemMessage", args); } else if (to_id.isNull()) { // Message to everyone from GOD args["NAME"] = name; args["MESSAGE"] = message; - LLNotifications::instance().add("GodMessage", args); + LLNotificationsUtil::add("GodMessage", args); // Treat like a system message and put in chat history. // Claim to be from a local agent so it doesn't go into // console. - chat.mText = name + separator_string + message.substr(message_offset); - BOOL local_agent = TRUE; - LLFloaterChat::addChat(chat, FALSE, local_agent); + chat.mText = name + separator_string + message; + + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); + if(nearby_chat) + { + nearby_chat->addMessage(chat); + } } else { @@ -1608,7 +1862,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); } - buffer = saved + message.substr(message_offset); + buffer = saved + message; LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; @@ -1630,19 +1884,22 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) region_id, position, true); - chat.mText = std::string("IM: ") + name + separator_string + saved + message.substr(message_offset); - - BOOL local_agent = FALSE; - LLFloaterChat::addChat( chat, TRUE, local_agent ); } else { + /* + EXT-5099 + currently there is no way to store in history only... + using LLNotificationsUtil::add will add message to Nearby Chat + // muted user, so don't start an IM session, just record line in chat // history. Pretend the chat is from a local agent, // so it will go into the history but not be shown on screen. - chat.mText = buffer; - BOOL local_agent = TRUE; - LLFloaterChat::addChat( chat, TRUE, local_agent ); + + LLSD args; + args["MESSAGE"] = buffer; + LLNotificationsUtil::add("SystemMessageTip", args); + */ } } break; @@ -1666,7 +1923,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // This is a block, modeless dialog. //*TODO: Translate args["MESSAGE"] = message; - LLNotifications::instance().add("SystemMessage", args); + LLNotificationsUtil::add("SystemMessageTip", args); } break; case IM_GROUP_NOTICE: @@ -1706,14 +1963,14 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) if (has_inventory) { - info = new LLOfferInfo; + info = new LLOfferInfo(); info->mIM = IM_GROUP_NOTICE; info->mFromID = from_id; info->mFromGroup = from_group; info->mTransactionID = session_id; info->mType = (LLAssetType::EType) asset_type; - info->mFolderID = gInventory.findCategoryUUIDForType(info->mType); + info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); std::string from_name; from_name += "A group member named "; @@ -1740,7 +1997,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // For requested notices, we don't want to send the popups. if (dialog != IM_GROUP_NOTICE_REQUESTED) { - LLSD payload; payload["subject"] = subj; payload["message"] = mes; payload["sender_name"] = name; @@ -1760,6 +2016,10 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLPanelGroup::showNotice(subj,mes,group_id,has_inventory,item_name,info); } + else + { + delete info; + } } break; case IM_GROUP_INVITATION: @@ -1799,7 +2059,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLSD args; args["MESSAGE"] = message; - LLNotifications::instance().add("JoinGroup", args, payload, join_group_response); + LLNotificationsUtil::add("JoinGroup", args, payload, join_group_response); } } break; @@ -1809,7 +2069,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // Someone has offered us some inventory. { LLOfferInfo* info = new LLOfferInfo; - bool mute_im = false; if (IM_INVENTORY_OFFERED == dialog) { struct offer_agent_bucket_t @@ -1821,22 +2080,19 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) if (sizeof(offer_agent_bucket_t) != binary_bucket_size) { LL_WARNS("Messaging") << "Malformed inventory offer from agent" << LL_ENDL; + delete info; break; } bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0]; info->mType = (LLAssetType::EType) bucketp->asset_type; info->mObjectID = bucketp->object_id; - - if(accept_im_from_only_friend&&!is_friend) - { - mute_im = true; - } } else { if (sizeof(S8) != binary_bucket_size) { LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; + delete info; break; } info->mType = (LLAssetType::EType) binary_bucket[0]; @@ -1847,7 +2103,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) info->mFromID = from_id; info->mFromGroup = from_group; info->mTransactionID = session_id; - info->mFolderID = gInventory.findCategoryUUIDForType(info->mType); + info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); if (dialog == IM_TASK_INVENTORY_OFFERED) { @@ -1861,14 +2117,21 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) info->mDesc = message; info->mHost = msg->getSender(); //if (((is_busy && !is_owned_by_me) || is_muted)) - if ( is_muted || mute_im) + if (is_muted) { + // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331) + LLInventoryFetchObserver::item_ref_t items; + items.push_back(info->mObjectID); + LLInventoryFetchObserver* fetch_item = new LLInventoryFetchObserver(); + fetch_item->fetchItems(items); + delete fetch_item; + // Same as closing window info->forceResponse(IOR_DECLINE); } else { - inventory_offer_handler(info, dialog == IM_TASK_INVENTORY_OFFERED); + inventory_offer_handler(info); } } break; @@ -1876,13 +2139,17 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) case IM_INVENTORY_ACCEPTED: { args["NAME"] = name; - LLNotifications::instance().add("InventoryAccepted", args); + LLSD payload; + payload["from_id"] = from_id; + LLNotificationsUtil::add("InventoryAccepted", args, payload); break; } case IM_INVENTORY_DECLINED: { args["NAME"] = name; - LLNotifications::instance().add("InventoryDeclined", args); + LLSD payload; + payload["from_id"] = from_id; + LLNotificationsUtil::add("InventoryDeclined", args, payload); break; } // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856 @@ -1918,7 +2185,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); } - buffer = saved + message.substr(message_offset); + buffer = saved + message; BOOL is_this_agent = FALSE; if(from_id == gAgentID) { @@ -1935,9 +2202,6 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) region_id, position, true); - - chat.mText = std::string("IM: ") + name + separator_string + saved + message.substr(message_offset); - LLFloaterChat::addChat(chat, TRUE, is_this_agent); } break; @@ -1948,9 +2212,82 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) return; } + // Build a link to open the object IM info window. + std::string location = ll_safe_string((char*)binary_bucket, binary_bucket_size-1); + + if (session_id.notNull()) + { + chat.mFromID = session_id; + } + else + { + // This message originated on a region without the updated code for task id and slurl information. + // We just need a unique ID for this object that isn't the owner ID. + // If it is the owner ID it will overwrite the style that contains the link to that owner's profile. + // This isn't ideal - it will make 1 style for all objects owned by the the same person/group. + // This works because the only thing we can really do in this case is show the owner name and link to their profile. + chat.mFromID = from_id ^ gAgent.getSessionID(); + } + + if(SYSTEM_FROM == name) + { + // System's UUID is NULL (fixes EXT-4766) + chat.mFromID = LLUUID::null; + } + + LLSD query_string; + query_string["owner"] = from_id; + query_string["slurl"] = location; + query_string["name"] = name; + if (from_group) + { + query_string["groupowned"] = "true"; + } + + std::ostringstream link; + link << "secondlife:///app/objectim/" << session_id << LLURI::mapToQueryString(query_string); + + chat.mURL = link.str(); + chat.mText = message; + chat.mSourceType = CHAT_SOURCE_OBJECT; + + // Note: lie to Nearby Chat, pretending that this is NOT an IM, because + // IMs from obejcts don't open IM sessions. + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); + if(nearby_chat) + { + LLSD args; + args["owner_id"] = from_id; + args["slurl"] = location; + args["type"] = LLNotificationsUI::NT_NEARBYCHAT; + LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); + } + + + //Object IMs send with from name: 'Second Life' need to be displayed also in notification toasts (EXT-1590) + if (SYSTEM_FROM != name) break; + LLSD substitutions; - substitutions["MSG"] = message.substr(message_offset); - LLNotifications::instance().add("ServerObjectMessage", substitutions); + substitutions["NAME"] = name; + substitutions["MSG"] = message; + + LLSD payload; + payload["object_id"] = session_id; + payload["owner_id"] = from_id; + payload["from_id"] = from_id; + payload["slurl"] = location; + payload["name"] = name; + std::string session_name; + if (from_group) + { + payload["group_owned"] = "true"; + } + + LLNotification::Params params("ServerObjectMessage"); + params.substitutions = substitutions; + params.payload = payload; + + LLPostponedNotification::add<LLPostponedServerObjectNotification>(params, from_id, false); } break; case IM_FROM_TASK_AS_ALERT: @@ -1962,7 +2299,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // Construct a viewer alert for this message. args["NAME"] = name; args["MESSAGE"] = message; - LLNotifications::instance().add("ObjectMessage", args); + LLNotificationsUtil::add("ObjectMessage", args); } break; case IM_BUSY_AUTO_RESPONSE: @@ -1974,7 +2311,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) else { // TODO: after LLTrans hits release, get "busy response" into translatable file - buffer = llformat("%s (%s): %s", name.c_str(), "busy response", message.substr(message_offset).c_str()); + buffer = llformat("%s (%s): %s", name.c_str(), "busy response", message.c_str()); gIMMgr->addMessage(session_id, from_id, name, buffer); } break; @@ -1993,13 +2330,13 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { LLSD args; // *TODO: Translate -> [FIRST] [LAST] (maybe) - args["NAME"] = name; + args["NAME_SLURL"] = LLSLURL::buildCommand("agent", from_id, "about"); args["MESSAGE"] = message; LLSD payload; payload["from_id"] = from_id; payload["lure_id"] = session_id; payload["godlike"] = FALSE; - LLNotifications::instance().add("TeleportOffered", args, payload); + LLNotificationsUtil::add("TeleportOffered", args, payload); } } break; @@ -2036,7 +2373,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) args["URL"] = url; LLSD payload; payload["url"] = url; - LLNotifications::instance().add("GotoURL", args, payload ); + LLNotificationsUtil::add("GotoURL", args, payload ); } break; @@ -2059,16 +2396,16 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } else { - args["[NAME]"] = name; + args["NAME_SLURL"] = LLSLURL::buildCommand("agent", from_id, "about"); if(message.empty()) { //support for frienship offers from clients before July 2008 - LLNotifications::instance().add("OfferFriendshipNoMessage", args, payload); + LLNotificationsUtil::add("OfferFriendshipNoMessage", args, payload); } else { args["[MESSAGE]"] = message; - LLNotifications::instance().add("OfferFriendship", args, payload); + LLNotificationsUtil::add("OfferFriendship", args, payload); } } } @@ -2086,7 +2423,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) send_generic_message("requestonlinenotification", strings); args["NAME"] = name; - LLNotifications::instance().add("FriendshipAccepted", args); + LLSD payload; + payload["from_id"] = from_id; + LLNotificationsUtil::add("FriendshipAccepted", args, payload); } break; @@ -2127,7 +2466,7 @@ void busy_message (LLMessageSystem* msg, LLUUID from_id) bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLUUID fid; LLUUID from_id; LLMessageSystem* msg = gMessageSystem; @@ -2141,7 +2480,7 @@ bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_TransactionBlock); msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); - fid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); + fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); msg->nextBlockFast(_PREHASH_FolderData); msg->addUUIDFast(_PREHASH_FolderID, fid); msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); @@ -2206,7 +2545,7 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) } else { - LLNotifications::instance().add("OfferCallingCard", args, payload); + LLNotificationsUtil::add("OfferCallingCard", args, payload); } } else @@ -2217,18 +2556,18 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) void process_accept_callingcard(LLMessageSystem* msg, void**) { - LLNotifications::instance().add("CallingCardAccepted"); + LLNotificationsUtil::add("CallingCardAccepted"); } void process_decline_callingcard(LLMessageSystem* msg, void**) { - LLNotifications::instance().add("CallingCardDeclined"); + LLNotificationsUtil::add("CallingCardDeclined"); } void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) { - LLChat chat; + LLChat chat; std::string mesg; std::string from_name; U8 source_temp; @@ -2248,7 +2587,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // Object owner for objects msg->getUUID("ChatData", "OwnerID", owner_id); - + msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp); chat.mSourceType = (EChatSourceType)source_temp; @@ -2277,7 +2616,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) if (chatter) { 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) @@ -2319,14 +2658,9 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) std::string prefix = mesg.substr(0, 4); if (prefix == "/me " || prefix == "/me'") { - chat.mText = from_name; - chat.mText += mesg.substr(3); ircstyle = TRUE; } - else - { - chat.mText = mesg; - } + chat.mText = mesg; // Look for the start of typing so we can put "..." in the bubbles. if (CHAT_TYPE_START == chat.mChatType) @@ -2352,19 +2686,6 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) return; } - // We have a real utterance now, so can stop showing "..." and proceed. - if (chatter && chatter->isAvatar()) - { - LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); - ((LLVOAvatar*)chatter)->stopTyping(); - - if (!is_muted && !is_busy) - { - visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles"); - ((LLVOAvatar*)chatter)->addChat(chat); - } - } - // Look for IRC-style emotes if (ircstyle) { @@ -2378,7 +2699,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) switch(chat.mChatType) { case CHAT_TYPE_WHISPER: - verb = "(" + LLTrans::getString("whisper") + ")"; + verb = LLTrans::getString("whisper") + " "; break; case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_OWNER: @@ -2386,7 +2707,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) verb = ""; break; case CHAT_TYPE_SHOUT: - verb = "(" + LLTrans::getString("shout") + ")"; + verb = LLTrans::getString("shout") + " "; break; case CHAT_TYPE_START: case CHAT_TYPE_STOP: @@ -2404,6 +2725,23 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) chat.mText += mesg; } + // We have a real utterance now, so can stop showing "..." and proceed. + if (chatter && chatter->isAvatar()) + { + LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); + ((LLVOAvatar*)chatter)->stopTyping(); + + if (!is_muted && !is_busy) + { + visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles"); + std::string formated_msg = ""; + LLViewerChat::formatChatMsg(chat, formated_msg); + LLChat chat_bubble = chat; + chat_bubble.mText = formated_msg; + ((LLVOAvatar*)chatter)->addChat(chat_bubble); + } + } + if (chatter) { chat.mPosAgent = chatter->getPositionAgent(); @@ -2423,25 +2761,13 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) chat.mMuted = is_muted && !is_linden; - if (!visible_in_chat_bubble - && (is_linden || !is_busy || is_owned_by_me)) - { - // show on screen and add to history - LLNotificationsUI::LLNotificationManager::instance().onChat( - chat, LLNotificationsUI::NT_NEARBYCHAT); + // pass owner_id to chat so that we can display the remote + // object inspect for an object that is chatting with you + LLSD args; + args["type"] = LLNotificationsUI::NT_NEARBYCHAT; + args["owner_id"] = owner_id; - // adding temporarily so that communications window chat bar - // works until the new chat window is ready - chat.mText = from_name + ": " + chat.mText; - LLFloaterChat::addChat(chat, FALSE, FALSE); - } - else - { - LLNotificationsUI::LLNotificationManager::instance().onChat( - chat, LLNotificationsUI::NT_NEARBYCHAT); - // adding temporarily - LLFloaterChat::addChatHistory(chat); - } + LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); } } @@ -2531,8 +2857,8 @@ public: LLInventoryModel::cat_array_t land_cats; LLInventoryModel::item_array_t land_items; - folder_ref_t::iterator it = mCompleteFolders.begin(); - folder_ref_t::iterator end = mCompleteFolders.end(); + uuid_vec_t::iterator it = mCompleteFolders.begin(); + uuid_vec_t::iterator end = mCompleteFolders.end(); for(; it != end; ++it) { gInventory.collectDescendentsIf( @@ -2553,13 +2879,13 @@ public: { // Show notification that they can now teleport to landmarks. Use a random landmark from the inventory S32 random_land = ll_rand( land_items.count() - 1 ); args["NAME"] = land_items[random_land]->getName(); - LLNotifications::instance().add("TeleportToLandmark",args); + LLNotificationsUtil::add("TeleportToLandmark",args); } if ( card_items.count() > 0 ) { // Show notification that they can now contact people. Use a random calling card from the inventory S32 random_card = ll_rand( card_items.count() - 1 ); args["NAME"] = card_items[random_card]->getName(); - LLNotifications::instance().add("TeleportToPerson",args); + LLNotificationsUtil::add("TeleportToPerson",args); } gInventory.removeObserver(this); @@ -2593,12 +2919,11 @@ BOOL LLPostTeleportNotifiers::tick() if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) { // get callingcards and landmarks available to the user arriving. - LLInventoryFetchDescendentsObserver::folder_ref_t folders; - LLUUID folder_id; - folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); - if(folder_id.notNull()) - folders.push_back(folder_id); - folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK); + uuid_vec_t folders; + const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); + if(callingcard_id.notNull()) + folders.push_back(callingcard_id); + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); if(folder_id.notNull()) folders.push_back(folder_id); if(!folders.empty()) @@ -2634,6 +2959,9 @@ void process_teleport_finish(LLMessageSystem* msg, void**) LL_WARNS("Messaging") << "Got teleport notification for wrong agent!" << LL_ENDL; return; } + + // Teleport is finished; it can't be cancelled now. + gViewerWindow->setProgressCancelButtonVisible(FALSE); // Do teleport effect for where you're leaving // VEFFECT: TeleportStart @@ -2679,18 +3007,18 @@ void process_teleport_finish(LLMessageSystem* msg, void**) /* // send camera update to new region - gAgent.updateCamera(); + gAgentCamera.updateCamera(); // likewise make sure the camera is behind the avatar - gAgent.resetView(TRUE); + gAgentCamera.resetView(TRUE); LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal()); gAgent.setRegion(regionp); gObjectList.shiftObjects(shift_vector); - if (gAgent.getAvatarObject()) + if (isAgentAvatarValid()) { - gAgent.getAvatarObject()->clearChatText(); - gAgent.slamLookAt(look_at); + gAgentAvatarp->clearChatText(); + gAgentCamera.slamLookAt(look_at); } gAgent.setPositionAgent(pos); gAssetStorage->setUpstream(sim); @@ -2769,8 +3097,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) std::string version_channel; msg->getString("SimData", "ChannelVersion", version_channel); - LLVOAvatar* avatarp = gAgent.getAvatarObject(); - if (!avatarp) + if (!isAgentAvatarValid()) { // Could happen if you were immediately god-teleported away on login, // maybe other cases. Continue, but warn. @@ -2791,7 +3118,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) << x << ":" << y << " current pos " << gAgent.getPositionGlobal() << LL_ENDL; - LLAppViewer::instance()->forceDisconnect("You were sent to an invalid region."); + LLAppViewer::instance()->forceDisconnect(LLTrans::getString("SentToInvalidRegion")); return; } @@ -2814,9 +3141,9 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) if( is_teleport ) { // Force the camera back onto the agent, don't animate. - gAgent.setFocusOnAvatar(TRUE, FALSE); - gAgent.slamLookAt(look_at); - gAgent.updateCamera(); + gAgentCamera.setFocusOnAvatar(TRUE, FALSE); + gAgentCamera.slamLookAt(look_at); + gAgentCamera.updateCamera(); gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); @@ -2824,17 +3151,22 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) // know what you look like. gAgent.sendAgentSetAppearance(); - if (avatarp) + if (isAgentAvatarValid()) { // Chat the "back" SLURL. (DEV-4907) - LLChat chat("Teleport completed from " + gAgent.getTeleportSourceSLURL()); - chat.mSourceType = CHAT_SOURCE_SYSTEM; - LLFloaterChat::addChatHistory(chat); + + LLSD substitution = LLSD().with("[T_SLURL]", gAgent.getTeleportSourceSLURL()); + std::string completed_from = LLAgent::sTeleportProgressMessages["completed_from"]; + LLStringUtil::format(completed_from, substitution); + + LLSD args; + args["MESSAGE"] = completed_from; + LLNotificationsUtil::add("SystemMessageTip", args); // Set the new position - avatarp->setPositionAgent(agent_pos); - avatarp->clearChat(); - avatarp->slamPosition(); + gAgentAvatarp->setPositionAgent(agent_pos); + gAgentAvatarp->clearChat(); + gAgentAvatarp->slamPosition(); } } else @@ -2860,7 +3192,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) global_agent_pos[1] += y; look_at = (LLVector3)beacon_pos - global_agent_pos; look_at.normVec(); - gAgent.slamLookAt(look_at); + gAgentCamera.slamLookAt(look_at); } } @@ -2894,9 +3226,9 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgent.clearBusy(); } - if (avatarp) + if (isAgentAvatarValid()) { - avatarp->mFootPlane.clearVec(); + gAgentAvatarp->mFootPlane.clearVec(); } // send walk-vs-run status @@ -2911,46 +3243,37 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) if (!gLastVersionChannel.empty()) { - LLSD payload; - payload["message"] = version_channel; - LLNotifications::instance().add("ServerVersionChanged", LLSD(), payload, server_version_changed_callback); - } - - gLastVersionChannel = version_channel; -} - -bool server_version_changed_callback(const LLSD& notification, const LLSD& response) -{ - if(notification["payload"]["message"].asString() =="") - return false; - std::string url ="http://wiki.secondlife.com/wiki/Release_Notes/"; - //parse the msg string - std::string server_version = notification["payload"]["message"].asString(); - std::vector<std::string> s_vect; - boost::algorithm::split(s_vect, server_version, isspace); - for(U32 i = 0; i < s_vect.size(); i++) - { - if (i != (s_vect.size() - 1)) + // work out the URL for this server's Release Notes + std::string url ="http://wiki.secondlife.com/wiki/Release_Notes/"; + std::string server_version = version_channel; + std::vector<std::string> s_vect; + boost::algorithm::split(s_vect, server_version, isspace); + for(U32 i = 0; i < s_vect.size(); i++) { - if(i != (s_vect.size() - 2)) + if (i != (s_vect.size() - 1)) { - url += s_vect[i] + "_"; + if(i != (s_vect.size() - 2)) + { + url += s_vect[i] + "_"; + } + else + { + url += s_vect[i] + "/"; + } } else { - url += s_vect[i] + "/"; + url += s_vect[i].substr(0,4); } } - else - { - url += s_vect[i].substr(0,4); - } + + LLSD args; + args["URL"] = url; + LLNotificationsUtil::add("ServerVersionChanged", args); } - - LLWeb::loadURL(url); - return false; -} + gLastVersionChannel = version_channel; +} void process_crossed_region(LLMessageSystem* msg, void**) { @@ -2992,6 +3315,7 @@ const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less th const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot // between these values we delay the updates (but no more than one second) +static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE_SEND("Send Message"); void send_agent_update(BOOL force_send, BOOL send_reliable) { @@ -3046,7 +3370,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion(); LLQuaternion head_rotation = gAgent.getHeadRotation(); - camera_pos_agent = gAgent.getCameraPositionAgent(); + camera_pos_agent = gAgentCamera.getCameraPositionAgent(); render_state = gAgent.getRenderState(); @@ -3150,6 +3474,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) if (duplicate_count < DUP_MSGS && !gDisconnected) { + LLFastTimer t(FTM_AGENT_UPDATE_SEND); // Build the message msg->newMessageFast(_PREHASH_AgentUpdate); msg->nextBlockFast(_PREHASH_AgentData); @@ -3169,7 +3494,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis()); msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); - msg->addF32Fast(_PREHASH_Far, gAgent.mDrawDistance); + msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); msg->addU32Fast(_PREHASH_ControlFlags, control_flags); @@ -3745,6 +4070,17 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; + // *HACK: Disabling flying mode if it has been enabled shortly before the agent + // stand up animation is signaled. In this case we don't get a signal to start + // flying animation from server, the AGENT_CONTROL_FLY flag remains set but the + // avatar does not play flying animation, so we switch flying mode off. + // See LLAgent::setFlying(). This may cause "Stop Flying" button to blink. + // See EXT-2781. + if (animation_id == ANIM_AGENT_STANDUP && gAgent.getFlying()) + { + gAgent.setFlying(FALSE); + } + if (i < num_source_blocks) { mesgsys->getUUIDFast(_PREHASH_AnimationSourceList, _PREHASH_ObjectID, object_id, i); @@ -3795,7 +4131,7 @@ void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); LLVOAvatar* avatarp = (LLVOAvatar *)gObjectList.findObject(uuid); - if( avatarp ) + if (avatarp) { avatarp->processAvatarAppearance( mesgsys ); } @@ -3810,7 +4146,7 @@ void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data) LLVector4 cameraCollidePlane; mesgsys->getVector4Fast(_PREHASH_CameraCollidePlane, _PREHASH_Plane, cameraCollidePlane); - gAgent.setCameraCollidePlane(cameraCollidePlane); + gAgentCamera.setCameraCollidePlane(cameraCollidePlane); } void near_sit_object(BOOL success, void *data) @@ -3843,20 +4179,18 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) BOOL force_mouselook; mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_ForceMouselook, force_mouselook); - LLVOAvatar* avatar = gAgent.getAvatarObject(); - - if (avatar && dist_vec_squared(camera_eye, camera_at) > 0.0001f) + if (isAgentAvatarValid() && dist_vec_squared(camera_eye, camera_at) > 0.0001f) { - gAgent.setSitCamera(sitObjectID, camera_eye, camera_at); + gAgentCamera.setSitCamera(sitObjectID, camera_eye, camera_at); } - gAgent.setForceMouselook(force_mouselook); + gAgentCamera.setForceMouselook(force_mouselook); LLViewerObject* object = gObjectList.findObject(sitObjectID); if (object) { LLVector3 sit_spot = object->getPositionAgent() + (sitPosition * object->getRotation()); - if (!use_autopilot || (avatar && avatar->isSitting() && avatar->getRoot() == object->getRoot())) + if (!use_autopilot || isAgentAvatarValid() && gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == object->getRoot()) { //we're already sitting on this object, so don't autopilot } @@ -4133,10 +4467,10 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) if (gStatusBar) { - S32 old_balance = gStatusBar->getBalance(); + // S32 old_balance = gStatusBar->getBalance(); // This is an update, not the first transmission of balance - if (old_balance != 0) + /* if (old_balance != 0) { // this is actually an update if (balance > old_balance) @@ -4148,7 +4482,7 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) LLFirstUse::useBalanceDecrease(balance - old_balance); } } - + */ gStatusBar->setBalance(balance); gStatusBar->setLandCredit(credit); gStatusBar->setLandCommitted(committed); @@ -4164,8 +4498,104 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) // have missed something during an event. // *TODO: Translate LLSD args; + + + // this is a marker to retrieve avatar name from server message: + // "<avatar name> paid you L$" + const std::string marker = "paid you L$"; + args["MESSAGE"] = desc; - LLNotifications::instance().add("SystemMessage", args); + + // extract avatar name from system message + S32 marker_pos = desc.find(marker, 0); + + std::string base_name = desc.substr(0, marker_pos); + + std::string name = base_name; + LLStringUtil::trim(name); + + // if name extracted and name cache contains avatar id send loggable notification + LLUUID from_id; + if(name.size() > 0 && gCacheName->getUUID(name, from_id)) + { + //description always comes not localized. lets fix this + + //ammount paid + std::string ammount = desc.substr(marker_pos + marker.length(),desc.length() - marker.length() - marker_pos); + + //reform description + LLStringUtil::format_map_t str_args; + str_args["NAME"] = base_name; + str_args["AMOUNT"] = ammount; + std::string new_description = LLTrans::getString("paid_you_ldollars", str_args); + + + args["MESSAGE"] = new_description; + args["NAME"] = name; + LLSD payload; + payload["from_id"] = from_id; + LLNotificationsUtil::add("PaymentRecived", args, payload); + } + //AD *HACK: Parsing incoming string to localize messages that come from server! EXT-5986 + // It's only a temporarily and ineffective measure. It doesn't affect performance much + // because we get here only for specific type of messages, but anyway it is not right to do it! + // *TODO: Server-side changes should be made and this code removed. + else + { + if(desc.find("You paid")==0) + { + // Regular expression for message parsing- change it in case of server-side changes. + // Each set of parenthesis will later be used to find arguments of message we generate + // in the end of this if- (.*) gives us name of money receiver, (\\d+)-amount of money we pay + // and ([^$]*)- reason of payment + boost::regex expr("You paid (?:.{0}|(.*) )L\\$(\\d+)\\s?([^$]*)\\."); + boost::match_results <std::string::const_iterator> matches; + if(boost::regex_match(desc, matches, expr)) + { + // Name of full localizable notification string + // there are three types of this string- with name of receiver and reason of payment, + // without name and without reason (but not simultaneously) + // example of string without name - You paid L$100 to create a group. + // example of string without reason - You paid Smdby Linden L$100. + // example of string with reason and name - You paid Smbdy Linden L$100 for a land access pass. + std::string line = "you_paid_ldollars_no_name"; + + // arguments of string which will be in notification + LLStringUtil::format_map_t str_args; + + // extracting amount of money paid (without L$ symbols). It is always present. + str_args["[AMOUNT]"] = std::string(matches[2]); + + // extracting name of person/group you are paying (it may be absent) + std::string name = std::string(matches[1]); + if(!name.empty()) + { + str_args["[NAME]"] = name; + line = "you_paid_ldollars"; + } + + // extracting reason of payment (it may be absent) + std::string reason = std::string(matches[3]); + if (reason.empty()) + { + line = "you_paid_ldollars_no_reason"; + } + else + { + std::string localized_reason; + // if we haven't found localized string for reason of payment leave it as it was + str_args["[REASON]"] = LLTrans::findString(localized_reason, reason) ? localized_reason : reason; + } + + // forming final message string by retrieving localized version from xml + // and applying previously found arguments + line = LLTrans::getString(line, str_args); + args["MESSAGE"] = line; + } + } + + LLNotificationsUtil::add("SystemMessage", args); + } // Once the 'recent' container gets large enough, chop some // off the beginning. @@ -4183,7 +4613,7 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) bool handle_special_notification_callback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (0 == option) { @@ -4204,18 +4634,18 @@ bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) llsdBlock["REGIONMATURITY"] = LLViewerRegion::accessToString(regionAccess); // we're going to throw the LLSD in there in case anyone ever wants to use it - LLNotifications::instance().add(notificationID+"_Notify", llsdBlock); + LLNotificationsUtil::add(notificationID+"_Notify", llsdBlock); if (regionAccess == SIM_ACCESS_MATURE) { if (gAgent.isTeen()) { - LLNotifications::instance().add(notificationID+"_KB", llsdBlock); + LLNotificationsUtil::add(notificationID+"_KB", llsdBlock); return true; } else if (gAgent.prefersPG()) { - LLNotifications::instance().add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); + LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); return true; } } @@ -4223,12 +4653,12 @@ bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) { if (!gAgent.isAdult()) { - LLNotifications::instance().add(notificationID+"_KB", llsdBlock); + LLNotificationsUtil::add(notificationID+"_KB", llsdBlock); return true; } else if (gAgent.prefersPG() || gAgent.prefersMature()) { - LLNotifications::instance().add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); + LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); return true; } } @@ -4288,7 +4718,7 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) } } - LLNotifications::instance().add(notificationID, llsdBlock); + LLNotificationsUtil::add(notificationID, llsdBlock); return true; } return false; @@ -4344,7 +4774,7 @@ void process_alert_core(const std::string& message, BOOL modal) std::string snap_filename = gDirUtilp->getLindenUserDir(); snap_filename += gDirUtilp->getDirDelimiter(); snap_filename += SCREEN_HOME_FILENAME; - gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight(), FALSE, FALSE); + gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE); } const std::string ALERT_PREFIX("ALERT: "); @@ -4354,14 +4784,14 @@ void process_alert_core(const std::string& message, BOOL modal) // Allow the server to spawn a named alert so that server alerts can be // translated out of English. std::string alert_name(message.substr(ALERT_PREFIX.length())); - LLNotifications::instance().add(alert_name); + LLNotificationsUtil::add(alert_name); } else if (message.find(NOTIFY_PREFIX) == 0) { // Allow the server to spawn a named notification so that server notifications can be // translated out of English. std::string notify_name(message.substr(NOTIFY_PREFIX.length())); - LLNotifications::instance().add(notify_name); + LLNotificationsUtil::add(notify_name); } else if (message[0] == '/') { @@ -4373,20 +4803,20 @@ void process_alert_core(const std::string& message, BOOL modal) S32 mins = 0; LLStringUtil::convertToS32(text.substr(18), mins); args["MINUTES"] = llformat("%d",mins); - LLNotifications::instance().add("RegionRestartMinutes", args); + LLNotificationsUtil::add("RegionRestartMinutes", args); } else if (text.substr(0,17) == "RESTART_X_SECONDS") { S32 secs = 0; LLStringUtil::convertToS32(text.substr(18), secs); args["SECONDS"] = llformat("%d",secs); - LLNotifications::instance().add("RegionRestartSeconds", args); + LLNotificationsUtil::add("RegionRestartSeconds", args); } else { std::string new_msg =LLNotifications::instance().getGlobalString(text); args["MESSAGE"] = new_msg; - LLNotifications::instance().add("SystemMessage", args); + LLNotificationsUtil::add("SystemMessage", args); } } else if (modal) @@ -4394,14 +4824,14 @@ void process_alert_core(const std::string& message, BOOL modal) LLSD args; std::string new_msg =LLNotifications::instance().getGlobalString(message); args["ERROR_MESSAGE"] = new_msg; - LLNotifications::instance().add("ErrorMessage", args); + LLNotificationsUtil::add("ErrorMessage", args); } else { LLSD args; std::string new_msg =LLNotifications::instance().getGlobalString(message); args["MESSAGE"] = new_msg; - LLNotifications::instance().add("SystemMessageTip", args); + LLNotificationsUtil::add("SystemMessageTip", args); } } @@ -4530,7 +4960,6 @@ void process_economy_data(LLMessageSystem *msg, void** /*user_data*/) gMenuHolder->childSetLabelArg("Upload Image", "[COST]", llformat("%d", upload_cost)); gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", llformat("%d", upload_cost)); - gMenuHolder->childSetLabelArg("Upload Model", "[COST]", llformat("%d", upload_cost)); gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", llformat("%d", upload_cost)); gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", llformat("%d", upload_cost)); } @@ -4611,14 +5040,14 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp if (caution) { LLChat chat(notice.getString()); - LLFloaterChat::addChat(chat, FALSE, FALSE); + // LLFloaterChat::addChat(chat, FALSE, FALSE); } } } bool script_question_cb(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLMessageSystem *msg = gMessageSystem; S32 orig = notification["payload"]["questions"].asInteger(); S32 new_questions = orig; @@ -4659,33 +5088,34 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) LLMuteList::getInstance()->add(LLMute(item_id, notification["payload"]["object_name"].asString(), LLMute::OBJECT)); // purge the message queue of any previously queued requests from the same source. DEV-4879 - class OfferMatcher : public LLNotifyBoxView::Matcher + class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher { public: OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - BOOL matches(const LLNotificationPtr notification) const + bool matches(const LLNotificationPtr notification) const { if (notification->getName() == "ScriptQuestionCaution" || notification->getName() == "ScriptQuestion") { return (notification->getPayload()["item_id"].asUUID() == blocked_id); } - return FALSE; + return false; } private: const LLUUID& blocked_id; }; - // should do this via the channel - gNotifyBoxView->purgeMessagesMatching(OfferMatcher(item_id)); + + LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID( + gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(item_id)); } if (response["Details"]) { // respawn notification... - LLNotifications::instance().add(notification["name"], notification["substitutions"], notification["payload"]); + LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); // ...with description on top - LLNotifications::instance().add("DebitPermissionDetails"); + LLNotificationsUtil::add("DebitPermissionDetails"); } return false; } @@ -4782,12 +5212,12 @@ void process_script_question(LLMessageSystem *msg, void **user_data) if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) { // display the caution permissions prompt - LLNotifications::instance().add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload); + LLNotificationsUtil::add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload); } else { // fall back to default behavior if cautions are entirely disabled - LLNotifications::instance().add("ScriptQuestion", args, payload); + LLNotificationsUtil::add("ScriptQuestion", args, payload); } } @@ -4805,27 +5235,26 @@ void container_inventory_arrived(LLViewerObject* object, void* data) { LL_DEBUGS("Messaging") << "container_inventory_arrived()" << LL_ENDL; - if( gAgent.cameraMouselook() ) + if( gAgentCamera.cameraMouselook() ) { - gAgent.changeCameraToDefault(); + gAgentCamera.changeCameraToDefault(); } - LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); + LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); if (inventory->size() > 2) { // create a new inventory category to put this in LLUUID cat_id; cat_id = gInventory.createNewCategory(gInventory.getRootFolderID(), - LLAssetType::AT_NONE, + LLFolderType::FT_NONE, LLTrans::getString("AcquiredItems")); InventoryObjectList::const_iterator it = inventory->begin(); InventoryObjectList::const_iterator end = inventory->end(); for ( ; it != end; ++it) { - if ((*it)->getType() != LLAssetType::AT_CATEGORY && - (*it)->getType() != LLAssetType::AT_ROOT_CATEGORY) + if ((*it)->getType() != LLAssetType::AT_CATEGORY) { LLInventoryObject* obj = (LLInventoryObject*)(*it); LLInventoryItem* item = (LLInventoryItem*)(obj); @@ -4849,9 +5278,9 @@ void container_inventory_arrived(LLViewerObject* object, } } gInventory.notifyObservers(); - if(view) + if(active_panel) { - view->getPanel()->setSelection(cat_id, TAKE_FOCUS_NO); + active_panel->setSelection(cat_id, TAKE_FOCUS_NO); } } else if (inventory->size() == 2) @@ -4860,14 +5289,13 @@ void container_inventory_arrived(LLViewerObject* object, // one actual object InventoryObjectList::iterator it = inventory->begin(); - if ((*it)->getType() == LLAssetType::AT_CATEGORY || - (*it)->getType() == LLAssetType::AT_ROOT_CATEGORY) + if ((*it)->getType() == LLAssetType::AT_CATEGORY) { ++it; } LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); - LLUUID category = gInventory.findCategoryUUIDForType(item->getType()); + const LLUUID category = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType())); LLUUID item_id; item_id.generate(); @@ -4886,9 +5314,9 @@ void container_inventory_arrived(LLViewerObject* object, new_item->updateServer(TRUE); gInventory.updateItem(new_item); gInventory.notifyObservers(); - if(view) + if(active_panel) { - view->getPanel()->setSelection(item_id, TAKE_FOCUS_NO); + active_panel->setSelection(item_id, TAKE_FOCUS_NO); } } @@ -4989,7 +5417,7 @@ void process_teleport_failed(LLMessageSystem *msg, void**) } } - LLNotifications::instance().add("CouldNotTeleportReason", args); + LLNotificationsUtil::add("CouldNotTeleportReason", args); // Let the interested parties know that teleport failed. LLViewerParcelMgr::getInstance()->onTeleportFailed(); @@ -5034,13 +5462,13 @@ void process_teleport_local(LLMessageSystem *msg,void**) } gAgent.setPositionAgent(pos); - gAgent.slamLookAt(look_at); + gAgentCamera.slamLookAt(look_at); // likewise make sure the camera is behind the avatar - gAgent.resetView(TRUE, TRUE); + gAgentCamera.resetView(TRUE, TRUE); // send camera update to new region - gAgent.updateCamera(); + gAgentCamera.updateCamera(); send_agent_update(TRUE, TRUE); @@ -5122,7 +5550,8 @@ void send_group_notice(const LLUUID& group_id, bool handle_lure_callback(const LLSD& notification, const LLSD& response) { std::string text = response["message"].asString(); - S32 option = LLNotification::getSelectedOption(notification, response); + text.append("\r\n").append(LLAgentUI::buildSLURL()); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if(0 == option) { @@ -5138,8 +5567,26 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response) it != notification["payload"]["ids"].endArray(); ++it) { + LLUUID target_id = it->asUUID(); + msg->nextBlockFast(_PREHASH_TargetData); - msg->addUUIDFast(_PREHASH_TargetID, it->asUUID()); + msg->addUUIDFast(_PREHASH_TargetID, target_id); + + // Record the offer. + { + std::string target_name; + gCacheName->getFullName(target_id, target_name); + LLSD args; + args["TO_NAME"] = target_name; + + LLSD payload; + + //*TODO please rewrite all keys to the same case, lower or upper + payload["from_id"] = target_id; + payload["SESSION_NAME"] = target_name; + payload["SUPPRESS_TOAST"] = true; + LLNotificationsUtil::add("TeleportOfferSent", args, payload); + } } gAgent.sendReliableMessage(); } @@ -5155,8 +5602,12 @@ void handle_lure(const LLUUID& invitee) } // Prompt for a message to the invited user. -void handle_lure(const std::vector<LLUUID>& ids) +void handle_lure(const uuid_vec_t& ids) { + if (ids.empty()) return; + + if (!gAgent.getRegion()) return; + LLSD edit_args; edit_args["REGION"] = gAgent.getRegion()->getName(); @@ -5169,11 +5620,11 @@ void handle_lure(const std::vector<LLUUID>& ids) } if (gAgent.isGodlike()) { - LLNotifications::instance().add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); + LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); } else { - LLNotifications::instance().add("OfferTeleport", edit_args, payload, handle_lure_callback); + LLNotificationsUtil::add("OfferTeleport", edit_args, payload, handle_lure_callback); } } @@ -5366,7 +5817,7 @@ std::vector<LLSD> gLoadUrlList; bool callback_load_url(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (0 == option) { @@ -5411,7 +5862,7 @@ void callback_load_url_name(const LLUUID& id, const std::string& first, const st args["OBJECTNAME"] = load_url_info["object_name"].asString(); args["NAME"] = owner_name; - LLNotifications::instance().add("LoadWebPage", args, load_url_info); + LLNotificationsUtil::add("LoadWebPage", args, load_url_info); } else { @@ -5466,7 +5917,7 @@ void callback_download_complete(void** data, S32 result, LLExtStat ext_status) std::string* filepath = (std::string*)data; LLSD args; args["DOWNLOAD_PATH"] = *filepath; - LLNotifications::instance().add("FinishedRawDownload", args); + LLNotificationsUtil::add("FinishedRawDownload", args); delete filepath; } @@ -5547,7 +5998,7 @@ void process_covenant_reply(LLMessageSystem* msg, void**) LLPanelLandCovenant::updateEstateOwnerName(owner_name); LLFloaterBuyLand::updateEstateOwnerName(owner_name); - LLPanelPlaceInfo* panel = LLSideTray::getInstance()->findChild<LLPanelPlaceInfo>("panel_place_info"); + LLPanelPlaceProfile* panel = LLSideTray::getInstance()->findChild<LLPanelPlaceProfile>("panel_place_profile"); if (panel) { panel->updateEstateName(estate_name); @@ -5681,7 +6132,7 @@ void onCovenantLoadComplete(LLVFS *vfs, LLPanelLandCovenant::updateCovenantText(covenant_text); LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid); - LLPanelPlaceInfo* panel = dynamic_cast<LLPanelPlaceInfo*>(LLSideTray::getInstance()->showPanel("panel_place_info", LLSD())); + LLPanelPlaceProfile* panel = LLSideTray::getInstance()->findChild<LLPanelPlaceProfile>("panel_place_profile"); if (panel) { panel->updateCovenantText(covenant_text); |