diff options
Diffstat (limited to 'indra/newview/llviewermessage.cpp')
-rwxr-xr-x | indra/newview/llviewermessage.cpp | 973 |
1 files changed, 729 insertions, 244 deletions
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index dca5cdd06d..2340436a01 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -42,6 +42,7 @@ #include "llinventorydefines.h" #include "lllslconstants.h" #include "llregionhandle.h" +#include "llsd.h" #include "llsdserialize.h" #include "llteleportflags.h" #include "lltransactionflags.h" @@ -64,10 +65,11 @@ #include "llfloatersnapshot.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" +#include "llimview.h" #include "llinventoryfunctions.h" #include "llinventoryobserver.h" #include "llinventorypanel.h" -#include "llnearbychat.h" +#include "llfloaterimnearbychat.h" #include "llnotifications.h" #include "llnotificationsutil.h" #include "llpanelgrouplandmoney.h" @@ -107,6 +109,7 @@ #include "llagentui.h" #include "llpanelblockedlist.h" #include "llpanelplaceprofile.h" +#include "llviewerregion.h" #include <boost/algorithm/string/split.hpp> // #include <boost/regex.hpp> @@ -118,6 +121,8 @@ #pragma warning (disable:4702) #endif +extern void on_new_message(const LLSD& msg); + // // Constants // @@ -132,9 +137,11 @@ static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT = 5; // requests static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds extern BOOL gDebugClicks; +extern bool gShiftFrame; // function prototypes bool check_offer_throttle(const std::string& from_name, bool check_only); +bool check_asset_previewable(const LLAssetType::EType asset_type); static void process_money_balance_reply_extended(LLMessageSystem* msg); //inventory offer throttle globals @@ -155,7 +162,8 @@ const std::string SCRIPT_QUESTIONS[SCRIPT_PERMISSION_EOF] = "AddAndRemoveJoints", "ChangePermissions", "TrackYourCamera", - "ControlYourCamera" + "ControlYourCamera", + "TeleportYourAgent" }; const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = @@ -170,7 +178,8 @@ const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = FALSE, // AddAndRemoveJoints FALSE, // ChangePermissions FALSE, // TrackYourCamera, - FALSE // ControlYourCamera + FALSE, // ControlYourCamera + FALSE // TeleportYourAgent }; bool friendship_offer_callback(const LLSD& notification, const LLSD& response) @@ -178,78 +187,82 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLMessageSystem* msg = gMessageSystem; const LLSD& payload = notification["payload"]; - - // add friend to recent people list - LLRecentPeople::instance().add(payload["from_id"]); - - switch(option) - { - case 0: - { - // accept - LLAvatarTracker::formFriendship(payload["from_id"]); - - const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - - // This will also trigger an onlinenotification if the user is online - msg->newMessageFast(_PREHASH_AcceptFriendship); - 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->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 - { - 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; - } + LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); + + // this will be skipped if the user offering friendship is blocked + if (notification_ptr) + { + // add friend to recent people list + LLRecentPeople::instance().add(payload["from_id"]); + + switch(option) + { + case 0: + { + // accept + LLAvatarTracker::formFriendship(payload["from_id"]); + + const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); + + // This will also trigger an onlinenotification if the user is online + msg->newMessageFast(_PREHASH_AcceptFriendship); + 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->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, fid); + msg->sendReliable(LLHost(payload["sender"].asString())); + + LLSD payload = notification["payload"]; + LLNotificationsUtil::add("FriendshipAcceptedByMe", + notification["substitutions"], payload); + break; + } + case 1: // Decline + { + LLSD payload = notification["payload"]; + 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; + } + + LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); + modified_form->setElementEnabled("Accept", false); + modified_form->setElementEnabled("Decline", false); + notification_ptr->updateForm(modified_form); + notification_ptr->repost(); + } return false; } static LLNotificationFunctorRegistration friendship_offer_callback_reg("OfferFriendship", friendship_offer_callback); static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("OfferFriendshipNoMessage", friendship_offer_callback); -//const char BUSY_AUTO_RESPONSE[] = "The Resident you messaged is in 'busy mode' which means they have " -// "requested not to be disturbed. Your message will still be shown in their IM " -// "panel for later viewing."; - -// // Functions // @@ -720,7 +733,7 @@ static void highlight_inventory_objects_in_panel(const std::vector<LLUUID>& item LLFolderView* fv = inventory_panel->getRootFolder(); if (fv) { - LLFolderViewItem* fv_item = fv->getItemByID(item_id); + LLFolderViewItem* fv_item = inventory_panel->getItemByID(item_id); if (fv_item) { LLFolderViewItem* fv_folder = fv_item->getParentFolder(); @@ -808,7 +821,13 @@ private: mSelectedItems.clear(); if (LLInventoryPanel::getActiveInventoryPanel()) { - mSelectedItems = LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList(); + std::set<LLFolderViewItem*> selection = LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList(); + for (std::set<LLFolderViewItem*>::iterator it = selection.begin(), end_it = selection.end(); + it != end_it; + ++it) + { + mSelectedItems.insert(static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID()); + } } mSelectedItems.erase(mMoveIntoFolderID); } @@ -843,7 +862,15 @@ private: } // get selected items (without destination folder) - selected_items_t selected_items = active_panel->getRootFolder()->getSelectionList(); + selected_items_t selected_items; + + std::set<LLFolderViewItem*> selection = LLInventoryPanel::getActiveInventoryPanel()->getRootFolder()->getSelectionList(); + for (std::set<LLFolderViewItem*>::iterator it = selection.begin(), end_it = selection.end(); + it != end_it; + ++it) + { + selected_items.insert(static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID()); + } selected_items.erase(mMoveIntoFolderID); // compare stored & current sets of selected items @@ -1064,7 +1091,9 @@ public: // If we now try to remove the inventory item, it will cause a nested // notifyObservers() call, which won't work. // So defer moving the item to trash until viewer gets idle (in a moment). - LLAppViewer::instance()->addOnIdleCallback(boost::bind(&LLInventoryModel::removeItem, &gInventory, mObjectID)); + // Use removeObject() rather than removeItem() because at this level, + // the object could be either an item or a folder. + LLAppViewer::instance()->addOnIdleCallback(boost::bind(&LLInventoryModel::removeObject, &gInventory, mObjectID)); gInventory.removeObserver(this); delete this; } @@ -1148,6 +1177,17 @@ bool check_offer_throttle(const std::string& from_name, bool check_only) } } +// Return "true" if we have a preview method for that asset type, "false" otherwise +bool check_asset_previewable(const LLAssetType::EType asset_type) +{ + return (asset_type == LLAssetType::AT_NOTECARD) || + (asset_type == LLAssetType::AT_LANDMARK) || + (asset_type == LLAssetType::AT_TEXTURE) || + (asset_type == LLAssetType::AT_ANIMATION) || + (asset_type == LLAssetType::AT_SCRIPT) || + (asset_type == LLAssetType::AT_SOUND); +} + void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_name) { for (uuid_vec_t::const_iterator obj_iter = objects.begin(); @@ -1171,7 +1211,7 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam // Either an inventory item or a category. const LLInventoryItem* item = dynamic_cast<const LLInventoryItem*>(obj); - if (item) + if (item && check_asset_previewable(asset_type)) { //////////////////////////////////////////////////////////////////////////////// // Special handling for various types. @@ -1246,6 +1286,7 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam LLFloaterReg::showInstance("preview_sound", LLSD(obj_id), take_focus); break; default: + LL_DEBUGS("Messaging") << "No preview method for previewable asset type : " << LLAssetType::lookupHumanReadable(asset_type) << LL_ENDL; break; } } @@ -1324,6 +1365,8 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id)); } +std::string LLOfferInfo::mResponderType = "offer_info"; + LLOfferInfo::LLOfferInfo() : LLNotificationResponderInterface() , mFromGroup(FALSE) @@ -1369,6 +1412,7 @@ LLOfferInfo::LLOfferInfo(const LLOfferInfo& info) LLSD LLOfferInfo::asLLSD() { LLSD sd; + sd["responder_type"] = mResponderType; sd["im_type"] = mIM; sd["from_id"] = mFromID; sd["from_group"] = mFromGroup; @@ -1458,16 +1502,15 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID); } + LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); + // 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 + if (IOR_MUTE == button) // Block { - LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); - - llassert(notification_ptr != NULL); if (notification_ptr != NULL) { gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback, _1, _2, _3)); @@ -1480,8 +1523,8 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // 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 = gAgent.getBusy(); - + LLNotificationFormPtr modified_form(notification_ptr ? new LLNotificationForm(*notification_ptr->getForm()) : new LLNotificationForm()); + switch(button) { case IOR_SHOW: @@ -1525,6 +1568,11 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL; break; } + + if (modified_form != NULL) + { + modified_form->setElementEnabled("Show", false); + } break; // end switch (mIM) @@ -1537,9 +1585,14 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& args["MESSAGE"] = log_message; LLNotificationsUtil::add("SystemMessageTip", args); } + break; case IOR_MUTE: + if (modified_form != NULL) + { + modified_form->setElementEnabled("Mute", false); + } // MUTE falls through to decline case IOR_DECLINE: { @@ -1569,12 +1622,13 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& { opener = discard_agent_offer; } - - - if (busy && (!mFromGroup && !mFromObject)) + + if (modified_form != NULL) { - busy_message(gMessageSystem, mFromID); + modified_form->setElementEnabled("Show", false); + modified_form->setElementEnabled("Discard", false); } + break; } default: @@ -1594,6 +1648,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& { delete this; } + return false; } @@ -1684,7 +1739,7 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const from_string = chatHistory_string = mFromName; } - bool busy = gAgent.getBusy(); + bool is_do_not_disturb = gAgent.isDoNotDisturb(); switch(button) { @@ -1757,9 +1812,9 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const LLNotificationsUtil::add("SystemMessageTip", args); } - if (busy && (!mFromGroup && !mFromObject)) + if (is_do_not_disturb && (!mFromGroup && !mFromObject)) { - busy_message(msg,mFromID); + send_do_not_disturb_message(msg,mFromID); } break; } @@ -1911,6 +1966,7 @@ void inventory_offer_handler(LLOfferInfo* info) p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info)); info->mPersist = true; p.name = "UserGiveItem"; + p.offer_from_agent = true; // Prefetch the item into your local inventory. LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID); @@ -1927,6 +1983,11 @@ void inventory_offer_handler(LLOfferInfo* info) // In viewer 2 we're now auto receiving inventory offers and messaging as such (not sending reject messages). info->send_auto_receive_response(); + if (gAgent.isDoNotDisturb()) + { + send_do_not_disturb_message(gMessageSystem, info->mFromID); + } + // Inform user that there is a script floater via toast system { payload["give_inventory_notification"] = TRUE; @@ -1971,10 +2032,62 @@ bool lure_callback(const LLSD& notification, const LLSD& response) lure_id); break; } + + LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); + + if (notification_ptr) + { + LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); + modified_form->setElementEnabled("Teleport", false); + modified_form->setElementEnabled("Cancel", false); + notification_ptr->updateForm(modified_form); + notification_ptr->repost(); + } + return false; } static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback); +bool mature_lure_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = 0; + if (response.isInteger()) + { + option = response.asInteger(); + } + else + { + option = LLNotificationsUtil::getSelectedOption(notification, response); + } + + LLUUID from_id = notification["payload"]["from_id"].asUUID(); + LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); + BOOL godlike = notification["payload"]["godlike"].asBoolean(); + U8 region_access = static_cast<U8>(notification["payload"]["region_maturity"].asInteger()); + + switch(option) + { + case 0: + { + // accept + gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(region_access)); + gAgent.setMaturityRatingChangeDuringTeleport(region_access); + gAgent.teleportViaLure(lure_id, godlike); + } + break; + case 1: + default: + // decline + send_simple_im(from_id, + LLStringUtil::null, + IM_LURE_DECLINED, + lure_id); + break; + } + return false; +} +static LLNotificationFunctorRegistration mature_lure_callback_reg("TeleportOffered_MaturityExceeded", mature_lure_callback); + bool goto_url_callback(const LLSD& notification, const LLSD& response) { std::string url = notification["payload"]["url"].asString(); @@ -2092,7 +2205,7 @@ static std::string clean_name_from_im(const std::string& name, EInstantMessage t case IM_SESSION_SEND: case IM_SESSION_LEAVE: //IM_FROM_TASK - case IM_BUSY_AUTO_RESPONSE: + case IM_DO_NOT_DISTURB_AUTO_RESPONSE: case IM_CONSOLE_AND_CHAT_HISTORY: case IM_LURE_USER: case IM_LURE_ACCEPTED: @@ -2133,16 +2246,7 @@ static std::string clean_name_from_task_im(const std::string& msg, // Don't try to clean up group names if (!from_group) { - if (LLAvatarNameCache::useDisplayNames()) - { - // ...just convert to username - final += LLCacheName::buildUsername(name); - } - else - { - // ...strip out legacy "Resident" name - final += LLCacheName::cleanFullName(name); - } + final += LLCacheName::buildUsername(name); } final += match[3].str(); return final; @@ -2150,13 +2254,13 @@ static std::string clean_name_from_task_im(const std::string& msg, return msg; } -void notification_display_name_callback(const LLUUID& id, +static void notification_display_name_callback(const LLUUID& id, const LLAvatarName& av_name, const std::string& name, LLSD& substitutions, const LLSD& payload) { - substitutions["NAME"] = av_name.mDisplayName; + substitutions["NAME"] = av_name.getDisplayName(); LLNotificationsUtil::add(name, substitutions, payload); } @@ -2174,7 +2278,7 @@ protected: }; // Callback for name resolution of a god/estate message -void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message) +static void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message) { LLSD args; args["NAME"] = av_name.getCompleteName(); @@ -2184,12 +2288,11 @@ void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string m // Treat like a system message and put in chat history. chat.mText = av_name.getCompleteName() + ": " + message; - LLNearbyChat* nearby_chat = LLNearbyChat::getInstance(); - if(nearby_chat) + LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); + if (nearby_chat) { nearby_chat->addMessage(chat); } - } void process_improved_im(LLMessageSystem *msg, void **user_data) @@ -2235,19 +2338,22 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { name = LLTrans::getString("Unnamed"); } + + // Preserve the unaltered name for use in group notice mute checking. + std::string original_name = name; + // IDEVO convert new-style "Resident" names for display name = clean_name_from_im(name, dialog); - BOOL is_busy = gAgent.getBusy(); + BOOL is_do_not_disturb = gAgent.isDoNotDisturb(); BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat) // object IMs contain sender object id in session_id (STORM-1209) || dialog == IM_FROM_TASK && LLMuteList::getInstance()->isMuted(session_id); - BOOL is_linden = LLMuteList::getInstance()->isLinden(name); BOOL is_owned_by_me = FALSE; BOOL is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL) ? false : true; BOOL accept_im_from_only_friend = gSavedSettings.getBOOL("VoiceCallsFriendsOnly"); - chat.mMuted = is_muted && !is_linden; + chat.mMuted = is_muted; chat.mFromID = from_id; chat.mFromName = name; chat.mSourceType = (from_id.isNull() || (name == std::string(SYSTEM_FROM))) ? CHAT_SOURCE_SYSTEM : CHAT_SOURCE_AGENT; @@ -2265,7 +2371,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLNotification::Params params; switch(dialog) - { + { case IM_CONSOLE_AND_CHAT_HISTORY: args["MESSAGE"] = message; payload["from_id"] = from_id; @@ -2285,29 +2391,18 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // do nothing -- don't distract newbies in // Prelude with global IMs } - else if (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM) + else if (offline == IM_ONLINE + && is_do_not_disturb + && from_id.notNull() //not a system message + && to_id.notNull()) //not global message { - // return a standard "busy" message, but only do it to online IM + // return a standard "do not disturb" message, but only do it to online IM // (i.e. not other auto responses and not store-and-forward IM) if (!gIMMgr->hasSession(session_id)) { // if there is not a panel for this conversation (i.e. it is a new IM conversation // initiated by the other party) then... - std::string my_name; - LLAgentUI::buildFullname(my_name); - std::string response = gSavedPerAccountSettings.getString("BusyModeResponse"); - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - from_id, - my_name, - response, - IM_ONLINE, - IM_BUSY_AUTO_RESPONSE, - session_id); - gAgent.sendReliableMessage(); + send_do_not_disturb_message(msg, from_id, session_id); } // now store incoming IM in chat history @@ -2322,6 +2417,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) from_id, name, buffer, + IM_OFFLINE == offline, LLStringUtil::null, dialog, parent_estate_id, @@ -2358,15 +2454,23 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) bool mute_im = is_muted; if(accept_im_from_only_friend&&!is_friend) { + if (!gIMMgr->isNonFriendSessionNotified(session_id)) + { + std::string message = LLTrans::getString("IM_unblock_only_groups_friends"); + gIMMgr->addMessage(session_id, from_id, name, message, IM_OFFLINE == offline); + gIMMgr->addNotifiedNonFriendSessionID(session_id); + } + mute_im = true; } - if (!mute_im || is_linden) + if (!mute_im) { gIMMgr->addMessage( session_id, from_id, name, buffer, + IM_OFFLINE == offline, LLStringUtil::null, dialog, parent_estate_id, @@ -2441,6 +2545,26 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) break; } + // The group notice packet does not have an AgentID. Obtain one from the name cache. + // If last name is "Resident" strip it out so the cache name lookup works. + U32 index = original_name.find(" Resident"); + if (index != std::string::npos) + { + original_name = original_name.substr(0, index); + } + std::string legacy_name = gCacheName->buildLegacyName(original_name); + LLUUID agent_id; + gCacheName->getUUID(legacy_name, agent_id); + + if (agent_id.isNull()) + { + LL_WARNS("Messaging") << "buildLegacyName returned null while processing " << original_name << LL_ENDL; + } + else if (LLMuteList::getInstance()->isMuted(agent_id)) + { + break; + } + notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0]; U8 has_inventory = notice_bin_bucket->header.has_inventory; U8 asset_type = notice_bin_bucket->header.asset_type; @@ -2491,7 +2615,10 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) payload["sender_name"] = name; payload["group_id"] = group_id; payload["inventory_name"] = item_name; - payload["inventory_offer"] = info ? info->asLLSD() : LLSD(); + if(info && info->asLLSD()) + { + payload["inventory_offer"] = info->asLLSD(); + } LLSD args; args["SUBJECT"] = subj; @@ -2513,11 +2640,9 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) break; case IM_GROUP_INVITATION: { - //if (!is_linden && (is_busy || is_muted)) - if ((is_busy || is_muted)) + if (is_do_not_disturb || is_muted) { - LLMessageSystem *msg = gMessageSystem; - busy_message(msg,from_id); + send_do_not_disturb_message(msg, from_id); } else { @@ -2600,7 +2725,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) info->mFromName = name; info->mDesc = message; info->mHost = msg->getSender(); - //if (((is_busy && !is_owned_by_me) || is_muted)) + //if (((is_do_not_disturb && !is_owned_by_me) || is_muted)) if (is_muted) { // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331) @@ -2611,9 +2736,11 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // Same as closing window info->forceResponse(IOR_DECLINE); } - else if (is_busy && dialog != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) + // old logic: busy mode must not affect interaction with objects (STORM-565) + // new logic: inventory offers from in-world objects should be auto-declined (CHUI-519) + else if (is_do_not_disturb && dialog == IM_TASK_INVENTORY_OFFERED) { - // Until throttling is implemented, busy mode should reject inventory instead of silently + // Until throttling is implemented, do not disturb mode should reject inventory instead of silently // accepting it. SEE SL-39554 info->forceResponse(IOR_DECLINE); } @@ -2658,7 +2785,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) case IM_SESSION_SEND: { - if (!is_linden && is_busy) + if (is_do_not_disturb) { return; } @@ -2687,6 +2814,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) from_id, name, buffer, + IM_OFFLINE == offline, ll_safe_string((char*)binary_bucket), IM_SESSION_INVITE, parent_estate_id, @@ -2698,7 +2826,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) case IM_FROM_TASK: { - if (is_busy && !is_owned_by_me) + if (is_do_not_disturb && !is_owned_by_me) { return; } @@ -2722,7 +2850,11 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) chat.mSourceType = CHAT_SOURCE_OBJECT; - if(SYSTEM_FROM == name) + // To conclude that the source type of message is CHAT_SOURCE_SYSTEM it's not + // enough to check only from name (i.e. fromName = "Second Life"). For example + // source type of messages from objects called "Second Life" should not be CHAT_SOURCE_SYSTEM. + bool chat_from_system = (SYSTEM_FROM == name) && region_id.isNull() && position.isNull(); + if(chat_from_system) { // System's UUID is NULL (fixes EXT-4766) chat.mFromID = LLUUID::null; @@ -2746,13 +2878,12 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // Note: lie to Nearby Chat, pretending that this is NOT an IM, because // IMs from obejcts don't open IM sessions. - LLNearbyChat* nearby_chat = LLNearbyChat::getInstance(); - if(SYSTEM_FROM != name && nearby_chat) + LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLFloaterIMNearbyChat>("nearby_chat"); + if(!chat_from_system && nearby_chat) { chat.mOwnerID = from_id; LLSD args; args["slurl"] = location; - args["type"] = LLNotificationsUI::NT_NEARBYCHAT; // Look for IRC-style emotes here so object name formatting is correct std::string prefix = message.substr(0, 4); @@ -2766,7 +2897,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) //Object IMs send with from name: 'Second Life' need to be displayed also in notification toasts (EXT-1590) - if (SYSTEM_FROM != name) break; + if (!chat_from_system) break; LLSD substitutions; substitutions["NAME"] = name; @@ -2792,7 +2923,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } break; case IM_FROM_TASK_AS_ALERT: - if (is_busy && !is_owned_by_me) + if (is_do_not_disturb && !is_owned_by_me) { return; } @@ -2803,17 +2934,15 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLNotificationsUtil::add("ObjectMessage", args); } break; - case IM_BUSY_AUTO_RESPONSE: + case IM_DO_NOT_DISTURB_AUTO_RESPONSE: if (is_muted) { - LL_DEBUGS("Messaging") << "Ignoring busy response from " << from_id << LL_ENDL; + LL_DEBUGS("Messaging") << "Ignoring do-not-disturb response from " << from_id << LL_ENDL; return; } else { - // TODO: after LLTrans hits release, get "busy response" into translatable file - buffer = llformat("%s (%s): %s", name.c_str(), "busy response", message.c_str()); - gIMMgr->addMessage(session_id, from_id, name, buffer); + gIMMgr->addMessage(session_id, from_id, name, message); } break; @@ -2823,23 +2952,62 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { return; } - else if (is_busy) + else if (is_do_not_disturb) { - busy_message(msg,from_id); + send_do_not_disturb_message(msg, from_id); } else { LLVector3 pos, look_at; U64 region_handle(0); - U8 region_access(0); + U8 region_access(SIM_ACCESS_MIN); std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); std::string region_access_str = LLStringUtil::null; std::string region_access_icn = LLStringUtil::null; + std::string region_access_lc = LLStringUtil::null; + + bool canUserAccessDstRegion = true; + bool doesUserRequireMaturityIncrease = false; if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) { region_access_str = LLViewerRegion::accessToString(region_access); region_access_icn = LLViewerRegion::getAccessIcon(region_access); + region_access_lc = region_access_str; + LLStringUtil::toLower(region_access_lc); + + if (!gAgent.isGodlike()) + { + switch (region_access) + { + case SIM_ACCESS_MIN : + case SIM_ACCESS_PG : + break; + case SIM_ACCESS_MATURE : + if (gAgent.isTeen()) + { + canUserAccessDstRegion = false; + } + else if (gAgent.prefersPG()) + { + doesUserRequireMaturityIncrease = true; + } + break; + case SIM_ACCESS_ADULT : + if (!gAgent.isAdult()) + { + canUserAccessDstRegion = false; + } + else if (!gAgent.prefersAdult()) + { + doesUserRequireMaturityIncrease = true; + } + break; + default : + llassert(0); + break; + } + } } LLSD args; @@ -2848,29 +3016,131 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) args["MESSAGE"] = message; args["MATURITY_STR"] = region_access_str; args["MATURITY_ICON"] = region_access_icn; + args["REGION_CONTENT_MATURITY"] = region_access_lc; LLSD payload; payload["from_id"] = from_id; payload["lure_id"] = session_id; payload["godlike"] = FALSE; + payload["region_maturity"] = region_access; + if (!canUserAccessDstRegion) + { + LLNotification::Params params("TeleportOffered_MaturityBlocked"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + send_simple_im(from_id, LLTrans::getString("TeleportMaturityExceeded"), IM_NOTHING_SPECIAL, session_id); + send_simple_im(from_id, LLStringUtil::null, IM_LURE_DECLINED, session_id); + } + else if (doesUserRequireMaturityIncrease) + { + LLNotification::Params params("TeleportOffered_MaturityExceeded"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + } + else + { LLNotification::Params params("TeleportOffered"); params.substitutions = args; params.payload = payload; LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); } + + } } break; case IM_GODLIKE_LURE_USER: { + LLVector3 pos, look_at; + U64 region_handle(0); + U8 region_access(SIM_ACCESS_MIN); + std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); + std::string region_access_str = LLStringUtil::null; + std::string region_access_icn = LLStringUtil::null; + std::string region_access_lc = LLStringUtil::null; + + bool canUserAccessDstRegion = true; + bool doesUserRequireMaturityIncrease = false; + + if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) + { + region_access_str = LLViewerRegion::accessToString(region_access); + region_access_icn = LLViewerRegion::getAccessIcon(region_access); + region_access_lc = region_access_str; + LLStringUtil::toLower(region_access_lc); + + if (!gAgent.isGodlike()) + { + switch (region_access) + { + case SIM_ACCESS_MIN : + case SIM_ACCESS_PG : + break; + case SIM_ACCESS_MATURE : + if (gAgent.isTeen()) + { + canUserAccessDstRegion = false; + } + else if (gAgent.prefersPG()) + { + doesUserRequireMaturityIncrease = true; + } + break; + case SIM_ACCESS_ADULT : + if (!gAgent.isAdult()) + { + canUserAccessDstRegion = false; + } + else if (!gAgent.prefersAdult()) + { + doesUserRequireMaturityIncrease = true; + } + break; + default : + llassert(0); + break; + } + } + } + + LLSD args; + // *TODO: Translate -> [FIRST] [LAST] (maybe) + args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); + args["MESSAGE"] = message; + args["MATURITY_STR"] = region_access_str; + args["MATURITY_ICON"] = region_access_icn; + args["REGION_CONTENT_MATURITY"] = region_access_lc; LLSD payload; payload["from_id"] = from_id; payload["lure_id"] = session_id; payload["godlike"] = TRUE; + payload["region_maturity"] = region_access; + + if (!canUserAccessDstRegion) + { + LLNotification::Params params("TeleportOffered_MaturityBlocked"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + send_simple_im(from_id, LLTrans::getString("TeleportMaturityExceeded"), IM_NOTHING_SPECIAL, session_id); + send_simple_im(from_id, LLStringUtil::null, IM_LURE_DECLINED, session_id); + } + else if (doesUserRequireMaturityIncrease) + { + LLNotification::Params params("TeleportOffered_MaturityExceeded"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + } + else + { // do not show a message box, because you're about to be // teleported. LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0); } + } break; case IM_GOTO_URL: @@ -2905,17 +3175,16 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) payload["online"] = (offline == IM_ONLINE); payload["sender"] = msg->getSender().getIPandPort(); - if (is_busy) - { - busy_message(msg, from_id); - LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); - } - else if (is_muted) + if (is_muted) { LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); } else { + if (is_do_not_disturb) + { + send_do_not_disturb_message(msg, from_id); + } args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); if(message.empty()) { @@ -2948,12 +3217,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) args["NAME"] = name; LLSD payload; payload["from_id"] = from_id; - LLAvatarNameCache::get(from_id, boost::bind(¬ification_display_name_callback, - _1, - _2, - "FriendshipAccepted", - args, - payload)); + LLAvatarNameCache::get(from_id, boost::bind(¬ification_display_name_callback,_1,_2,"FriendshipAccepted",args,payload)); } break; @@ -2971,15 +3235,15 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) } } -void busy_message (LLMessageSystem* msg, LLUUID from_id) +void send_do_not_disturb_message (LLMessageSystem* msg, const LLUUID& from_id, const LLUUID& session_id) { - if (gAgent.getBusy()) + if (gAgent.isDoNotDisturb()) { std::string my_name; LLAgentUI::buildFullname(my_name); - std::string response = gSavedPerAccountSettings.getString("BusyModeResponse"); + std::string response = gSavedPerAccountSettings.getString("DoNotDisturbModeResponse"); pack_instant_message( - gMessageSystem, + msg, gAgent.getID(), FALSE, gAgent.getSessionID(), @@ -2987,7 +3251,8 @@ void busy_message (LLMessageSystem* msg, LLUUID from_id) my_name, response, IM_ONLINE, - IM_BUSY_AUTO_RESPONSE); + IM_DO_NOT_DISTURB_AUTO_RESPONSE, + session_id); gAgent.sendReliableMessage(); } } @@ -3022,7 +3287,7 @@ bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) msg->nextBlockFast(_PREHASH_TransactionBlock); msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - busy_message(msg, notification["payload"]["source_id"].asUUID()); + send_do_not_disturb_message(msg, notification["payload"]["source_id"].asUUID()); break; default: // close button probably, possibly timed out @@ -3064,7 +3329,7 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) if(!source_name.empty()) { - if (gAgent.getBusy() + if (gAgent.isDoNotDisturb() || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat)) { // automatically decline offer @@ -3104,9 +3369,9 @@ public : { } - static boost::intrusive_ptr<ChatTranslationReceiver> build(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, const LLChat &chat, const LLSD &toast_args) + static ChatTranslationReceiver* build(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, const LLChat &chat, const LLSD &toast_args) { - return boost::intrusive_ptr<ChatTranslationReceiver>(new ChatTranslationReceiver(from_lang, to_lang, mesg, chat, toast_args)); + return new ChatTranslationReceiver(from_lang, to_lang, mesg, chat, toast_args); } protected: @@ -3181,7 +3446,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) LLAvatarName av_name; if (LLAvatarNameCache::get(from_id, &av_name)) { - chat.mFromName = av_name.mDisplayName; + chat.mFromName = av_name.getDisplayName(); } else { @@ -3193,7 +3458,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) chat.mFromName = from_name; } - BOOL is_busy = gAgent.getBusy(); + BOOL is_do_not_disturb = gAgent.isDoNotDisturb(); BOOL is_muted = FALSE; BOOL is_linden = FALSE; @@ -3227,7 +3492,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // record last audible utterance if (is_audible - && (is_linden || (!is_muted && !is_busy))) + && (is_linden || (!is_muted && !is_do_not_disturb))) { if (chat.mChatType != CHAT_TYPE_START && chat.mChatType != CHAT_TYPE_STOP) @@ -3322,7 +3587,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); ((LLVOAvatar*)chatter)->stopTyping(); - if (!is_muted && !is_busy) + if (!is_muted && !is_do_not_disturb) { visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles"); std::string formated_msg = ""; @@ -3355,7 +3620,6 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // 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; chat.mOwnerID = owner_id; if (gSavedSettings.getBOOL("TranslateChat") && chat.mSourceType != CHAT_SOURCE_SYSTEM) @@ -3374,6 +3638,11 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) { LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); } + + LLSD msg_notify = LLSD(LLSD::emptyMap()); + msg_notify["session_id"] = LLUUID(); + msg_notify["from_id"] = chat.mFromID; + on_new_message(msg_notify); } } @@ -3393,6 +3662,9 @@ void process_teleport_start(LLMessageSystem *msg, void**) LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL; + // *NOTE: The server sends two StartTeleport packets when you are teleporting to a LM + LLViewerMessage::getInstance()->mTeleportStartedSignal(); + if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) { gViewerWindow->setProgressCancelButtonVisible(FALSE); @@ -3412,11 +3684,17 @@ void process_teleport_start(LLMessageSystem *msg, void**) make_ui_sound("UISndTeleportOut"); LL_INFOS("Messaging") << "Teleport initiated by remote TeleportStart message with TeleportFlags: " << teleport_flags << LL_ENDL; + // Don't call LLFirstUse::useTeleport here because this could be // due to being killed, which would send you home, not to a Telehub } } +boost::signals2::connection LLViewerMessage::setTeleportStartedCallback(teleport_started_callback_t cb) +{ + return mTeleportStartedSignal.connect(cb); +} + void process_teleport_progress(LLMessageSystem* msg, void**) { LLUUID agent_id; @@ -3638,6 +3916,9 @@ void process_teleport_finish(LLMessageSystem* msg, void**) gCacheName->setUpstream(sim); */ + // Make sure we're standing + gAgent.standUp(); + // now, use the circuit info to tell simulator about us! LL_INFOS("Messaging") << "process_teleport_finish() Enabling " << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL; @@ -3683,6 +3964,7 @@ void process_avatar_init_complete(LLMessageSystem* msg, void**) void process_agent_movement_complete(LLMessageSystem* msg, void**) { + gShiftFrame = true; gAgentMovementCompleted = true; LLUUID agent_id; @@ -3848,14 +4130,14 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgent.setFlying(gAgent.canFly()); } - // force simulator to recognize busy state - if (gAgent.getBusy()) + // force simulator to recognize do not disturb state + if (gAgent.isDoNotDisturb()) { - gAgent.setBusy(); + gAgent.setDoNotDisturb(true); } else { - gAgent.clearBusy(); + gAgent.setDoNotDisturb(false); } if (isAgentAvatarValid()) @@ -4013,6 +4295,8 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) head_rot_chg = dot(last_head_rot, head_rotation); + //static S32 msg_number = 0; // Used for diagnostic log messages + if (force_send || (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) || (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) || @@ -4021,19 +4305,20 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) control_flag_change != 0 || flag_change != 0) { -/* + /* Diagnotics to show why we send the AgentUpdate message. Also un-commment the msg_number code above and below this block + msg_number += 1; if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) { //LL_INFOS("Messaging") << "head rot " << head_rotation << LL_ENDL; - LL_INFOS("Messaging") << "head_rot_chg = " << head_rot_chg << LL_ENDL; + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", head_rot_chg " << head_rot_chg << LL_ENDL; } if (cam_rot_chg.magVec() > ROTATION_THRESHOLD) { - LL_INFOS("Messaging") << "cam rot " << cam_rot_chg.magVec() << LL_ENDL; + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam rot " << cam_rot_chg.magVec() << LL_ENDL; } if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) { - LL_INFOS("Messaging") << "cam center " << cam_center_chg.magVec() << LL_ENDL; + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam center " << cam_center_chg.magVec() << LL_ENDL; } // if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD) // { @@ -4041,7 +4326,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) // } if (control_flag_change) { - LL_INFOS("Messaging") << "dcf = " << control_flag_change << LL_ENDL; + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", dcf = " << control_flag_change << LL_ENDL; } */ @@ -4078,6 +4363,26 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) if (duplicate_count < DUP_MSGS && !gDisconnected) { + /* More diagnostics to count AgentUpdate messages + static S32 update_sec = 0; + static S32 update_count = 0; + static S32 max_update_count = 0; + S32 cur_sec = lltrunc( LLTimer::getTotalSeconds() ); + update_count += 1; + if (cur_sec != update_sec) + { + if (update_sec != 0) + { + update_sec = cur_sec; + //msg_number = 0; + max_update_count = llmax(max_update_count, update_count); + llinfos << "Sent " << update_count << " AgentUpdate messages per second, max is " << max_update_count << llendl; + } + update_sec = cur_sec; + update_count = 0; + } + */ + LLFastTimer t(FTM_AGENT_UPDATE_SEND); // Build the message msg->newMessageFast(_PREHASH_AgentUpdate); @@ -4148,7 +4453,6 @@ extern U32 gObjectBits; void process_object_update(LLMessageSystem *mesgsys, void **user_data) { - LLMemType mt(LLMemType::MTYPE_OBJECT); // Update the data counters if (mesgsys->getReceiveCompressedSize()) { @@ -4165,7 +4469,6 @@ void process_object_update(LLMessageSystem *mesgsys, void **user_data) void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data) { - LLMemType mt(LLMemType::MTYPE_OBJECT); // Update the data counters if (mesgsys->getReceiveCompressedSize()) { @@ -4182,7 +4485,6 @@ void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) { - LLMemType mt(LLMemType::MTYPE_OBJECT); // Update the data counters if (mesgsys->getReceiveCompressedSize()) { @@ -4200,7 +4502,6 @@ void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_data) { - LLMemType mt(LLMemType::MTYPE_OBJECT); if (mesgsys->getReceiveCompressedSize()) { gObjectBits += mesgsys->getReceiveCompressedSize() * 8; @@ -4213,7 +4514,7 @@ void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_ gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED); } -static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects"); +static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Kill Objects"); void process_kill_object(LLMessageSystem *mesgsys, void **user_data) @@ -4246,8 +4547,6 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL; } - LLSelectMgr::getInstance()->removeObjectFromSelections(id); - // ...don't kill the avatar if (!(id == gAgentID)) { @@ -4270,6 +4569,12 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) gObjectList.mNumUnknownKills++; } } + + // We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab, + // which is using the object, release the mouse capture correctly when the object dies. + // See LLToolGrab::handleHoverActive() and LLToolGrab::handleHoverNonPhysical(). + LLSelectMgr::getInstance()->removeObjectFromSelections(id); + } } @@ -4579,6 +4884,18 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) case LL_SIM_STAT_IOPUMPTIME: LLViewerStats::getInstance()->mSimPumpIOMsec.addValue(stat_value); break; + case LL_SIM_STAT_PCTSCRIPTSRUN: + LLViewerStats::getInstance()->mSimPctScriptsRun.addValue(stat_value); + break; + case LL_SIM_STAT_SIMAISTEPTIMEMS: + LLViewerStats::getInstance()->mSimSimAIStepMsec.addValue(stat_value); + break; + case LL_SIM_STAT_SKIPPEDAISILSTEPS_PS: + LLViewerStats::getInstance()->mSimSimSkippedSilhouetteSteps.addValue(stat_value); + break; + case LL_SIM_STAT_PCTSTEPPEDCHARACTERS: + LLViewerStats::getInstance()->mSimSimPctSteppedCharacters.addValue(stat_value); + break; default: // Used to be a commented out warning. LL_DEBUGS("Messaging") << "Unknown stat id" << stat_id << LL_ENDL; @@ -4688,7 +5005,7 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) LLViewerObject* object = gObjectList.findObject(object_id); if (object) { - object->mFlags |= FLAGS_ANIM_SOURCE; + object->setFlagsWithoutUpdate(FLAGS_ANIM_SOURCE, TRUE); BOOL anim_found = FALSE; LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); @@ -4835,7 +5152,7 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat LLViewerObject* objectp = gObjectList.findObject(source_id); if (objectp) { - objectp->mFlags |= FLAGS_CAMERA_SOURCE; + objectp->setFlagsWithoutUpdate(FLAGS_CAMERA_SOURCE, TRUE); } S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty"); @@ -5203,6 +5520,7 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) BOOL is_dest_group = FALSE; S32 amount = 0; std::string item_description; + BOOL success = FALSE; msg->getS32("TransactionInfo", "TransactionType", transaction_type); msg->getUUID("TransactionInfo", "SourceID", source_id); @@ -5211,6 +5529,7 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) msg->getBOOL("TransactionInfo", "IsDestGroup", is_dest_group); msg->getS32("TransactionInfo", "Amount", amount); msg->getString("TransactionInfo", "ItemDescription", item_description); + msg->getBOOL("MoneyData", "TransactionSuccess", success); LL_INFOS("Money") << "MoneyBalanceReply source " << source_id << " dest " << dest_id << " type " << transaction_type @@ -5272,28 +5591,32 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) { if (dest_id.notNull()) { - message = LLTrans::getString("you_paid_ldollars", args); + message = success ? LLTrans::getString("you_paid_ldollars", args) : + LLTrans::getString("you_paid_failure_ldollars", args); } else { // transaction fee to the system, eg, to create a group - message = LLTrans::getString("you_paid_ldollars_no_name", args); + message = success ? LLTrans::getString("you_paid_ldollars_no_name", args) : + LLTrans::getString("you_paid_failure_ldollars_no_name", args); } } else { if (dest_id.notNull()) { - message = LLTrans::getString("you_paid_ldollars_no_reason", args); + message = success ? LLTrans::getString("you_paid_ldollars_no_reason", args) : + LLTrans::getString("you_paid_failure_ldollars_no_reason", args); } else { // no target, no reason, you just paid money - message = LLTrans::getString("you_paid_ldollars_no_info", args); + message = success ? LLTrans::getString("you_paid_ldollars_no_info", args) : + LLTrans::getString("you_paid_failure_ldollars_no_info", args); } } final_args["MESSAGE"] = message; - notification = "PaymentSent"; + notification = success ? "PaymentSent" : "PaymentFailure"; } else { // ...someone paid you @@ -5324,31 +5647,41 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) _1, _2, _3, notification, final_args, payload)); } - else { - LLAvatarNameCache::get(name_id, - boost::bind(&money_balance_avatar_notify, - _1, _2, - notification, final_args, payload)); + else + { + LLAvatarNameCache::get(name_id, boost::bind(&money_balance_avatar_notify, _1, _2, notification, final_args, payload)); } } +bool handle_prompt_for_maturity_level_change_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + // set the preference to the maturity of the region we're calling + U8 preferredMaturity = static_cast<U8>(notification["payload"]["_region_access"].asInteger()); + gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(preferredMaturity)); + } -bool handle_special_notification_callback(const LLSD& notification, const LLSD& response) + return false; +} + +bool handle_prompt_for_maturity_level_change_and_reteleport_callback(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (0 == option) { // set the preference to the maturity of the region we're calling - int preferredMaturity = notification["payload"]["_region_access"].asInteger(); - gSavedSettings.setU32("PreferredMaturity", preferredMaturity); - gAgent.sendMaturityPreferenceToServer(preferredMaturity); - - // notify user that the maturity preference has been changed - LLSD args; - args["RATING"] = LLViewerRegion::accessToString(preferredMaturity); - LLNotificationsUtil::add("PreferredMaturityChanged", args); + U8 preferredMaturity = static_cast<U8>(notification["payload"]["_region_access"].asInteger()); + gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(preferredMaturity)); + gAgent.setMaturityRatingChangeDuringTeleport(preferredMaturity); + gAgent.restartFailedTeleportRequest(); + } + else + { + gAgent.clearTeleportRequest(); } return false; @@ -5357,39 +5690,148 @@ bool handle_special_notification_callback(const LLSD& notification, const LLSD& // some of the server notifications need special handling. This is where we do that. bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) { - int regionAccess = llsdBlock["_region_access"].asInteger(); - llsdBlock["REGIONMATURITY"] = LLViewerRegion::accessToString(regionAccess); + U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; - // we're going to throw the LLSD in there in case anyone ever wants to use it - LLNotificationsUtil::add(notificationID+"_Notify", llsdBlock); + bool returnValue = false; + LLNotificationPtr maturityLevelNotification; + std::string notifySuffix = "_Notify"; + if (regionAccess == SIM_ACCESS_MATURE) + { + if (gAgent.isTeen()) + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); + returnValue = true; + } + } + else if (regionAccess == SIM_ACCESS_ADULT) + { + if (!gAgent.isAdult()) + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG() || gAgent.prefersMature()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); + returnValue = true; + } + } + + if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored()) + { + // Given a simple notification if no maturityLevelNotification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); + } + + return returnValue; +} + +// some of the server notifications need special handling. This is where we do that. +bool handle_teleport_access_blocked(LLSD& llsdBlock) +{ + std::string notificationID("TeleportEntryAccessBlocked"); + U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; + bool returnValue = false; + LLNotificationPtr maturityLevelNotification; + std::string notifySuffix = "_Notify"; if (regionAccess == SIM_ACCESS_MATURE) { if (gAgent.isTeen()) { - LLNotificationsUtil::add(notificationID+"_KB", llsdBlock); - return true; + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; } else if (gAgent.prefersPG()) { - LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); - return true; + if (gAgent.hasRestartableFailedTeleportRequest()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; } } else if (regionAccess == SIM_ACCESS_ADULT) { if (!gAgent.isAdult()) { - LLNotificationsUtil::add(notificationID+"_KB", llsdBlock); - return true; + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; } else if (gAgent.prefersPG() || gAgent.prefersMature()) { - LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); - return true; + if (gAgent.hasRestartableFailedTeleportRequest()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } } + + if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored()) + { + // Given a simple notification if no maturityLevelNotification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); } - return false; + + return returnValue; } bool attempt_standard_notification(LLMessageSystem* msgsystem) @@ -5433,16 +5875,20 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) RegionEntryAccessBlocked RegionEntryAccessBlocked_Notify + RegionEntryAccessBlocked_NotifyAdultsOnly RegionEntryAccessBlocked_Change - RegionEntryAccessBlocked_KB + RegionEntryAccessBlocked_AdultsOnlyContent + RegionEntryAccessBlocked_ChangeAndReTeleport LandClaimAccessBlocked LandClaimAccessBlocked_Notify + LandClaimAccessBlocked_NotifyAdultsOnly LandClaimAccessBlocked_Change - LandClaimAccessBlocked_KB + LandClaimAccessBlocked_AdultsOnlyContent LandBuyAccessBlocked LandBuyAccessBlocked_Notify + LandBuyAccessBlocked_NotifyAdultsOnly LandBuyAccessBlocked_Change - LandBuyAccessBlocked_KB + LandBuyAccessBlocked_AdultsOnlyContent -----------------------------------------------------------------------*/ if (handle_special_notification(notificationID, llsdBlock)) @@ -5494,6 +5940,30 @@ void process_alert_message(LLMessageSystem *msgsystem, void **user_data) } } +bool handle_not_age_verified_alert(const std::string &pAlertName) +{ + LLNotificationPtr notification = LLNotificationsUtil::add(pAlertName); + if ((notification == NULL) || notification->isIgnored()) + { + LLNotificationsUtil::add(pAlertName + "_Notify"); + } + + return true; +} + +bool handle_special_alerts(const std::string &pAlertName) +{ + bool isHandled = false; + + if (LLStringUtil::compareStrings(pAlertName, "NotAgeVerified") == 0) + { + + isHandled = handle_not_age_verified_alert(pAlertName); + } + + return isHandled; +} + void process_alert_core(const std::string& message, BOOL modal) { // HACK -- handle callbacks for specific alerts. It also is localized in notifications.xml @@ -5517,8 +5987,11 @@ 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())); + if (!handle_special_alerts(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 @@ -5783,6 +6256,16 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) S32 orig = notification["payload"]["questions"].asInteger(); S32 new_questions = orig; + if (response["Details"]) + { + // respawn notification... + LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); + + // ...with description on top + LLNotificationsUtil::add("DebitPermissionDetails"); + return false; + } + // check whether permissions were granted or denied BOOL allowed = TRUE; // the "yes/accept" button is the first button in the template, making it button 0 @@ -5840,14 +6323,6 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(item_id)); } - if (response["Details"]) - { - // respawn notification... - LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); - - // ...with description on top - LLNotificationsUtil::add("DebitPermissionDetails"); - } return false; } static LLNotificationFunctorRegistration script_question_cb_reg_1("ScriptQuestion", script_question_cb); @@ -5917,16 +6392,21 @@ void process_script_question(LLMessageSystem *msg, void **user_data) args["OBJECTNAME"] = object_name; args["NAME"] = LLCacheName::cleanFullName(owner_name); + BOOL has_not_only_debit = questions ^ LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_DEBIT]; // check the received permission flags against each permission for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++) { if (questions & LSCRIPTRunTimePermissionBits[i]) { count++; - script_question += " " + LLTrans::getString(SCRIPT_QUESTIONS[i]) + "\n"; // check whether permission question should cause special caution dialog caution |= (SCRIPT_QUESTION_IS_CAUTION[i]); + + if (("ScriptTakeMoney" == SCRIPT_QUESTIONS[i]) && has_not_only_debit) + continue; + + script_question += " " + LLTrans::getString(SCRIPT_QUESTIONS[i]) + "\n"; } } args["QUESTIONS"] = script_question; @@ -5942,6 +6422,10 @@ void process_script_question(LLMessageSystem *msg, void **user_data) // check whether cautions are even enabled or not if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) { + if (caution) + { + args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n\n" + script_question : ""; + } // display the caution permissions prompt LLNotificationsUtil::add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload); } @@ -6092,6 +6576,9 @@ void process_teleport_failed(LLMessageSystem *msg, void**) std::string big_reason; LLSD args; + // Let the interested parties know that teleport failed. + LLViewerParcelMgr::getInstance()->onTeleportFailed(); + // if we have additional alert data if (msg->has(_PREHASH_AlertInfo) && msg->getSizeFast(_PREHASH_AlertInfo, _PREHASH_Message) > 0) { @@ -6121,7 +6608,7 @@ void process_teleport_failed(LLMessageSystem *msg, void**) else { // change notification name in this special case - if (handle_special_notification("RegionEntryAccessBlocked", llsd_block)) + if (handle_teleport_access_blocked(llsd_block)) { if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) { @@ -6150,9 +6637,6 @@ void process_teleport_failed(LLMessageSystem *msg, void**) LLNotificationsUtil::add("CouldNotTeleportReason", args); - // Let the interested parties know that teleport failed. - LLViewerParcelMgr::getInstance()->onTeleportFailed(); - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) { gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); @@ -6341,7 +6825,6 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response) //*TODO please rewrite all keys to the same case, lower or upper payload["from_id"] = target_id; - payload["SUPPRESS_TOAST"] = true; LLNotificationsUtil::add("TeleportOfferSent", args, payload); // Add the recepient to the recent people list. @@ -6462,7 +6945,7 @@ void process_user_info_reply(LLMessageSystem* msg, void**) std::string dir_visibility; msg->getString( "UserData", "DirectoryVisibility", dir_visibility); - LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email); + LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email); LLFloaterSnapshot::setAgentEmail(email); } @@ -6790,12 +7273,14 @@ void process_covenant_reply(LLMessageSystem* msg, void**) LLPanelEstateCovenant::updateEstateName(estate_name); LLPanelLandCovenant::updateEstateName(estate_name); + LLPanelEstateInfo::updateEstateName(estate_name); LLFloaterBuyLand::updateEstateName(estate_name); std::string owner_name = LLSLURL("agent", estate_owner_id, "inspect").getSLURLString(); LLPanelEstateCovenant::updateEstateOwnerName(owner_name); LLPanelLandCovenant::updateEstateOwnerName(owner_name); + LLPanelEstateInfo::updateEstateOwnerName(owner_name); LLFloaterBuyLand::updateEstateOwnerName(owner_name); LLPanelPlaceProfile* panel = LLFloaterSidePanelContainer::getPanel<LLPanelPlaceProfile>("places", "panel_place_profile"); |