From 842d1b8d93fadc169f40d7a8b57640ae243bf921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Liru=20F=C3=A6rs?= Date: Tue, 25 Feb 2020 02:32:14 -0500 Subject: [PATCH] Add LLIMProcessing and support for new message caps! And UserInfo cap! Also delayed sound support! Fixed memory leaks and pass by values that LL likes to introduce. Extended LLCoroResponder to have a responder for Raw strings, also clean it Adds friend request message logging. --- indra/llmessage/llcororesponder.h | 32 +- indra/newview/CMakeLists.txt | 2 + indra/newview/llagent.cpp | 248 +- indra/newview/llagent.h | 22 +- indra/newview/llappviewer.cpp | 24 +- indra/newview/llfloaterpreference.cpp | 20 +- indra/newview/llfloaterpreference.h | 4 +- indra/newview/llfloaterworldmap.cpp | 4 +- indra/newview/llimprocessing.cpp | 2000 +++++++++++ indra/newview/llimprocessing.h | 68 + indra/newview/llprefsim.cpp | 27 +- indra/newview/llprefsim.h | 2 +- indra/newview/llviewermessage.cpp | 3085 +++++------------ indra/newview/llviewermessage.h | 6 +- indra/newview/llviewerregion.cpp | 5 + .../skins/default/xui/en-us/notifications.xml | 32 +- .../xui/en-us/panel_preferences_im.xml | 9 +- 17 files changed, 3221 insertions(+), 2369 deletions(-) create mode 100644 indra/newview/llimprocessing.cpp create mode 100644 indra/newview/llimprocessing.h diff --git a/indra/llmessage/llcororesponder.h b/indra/llmessage/llcororesponder.h index f65492942..bacec85a8 100644 --- a/indra/llmessage/llcororesponder.h +++ b/indra/llmessage/llcororesponder.h @@ -28,15 +28,35 @@ #include #include "llhttpclient.h" -struct LLCoroResponder final : public LLHTTPClient::ResponderWithCompleted +struct LLCoroResponderBase : public LLHTTPClient::ResponderWithCompleted +{ + const AIHTTPReceivedHeaders& getHeaders() const { return mReceivedHeaders; } + const LLSD& getContent() const { return mContent; } + + char const* getName() const override final { return "LLCoroResponder"; } +protected: + LLCoroResponderBase() {} +}; + +struct LLCoroResponder final : public LLCoroResponderBase { typedef std::function cb_t; - LLCoroResponder(const cb_t& cb) : mCB(cb) {} + LLCoroResponder(const cb_t& cb) : mCB(cb) {} void httpCompleted() override { mCB(*this); } - const AIHTTPReceivedHeaders& getHeaders() const { return mReceivedHeaders; } - const LLSD& getContent() const { return mContent; } - - char const* getName() const override { return "LLCoroResponder"; } +private: + const cb_t mCB; +}; + +struct LLCoroResponderRaw final : public LLCoroResponderBase +{ + typedef std::function cb_t; + LLCoroResponderRaw(const cb_t& cb) : mCB(cb) {} + void completedRaw(const LLChannelDescriptors& channels, const buffer_ptr_t& buffer) override + { + std::string content; + decode_raw_body(channels, buffer, content); + mCB(*this, content); + } private: const cb_t mCB; }; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 530d5f7dd..299fdfbcf 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -324,6 +324,7 @@ set(viewer_SOURCE_FILES llhudtext.cpp llhudview.cpp llimpanel.cpp + llimprocessing.cpp llimview.cpp llinventoryactions.cpp llinventorybridge.cpp @@ -867,6 +868,7 @@ set(viewer_HEADER_FILES llhudtext.h llhudview.h llimpanel.h + llimprocessing.h llimview.h llinventorybridge.h llinventoryclipboard.h diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 99153014d..ed765ff27 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -38,11 +38,14 @@ #include "llanimationstates.h" #include "llcallingcard.h" #include "llcapabilitylistener.h" +#include "llcororesponder.h" #include "llconsole.h" #include "llenvmanager.h" #include "llfirstuse.h" #include "llfloatercamera.h" #include "llfloatertools.h" +#include "llfloaterpostcard.h" +#include "llfloaterpreference.h" #include "llgroupactions.h" #include "llgroupmgr.h" #include "llhomelocationresponder.h" @@ -184,10 +187,10 @@ public: LLTeleportRequestViaLandmark(const LLUUID &pLandmarkId); virtual ~LLTeleportRequestViaLandmark(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); - virtual void restartTeleport(); + void startTeleport() override; + void restartTeleport() override; protected: inline const LLUUID &getLandmarkId() const {return mLandmarkId;}; @@ -196,15 +199,15 @@ private: LLUUID mLandmarkId; }; -class LLTeleportRequestViaLure : public LLTeleportRequestViaLandmark +class LLTeleportRequestViaLure final : public LLTeleportRequestViaLandmark { public: LLTeleportRequestViaLure(const LLUUID &pLureId, BOOL pIsLureGodLike); virtual ~LLTeleportRequestViaLure(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); + void startTeleport() override; protected: inline BOOL isLureGodLike() const {return mIsLureGodLike;}; @@ -219,10 +222,10 @@ public: LLTeleportRequestViaLocation(const LLVector3d &pPosGlobal); virtual ~LLTeleportRequestViaLocation(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); - virtual void restartTeleport(); + void startTeleport() override; + void restartTeleport() override; protected: inline const LLVector3d &getPosGlobal() const {return mPosGlobal;}; @@ -232,16 +235,16 @@ private: }; -class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation +class LLTeleportRequestViaLocationLookAt final : public LLTeleportRequestViaLocation { public: LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal); virtual ~LLTeleportRequestViaLocationLookAt(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); - virtual void restartTeleport(); + void startTeleport() override; + void restartTeleport() override; protected: @@ -258,12 +261,12 @@ const F32 LLAgent::TYPING_TIMEOUT_SECS = 5.f; std::map LLAgent::sTeleportErrorMessages; std::map LLAgent::sTeleportProgressMessages; -class LLAgentFriendObserver : public LLFriendObserver +class LLAgentFriendObserver final : public LLFriendObserver { public: - LLAgentFriendObserver() {} - virtual ~LLAgentFriendObserver() {} - virtual void changed(U32 mask); + LLAgentFriendObserver() = default; + virtual ~LLAgentFriendObserver() = default; + void changed(U32 mask) override; }; void LLAgentFriendObserver::changed(U32 mask) @@ -293,7 +296,7 @@ bool LLAgent::isActionAllowed(const LLSD& sdname) { bool allow_agent_voice = false; LLVoiceChannel* channel = LLVoiceChannel::getCurrentVoiceChannel(); - if (channel != NULL) + if (channel != nullptr) { if (channel->getSessionName().empty() && channel->getSessionID().isNull()) { @@ -2589,15 +2592,11 @@ void LLAgent::onAnimStop(const LLUUID& id) } else if (id == ANIM_AGENT_AWAY) { -// clearAFK(); // [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Added: RLVa-1.1.0g -#ifdef RLV_EXTENSION_CMD_ALLOWIDLE if (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) clearAFK(); -#else - clearAFK(); -#endif // RLV_EXTENSION_CMD_ALLOWIDLE // [/RLVa:KB] +// clearAFK(); } else if (id == ANIM_AGENT_STANDUP) { @@ -2668,7 +2667,7 @@ bool LLAgent::canAccessMaturityInRegion( U64 region_handle ) const return true; } -bool LLAgent::canAccessMaturityAtGlobal( LLVector3d pos_global ) const +bool LLAgent::canAccessMaturityAtGlobal(const LLVector3d& pos_global ) const { U64 region_handle = to_region_handle_global( pos_global.mdV[0], pos_global.mdV[1] ); return canAccessMaturityInRegion( region_handle ); @@ -2715,7 +2714,7 @@ int LLAgent::convertTextToMaturity(char text) return LLAgentAccess::convertTextToMaturity(text); } -class LLMaturityPreferencesResponder : public LLHTTPClient::ResponderWithResult +class LLMaturityPreferencesResponder final : public LLHTTPClient::ResponderWithResult { LOG_CLASS(LLMaturityPreferencesResponder); public: @@ -2723,12 +2722,10 @@ public: virtual ~LLMaturityPreferencesResponder(); protected: - virtual void httpSuccess(); - virtual void httpFailure(); - - /*virtual*/ char const* getName(void) const { return "LLMaturityPreferencesResponder"; } -protected: + void httpSuccess() override; + void httpFailure() override; + char const* getName() const override { return "LLMaturityPreferencesResponder"; } private: U8 parseMaturityFromServerResponse(const LLSD &pContent) const; @@ -2929,7 +2926,7 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity) boost::intrusive_ptr responderPtr = boost::intrusive_ptr(new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity)); // If we don't have a region, report it as an error - if (getRegion() == NULL) + if (getRegion() == nullptr) { responderPtr->failureResult(0U, "region is not defined", LLSD()); } @@ -3206,24 +3203,27 @@ void LLAgent::sendAnimationRequests(const uuid_vec_t &anim_ids, EAnimRequest req msg->addUUIDFast(_PREHASH_AgentID, getID()); msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); - for (U32 i = 0; i < anim_ids.size(); i++) + for (auto anim_id : anim_ids) { - if (anim_ids[i].isNull()) + if (anim_id.isNull()) { continue; } msg->nextBlockFast(_PREHASH_AnimationList); - msg->addUUIDFast(_PREHASH_AnimID, (anim_ids[i]) ); + msg->addUUIDFast(_PREHASH_AnimID, anim_id); msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE); num_valid_anims++; } + if (!num_valid_anims) + { + msg->clearMessage(); + return; + } msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList); - msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0); - if (num_valid_anims) - { - sendReliableMessage(); - } + msg->addBinaryDataFast(_PREHASH_TypeData, nullptr, 0); + + sendReliableMessage(); } void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request) @@ -3244,7 +3244,7 @@ void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request) msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE); msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList); - msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0); + msg->addBinaryDataFast(_PREHASH_TypeData, nullptr, 0); sendReliableMessage(); } @@ -3268,7 +3268,7 @@ void LLAgent::sendAnimationStateReset() msg->addBOOLFast(_PREHASH_StartAnim, FALSE); msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList); - msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0); + msg->addBinaryDataFast(_PREHASH_TypeData, nullptr, 0); sendReliableMessage(); } @@ -3507,8 +3507,8 @@ void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **) // Remove the group if it already exists remove it and add the new data to pick up changes. LLGroupData gd; gd.mID = group_id; - std::vector::iterator found_it = std::find(gAgent.mGroups.begin(), gAgent.mGroups.end(), gd); - if (found_it != gAgent.mGroups.end()) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), gd); + if (found_it != gAgent.mGroups.cend()) { gAgent.mGroups.erase(found_it); if (gAgent.getGroupID() == group_id) @@ -3534,12 +3534,12 @@ void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **) } } -class LLAgentDropGroupViewerNode : public LLHTTPNode +class LLAgentDropGroupViewerNode final : public LLHTTPNode { - virtual void post( + void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { if ( @@ -3566,11 +3566,8 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode //there is only one set of data in the AgentData block LLSD agent_data = body["AgentData"][0]; - LLUUID agent_id; - LLUUID group_id; - - agent_id = agent_data["AgentID"].asUUID(); - group_id = agent_data["GroupID"].asUUID(); + LLUUID agent_id = agent_data["AgentID"].asUUID(); + LLUUID group_id = agent_data["GroupID"].asUUID(); if (agent_id != gAgentID) { @@ -3585,8 +3582,8 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode // and add the new data to pick up changes. LLGroupData gd; gd.mID = group_id; - std::vector::iterator found_it = std::find(gAgent.mGroups.begin(), gAgent.mGroups.end(), gd); - if (found_it != gAgent.mGroups.end()) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), gd); + if (found_it != gAgent.mGroups.cend()) { gAgent.mGroups.erase(found_it); if (gAgent.getGroupID() == group_id) @@ -3657,8 +3654,8 @@ void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **) { need_floater_update = true; // Remove the group if it already exists remove it and add the new data to pick up changes. - std::vector::iterator found_it = std::find(gAgent.mGroups.begin(), gAgent.mGroups.end(), group); - if (found_it != gAgent.mGroups.end()) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), group); + if (found_it != gAgent.mGroups.cend()) { gAgent.mGroups.erase(found_it); } @@ -3672,12 +3669,12 @@ void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **) } -class LLAgentGroupDataUpdateViewerNode : public LLHTTPNode +class LLAgentGroupDataUpdateViewerNode final : public LLHTTPNode { - virtual void post( + void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { LLSD body = input["body"]; if(body.has("body")) @@ -3717,8 +3714,8 @@ class LLAgentGroupDataUpdateViewerNode : public LLHTTPNode { need_floater_update = true; // Remove the group if it already exists remove it and add the new data to pick up changes. - std::vector::iterator found_it = std::find(gAgent.mGroups.begin(), gAgent.mGroups.end(), group); - if (found_it != gAgent.mGroups.end()) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), group); + if (found_it != gAgent.mGroups.cend()) { gAgent.mGroups.erase(found_it); } @@ -3919,7 +3916,7 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void * return; } - if (gAgentAvatarp->isEditingAppearance()) + if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) { // ignore baked textures when in customize mode return; @@ -4050,6 +4047,7 @@ void LLAgent::clearVisualParams(void *data) // protected bool LLAgent::teleportCore(bool is_local) { + LL_INFOS("Teleport") << "In teleport core!" << LL_ENDL; if ((TELEPORT_NONE != mTeleportState) && (mTeleportState != TELEPORT_PENDING)) { LL_WARNS() << "Attempt to teleport when already teleporting." << LL_ENDL; @@ -4067,7 +4065,7 @@ bool LLAgent::teleportCore(bool is_local) // Stop all animation before actual teleporting if (isAgentAvatarValid()) { - for ( LLVOAvatar::AnimIterator anim_it= gAgentAvatarp->mPlayingAnimations.begin(); + for ( auto anim_it= gAgentAvatarp->mPlayingAnimations.begin(); anim_it != gAgentAvatarp->mPlayingAnimations.end(); ++anim_it) { @@ -4086,8 +4084,7 @@ bool LLAgent::teleportCore(bool is_local) LLFloaterWorldMap::hide(); // hide land floater too - it'll be out of date - if (LLFloaterLand::findInstance()) - LLFloaterLand::hideInstance(); + if (LLFloaterLand::findInstance()) LLFloaterLand::hideInstance(); LLViewerParcelMgr::getInstance()->deselectLand(); LLViewerMediaFocus::getInstance()->clearFocus(); @@ -4861,7 +4858,7 @@ void LLAgent::sendAgentSetAppearance() // This means the baked texture IDs on the server will be untouched. // Once all textures are baked, another AvatarAppearance message will be sent to update the TEs msg->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, NULL, 0); + gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, nullptr, 0); } @@ -4884,9 +4881,7 @@ void LLAgent::sendAgentSetAppearance() } LL_INFOS() << "Avatar XML num VisualParams transmitted = " << transmitted_params << LL_ENDL; - if(transmitted_params < 218) { - LLNotificationsUtil::add("SGIncompleteAppearance"); - } + if (transmitted_params < 218) LLNotificationsUtil::add("SGIncompleteAppearance"); sendReliableMessage(); } @@ -4901,8 +4896,96 @@ void LLAgent::sendAgentDataUpdateRequest() void LLAgent::sendAgentUserInfoRequest() { - if(getID().isNull()) + std::string cap; + + if (getID().isNull()) return; // not logged in + + if (mRegionp) + cap = mRegionp->getCapability("UserInfo"); + + if (!cap.empty()) + { + LLHTTPClient::get(cap, new LLCoroResponder( + boost::bind(&LLAgent::requestAgentUserInfoCoro, this, _1))); + } + else + { + sendAgentUserInfoRequestMessage(); + } +} + +void LLAgent::requestAgentUserInfoCoro(const LLCoroResponder& responder) +{ + const auto& result = responder.getContent(); + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("UserInfo") << "Failed to get user information: " << result["message"] << "Status " << status << " Reason: " << responder.getReason() << LL_ENDL; + return; + } + + bool im_via_email; + bool is_verified_email; + std::string email; + std::string dir_visibility; + + im_via_email = result["im_via_email"].asBoolean(); + is_verified_email = result["is_verified"].asBoolean(); + email = result["email"].asString(); + dir_visibility = result["directory_visibility"].asString(); + + // TODO: This should probably be changed. I'm not entirely comfortable + // having LLAgent interact directly with the UI in this way. + LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email, is_verified_email); + LLFloaterPostcard::updateUserInfo(email); +} + +void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility) +{ + std::string cap; + + if (getID().isNull()) + return; // not logged in + + if (mRegionp) + cap = mRegionp->getCapability("UserInfo"); + + if (!cap.empty()) + { + LLSD body(LLSDMap + ("dir_visibility", LLSD::String(directory_visibility)) + ("im_via_email", LLSD::Boolean(im_via_email))); + LLHTTPClient::post(cap, body, new LLCoroResponder( + boost::bind(&LLAgent::updateAgentUserInfoCoro, this, _1))); + } + else + { + sendAgentUpdateUserInfoMessage(im_via_email, directory_visibility); + } +} + + +void LLAgent::updateAgentUserInfoCoro(const LLCoroResponder& responder) +{ + const auto& result = responder.getContent(); + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("UserInfo") << "Failed to set user information." << LL_ENDL; + } + else if (!result["success"].asBoolean()) + { + LL_WARNS("UserInfo") << "Failed to set user information: " << result["message"] << LL_ENDL; + } +} + +// deprecated: +// May be removed when UserInfo cap propagates to all simhosts in grid +void LLAgent::sendAgentUserInfoRequestMessage() +{ gMessageSystem->newMessageFast(_PREHASH_UserInfoRequest); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); @@ -4910,6 +4993,21 @@ void LLAgent::sendAgentUserInfoRequest() sendReliableMessage(); } +void LLAgent::sendAgentUpdateUserInfoMessage(bool im_via_email, const std::string& directory_visibility) +{ + gMessageSystem->newMessageFast(_PREHASH_UpdateUserInfo); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_UserData); + gMessageSystem->addBOOLFast(_PREHASH_IMViaEMail, im_via_email); + gMessageSystem->addString("DirectoryVisibility", directory_visibility); + gAgent.sendReliableMessage(); + +} +// end deprecated +//------ + void LLAgent::observeFriends() { if(!mFriendObserver) @@ -4977,18 +5075,6 @@ const void LLAgent::getTeleportSourceSLURL(LLSLURL& slurl) const slurl = *mTeleportSourceSLURL; } -void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility ) -{ - gMessageSystem->newMessageFast(_PREHASH_UpdateUserInfo); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_UserData); - gMessageSystem->addBOOLFast(_PREHASH_IMViaEMail, im_via_email); - gMessageSystem->addString("DirectoryVisibility", directory_visibility); - gAgent.sendReliableMessage(); -} - void LLAgent::dumpGroupInfo() { LL_INFOS() << "group " << mGroupName << LL_ENDL; diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index e0bf928ae..6fd97b679 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -33,8 +33,6 @@ #ifndef LL_LLAGENT_H #define LL_LLAGENT_H -#include - #include "indra_constants.h" #include "llevent.h" // LLObservable base class #include "llagentconstants.h" @@ -46,7 +44,6 @@ #include "llinventorymodel.h" #include "v3dmath.h" -#include #include #include @@ -70,6 +67,7 @@ class LLAgentAccess; class LLSLURL; class LLSimInfo; class LLTeleportRequest; +struct LLCoroResponder; typedef boost::shared_ptr LLTeleportRequestPtr; @@ -100,7 +98,7 @@ struct LLGroupData //------------------------------------------------------------------------ // LLAgent //------------------------------------------------------------------------ -class LLAgent : public LLOldEvents::LLObservable +class LLAgent final : public LLOldEvents::LLObservable { LOG_CLASS(LLAgent); @@ -248,7 +246,7 @@ public: void changeParcels(); // called by LLViewerParcelMgr when we cross a parcel boundary // Register a boost callback to be called when the agent changes parcels - typedef boost::function parcel_changed_callback_t; + typedef std::function parcel_changed_callback_t; boost::signals2::connection addParcelChangedCallback(parcel_changed_callback_t); private: @@ -786,7 +784,7 @@ public: void requestEnterGodMode(); void requestLeaveGodMode(); - typedef boost::function god_level_change_callback_t; + typedef std::function god_level_change_callback_t; typedef boost::signals2::signal god_level_change_signal_t; typedef boost::signals2::connection god_level_change_slot_t; @@ -808,7 +806,7 @@ public: bool canAccessMature() const; bool canAccessAdult() const; bool canAccessMaturityInRegion( U64 region_handle ) const; - bool canAccessMaturityAtGlobal( LLVector3d pos_global ) const; + bool canAccessMaturityAtGlobal( const LLVector3d& pos_global ) const; bool prefersPG() const; bool prefersMature() const; bool prefersAdult() const; @@ -965,9 +963,17 @@ public: void sendAgentSetAppearance(); void sendAgentDataUpdateRequest(); void sendAgentUserInfoRequest(); - // IM to Email and Online visibility + +// IM to Email and Online visibility void sendAgentUpdateUserInfo(bool im_to_email, const std::string& directory_visibility); +private: + void requestAgentUserInfoCoro(const LLCoroResponder& responder); + void updateAgentUserInfoCoro(const LLCoroResponder& responder); + // DEPRECATED: may be removed when User Info cap propagates + void sendAgentUserInfoRequestMessage(); + void sendAgentUpdateUserInfoMessage(bool im_via_email, const std::string& directory_visibility); + //-------------------------------------------------------------------- // Receive //-------------------------------------------------------------------- diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6871500f0..77382fd07 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -47,6 +47,7 @@ #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" +#include "llimprocessing.h" #include "llwindow.h" #include "llviewerstats.h" #include "llmarketplacefunctions.h" @@ -430,27 +431,6 @@ static void ui_audio_callback(const LLUUID& uuid) } } -void request_initial_instant_messages() -{ - static BOOL requested = FALSE; - if (!requested - && gMessageSystem - && LLMuteList::getInstance()->isLoaded() - && isAgentAvatarValid()) - { - // Auto-accepted inventory items may require the avatar object - // to build a correct name. Likewise, inventory offers from - // muted avatars require the mute list to properly mute. - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RetrieveInstantMessages); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - requested = TRUE; - } -} - // Use these strictly for things that are constructed at startup, // or for things that are performance critical. JC static void settings_to_globals() @@ -4050,7 +4030,7 @@ void LLAppViewer::idle() // here. { LAZY_FT("request_initial_instant_messages"); - request_initial_instant_messages(); + LLIMProcessing::requestOfflineMessages(); } /////////////////////////////////// diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index bfdaf6abb..680fa258e 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -333,9 +333,9 @@ void LLPreferenceCore::onTabChanged(LLUICtrl* ctrl) } -void LLPreferenceCore::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLPreferenceCore::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { - mPrefsIM->setPersonalInfo(visibility, im_via_email, email); + mPrefsIM->setPersonalInfo(visibility, im_via_email, email, is_verified); } ////////////////////////////////////////////// @@ -408,15 +408,7 @@ void LLFloaterPreference::show(void*) sInstance->open(); /* Flawfinder: ignore */ - if(!gAgent.getID().isNull()) - { - // we're logged in, so we can get this info. - gMessageSystem->newMessageFast(_PREHASH_UserInfoRequest); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - } + gAgent.sendAgentUserInfoRequest(); LLPanelLogin::setAlwaysRefresh(true); } @@ -496,11 +488,11 @@ void LLFloaterPreference::onBtnCancel() // static -void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { - if(sInstance && sInstance->mPreferenceCore) + if (sInstance && sInstance->mPreferenceCore) { - sInstance->mPreferenceCore->setPersonalInfo(visibility, im_via_email, email); + sInstance->mPreferenceCore->setPersonalInfo(visibility, im_via_email, email, is_verified); } } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index e16f40cb6..4ee0053f2 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -73,7 +73,7 @@ public: LLTabContainer* getTabContainer() { return mTabContainer; } - void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); + void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified); static void onTabChanged(LLUICtrl* ctrl); @@ -109,7 +109,7 @@ public: static void show(void*); // static data update, called from message handler - static void updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email); + static void updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified = false); static void switchTab(S32 i); diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index caca3f627..6d2ce45a7 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -1656,8 +1656,6 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim) LLScrollListCtrl *list = getChild("search_results"); list->operateOnAll(LLCtrlListInterface::OP_DELETE); - S32 name_length = mCompletingRegionName.length(); - LLSD match; S32 num_results = 0; @@ -1671,7 +1669,7 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim) std::string sim_name_lower = info->getName(); LLStringUtil::toLower(sim_name_lower); - if (sim_name_lower.substr(0, name_length) == mCompletingRegionName) + if (sim_name_lower.substr(0, mCompletingRegionName) != std::string::npos) { if (sim_name_lower == mCompletingRegionName) { diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp new file mode 100644 index 000000000..af083f75f --- /dev/null +++ b/indra/newview/llimprocessing.cpp @@ -0,0 +1,2000 @@ +/** +* @file LLIMProcessing.cpp +* @brief Container for Instant Messaging +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llimprocessing.h" + +#include "hippofloaterxml.h" +#include "llagent.h" +#include "llagentui.h" +#include "llavataractions.h" +#include "llavatarnamecache.h" +#include "llbase64.h" +#include "llcororesponder.h" +#include "llfloaterchat.h" +#include "llgiveinventory.h" +#include "llgroupactions.h" +#include "llimpanel.h" +#include "llimview.h" +#include "llinventoryobserver.h" +#include "llmutelist.h" +#include "llnotificationsutil.h" +#include "llslurl.h" +#include "lltrans.h" +#include "llversioninfo.h" +#include "llviewergenericmessage.h" +#include "llviewerobjectlist.h" +#include "llviewermessage.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "llwindow.h" +#include "NACLantispam.h" +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvui.h" +// [/RLVa:KB] + +#include // +#include +#include +#include + +bool has_spam_bypass(bool is_friend, bool is_owned_by_me); + + +// Replace wild cards in message strings +std::string replace_wildcards(std::string input, const LLUUID& id, const std::string& name) +{ + boost::algorithm::replace_all(input, "#n", name); + + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + boost::algorithm::replace_all(input, "#r", slurl.getSLURLString()); + + LLAvatarName av_name; + boost::algorithm::replace_all(input, "#d", LLAvatarNameCache::get(id, &av_name) ? av_name.getDisplayName() : name); + + if (isAgentAvatarValid()) + { + LLStringUtil::format_map_t args; + args["[MINS]"] = boost::lexical_cast(gAgentAvatarp->mIdleTimer.getElapsedTimeF32()/60); + boost::algorithm::replace_all(input, "#i", LLTrans::getString("IM_autoresponse_minutes", args)); + } + + return input; +} + +void autoresponder_finish(bool show_autoresponded, const LLUUID& session_id, const LLUUID& from_id, const std::string& name, const LLUUID& itemid, bool is_muted) +{ + void cmdline_printchat(const std::string& message); + if (show_autoresponded) + { + const std::string notice(LLTrans::getString("IM_autoresponded_to") + ' ' + LLAvatarActions::getSLURL(from_id)); + is_muted ? cmdline_printchat(notice) : gIMMgr->addMessage(session_id, from_id, name, notice); + } + if (LLViewerInventoryItem* item = gInventory.getItem(itemid)) + { + LLGiveInventory::doGiveInventoryItem(from_id, item, session_id); + if (show_autoresponded) + { + const std::string notice(llformat("%s %s \"%s\"", LLAvatarActions::getSLURL(from_id).data(), LLTrans::getString("IM_autoresponse_sent_item").c_str(), item->getName().c_str())); + is_muted ? cmdline_printchat(notice) : gIMMgr->addMessage(session_id, from_id, name, notice); + } + } +} + +// defined in llchatbar.cpp, but not declared in any header +void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); + +void script_msg_api(const std::string& msg) +{ + static const LLCachedControl channel("ScriptMessageAPI"); + if (!channel) return; + static const LLCachedControl key("ScriptMessageAPIKey"); + std::string str; + for (size_t i = 0, keysize = key().size(); i != msg.size(); ++i) + str += msg[i] ^ key()[i%keysize]; + send_chat_from_viewer(LLBase64::encode(reinterpret_cast(str.c_str()), str.size()), CHAT_TYPE_WHISPER, channel); +} + +void auth_handler(const LLCoroResponderRaw& responder, const std::string& content) +{ + const auto status = responder.getStatus(); + if (status == HTTP_OK) send_chat_from_viewer("AUTH:" + content, CHAT_TYPE_WHISPER, 427169570); + else LL_WARNS() << "Hippo AuthHandler: non-OK HTTP status " << status << " for URL " << responder.getURL() << " (" << responder.getReason() << "). Error body: \"" << content << "\"." << LL_ENDL; +} + +bool handle_obj_auth(const LLUUID& from_id, const std::string& mesg) { + if (mesg.size() < 4 || mesg.substr(0, 3) != "># ") + return false; + + static std::set sChatObjectAuth; + if (mesg.size() >= 5 && mesg.substr(mesg.size()-3, 3) == " #<"){ + // hello from object + if (from_id.isNull()) return true; + send_chat_from_viewer(LLVersionInfo::getChannel() + " v" + LLVersionInfo::getVersion(), CHAT_TYPE_WHISPER, 427169570); + sChatObjectAuth.insert(from_id); + } + else if (from_id.isNull() || sChatObjectAuth.find(from_id) != sChatObjectAuth.end()) { + LLUUID key; + if (mesg.size() >= 39 && key.set(mesg.substr(3, 36), false)) { + // object command found + if (key.isNull() && mesg.size() == 39) { + // clear all nameplates + for (auto& pair : gObjectList.mUUIDAvatarMap) + if (auto& avatar = pair.second) + avatar->clearNameFromChat(); + } + else if (LLVOAvatar *avatar = key.isNull() ? nullptr : gObjectList.findAvatar(key)) { + if (mesg.size() == 39) avatar->clearNameFromChat(); + else if (mesg.size() > 40 && mesg[39] == ' ') + avatar->setNameFromChat(mesg.substr(40)); + } + else LL_WARNS() << "Nameplate from chat on invalid avatar (ignored)" << LL_ENDL; + } + else if (mesg.size() > 11 && mesg.substr(2, 9) == " floater ") + HippoFloaterXml::execute(mesg.substr(11)); + else if (mesg.size() > 8 && mesg.substr(2, 6) == " auth ") { + std::string authUrl = mesg.substr(8); + authUrl += (authUrl.find('?') != std::string::npos)? "&auth=": "?auth="; + authUrl += gAuthString; + LLHTTPClient::get(authUrl, new LLCoroResponderRaw(auth_handler)); + } + else return false; + } + else return false; + return true; +} + +// Strip out "Resident" for display, but only if the message came from a user +// (rather than a script) +static std::string clean_name_from_im(const std::string& name, EInstantMessage type) +{ + switch (type) + { + case IM_NOTHING_SPECIAL: + case IM_MESSAGEBOX: + case IM_GROUP_INVITATION: + case IM_INVENTORY_OFFERED: + case IM_INVENTORY_ACCEPTED: + case IM_INVENTORY_DECLINED: + case IM_GROUP_VOTE: + case IM_GROUP_MESSAGE_DEPRECATED: + //IM_TASK_INVENTORY_OFFERED + //IM_TASK_INVENTORY_ACCEPTED + //IM_TASK_INVENTORY_DECLINED + case IM_NEW_USER_DEFAULT: + case IM_SESSION_INVITE: + case IM_SESSION_P2P_INVITE: + case IM_SESSION_GROUP_START: + case IM_SESSION_CONFERENCE_START: + case IM_SESSION_SEND: + case IM_SESSION_LEAVE: + //IM_FROM_TASK + case IM_BUSY_AUTO_RESPONSE: + case IM_CONSOLE_AND_CHAT_HISTORY: + case IM_LURE_USER: + case IM_LURE_ACCEPTED: + case IM_LURE_DECLINED: + case IM_GODLIKE_LURE_USER: + case IM_TELEPORT_REQUEST: + case IM_GROUP_ELECTION_DEPRECATED: + //IM_GOTO_URL + //IM_FROM_TASK_AS_ALERT + case IM_GROUP_NOTICE: + case IM_GROUP_NOTICE_INVENTORY_ACCEPTED: + case IM_GROUP_NOTICE_INVENTORY_DECLINED: + case IM_GROUP_INVITATION_ACCEPT: + case IM_GROUP_INVITATION_DECLINE: + case IM_GROUP_NOTICE_REQUESTED: + case IM_FRIENDSHIP_OFFERED: + case IM_FRIENDSHIP_ACCEPTED: + case IM_FRIENDSHIP_DECLINED_DEPRECATED: + case IM_TYPING_START: + //IM_TYPING_STOP + return LLCacheName::cleanFullName(name); + default: + return name; + } +} + +static std::string clean_name_from_task_im(const std::string& msg, + BOOL from_group) +{ + boost::smatch match; + static const boost::regex returned_exp( + "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)"); + if (boost::regex_match(msg, match, returned_exp)) + { + // match objects are 1-based for groups + std::string final = match[1].str(); + std::string name = match[2].str(); + // Don't try to clean up group names + if (!from_group) + { + if (LLAvatarName::useDisplayNames()) + { + // ...just convert to username + final += LLCacheName::buildUsername(name); + } + else + { + // ...strip out legacy "Resident" name + final += LLCacheName::cleanFullName(name); + } + } + final += match[3].str(); + return final; + } + return msg; +} + +const std::string NOT_ONLINE_MSG("User not online - message will be stored and delivered later."); +const std::string NOT_ONLINE_INVENTORY("User not online - inventory has been saved."); +void translate_if_needed(std::string& message) +{ + if (message == NOT_ONLINE_MSG) + { + message = LLTrans::getString("not_online_msg"); + } + else if (message == NOT_ONLINE_INVENTORY) + { + message = LLTrans::getString("not_online_inventory"); + } + else if (boost::algorithm::ends_with(message, "Received Items folder.")) + { + boost::smatch match; + const boost::regex gift_exp("^You've received a gift! (.*) has given you \\\"(.*)\\\", and says \\\"(.*)\\\"\\. You can find your gift in your Received Items folder\\.$"); + bool gift = boost::regex_match(message, match, gift_exp); + if (gift || boost::regex_match(message, match, boost::regex("^Your purchase of (.*) has been delivered to your Received Items folder\\.$"))) + message = LLTrans::getString(gift ? "ReceivedGift" : "ReceivedPurchase", + gift ? LLSD().with("USER", match[1].str()).with("PRODUCT", match[2].str()).with("MESSAGE", match[3].str()) + : LLSD().with("PRODUCT", match[1].str())); + if (gSavedSettings.getBOOL("LiruReceivedItemsNotify")) LLNotificationsUtil::add("SystemMessage", LLSD().with("MESSAGE", message)); + } +} + +void inventory_offer_handler(LLOfferInfo* info, bool is_friend, bool is_owned_by_me) +{ + // NaCl - Antispam Registry + static const LLCachedControl no_landmarks("AntiSpamItemOffersLandmarks"); + auto antispam = NACLAntiSpamRegistry::getIfExists(); + if ((antispam && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_INVENTORY, info->mFromID, info->mFromGroup ? LFIDBearer::GROUP : LFIDBearer::AVATAR)) + || (!has_spam_bypass(is_friend, is_owned_by_me) + && (no_landmarks && info->mType == LLAssetType::AT_LANDMARK))) + { + delete info; + return; + } + // NaCl End + + // If muted, don't even go through the messaging stuff. Just curtail the offer here. + // Passing in a null UUID handles the case of where you have muted one of your own objects by_name. + // The solution for STORM-1297 seems to handle the cases where the object is owned by someone else. + if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName) || + LLMuteList::getInstance()->isMuted(LLUUID::null, info->mFromName)) + { + info->forceResponse(IOR_MUTE); + return; + } + + if (!info->mFromGroup) script_msg_api(info->mFromID.asString() + ", 1"); + + // If the user wants to, accept all offers of any kind + if (gSavedSettings.getBOOL("AutoAcceptAllNewInventory")) + { + info->forceResponse(IOR_ACCEPT); + return; + } + + // Avoid the Accept/Discard dialog if the user so desires. JC + if (gSavedSettings.getBOOL("AutoAcceptNewInventory") + && (info->mType == LLAssetType::AT_NOTECARD + || info->mType == LLAssetType::AT_LANDMARK + || info->mType == LLAssetType::AT_TEXTURE)) + { + // For certain types, just accept the items into the inventory, + // and possibly open them on receipt depending upon "ShowNewInventory". + info->forceResponse(IOR_ACCEPT); + return; + } + + if (gAgent.isDoNotDisturb() && info->mIM != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) + { + // Until throttling is implemented, busy mode should reject inventory instead of silently + // accepting it. SEE SL-39554 + info->forceResponse(IOR_DECLINE); + return; + } + + // 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; + + LLSD payload; + + // must protect against a NULL return from lookupHumanReadable() + std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType)); + if (!typestr.empty()) + { + // human readable matches string name from strings.xml + // lets get asset type localized name + args["OBJECTTYPE"] = LLTrans::getString(typestr); + } + else + { + LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL; + args["OBJECTTYPE"] = ""; + + // This seems safest, rather than propagating bogosity + LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL; + info->forceResponse(IOR_DECLINE); + return; + } + + // Name cache callbacks don't store userdata, so can't save + // off the LLOfferInfo. Argh. + payload["from_id"] = info->mFromID; + args["OBJECTFROMNAME"] = info->mFromName; + args["NAME"] = info->mFromName; + if (info->mFromGroup) + { + args["NAME"] = LLGroupActions::getSLURL(info->mFromID); + } + else + { + std::string full_name = LLAvatarActions::getSLURL(info->mFromID); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only filter if the object owner is a nearby agent + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) ) + { + full_name = RlvStrings::getAnonym(full_name); + } +// [/RLVa:KB] + args["NAME"] = full_name; + } + + + LLNotification::Params p("ObjectGiveItem"); + p.substitutions(args).payload(payload).functor(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2)); + + // Object -> Agent Inventory Offer + if (info->mFromObject) + { + p.name = "ObjectGiveItem"; + } + else // Agent -> Agent Inventory Offer + { +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only filter if the offer is from a nearby agent and if there's no open IM session (doesn't necessarily have to be focused) + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) && + (!RlvUIEnabler::hasOpenIM(info->mFromID)) ) + { + args["NAME"] = RlvStrings::getAnonym(info->mFromName); + } +// [/RLVa:KB] + p.name = "UserGiveItem"; + } + + LLNotifications::instance().add(p); +} + +// Callback for name resolution of a god/estate message +static void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message) +{ + LLSD args; + args["NAME"] = av_name.getNSName(); + args["MESSAGE"] = message; + LLNotificationsUtil::add("GodMessage", args); + + // Treat like a system message and put in chat history. + chat.mSourceType = CHAT_SOURCE_SYSTEM; + chat.mText = av_name.getNSName() + ": " + message; + + // Claim to be from a local agent so it doesn't go into console. + LLFloaterChat::addChat(chat, false, true); + +} + +static bool parse_lure_bucket(const std::string& bucket, + U64& region_handle, + LLVector3& pos, + LLVector3& look_at, + U8& region_access) +{ + // tokenize the bucket + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(bucket, sep); + tokenizer::iterator iter = tokens.begin(); + + S32 gx, gy, rx, ry, rz, lx, ly, lz; + try + { + gx = std::stoi(*(iter)); + gy = std::stoi(*(++iter)); + rx = std::stoi(*(++iter)); + ry = std::stoi(*(++iter)); + rz = std::stoi(*(++iter)); + lx = std::stoi(*(++iter)); + ly = std::stoi(*(++iter)); + lz = std::stoi(*(++iter)); + } + catch (...) + { + LL_WARNS("parse_lure_bucket") + << "Couldn't parse lure bucket." + << LL_ENDL; + return false; + } + + // Grab region access + region_access = SIM_ACCESS_MIN; + if (++iter != tokens.end()) + { + std::string access_str((*iter).c_str()); + LLStringUtil::trim(access_str); + if (access_str == "A") + { + region_access = SIM_ACCESS_ADULT; + } + else if (access_str == "M") + { + region_access = SIM_ACCESS_MATURE; + } + else if (access_str == "PG") + { + region_access = SIM_ACCESS_PG; + } + } + + pos.setVec((F32)rx, (F32)ry, (F32)rz); + look_at.setVec((F32)lx, (F32)ly, (F32)lz); + + region_handle = to_region_handle(gx, gy); + return true; +} + +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.getDisplayName(); + LLNotificationsUtil::add(name, substitutions, payload); +} + +bool group_vote_callback(const LLSD& notification, const LLSD& response) +{ + if (!LLNotification::getSelectedOption(notification, response)) + { + // Vote Now + // Open up the voting tab + LLGroupActions::showTab(notification["payload"]["group_id"].asUUID(), "voting_tab"); + } + return false; +} +static LLNotificationFunctorRegistration group_vote_callback_reg("GroupVote", group_vote_callback); + +void LLIMProcessing::processNewMessage(LLUUID from_id, + BOOL from_group, + LLUUID to_id, + U8 offline, + EInstantMessage dialog, // U8 + LLUUID session_id, + U32 timestamp, + std::string name, + std::string message, + U32 parent_estate_id, + LLUUID region_id, + LLVector3 position, + U8 *binary_bucket, + S32 binary_bucket_size, + LLHost &sender, + LLUUID aux_id) +{ + LLChat chat; + std::string buffer; + + // make sure that we don't have an empty or all-whitespace name + LLStringUtil::trim(name); + if (name.empty()) + { + 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); + + // + if (region_id.notNull()) + LL_INFOS() << "RegionID: " << region_id.asString() << LL_ENDL; + // + + bool is_do_not_disturb = gAgent.isDoNotDisturb(); + bool is_owned_by_me = false; + bool is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == nullptr) ? false : true; + bool accept_im_from_only_friend = gSavedSettings.getBOOL("InstantMessagesFriendsOnly"); + + chat.mFromID = from_id; + chat.mFromName = name; + chat.mSourceType = (from_id.isNull() || (name == SYSTEM_FROM)) ? CHAT_SOURCE_SYSTEM : + (dialog == IM_FROM_TASK && dialog == IM_FROM_TASK_AS_ALERT) ? CHAT_SOURCE_OBJECT : CHAT_SOURCE_AGENT; + + bool is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat) + // object IMs contain sender object id in session_id (STORM-1209) + || (chat.mSourceType == CHAT_SOURCE_OBJECT && LLMuteList::getInstance()->isMuted(session_id)); + + bool is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && + LLMuteList::getInstance()->isLinden(name); + chat.mMuted = is_muted && !is_linden; + + if (chat.mSourceType == CHAT_SOURCE_SYSTEM) + { // Translate server message if required (MAINT-6109) + translate_if_needed(message); + } + + LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing. + if (source || (source = gObjectList.findObject(from_id))) + { + is_owned_by_me = source->permYouOwner(); + } + + // NaCl - Antispam + bool is_spam_filtered(const EInstantMessage& dialog, bool is_friend, bool is_owned_by_me); + if (is_spam_filtered(dialog, is_friend, is_owned_by_me)) return; + // NaCl End + + 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'") + { + chat.mChatStyle = CHAT_STYLE_IRC; + separator_string = ""; + message_offset = 3; + } + + // These bools are here because they would make mess of logic down below in IM_NOTHING_SPECIAL. + static LLCachedControl sAutorespond(gSavedPerAccountSettings, "AutoresponseAnyone", false); + static LLCachedControl sAutorespondFriendsOnly(gSavedPerAccountSettings, "AutoresponseAnyoneFriendsOnly", false); + static LLCachedControl sAutorespondAway(gSavedPerAccountSettings, "AutoresponseOnlyIfAway", false); + static LLCachedControl sAutorespondNonFriend(gSavedPerAccountSettings, "AutoresponseNonFriends", false); + static LLCachedControl sAutorespondMuted(gSavedPerAccountSettings, "AutoresponseMuted", false); + static LLCachedControl sAutorespondRepeat(gSavedPerAccountSettings, "AscentInstantMessageResponseRepeat", false); + static LLCachedControl sFakeAway(gSavedSettings, "FakeAway", false); + bool autorespond_status = !sAutorespondAway || sFakeAway || gAgent.getAFK(); + bool is_autorespond = !is_muted && autorespond_status && (is_friend || !sAutorespondFriendsOnly) && sAutorespond; + bool is_autorespond_muted = is_muted && sAutorespondMuted; + bool is_autorespond_nonfriends = !is_friend && !is_muted && autorespond_status && sAutorespondNonFriend; + + LLSD args; + switch (dialog) + { + case IM_CONSOLE_AND_CHAT_HISTORY: + args["MESSAGE"] = message; + + // Note: don't put the message in the IM history, even though was sent + // via the IM mechanism. + LLNotificationsUtil::add("SystemMessageTip",args); + break; + + case IM_NOTHING_SPECIAL: // p2p IM + // Don't show dialog, just do IM + if (!gAgent.isGodlike() + && gAgent.getRegion()->isPrelude() + && to_id.isNull()) + { + // do nothing -- don't distract newbies in + // Prelude with global IMs + } +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0) + else if ( (rlv_handler_t::isEnabled()) && (offline == IM_ONLINE) && ("@version" == message) && + (!is_muted) && ((!accept_im_from_only_friend) || (is_friend)) ) + { + RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(), session_id); + // We won't receive a typing stop message, so do that manually (see comment at the end of LLFloaterIMPanel::sendMsg) + LLPointer im_info = new LLIMInfo(gMessageSystem); + gIMMgr->processIMTypingStop(im_info); + } +// [/RLVa:KB] + else if (offline == IM_ONLINE + && is_do_not_disturb + && !is_muted // Note: Never if muted + && from_id.notNull() //not a system message + && to_id.notNull() //not global message +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + && RlvActions::canReceiveIM(from_id)) +// [/RLVa:KB] + { + // now store incoming IM in chat history + buffer = separator_string + message.substr(message_offset); + + LL_INFOS("Messaging") << "session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + script_msg_api(from_id.asString() + ", 0"); + + // add to IM panel, but do not bother the user + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + name, + dialog, + parent_estate_id, + 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); + + if (sAutorespondRepeat || !gIMMgr->hasSession(session_id)) + { + // if the user wants to repeat responses over and over or + // if there is not a panel for this conversation (i.e. it is a new IM conversation + // initiated by the other party) then... + // 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) + send_do_not_disturb_message(gMessageSystem, from_id, session_id); + } + } + else if (offline == IM_ONLINE + && (is_autorespond || is_autorespond_nonfriends || is_autorespond_muted) + && from_id.notNull() //not a system message + && to_id.notNull() //not global message +// [RLVa:LF] - Same as above: Checked: 2010-11-30 (RLVa-1.3.0) + && RlvActions::canReceiveIM(from_id) && RlvActions::canSendIM(from_id)) +// [/RLVa:LF] + { + buffer = separator_string + message.substr(message_offset); + + LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + if (!is_muted) script_msg_api(from_id.asString() + ", 0"); + + bool send_response = !gIMMgr->hasSession(session_id) || sAutorespondRepeat; + + // add to IM panel, but do not bother the user + gIMMgr->addMessage(session_id, + from_id, + name, + buffer, + name, + dialog, + parent_estate_id, + 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 ); + + if (send_response) + { + // 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; + bool show_autoresponded = false; + LLUUID itemid; + if (is_muted) + { + response = gSavedPerAccountSettings.getString("AutoresponseMutedMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseMutedShow"); + } + else if (is_autorespond_nonfriends) + { + response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); + } + else if (is_autorespond) + { + response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); + } + pack_instant_message( + gMessageSystem, + gAgentID, + FALSE, + gAgentSessionID, + from_id, + my_name, + replace_wildcards(response, from_id, name), + IM_ONLINE, + IM_BUSY_AUTO_RESPONSE, + session_id); + gAgent.sendReliableMessage(); + + autoresponder_finish(show_autoresponded, session_id, from_id, name, itemid, is_muted); + } + } + 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); + } + else if (to_id.isNull()) + { + // Message to everyone from GOD, look up the fullname since + // server always slams name to legacy names + LLAvatarNameCache::get(from_id, boost::bind(god_message_name_cb, _2, chat, message)); + } + else + { + // standard message, not from system + bool mute_im = is_muted; + if (accept_im_from_only_friend && !is_friend && !is_linden) + { + if (!gIMMgr->isNonFriendSessionNotified(session_id)) + { + std::string message = LLTrans::getString("IM_unblock_only_groups_friends"); + gIMMgr->addMessage(session_id, from_id, name, message); + gIMMgr->addNotifiedNonFriendSessionID(session_id); + } + + mute_im = true; + } + + std::string saved; + if(offline == IM_OFFLINE) + { + LLStringUtil::format_map_t args; + args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); + saved = LLTrans::getString("Saved_message", args); + } + else if (!mute_im) script_msg_api(from_id.asString() + ", 0"); + buffer = separator_string + saved + message.substr(message_offset); + + LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + + // Muted nonfriend code moved up + +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + // Don't block offline IMs, or IMs from Lindens + if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!RlvActions::canReceiveIM(from_id)) && (!is_linden) ) + { + if (!mute_im) + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id); + buffer = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + } +// [/RLVa:KB] + + if (!mute_im || is_linden) + { + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + name, + dialog, + parent_estate_id, + region_id, + position, + true); + chat.mText = std::string("IM: ") + name + separator_string + saved + message.substr(message_offset); + LLFloaterChat::addChat(chat, true, false); + } + else + { + // 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; + LLFloaterChat::addChat(chat, true, true); + + // Autoresponse to muted avatars + if (!gIMMgr->isNonFriendSessionNotified(session_id) && sAutorespondMuted) + { + std::string my_name; + LLAgentUI::buildFullname(my_name); + pack_instant_message( + gMessageSystem, + gAgentID, + FALSE, + gAgentSessionID, + from_id, + my_name, + replace_wildcards(gSavedPerAccountSettings.getString("AutoresponseMutedMessage"), from_id, name), + IM_ONLINE, + IM_BUSY_AUTO_RESPONSE, + session_id); + gAgent.sendReliableMessage(); + autoresponder_finish(gSavedPerAccountSettings.getBOOL("AutoresponseMutedShow"), session_id, from_id, name, gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem") ? static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")) : LLUUID::null, true); + } + } + } + break; + + case IM_TYPING_START: + { + static LLCachedControl sNotifyIncomingMessage(gSavedSettings, "AscentInstantMessageAnnounceIncoming"); + // Don't announce that someone has started messaging, if they're muted or when in busy mode + if (sNotifyIncomingMessage && + !gIMMgr->hasSession(session_id) && + ((accept_im_from_only_friend && (is_friend || is_linden)) || + (!(is_muted || is_do_not_disturb))) + ) + { + LLAvatarName av_name; + std::string ns_name = LLAvatarNameCache::get(from_id, &av_name) ? av_name.getNSName() : name; + + gIMMgr->addMessage(session_id, + from_id, + name, + llformat("%s ", ns_name.c_str()) + LLTrans::getString("IM_announce_incoming"), + name, + IM_NOTHING_SPECIAL, + parent_estate_id, + region_id, + position, + false); + + + // This block is very similar to the one above, but is necessary, since a session is opened to announce incoming message.. + // In order to prevent doubling up on the first response, We neglect to send this if Repeat for each message is on. + if ((is_autorespond_nonfriends || is_autorespond) && !sAutorespondRepeat) + { + std::string my_name; + LLAgentUI::buildFullname(my_name); + std::string response; + bool show_autoresponded = false; + LLUUID itemid; + if (is_autorespond_nonfriends) + { + response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); + } + else if (is_autorespond) + { + response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); + } + pack_instant_message(gMessageSystem, gAgentID, false, gAgentSessionID, from_id, my_name, replace_wildcards(response, from_id, name), IM_ONLINE, IM_BUSY_AUTO_RESPONSE, session_id); + gAgent.sendReliableMessage(); + + autoresponder_finish(show_autoresponded, session_id, from_id, name, itemid, is_muted); + } + } + LLPointer im_info = new LLIMInfo(gMessageSystem); + gIMMgr->processIMTypingStart(im_info); + script_msg_api(from_id.asString() + ", 4"); + } + break; + + case IM_TYPING_STOP: + { + LLPointer im_info = new LLIMInfo(gMessageSystem); + gIMMgr->processIMTypingStop(im_info); + script_msg_api(from_id.asString() + ", 5"); + } + break; + + case IM_MESSAGEBOX: + { + // This is a block, modeless dialog. + args["MESSAGE"] = message; + LLNotificationsUtil::add("SystemMessageTip", args); + } + break; + case IM_GROUP_NOTICE: + case IM_GROUP_NOTICE_REQUESTED: + { + LL_INFOS("Messaging") << "Received IM_GROUP_NOTICE message." << LL_ENDL; + + LLUUID agent_id; + U8 has_inventory; + U8 asset_type = 0; + LLUUID group_id; + std::string item_name; + + if (aux_id.notNull()) + { + // aux_id contains group id, binary bucket contains name and asset type + group_id = aux_id; + has_inventory = binary_bucket_size > 1 ? TRUE : FALSE; + from_group = TRUE; // inaccurate value correction + if (has_inventory) + { + std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); + + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(str_bucket, sep); + tokenizer::iterator iter = tokens.begin(); + + asset_type = (LLAssetType::EType)(atoi((*(iter++)).c_str())); + iter++; // wearable type if applicable, otherwise asset type + item_name = std::string((*(iter++)).c_str()); + // Note There is more elements in 'tokens' ... + + + for (int i = 0; i < 6; i++) + { + LL_WARNS() << *(iter++) << LL_ENDL; + iter++; + } + } + } + else + { + // All info is in binary bucket, read it for more information. + struct notice_bucket_header_t + { + U8 has_inventory; + U8 asset_type; + LLUUID group_id; + }; + struct notice_bucket_full_t + { + struct notice_bucket_header_t header; + U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE]; + }*notice_bin_bucket; + + // Make sure the binary bucket is big enough to hold the header + // and a null terminated item name. + if ((binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8)))) + || (binary_bucket[binary_bucket_size - 1] != '\0')) + { + LL_WARNS("Messaging") << "Malformed group notice binary bucket" << LL_ENDL; + break; + } + + notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0]; + has_inventory = notice_bin_bucket->header.has_inventory; + asset_type = notice_bin_bucket->header.asset_type; + group_id = notice_bin_bucket->header.group_id; + item_name = ll_safe_string((const char*)notice_bin_bucket->item_name); + } + + if (group_id != from_id) + { + agent_id = from_id; + } + else + { + std::string::size_type index = original_name.find(" Resident"); + if (index != std::string::npos) + { + original_name = original_name.substr(0, index); + } + + // 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. + std::string legacy_name = gCacheName->buildLegacyName(original_name); + gCacheName->getUUID(legacy_name, agent_id); + + if (agent_id.isNull()) + { + LL_WARNS("Messaging") << "buildLegacyName returned null while processing " << original_name << LL_ENDL; + } + } + + if (agent_id.notNull() && LLMuteList::getInstance()->isMuted(agent_id)) + { + break; + } + + // If there is inventory, give the user the inventory offer. + LLOfferInfo* info = nullptr; + + if (has_inventory) + { + info = new LLOfferInfo(); + + info->mIM = IM_GROUP_NOTICE; + info->mFromID = from_id; + info->mFromGroup = true; + info->mFromObject = false; + info->mTransactionID = session_id; + info->mType = (LLAssetType::EType) asset_type; + info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); + info->mFromName = LLTrans::getString("AGroupMemberNamed", LLSD().with("GROUP_ID", group_id).with("FROM_ID", from_id)); + info->mDesc = item_name; + info->mHost = sender; + } + + // Tokenize the string. + // TODO: Support escaped tokens ("||" -> "|") + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(message, sep); + tokenizer::iterator iter = tokens.begin(); + + std::string subj(*iter++); + std::string mes(*iter++); + + // Send the notification down the new path. + // 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; + payload["sender_id"] = agent_id; + payload["group_id"] = group_id; + payload["inventory_name"] = item_name; + payload["received_time"] = LLDate::now(); + if (info && info->asLLSD()) + { + payload["inventory_offer"] = info->asLLSD(); + } + + LLSD args; + args["SUBJECT"] = subj; + args["MESSAGE"] = mes; + LLDate notice_date = LLDate(timestamp).notNull() ? LLDate(timestamp) : LLDate::now(); + LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).timestamp(notice_date)); + } + + // Also send down the old path for now. + if (IM_GROUP_NOTICE_REQUESTED == dialog) + { + LLGroupActions::showNotice(subj,mes,group_id,has_inventory,item_name,info); + } + else + { + delete info; + } + } + break; + case IM_GROUP_INVITATION: + { + if (!is_muted) + { + // group is not blocked, but we still need to check agent that sent the invitation + // and we have no agent's id + // Note: server sends username "first.last". + size_t 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 + { + is_muted |= (bool) LLMuteList::getInstance()->isMuted(agent_id); + } + } + //if (is_do_not_disturb || is_muted) + if (is_muted) return; + if (is_do_not_disturb) + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + + //if (!is_muted) + { + LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL; + // Read the binary bucket for more information. + struct invite_bucket_t + { + S32 membership_fee; + LLUUID role_id; + }* invite_bucket; + + // Make sure the binary bucket is the correct size. + if (binary_bucket_size != sizeof(invite_bucket_t)) + { + LL_WARNS("Messaging") << "Malformed group invite binary bucket" << LL_ENDL; + break; + } + + invite_bucket = (struct invite_bucket_t*) &binary_bucket[0]; + S32 membership_fee = ntohl(invite_bucket->membership_fee); + // NaCl - Antispam + if (membership_fee > 0 && gSavedSettings.getBOOL("AntiSpamGroupFeeInvites")) + return; + // NaCl End + + LLSD payload; + payload["transaction_id"] = session_id; + payload["group_id"] = from_group ? from_id : aux_id; + payload["name"] = name; + payload["message"] = message; + payload["fee"] = membership_fee; + payload["use_offline_cap"] = session_id.isNull() && (offline == IM_OFFLINE); + + LLSD args; + args["MESSAGE"] = message; + // we shouldn't pass callback functor since it is registered in LLFunctorRegistration + LLNotificationsUtil::add("JoinGroup", args, payload); + } + } + break; + + case IM_INVENTORY_OFFERED: + case IM_TASK_INVENTORY_OFFERED: + // Someone has offered us some inventory. + { + LLOfferInfo* info = new LLOfferInfo; + if (IM_INVENTORY_OFFERED == dialog) + { + struct offer_agent_bucket_t + { + S8 asset_type; + LLUUID object_id; + }* bucketp; + + 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; + info->mFromObject = FALSE; + } + else // IM_TASK_INVENTORY_OFFERED + { + if (offline == IM_OFFLINE && session_id.isNull() && aux_id.notNull() && binary_bucket_size > sizeof(S8)* 5) + { + // cap received offline message + std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(str_bucket, sep); + tokenizer::iterator iter = tokens.begin(); + + info->mType = (LLAssetType::EType)(atoi((*(iter++)).c_str())); + // Note There is more elements in 'tokens' ... + + info->mObjectID = LLUUID::null; + info->mFromObject = 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]; + info->mObjectID = LLUUID::null; + info->mFromObject = TRUE; + } + } + + info->mIM = dialog; + info->mFromID = from_id; + info->mFromGroup = from_group; + info->mTransactionID = session_id; + info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); + + info->mFromName = name; + info->mDesc = message; + info->mHost = sender; + //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) + if (IM_INVENTORY_OFFERED == dialog) + { + LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID); + fetch_item->startFetch(); + delete fetch_item; + // Same as closing window + info->forceResponse(IOR_DECLINE); + } + else + { + info->forceResponse(IOR_MUTE); + } + } + /* Singu Note: Handle this inside inventory_offer_handler so if the user wants to autoaccept offers, they can while busy. + // 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) + // Singu Note: We should use old logic + else if (is_do_not_disturb && dialog != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) + { + // Until throttling is implemented, do not disturb mode should reject inventory instead of silently + // accepting it. SEE SL-39554 + info->forceResponse(IOR_DECLINE); + } + */ + else + { + inventory_offer_handler(info, is_friend, is_owned_by_me); + } + } + break; + + case IM_INVENTORY_ACCEPTED: + { +// args["NAME"] = LLAvatarActions::getSLURL(from_id); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && + (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = (!fRlvFilterName) ? LLAvatarActions::getSLURL(from_id) : RlvStrings::getAnonym(name); +// [/RLVa:KB] + LLNotificationsUtil::add("InventoryAccepted", args); + break; + } + case IM_INVENTORY_DECLINED: + { +// args["NAME"] = LLAvatarActions::getSLURL(from_id); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && + (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = (!fRlvFilterName) ? LLAvatarActions::getSLURL(from_id) : RlvStrings::getAnonym(name); +// [/RLVa:KB] + LLNotificationsUtil::add("InventoryDeclined", args); + break; + } + // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856 + case IM_GROUP_VOTE: + { + LLSD args; + args["NAME"] = name; + args["MESSAGE"] = message; + + LLSD payload; + payload["group_id"] = session_id; + LLNotificationsUtil::add("GroupVote", args, payload); + } + break; + + case IM_GROUP_ELECTION_DEPRECATED: + { + LL_WARNS("Messaging") << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << LL_ENDL; + } + break; + + case IM_FROM_TASK: + { + if (is_do_not_disturb && !is_owned_by_me) + { + return; + } + chat.mText = name + separator_string + message.substr(message_offset); + chat.mFromName = name; + + // 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(); + } + + chat.mSourceType = CHAT_SOURCE_OBJECT; + + // 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; + chat.mSourceType = CHAT_SOURCE_SYSTEM; + } + else script_msg_api(chat.mFromID.asString() + ", 6"); + + // IDEVO Some messages have embedded resident names + message = clean_name_from_task_im(message, from_group); + + LLSD query_string; + query_string["owner"] = from_id; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if (rlv_handler_t::isEnabled()) + { + // NOTE: the chat message itself will be filtered in LLNearbyChatHandler::processChat() + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && (!from_group) && (RlvUtil::isNearbyAgent(from_id)) ) + { + query_string["rlv_shownames"] = TRUE; + + RlvUtil::filterNames(name); + chat.mFromName = name; + } + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + std::string::size_type idxPos = location.find('/'); + if ( (std::string::npos != idxPos) && (RlvUtil::isNearbyRegion(location.substr(0, idxPos))) ) + location = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + } + } +// [/RLVa:KB] + query_string["slurl"] = location; + query_string["name"] = name; + if (from_group) + { + query_string["groupowned"] = "true"; + } + +// chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); +// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + chat.mURL = LLSLURL("objectim", session_id, LLURI::mapToQueryString(query_string)).getSLURLString(); +// [/SL:KB] + chat.mText = name + separator_string + message.substr(message_offset); + + // Note: lie to Nearby Chat, pretending that this is NOT an IM, because + // IMs from objects don't open IM sessions. + LLFloaterChat::addChat(chat, FALSE, FALSE); + } + break; + + case IM_SESSION_SEND: // ad-hoc or group IMs + { + if (!is_linden && is_do_not_disturb) return; + + // Only show messages if we have a session open (which + // should happen after you get an "invitation" +// if ( !gIMMgr->hasSession(session_id) ) +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + LLFloaterIMPanel* pIMFloater = gIMMgr->findFloaterBySession(session_id); + if (!pIMFloater) + { + return; + } + + if (from_id != gAgentID && (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM) || gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM))) + { + switch (pIMFloater->getSessionType()) + { + case LLFloaterIMPanel::GROUP_SESSION: // Group chat + if (!RlvActions::canReceiveIM(session_id)) + return; + break; + case LLFloaterIMPanel::ADHOC_SESSION: // Conference chat + if (!RlvActions::canReceiveIM(from_id)) + message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + break; + default: + RLV_ASSERT(false); + return; + } + } +// [/RLVa:KB] + + // standard message, not from system + std::string saved; + if (offline == IM_OFFLINE) + { + LLStringUtil::format_map_t args; + args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); + saved = LLTrans::getString("Saved_message", args); + } + buffer = separator_string + saved + message.substr(message_offset); + + LL_DEBUGS("Messaging") << "standard message session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + ll_safe_string((char*)binary_bucket), + IM_SESSION_INVITE, + parent_estate_id, + region_id, + position, + true); + + std::string prepend_msg; + if (gAgent.isInGroup(session_id)&& gSavedSettings.getBOOL("OptionShowGroupNameInChatIM")) + { + prepend_msg = '['; + prepend_msg += std::string((char*)binary_bucket); + prepend_msg += "] "; + } + else + { + prepend_msg = std::string("IM: "); + } + chat.mText = prepend_msg + name + separator_string + saved + message.substr(message_offset); + LLFloaterChat::addChat(chat, TRUE, from_id == gAgentID); + + break; + } + case IM_FROM_TASK_AS_ALERT: + if (is_do_not_disturb && !is_owned_by_me) + { + return; + } + { + // Construct a viewer alert for this message. + args["NAME"] = name; + args["MESSAGE"] = message; + LLNotificationsUtil::add("ObjectMessage", args); + } + break; + case IM_BUSY_AUTO_RESPONSE: + if (is_muted) + { + LL_DEBUGS("Messaging") << "Ignoring do-not-disturb response from " << from_id << LL_ENDL; + return; + } + else + { + gIMMgr->addMessage(session_id, from_id, name, separator_string + message.substr(message_offset), name, dialog, parent_estate_id, region_id, position, true); + } + break; + + case IM_LURE_USER: + case IM_TELEPORT_REQUEST: + { + // [RLVa:KB] - Checked: RLVa-1.4.9 + // If we auto-accept the offer/request then this will override DnD status (but we'll still let the other party know later) + bool fRlvAutoAccept = (rlv_handler_t::isEnabled()) && + ( ((IM_LURE_USER == dialog) && (RlvActions::autoAcceptTeleportOffer(from_id))) || + ((IM_TELEPORT_REQUEST == dialog) && (RlvActions::autoAcceptTeleportRequest(from_id))) ); +// [/RLVa:KB] + + bool following = gAgent.getAutoPilotLeaderID() == from_id; + + if (!following && is_muted) + { + return; + } +// else if (!following && is_do_not_disturb) +// [RLVa:KB] - Checked: 2013-11-08 (RLVa-1.4.9) + else if (!following && is_do_not_disturb && !fRlvAutoAccept ) +// [/RLVa:KB] + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + else + { +// if (!following && is_do_not_disturb) +// [RLVa:KB] - Checked: RLVa-1.4.9 + if (!following && (is_do_not_disturb) && (!fRlvAutoAccept) ) +// [/RLVa:KB] + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + + 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; + + // Do not parse the (empty) lure bucket for TELEPORT_REQUEST + if (IM_TELEPORT_REQUEST != dialog && 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; + } + } + } + +// [RLVa:KB] - Checked: RLVa-1.4.9 + if (rlv_handler_t::isEnabled()) + { + if ( ((IM_LURE_USER == dialog) && (!RlvActions::canAcceptTpOffer(from_id))) || + ((IM_TELEPORT_REQUEST == dialog) && (!RlvActions::canAcceptTpRequest(from_id))) ) + { + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLUREREQ_REMOTE)); + if (is_do_not_disturb) + send_do_not_disturb_message(gMessageSystem, from_id); + return; + } + + // Censor message if: 1) restricted from receiving IMs from the sender, or 2) teleport offer/request and @showloc=n restricted + if ( (!RlvActions::canReceiveIM(from_id)) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (IM_LURE_USER == dialog || IM_TELEPORT_REQUEST == dialog)) ) + { + message = RlvStrings::getString(RLV_STRING_HIDDEN); + } + } +// [/RLVa:KB] + + LLSD args; + // *TODO: Translate -> [FIRST] [LAST] (maybe) + args["NAME"] = LLAvatarActions::getSLURL(from_id); + 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; + + /* Singu TODO: Figure if we should use these + if (!canUserAccessDstRegion) + { + LLNotification::Params params("TeleportOffered_MaturityBlocked"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add(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(params, from_id, false); + } + else + */ + { + /* Singu Note: No default constructor for LLNotification::Params + LLNotification::Params params; + if (IM_LURE_USER == dialog) + { + params.name = "TeleportOffered"; + params.functor_name = "TeleportOffered"; + } + else if (IM_TELEPORT_REQUEST == dialog) + { + params.name = "TeleportRequest"; + params.functor_name = "TeleportRequest"; + } + */ + LLNotification::Params params(IM_LURE_USER == dialog ? "TeleportOffered" : "TeleportRequest"); + params.substitutions = args; + params.payload = payload; + + if (following) + { + LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0); + } + else +// [RLVa:KB] - Checked: 20103-11-08 (RLVa-1.4.9) + if ( (rlv_handler_t::isEnabled()) && (fRlvAutoAccept) ) + { + if (IM_LURE_USER == dialog) + gRlvHandler.setCanCancelTp(false); + if (is_do_not_disturb) + send_do_not_disturb_message(gMessageSystem, from_id); + LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0); + } + else + { + LLNotifications::instance().add(params); + + // + if (IM_LURE_USER == dialog) + gAgent.showLureDestination(LLAvatarActions::getSLURL(from_id), region_handle, pos.mV[VX], pos.mV[VY], pos.mV[VZ]); + script_msg_api(from_id.asString().append(IM_LURE_USER == dialog ? ", 2" : ", 3")); + // + } +// [/RLVa:KB] +// LLNotifications::instance().add(params); + } + } + } + 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"] = LLAvatarActions::getSLURL(from_id); + 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(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(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: + { + LLSD args; + // n.b. this is for URLs sent by the system, not for + // URLs sent by scripts (i.e. llLoadURL) + if (binary_bucket_size <= 0) + { + LL_WARNS("Messaging") << "bad binary_bucket_size: " + << binary_bucket_size + << " - aborting function." << LL_ENDL; + return; + } + + std::string url; + + url.assign((char*)binary_bucket, binary_bucket_size-1); + args["MESSAGE"] = message; + args["URL"] = url; + LLSD payload; + payload["url"] = url; + LLNotificationsUtil::add("GotoURL", args, payload); + } + break; + + case IM_FRIENDSHIP_OFFERED: + { + LLSD payload; + payload["from_id"] = from_id; + payload["session_id"] = session_id; + payload["online"] = (offline == IM_ONLINE); + payload["sender"] = sender.getIPandPort(); + + if (is_muted) + { + LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); + } + else + { + if (is_do_not_disturb) + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + args["[NAME_SLURL]"] = LLAvatarActions::getSLURL(from_id); + if (message.empty()) + { + //support for frienship offers from clients before July 2008 + LLNotificationsUtil::add("OfferFriendshipNoMessage", args, payload); + } + else + { + args["[MESSAGE]"] = message; + LLNotificationsUtil::add("OfferFriendship", args, payload); + } + } + } + break; + + case IM_FRIENDSHIP_ACCEPTED: + { + // In the case of an offline IM, the formFriendship() may be extraneous + // as the database should already include the relationship. But it + // doesn't hurt for dupes. + LLAvatarTracker::formFriendship(from_id); + + std::vector strings; + strings.push_back(from_id.asString()); + send_generic_message("requestonlinenotification", strings); + + 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)); + } + break; + + case IM_FRIENDSHIP_DECLINED_DEPRECATED: + default: + LL_WARNS("Messaging") << "Instant message calling for unknown dialog " + << (S32)dialog << LL_ENDL; + break; + } + + LLWindow* viewer_window = gViewerWindow->getWindow(); + if (viewer_window && viewer_window->getMinimized() && gSavedSettings.getBOOL("LiruFlashWhenMinimized")) + { + viewer_window->flashIcon(5.f); + } +} + +void LLIMProcessing::requestOfflineMessages() +{ + static BOOL requested = FALSE; + if (!requested + && gMessageSystem + && LLMuteList::getInstance()->isLoaded() + && isAgentAvatarValid() + && gAgent.getRegion() + && gAgent.getRegion()->capabilitiesReceived()) + { + std::string cap_url = gAgent.getRegionCapability("ReadOfflineMsgs"); + + // Auto-accepted inventory items may require the avatar object + // to build a correct name. Likewise, inventory offers from + // muted avatars require the mute list to properly mute. + if (cap_url.empty() + || gAgent.getRegionCapability("AcceptFriendship").empty() + || gAgent.getRegionCapability("AcceptGroupInvite").empty()) + { + // Offline messages capability provides no session/transaction ids for message AcceptFriendship and IM_GROUP_INVITATION to work + // So make sure we have the caps before using it. + requestOfflineMessagesLegacy(); + } + else + { + LLHTTPClient::get(cap_url, new LLCoroResponder( + LLIMProcessing::requestOfflineMessagesCoro)); + } + requested = TRUE; + } +} + +void LLIMProcessing::requestOfflineMessagesCoro(const LLCoroResponder& responder) +{ + auto status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) // success = httpResults["success"].asBoolean(); + { + LL_WARNS("Messaging") << "Error requesting offline messages via capability " << responder.getURL() << ", Status: " << status << ", Reason: " << responder.getReason() << "\nFalling back to legacy method." << LL_ENDL; + + requestOfflineMessagesLegacy(); + return; + } + + const auto& contents = responder.getContent(); + + if (!contents.size()) + { + LL_WARNS("Messaging") << "No contents received for offline messages via capability " << responder.getURL() << LL_ENDL; + return; + } + + // Todo: once dirtsim-369 releases, remove one of the map/array options + LLSD messages; + if (contents.isArray()) + { + messages = *contents.beginArray(); + } + else if (contents.has("messages")) + { + messages = contents["messages"]; + } + else + { + LL_WARNS("Messaging") << "Invalid offline message content received via capability " << responder.getURL() << LL_ENDL; + return; + } + + if (!messages.isArray()) + { + LL_WARNS("Messaging") << "Invalid offline message content received via capability " << responder.getURL() << LL_ENDL; + return; + } + + if (messages.emptyArray()) + { + // Nothing to process + return; + } + + LL_INFOS("Messaging") << "Processing offline messages." << LL_ENDL; + + std::vector data; + S32 binary_bucket_size = 0; + LLHost sender = gAgent.getRegion()->getHost(); + + LLSD::array_iterator i = messages.beginArray(); + LLSD::array_iterator iEnd = messages.endArray(); + for (; i != iEnd; ++i) + { + const LLSD &message_data(*i); + + LLVector3 position(message_data["local_x"].asReal(), message_data["local_y"].asReal(), message_data["local_z"].asReal()); + data = message_data["binary_bucket"].asBinary(); + binary_bucket_size = data.size(); // message_data["count"] always 0 + U32 parent_estate_id = message_data.has("parent_estate_id") ? message_data["parent_estate_id"].asInteger() : 1; // 1 - IMMainland + + // Todo: once dirtsim-369 releases, remove one of the int/str options + BOOL from_group; + if (message_data["from_group"].isInteger()) + { + from_group = message_data["from_group"].asInteger(); + } + else + { + from_group = message_data["from_group"].asString() == "Y"; + } + + LLIMProcessing::processNewMessage(message_data["from_agent_id"].asUUID(), + from_group, + message_data["to_agent_id"].asUUID(), + IM_OFFLINE, + (EInstantMessage)message_data["dialog"].asInteger(), + LLUUID::null, // session id, since there is none we can only use frienship/group invite caps + message_data["timestamp"].asInteger(), + message_data["from_agent_name"].asString(), + message_data["message"].asString(), + parent_estate_id, + message_data["region_id"].asUUID(), + position, + &data[0], + binary_bucket_size, + sender, + message_data["asset_id"].asUUID()); // not necessarily an asset + } +} + +void LLIMProcessing::requestOfflineMessagesLegacy() +{ + LL_INFOS("Messaging") << "Requesting offline messages (Legacy)." << LL_ENDL; + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RetrieveInstantMessages); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); +} + diff --git a/indra/newview/llimprocessing.h b/indra/newview/llimprocessing.h new file mode 100644 index 000000000..dfe9aa0e1 --- /dev/null +++ b/indra/newview/llimprocessing.h @@ -0,0 +1,68 @@ +/** +* @file LLIMMgr.h +* @brief Container for Instant Messaging +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_LLIMPROCESSING_H +#define LL_LLIMPROCESSING_H + +#include "llinstantmessage.h" + +struct LLCoroResponder; + +std::string replace_wildcards(std::string input, const LLUUID& id, const std::string& name); +bool handle_obj_auth(const LLUUID& from_id, const std::string& mesg); + +class LLIMProcessing +{ +public: + // Pre-process message for IM manager + static void processNewMessage(LLUUID from_id, + BOOL from_group, + LLUUID to_id, + U8 offline, + EInstantMessage dialog, // U8 + LLUUID session_id, + U32 timestamp, + std::string agentName, + std::string message, + U32 parent_estate_id, + LLUUID region_id, + LLVector3 position, + U8 *binary_bucket, + S32 binary_bucket_size, + LLHost &sender, + LLUUID aux_id = LLUUID::null); + + // Either receives list of offline messages from 'ReadOfflineMsgs' capability + // or uses legacy method + static void requestOfflineMessages(); + +private: + static void requestOfflineMessagesCoro(const LLCoroResponder& responder); + static void requestOfflineMessagesLegacy(); +}; + + +#endif // LL_LLLLIMPROCESSING_H diff --git a/indra/newview/llprefsim.cpp b/indra/newview/llprefsim.cpp index 2f7faca75..8023cd1a3 100644 --- a/indra/newview/llprefsim.cpp +++ b/indra/newview/llprefsim.cpp @@ -63,7 +63,7 @@ public: void apply(); void cancel(); - void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); + void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified); void enableHistory(); static void onClickLogPath(void* user_data); @@ -193,13 +193,6 @@ void LLPrefsIMImpl::apply() if((new_im_via_email != mOriginalIMViaEmail) ||(new_hide_online != mOriginalHideOnlineStatus)) { - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_UpdateUserInfo); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_UserData); - msg->addBOOLFast(_PREHASH_IMViaEMail, new_im_via_email); // This hack is because we are representing several different // possible strings with a single checkbox. Since most users // can only select between 2 values, we represent it as a @@ -212,8 +205,7 @@ void LLPrefsIMImpl::apply() //Update showonline value, otherwise multiple applys won't work mOriginalHideOnlineStatus = new_hide_online; } - msg->addString("DirectoryVisibility", mDirectoryVisibility); - gAgent.sendReliableMessage(); + gAgent.sendAgentUpdateUserInfo(new_im_via_email, mDirectoryVisibility); } } else @@ -227,7 +219,7 @@ void LLPrefsIMImpl::apply() } } -void LLPrefsIMImpl::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLPrefsIMImpl::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { mGotPersonalInfo = true; mOriginalIMViaEmail = im_via_email; @@ -254,8 +246,13 @@ void LLPrefsIMImpl::setPersonalInfo(const std::string& visibility, bool im_via_e childSetValue("online_visibility", mOriginalHideOnlineStatus); childSetLabelArg("online_visibility", "[DIR_VIS]", mDirectoryVisibility); - childEnable("send_im_to_email"); - childSetValue("send_im_to_email", im_via_email); + if (auto child = getChildView("send_im_to_email")) + { + child->setValue(im_via_email); + child->setEnabled(is_verified); + if (!is_verified) + child->setToolTip(getString("email_unverified_tooltip")); + } childEnable("log_instant_messages"); childEnable("log_chat"); childEnable("log_instant_messages_timestamp"); @@ -332,9 +329,9 @@ void LLPrefsIM::cancel() impl.cancel(); } -void LLPrefsIM::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLPrefsIM::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { - impl.setPersonalInfo(visibility, im_via_email, email); + impl.setPersonalInfo(visibility, im_via_email, email, is_verified); } LLPanel* LLPrefsIM::getPanel() diff --git a/indra/newview/llprefsim.h b/indra/newview/llprefsim.h index 90bf4656a..7b7b3cefc 100644 --- a/indra/newview/llprefsim.h +++ b/indra/newview/llprefsim.h @@ -45,7 +45,7 @@ public: void apply(); void cancel(); - void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); + void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified); LLPanel* getPanel(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 52bcc9d4e..6f4825503 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -38,7 +38,7 @@ #include "llaudioengine.h" #include "llavataractions.h" #include "llavatarnamecache.h" -#include "llbase64.h" +#include "llcororesponder.h" #include "../lscript/lscript_byteformat.h" //Need LSCRIPTRunTimePermissionBits and SCRIPT_PERMISSION_* #include "lleconomy.h" #include "llfocusmgr.h" @@ -74,7 +74,7 @@ #include "llgroupactions.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" -#include "llimpanel.h" +#include "llimprocessing.h" #include "llinventorybridge.h" #include "llinventorymodel.h" #include "llinventorypanel.h" @@ -95,7 +95,6 @@ #include "llspeakers.h" #include "lltrans.h" #include "llviewerfoldertype.h" -#include "llviewergenericmessage.h" #include "llviewermenu.h" #include "llviewerinventory.h" #include "llviewerjoystick.h" @@ -134,12 +133,11 @@ #include "hippogridmanager.h" #include "hippolimits.h" -#include "hippofloaterxml.h" -#include "llversioninfo.h" #include "m7wlinterface.h" #include "llgiveinventory.h" +#include #include #if LL_WINDOWS // For Windows specific error handler @@ -225,15 +223,63 @@ constexpr bool SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = false, // ScriptReturnObjects }; +void accept_friendship_coro(const LLCoroResponder& responder, const LLSD& notification) +{ + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("Friendship") << "HTTP status " << status << ": " << responder.getReason() << + ". friendship offer accept failed." << LL_ENDL; + } + else + { + { + LLSD payload = notification["payload"]; + LL_DEBUGS("Friendship") << "Adding friend to list" << responder.getContent() << LL_ENDL; + // add friend to recent people list + //LLRecentPeople::instance().add(payload["from_id"]); + + LLNotificationsUtil::add("FriendshipAcceptedByMe", + notification["substitutions"], payload); + } + } +} + +void decline_friendship_coro(const LLCoroResponder& responder, const LLSD& notification, S32 option) +{ + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("Friendship") << "HTTP status " << status << ": " << responder.getReason() << + ". friendship offer decline failed." << LL_ENDL; + } + else + { + { + const auto& payload = notification["payload"]; + LL_DEBUGS("Friendship") << "Friendship declined" << responder.getContent() << LL_ENDL; + if (option == 1) + { + LLNotificationsUtil::add("FriendshipDeclinedByMe", + notification["substitutions"], payload); + } + else if (option == 2) + { + // start IM session + LLAvatarActions::startIM(payload["from_id"].asUUID()); + } + } + } +} + 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: @@ -244,38 +290,108 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) 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())); + std::string url = gAgent.getRegionCapability("AcceptFriendship"); + LL_DEBUGS("Friendship") << "Cap string: " << url << LL_ENDL; + if (!url.empty() && payload.has("online") && payload["online"].asBoolean() == false) + { + LL_DEBUGS("Friendship") << "Accepting friendship via capability" << LL_ENDL; + url += "?from=" + payload["from_id"].asString(); + url += "&agent_name=\"" + LLURI::escape(gAgentAvatarp->getFullname()) + '"'; + LLHTTPClient::post(url, LLSD(), new LLCoroResponder( + boost::bind(accept_friendship_coro, _1, notification))); + } + else if (payload.has("session_id") && payload["session_id"].asUUID().notNull()) + { + LL_DEBUGS("Friendship") << "Accepting friendship via viewer message" << LL_ENDL; + 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())); + + // add friend to recent people list + //LLRecentPeople::instance().add(payload["from_id"]); + LLNotificationsUtil::add("FriendshipAcceptedByMe", + notification["substitutions"], payload); + } + else + { + LL_WARNS("Friendship") << "Failed to accept friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; + } break; } - case 1: + case 1: // Decline + // fall-through + //case 3: // 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())); - break; - case 3: - // profile - LLAvatarActions::showProfile(payload["from_id"]); - LLNotificationsUtil::add(notification["name"], notification["substitutions"], payload); //Respawn! + std::string url = gAgent.getRegionCapability("DeclineFriendship"); + LL_DEBUGS("Friendship") << "Cap string: " << url << LL_ENDL; + if (!url.empty() && payload.has("online") && payload["online"].asBoolean() == false) + { + LL_DEBUGS("Friendship") << "Declining friendship via capability" << LL_ENDL; + url += "?from=" + payload["from_id"].asString(); + LLHTTPClient::del(url, new LLCoroResponder( + boost::bind(decline_friendship_coro, _1, notification, option))); + } + else if (payload.has("session_id") && payload["session_id"].asUUID().notNull()) + { + LL_DEBUGS("Friendship") << "Declining friendship via viewer message" << LL_ENDL; + 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())); + + if (option == 1) // due to fall-through + { + LLNotificationsUtil::add("FriendshipDeclinedByMe", + notification["substitutions"], payload); + } + /*else if (option == 3) + { + // start IM session + LLAvatarActions::startIM(payload["from_id"].asUUID()); + }*/ + } + else + { + LL_WARNS("Friendship") << "Failed to decline friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; + } + } default: // close button probably, possibly timed out break; } + // TODO: this set of calls has undesirable behavior under Windows OS (CHUI-985): + // here appears three additional toasts instead one modified + // need investigation and fix + + // LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); + // modified_form->setElementEnabled("Accept", false); + // modified_form->setElementEnabled("Decline", false); + // notification_ptr->updateForm(modified_form); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +// // Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell +// /*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel(); +// /*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification["id"].asUUID()) : NULL; +// if ( (!pToast) || (!pToast->getCanBeStored()) ) +// { +// [/SL:KB] +// notification_ptr->repost(); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +// } +// [/SL:KB] + return false; } @@ -288,25 +404,25 @@ static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("Offer void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group, S32 trx_type, const std::string& desc) { - if(0 == amount || !region) return; + if (0 == amount || !region) return; amount = abs(amount); - LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL; - if(can_afford_transaction(amount)) + LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")" << LL_ENDL; + if (can_afford_transaction(amount)) { -// gStatusBar->debitBalance(amount); + // gStatusBar->debitBalance(amount); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_MoneyTransferRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_MoneyData); - msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); msg->addUUIDFast(_PREHASH_DestID, uuid); msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group)); msg->addS32Fast(_PREHASH_Amount, amount); msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addS32Fast(_PREHASH_TransactionType, trx_type ); + msg->addS32Fast(_PREHASH_TransactionType, trx_type); msg->addStringFast(_PREHASH_Description, desc); msg->sendReliable(region->getHost()); } @@ -338,19 +454,19 @@ void process_logout_reply(LLMessageSystem* msg, void**) msg->getUUID("AgentData", "AgentID", agent_id); LLUUID session_id; msg->getUUID("AgentData", "SessionID", session_id); - if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID())) + if ((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID())) { LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL; } LLInventoryModel::update_map_t parents; - S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData ); - for(S32 i = 0; i < count; ++i) + S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + for (S32 i = 0; i < count; ++i) { LLUUID item_id; msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); - if( (1 == count) && item_id.isNull() ) + if ((1 == count) && item_id.isNull()) { // Detect dummy item. Indicates an empty list. break; @@ -359,8 +475,8 @@ void process_logout_reply(LLMessageSystem* msg, void**) // We do not need to track the asset ids, just account for an // updated inventory version. LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL; - LLInventoryItem* item = gInventory.getItem( item_id ); - if( item ) + LLInventoryItem* item = gInventory.getItem(item_id); + if (item) { parents[item->getParentUUID()] = 0; gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id); @@ -373,13 +489,13 @@ void process_logout_reply(LLMessageSystem* msg, void**) LLAppViewer::instance()->forceQuit(); } -void process_layer_data(LLMessageSystem *mesgsys, void **user_data) +void process_layer_data(LLMessageSystem* mesgsys, void** user_data) { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); + LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); LL_DEBUGS_ONCE("SceneLoadTiming") << "Received layer data" << LL_ENDL; - if(!regionp || gNoRender) + if (!regionp || gNoRender) { LL_WARNS() << "Invalid region for layer data." << LL_ENDL; return; @@ -402,9 +518,9 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data) << LL_ENDL; return; } - U8 *datap = new U8[size]; + U8* datap = new U8[size]; mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size); - LLVLData *vl_datap = new LLVLData(regionp, type, datap, size); + LLVLData* vl_datap = new LLVLData(regionp, type, datap, size); if (mesgsys->getReceiveCompressedSize()) { gVLManager.addLayerData(vl_datap, mesgsys->getReceiveCompressedSize()); @@ -417,7 +533,7 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data) void process_derez_ack(LLMessageSystem*, void**) { - if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); + if (gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); } void process_places_reply(LLMessageSystem* msg, void** data) @@ -429,7 +545,7 @@ void process_places_reply(LLMessageSystem* msg, void** data) { LLFloaterLandHoldings::processPlacesReply(msg, data); } - else if(gAgent.isInGroup(query_id)) + else if (gAgent.isInGroup(query_id)) { LLPanelGroupLandMoney::processPlacesReply(msg, data); } @@ -441,7 +557,7 @@ void process_places_reply(LLMessageSystem* msg, void** data) void send_sound_trigger(const LLUUID& sound_id, F32 gain) { - if (sound_id.isNull() || gAgent.getRegion() == NULL) + if (sound_id.isNull() || gAgent.getRegion() == nullptr) { // disconnected agent or zero guids don't get sent (no sound) return; @@ -452,9 +568,9 @@ void send_sound_trigger(const LLUUID& sound_id, F32 gain) msg->nextBlockFast(_PREHASH_SoundData); msg->addUUIDFast(_PREHASH_SoundID, sound_id); // Client untrusted, ids set on sim - msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null ); + msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null); + msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null); + msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null); msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle()); @@ -465,33 +581,163 @@ void send_sound_trigger(const LLUUID& sound_id, F32 gain) gAgent.sendMessage(); } +static LLSD sSavedGroupInvite; +static LLSD sSavedResponse; + +void response_group_invitation_coro(const LLCoroResponder& responder, const LLUUID& group_id, bool notify_and_update) +{ + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("GroupInvite") << "HTTP status " << status << ": " << responder.getReason() << + ". Group " << group_id << " invitation response processing failed." << LL_ENDL; + } + else + { + { + LL_DEBUGS("GroupInvite") << "Successfully sent response to group " << group_id << " invitation" << LL_ENDL; + if (notify_and_update) + { + LLNotificationsUtil::add("JoinGroupSuccess"); + gAgent.sendAgentDataUpdateRequest(); + + LLGroupMgr::getInstance()->clearGroupData(group_id); + // refresh the floater for this group, if any. + LLGroupActions::refresh(group_id); + } + } + } +} + +void send_join_group_response(const LLUUID& group_id, const LLUUID& transaction_id, bool accept_invite, S32 fee, bool use_offline_cap, LLSD& payload) +{ + if (accept_invite && fee > 0) + { + // If there is a fee to join this group, make + // sure the user is sure they want to join. + LLSD args; + args["COST"] = llformat("%d", fee); + // Set the fee for next time to 0, so that we don't keep + // asking about a fee. + LLSD next_payload = payload; + next_payload["fee"] = 0; + LLNotificationsUtil::add("JoinGroupCanAfford", + args, + next_payload); + } + else if (use_offline_cap) + { + std::string url; + if (accept_invite) + { + url = gAgent.getRegionCapability("AcceptGroupInvite"); + } + else + { + url = gAgent.getRegionCapability("DeclineGroupInvite"); + } + + if (!url.empty()) + { + LL_DEBUGS("GroupInvite") << "Capability url: " << url << LL_ENDL; + LLSD payload; + payload["group"] = group_id; + LLHTTPClient::post(url, payload, new LLCoroResponder( + boost::bind(response_group_invitation_coro, _1, group_id, accept_invite))); + } + else + { + // if sim has no this cap, we can do nothing - regular request will fail + LL_WARNS("GroupInvite") << "No capability, can't reply to offline invitation!" << LL_ENDL; + } + } + else + { + LL_DEBUGS("GroupInvite") << "Replying to group invite via IM message" << LL_ENDL; + + EInstantMessage type = accept_invite ? IM_GROUP_INVITATION_ACCEPT : IM_GROUP_INVITATION_DECLINE; + + send_improved_im(group_id, + std::string("name"), + std::string("message"), + IM_ONLINE, + type, + transaction_id); + } +} + +void send_join_group_response(const LLUUID& group_id, const LLUUID& transaction_id, bool accept_invite, S32 fee, bool use_offline_cap) +{ + LLSD payload; + if (accept_invite) + { + payload["group_id"] = group_id; + payload["transaction_id"] = transaction_id; + payload["fee"] = fee; + payload["use_offline_cap"] = use_offline_cap; + } + send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, payload); +} + bool join_group_response(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // A bit of variable saving and restoring is used to deal with the case where your group list is full and you + // receive an invitation to another group. The data from that invitation is stored in the sSaved + // variables. If you then drop a group and click on the Join button the stored data is restored and used + // to join the group. + LLSD notification_adjusted = notification; + LLSD response_adjusted = response; + + std::string action = notification["name"]; + + // Storing all the information by group id allows for the rare case of being at your maximum + // group count and receiving more than one invitation. + std::string id = notification_adjusted["payload"]["group_id"].asString(); + + if ("JoinGroup" == action || "JoinGroupCanAfford" == action) + { + sSavedGroupInvite[id] = notification; + sSavedResponse[id] = response; + } + else if ("JoinedTooManyGroupsMember" == action) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == opt) // Join button pressed + { + notification_adjusted = sSavedGroupInvite[id]; + response_adjusted = sSavedResponse[id]; + } + sSavedGroupInvite.erase(id); + sSavedResponse.erase(id); + } + + S32 option = LLNotificationsUtil::getSelectedOption(notification_adjusted, response_adjusted); bool accept_invite = false; - LLUUID group_id = notification["payload"]["group_id"].asUUID(); - LLUUID transaction_id = notification["payload"]["transaction_id"].asUUID(); - std::string name = notification["payload"]["name"].asString(); - std::string message = notification["payload"]["message"].asString(); - S32 fee = notification["payload"]["fee"].asInteger(); + LLUUID group_id = notification_adjusted["payload"]["group_id"].asUUID(); + LLUUID transaction_id = notification_adjusted["payload"]["transaction_id"].asUUID(); + std::string name = notification_adjusted["payload"]["name"].asString(); + std::string message = notification_adjusted["payload"]["message"].asString(); + S32 fee = notification_adjusted["payload"]["fee"].asInteger(); + U8 use_offline_cap = notification_adjusted["payload"]["use_offline_cap"].asInteger(); if (option == 2 && !group_id.isNull()) { LLGroupActions::show(group_id); LLSD args; args["MESSAGE"] = message; - LLNotificationsUtil::add("JoinGroup", args, notification["payload"]); + LLNotificationsUtil::add("JoinGroup", args, notification_adjusted["payload"]); return false; } - if(option == 0 && !group_id.isNull()) + if (option == 0 && !group_id.isNull()) { // check for promotion or demotion. S32 max_groups = gHippoLimits->getMaxAgentGroups(); - if(gAgent.isInGroup(group_id)) ++max_groups; + if (gAgent.isInGroup(group_id)) ++max_groups; - if((S32)gAgent.mGroups.size() < max_groups) + if ((S32)gAgent.mGroups.size() < max_groups) { accept_invite = true; } @@ -504,42 +750,10 @@ bool join_group_response(const LLSD& notification, const LLSD& response) return false; } } + send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, notification_adjusted["payload"]); - if (accept_invite) - { - // If there is a fee to join this group, make - // sure the user is sure they want to join. - if (fee > 0) - { - LLSD args; - args["COST"] = llformat("%d", fee); - // Set the fee for next time to 0, so that we don't keep - // asking about a fee. - LLSD next_payload = notification["payload"]; - next_payload["fee"] = 0; - LLNotificationsUtil::add("JoinGroupCanAfford", - args, - next_payload); - } - else - { - send_improved_im(group_id, - std::string("name"), - std::string("message"), - IM_ONLINE, - IM_GROUP_INVITATION_ACCEPT, - transaction_id); - } - } - else - { - send_improved_im(group_id, - std::string("name"), - std::string("message"), - IM_ONLINE, - IM_GROUP_INVITATION_DECLINE, - transaction_id); - } + sSavedGroupInvite[id] = LLSD::emptyMap(); + sSavedResponse[id] = LLSD::emptyMap(); return false; } @@ -548,12 +762,9 @@ static void highlight_inventory_objects_in_panel(const uuid_vec_t& items, LLInve { if (nullptr == inventory_panel) return; - for (auto item_iter = items.begin(); - item_iter != items.end(); - ++item_iter) + for (auto item_id : items) { - const LLUUID& item_id = (*item_iter); - if(!highlight_offered_object(item_id)) + if (!highlight_offered_object(item_id)) { continue; } @@ -648,7 +859,7 @@ public: { } - void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; } + void setMoveIntoFolderID(const LLUUID& into_folder_uuid) { mMoveIntoFolderID = into_folder_uuid; } private: /*virtual */ @@ -710,7 +921,7 @@ private: LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size() << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL; - return different_items.size() > 0; + return !different_items.empty(); } LLHandle mActivePanel; @@ -763,9 +974,7 @@ public: } } - virtual ~LLViewerInventoryMoveObserver() - { - } + virtual ~LLViewerInventoryMoveObserver() = default; void changed(U32 mask) override; @@ -784,7 +993,7 @@ void LLViewerInventoryMoveObserver::changed(U32 mask) return; } - if((mask & (LLInventoryObserver::STRUCTURE)) != 0) + if ((mask & (STRUCTURE)) != 0) { const uuid_set_t& changed_items = gInventory.getChangedIDs(); @@ -823,9 +1032,9 @@ protected: void done() override { uuid_vec_t added; - for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) + for (auto it : gInventory.getAddedIDs()) { - added.push_back(*it); + added.push_back(it); } for (uuid_vec_t::iterator it = added.begin(); it != added.end();) { @@ -856,7 +1065,7 @@ protected: open_inventory_offer(added, ""); } - }; +}; class LLOpenTaskGroupOffer final : public LLInventoryAddedObserver { @@ -865,9 +1074,9 @@ protected: void done() override { uuid_vec_t added; - for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) + for (auto it : gInventory.getAddedIDs()) { - added.push_back(*it); + added.push_back(it); } open_inventory_offer(added, "group_offer"); gInventory.removeObserver(this); @@ -964,11 +1173,11 @@ bool check_offer_throttle(const std::string& from_name, bool check_only) return gThrottleTimer.hasExpired(); } - if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME)) + if (gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME)) { LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL; - throttle_count=1; - throttle_logged=false; + throttle_count = 1; + throttle_logged = false; return true; } //has not expired @@ -985,8 +1194,8 @@ bool check_offer_throttle(const std::string& from_name, bool check_only) LLStringUtil::format_map_t arg; std::string log_msg; - std::ostringstream time ; - time<getSecondLifeTitle(); arg["TIME"] = time.str(); @@ -1005,7 +1214,7 @@ bool check_offer_throttle(const std::string& from_name, bool check_only) chat.mText = log_msg; LLFloaterChat::addChat(chat, FALSE, FALSE); - throttle_logged=true; + throttle_logged = true; } return false; } @@ -1027,17 +1236,14 @@ bool check_asset_previewable(const LLAssetType::EType asset_type) void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_name) { if (gAgent.isDoNotDisturb()) return; - for (uuid_vec_t::const_iterator obj_iter = objects.begin(); - obj_iter != objects.end(); - ++obj_iter) + for (auto obj_id : objects) { - const LLUUID& obj_id = (*obj_iter); - if(!highlight_offered_object(obj_id)) + if (!highlight_offered_object(obj_id)) { continue; } - const LLInventoryObject *obj = gInventory.getObject(obj_id); + const LLInventoryObject* obj = gInventory.getObject(obj_id); if (!obj) { LL_WARNS() << "Cannot find object [ itemID:" << obj_id << " ] to open." << LL_ENDL; @@ -1126,7 +1332,7 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam bool highlight_offered_object(const LLUUID& obj_id) { const LLInventoryObject* obj = gInventory.getObject(obj_id); - if(!obj) + if (!obj) { LL_WARNS("Messaging") << "Unable to show inventory item: " << obj_id << LL_ENDL; return false; @@ -1135,9 +1341,9 @@ bool highlight_offered_object(const LLUUID& obj_id) //////////////////////////////////////////////////////////////////////////////// // 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()) + if (!gAgent.getAFK()) { - const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); + const LLViewerInventoryCategory* parent = gInventory.getFirstNondefaultParent(obj_id); if (parent) { const LLFolderType::EType parent_type = parent->getPreferredType(); @@ -1578,7 +1784,6 @@ bool has_spam_bypass(bool is_friend, bool is_owned_by_me) return (antispam_not_mine && is_owned_by_me) || (antispam_not_friend && is_friend); } -void script_msg_api(const std::string& msg); bool is_spam_filtered(const EInstantMessage& dialog, bool is_friend, bool is_owned_by_me) { // First, check that this doesn't bypass. @@ -1639,160 +1844,6 @@ bool is_spam_filtered(const EInstantMessage& dialog, bool is_friend, bool is_own } } -void inventory_offer_handler(LLOfferInfo* info, bool is_friend, bool is_owned_by_me) -{ - // NaCl - Antispam Registry - static const LLCachedControl no_landmarks("AntiSpamItemOffersLandmarks"); - auto antispam = NACLAntiSpamRegistry::getIfExists(); - if ((antispam && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_INVENTORY, info->mFromID, info->mFromGroup ? LFIDBearer::GROUP : LFIDBearer::AVATAR)) - || (!has_spam_bypass(is_friend, is_owned_by_me) - && (no_landmarks && info->mType == LLAssetType::AT_LANDMARK))) - { - delete info; - return; - } - // NaCl End - //If muted, don't even go through the messaging stuff. Just curtail the offer here. - if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName)) - { - info->forceResponse(IOR_MUTE); - return; - } - - if (!info->mFromGroup) script_msg_api(info->mFromID.asString() + ", 1"); - - // If the user wants to, accept all offers of any kind - if (gSavedSettings.getBOOL("AutoAcceptAllNewInventory")) - { - info->forceResponse(IOR_ACCEPT); - return; - } - - // Avoid the Accept/Discard dialog if the user so desires. JC - if (gSavedSettings.getBOOL("AutoAcceptNewInventory") - && (info->mType == LLAssetType::AT_NOTECARD - || info->mType == LLAssetType::AT_LANDMARK - || info->mType == LLAssetType::AT_TEXTURE)) - { - // For certain types, just accept the items into the inventory, - // and possibly open them on receipt depending upon "ShowNewInventory". - info->forceResponse(IOR_ACCEPT); - return; - } - - if (gAgent.isDoNotDisturb() && info->mIM != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) - { - // Until throttling is implemented, busy mode should reject inventory instead of silently - // accepting it. SEE SL-39554 - info->forceResponse(IOR_DECLINE); - return; - } - - // 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; - - LLSD payload; - - // must protect against a NULL return from lookupHumanReadable() - std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType)); - if (!typestr.empty()) - { - // human readable matches string name from strings.xml - // lets get asset type localized name - args["OBJECTTYPE"] = LLTrans::getString(typestr); - } - else - { - LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL; - args["OBJECTTYPE"] = ""; - - // This seems safest, rather than propagating bogosity - LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL; - info->forceResponse(IOR_DECLINE); - return; - } - - // Name cache callbacks don't store userdata, so can't save - // off the LLOfferInfo. Argh. - payload["from_id"] = info->mFromID; - args["OBJECTFROMNAME"] = info->mFromName; - args["NAME"] = info->mFromName; - if (info->mFromGroup) - { - args["NAME"] = LLGroupActions::getSLURL(info->mFromID); - } - else - { - std::string full_name = LLAvatarActions::getSLURL(info->mFromID); -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only filter if the object owner is a nearby agent - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) ) - { - full_name = RlvStrings::getAnonym(full_name); - } -// [/RLVa:KB] - args["NAME"] = full_name; - } - - - LLNotification::Params p("ObjectGiveItem"); - p.substitutions(args).payload(payload).functor(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2)); - - // Object -> Agent Inventory Offer - if (info->mFromObject) - { - p.name = "ObjectGiveItem"; - } - else // Agent -> Agent Inventory Offer - { -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only filter if the offer is from a nearby agent and if there's no open IM session (doesn't necessarily have to be focused) - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) && - (!RlvUIEnabler::hasOpenIM(info->mFromID)) ) - { - args["NAME"] = RlvStrings::getAnonym(info->mFromName); - } -// [/RLVa:KB] - p.name = "UserGiveItem"; - } - - LLNotifications::instance().add(p); -} - - -bool group_vote_callback(const LLSD& notification, const LLSD& response) -{ - LLUUID group_id = notification["payload"]["group_id"].asUUID(); - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case 0: - // Vote Now - // Open up the voting tab - LLGroupActions::showTab(group_id, "voting_tab"); - break; - default: - // Vote Later or - // close button - break; - } - return false; -} -static LLNotificationFunctorRegistration group_vote_callback_reg("GroupVote", group_vote_callback); - bool lure_callback(const LLSD& notification, const LLSD& response) { S32 option = 0; @@ -1809,7 +1860,7 @@ bool lure_callback(const LLSD& notification, const LLSD& response) LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); BOOL godlike = notification["payload"]["godlike"].asBoolean(); - switch(option) + switch (option) { case 0: { @@ -1817,11 +1868,6 @@ bool lure_callback(const LLSD& notification, const LLSD& response) gAgent.teleportViaLure(lure_id, godlike); } break; - case 3: - // profile - LLAvatarActions::showProfile(from_id); - LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); //Respawn! - break; case 1: default: // decline @@ -1846,240 +1892,6 @@ bool goto_url_callback(const LLSD& notification, const LLSD& response) return false; } static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback); -static bool parse_lure_bucket(const std::string& bucket, - U64& region_handle, - LLVector3& pos, - LLVector3& look_at, - U8& region_access) -{ - // tokenize the bucket - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("|", "", boost::keep_empty_tokens); - tokenizer tokens(bucket, sep); - tokenizer::iterator iter = tokens.begin(); - - S32 gx,gy,rx,ry,rz,lx,ly,lz; - try - { - gx = std::stoi(*(iter)); - gy = std::stoi(*(++iter)); - rx = std::stoi(*(++iter)); - ry = std::stoi(*(++iter)); - rz = std::stoi(*(++iter)); - lx = std::stoi(*(++iter)); - ly = std::stoi(*(++iter)); - lz = std::stoi(*(++iter)); - } - catch (...) - { - LL_WARNS("parse_lure_bucket") - << "Couldn't parse lure bucket." - << LL_ENDL; - return false; - } - - // Grab region access - region_access = SIM_ACCESS_MIN; - if (++iter != tokens.end()) - { - std::string access_str((*iter).c_str()); - LLStringUtil::trim(access_str); - if ( access_str == "A" ) - { - region_access = SIM_ACCESS_ADULT; - } - else if ( access_str == "M" ) - { - region_access = SIM_ACCESS_MATURE; - } - else if ( access_str == "PG" ) - { - region_access = SIM_ACCESS_PG; - } - } - - pos.setVec((F32)rx, (F32)ry, (F32)rz); - look_at.setVec((F32)lx, (F32)ly, (F32)lz); - - region_handle = to_region_handle(gx, gy); - return true; -} - -// Strip out "Resident" for display, but only if the message came from a user -// (rather than a script) -static std::string clean_name_from_im(const std::string& name, EInstantMessage type) -{ - switch(type) - { - case IM_NOTHING_SPECIAL: - case IM_MESSAGEBOX: - case IM_GROUP_INVITATION: - case IM_INVENTORY_OFFERED: - case IM_INVENTORY_ACCEPTED: - case IM_INVENTORY_DECLINED: - case IM_GROUP_VOTE: - case IM_GROUP_MESSAGE_DEPRECATED: - //IM_TASK_INVENTORY_OFFERED - //IM_TASK_INVENTORY_ACCEPTED - //IM_TASK_INVENTORY_DECLINED - case IM_NEW_USER_DEFAULT: - case IM_SESSION_INVITE: - case IM_SESSION_P2P_INVITE: - case IM_SESSION_GROUP_START: - case IM_SESSION_CONFERENCE_START: - case IM_SESSION_SEND: - case IM_SESSION_LEAVE: - //IM_FROM_TASK - case IM_BUSY_AUTO_RESPONSE: - case IM_CONSOLE_AND_CHAT_HISTORY: - case IM_LURE_USER: - case IM_LURE_ACCEPTED: - case IM_LURE_DECLINED: - case IM_GODLIKE_LURE_USER: - case IM_TELEPORT_REQUEST: - case IM_GROUP_ELECTION_DEPRECATED: - //IM_GOTO_URL - //IM_FROM_TASK_AS_ALERT - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_INVENTORY_ACCEPTED: - case IM_GROUP_NOTICE_INVENTORY_DECLINED: - case IM_GROUP_INVITATION_ACCEPT: - case IM_GROUP_INVITATION_DECLINE: - case IM_GROUP_NOTICE_REQUESTED: - case IM_FRIENDSHIP_OFFERED: - case IM_FRIENDSHIP_ACCEPTED: - case IM_FRIENDSHIP_DECLINED_DEPRECATED: - case IM_TYPING_START: - //IM_TYPING_STOP - return LLCacheName::cleanFullName(name); - default: - return name; - } -} - -static std::string clean_name_from_task_im(const std::string& msg, - BOOL from_group) -{ - boost::smatch match; - static const boost::regex returned_exp( - "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)"); - if (boost::regex_match(msg, match, returned_exp)) - { - // match objects are 1-based for groups - std::string final = match[1].str(); - std::string name = match[2].str(); - // Don't try to clean up group names - if (!from_group) - { - if (LLAvatarName::useDisplayNames()) - { - // ...just convert to username - final += LLCacheName::buildUsername(name); - } - else - { - // ...strip out legacy "Resident" name - final += LLCacheName::cleanFullName(name); - } - } - final += match[3].str(); - return final; - } - return msg; -} - -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.getDisplayName(); - LLNotificationsUtil::add(name, substitutions, payload); -} - -// Callback for name resolution of a god/estate message -void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message) -{ - LLSD args; - args["NAME"] = av_name.getNSName(); - args["MESSAGE"] = message; - LLNotificationsUtil::add("GodMessage", args); - - // Treat like a system message and put in chat history. - chat.mText = av_name.getNSName() + ": " + message; - - // Claim to be from a local agent so it doesn't go into console. - LLFloaterChat::addChat(chat, false, true); - -} - -// Replace wild cards in message strings -std::string replace_wildcards(std::string input, const LLUUID& id, const std::string& name) -{ - boost::algorithm::replace_all(input, "#n", name); - - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - boost::algorithm::replace_all(input, "#r", slurl.getSLURLString()); - - LLAvatarName av_name; - boost::algorithm::replace_all(input, "#d", LLAvatarNameCache::get(id, &av_name) ? av_name.getDisplayName() : name); - - if (isAgentAvatarValid()) - { - LLStringUtil::format_map_t args; - args["[MINS]"] = boost::lexical_cast(gAgentAvatarp->mIdleTimer.getElapsedTimeF32()/60); - boost::algorithm::replace_all(input, "#i", LLTrans::getString("IM_autoresponse_minutes", args)); - } - - return input; -} - -void autoresponder_finish(bool show_autoresponded, const LLUUID& session_id, const LLUUID& from_id, const std::string& name, const LLUUID& itemid, bool is_muted) -{ - void cmdline_printchat(const std::string& message); - if (show_autoresponded) - { - const std::string notice(LLTrans::getString("IM_autoresponded_to") + ' ' + LLAvatarActions::getSLURL(from_id)); - is_muted ? cmdline_printchat(notice) : gIMMgr->addMessage(session_id, from_id, name, notice); - } - if (LLViewerInventoryItem* item = gInventory.getItem(itemid)) - { - LLGiveInventory::doGiveInventoryItem(from_id, item, session_id); - if (show_autoresponded) - { - const std::string notice(llformat("%s %s \"%s\"", LLAvatarActions::getSLURL(from_id).data(), LLTrans::getString("IM_autoresponse_sent_item").c_str(), item->getName().c_str())); - is_muted ? cmdline_printchat(notice) : gIMMgr->addMessage(session_id, from_id, name, notice); - } - } -} - -#include -const std::string NOT_ONLINE_MSG("User not online - message will be stored and delivered later."); -const std::string NOT_ONLINE_INVENTORY("User not online - inventory has been saved."); -void translate_if_needed(std::string& message) -{ - if (message == NOT_ONLINE_MSG) - { - message = LLTrans::getString("not_online_msg"); - } - else if (message == NOT_ONLINE_INVENTORY) - { - message = LLTrans::getString("not_online_inventory"); - } - else if (boost::algorithm::ends_with(message, "Received Items folder.")) - { - boost::smatch match; - const boost::regex gift_exp("^You've received a gift! (.*) has given you \\\"(.*)\\\", and says \\\"(.*)\\\"\\. You can find your gift in your Received Items folder\\.$"); - bool gift = boost::regex_match(message, match, gift_exp); - if (gift || boost::regex_match(message, match, boost::regex("^Your purchase of (.*) has been delivered to your Received Items folder\\.$"))) - message = LLTrans::getString(gift ? "ReceivedGift" : "ReceivedPurchase", - gift ? LLSD().with("USER", match[1].str()).with("PRODUCT", match[2].str()).with("MESSAGE", match[3].str()) - : LLSD().with("PRODUCT", match[1].str())); - if (gSavedSettings.getBOOL("LiruReceivedItemsNotify")) LLNotificationsUtil::add("SystemMessage", LLSD().with("MESSAGE", message)); - } -} void process_improved_im(LLMessageSystem *msg, void **user_data) { @@ -2094,26 +1906,24 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) U8 d = 0; LLUUID session_id; U32 timestamp; - std::string name; + std::string agentName; std::string message; U32 parent_estate_id = 0; LLUUID region_id; LLVector3 position; U8 binary_bucket[MTUBYTES]; S32 binary_bucket_size; - LLChat chat; - std::string buffer; // *TODO: Translate - need to fix the full name to first/last (maybe) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, from_id); msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, from_group); msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, to_id); - msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Offline, offline); - msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Dialog, d); + msg->getU8Fast(_PREHASH_MessageBlock, _PREHASH_Offline, offline); + msg->getU8Fast(_PREHASH_MessageBlock, _PREHASH_Dialog, d); msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id); - msg->getU32Fast( _PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp); + msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp); //msg->getData("MessageBlock", "Count", &count); - msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, name); + msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, agentName); msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message); // NaCl - Newline flood protection auto antispam = NACLAntiSpamRegistry::getIfExists(); @@ -2139,7 +1949,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id); msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id); msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position); - msg->getBinaryDataFast( _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES); + msg->getBinaryDataFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES); binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket); EInstantMessage dialog = (EInstantMessage)d; @@ -2149,1215 +1959,23 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) return; // NaCl End - // make sure that we don't have an empty or all-whitespace name - LLStringUtil::trim(name); - if (name.empty()) - { - 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); - - // - if (region_id.notNull()) - LL_INFOS() << "RegionID: " << region_id.asString() << LL_ENDL; - // - - bool is_do_not_disturb = gAgent.isDoNotDisturb(); - 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("InstantMessagesFriendsOnly"); - - chat.mFromID = from_id; - chat.mFromName = name; - chat.mSourceType = (from_id.isNull() || (name == std::string(SYSTEM_FROM))) ? CHAT_SOURCE_SYSTEM : - (dialog == IM_FROM_TASK && dialog == IM_FROM_TASK_AS_ALERT) ? CHAT_SOURCE_OBJECT : CHAT_SOURCE_AGENT; - - bool is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat) - // object IMs contain sender object id in session_id (STORM-1209) - || (chat.mSourceType == CHAT_SOURCE_OBJECT && LLMuteList::getInstance()->isMuted(session_id)); - - bool is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && - LLMuteList::getInstance()->isLinden(name); - chat.mMuted = is_muted && !is_linden; - - if(chat.mSourceType == CHAT_SOURCE_AGENT) - { - LLSD args; - args["NAME"] = name; - } - - // Singu TODO: LLIMProcessing goes here - if (chat.mSourceType == CHAT_SOURCE_SYSTEM) - { // Translate server message if required (MAINT-6109) - translate_if_needed(message); - } - - LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing. - if (source || (source = gObjectList.findObject(from_id))) - { - is_owned_by_me = source->permYouOwner(); - } - - // NaCl - Antispam - if (is_spam_filtered(dialog, is_friend, is_owned_by_me)) return; - // NaCl End - - 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'") - { - chat.mChatStyle = CHAT_STYLE_IRC; - separator_string = ""; - message_offset = 3; - } - - // These bools are here because they would make mess of logic down below in IM_NOTHING_SPECIAL. - static LLCachedControl sAutorespond(gSavedPerAccountSettings, "AutoresponseAnyone", false); - static LLCachedControl sAutorespondFriendsOnly(gSavedPerAccountSettings, "AutoresponseAnyoneFriendsOnly", false); - static LLCachedControl sAutorespondAway(gSavedPerAccountSettings, "AutoresponseOnlyIfAway", false); - static LLCachedControl sAutorespondNonFriend(gSavedPerAccountSettings, "AutoresponseNonFriends", false); - static LLCachedControl sAutorespondMuted(gSavedPerAccountSettings, "AutoresponseMuted", false); - static LLCachedControl sAutorespondRepeat(gSavedPerAccountSettings, "AscentInstantMessageResponseRepeat", false); - static LLCachedControl sFakeAway(gSavedSettings, "FakeAway", false); - bool autorespond_status = !sAutorespondAway || sFakeAway || gAgent.getAFK(); - bool is_autorespond = !is_muted && autorespond_status && (is_friend || !sAutorespondFriendsOnly) && sAutorespond; - bool is_autorespond_muted = is_muted && sAutorespondMuted; - bool is_autorespond_nonfriends = !is_friend && !is_muted && autorespond_status && sAutorespondNonFriend; - - LLSD args; - switch(dialog) - { - case IM_CONSOLE_AND_CHAT_HISTORY: - args["MESSAGE"] = message; - - // Note: don't put the message in the IM history, even though was sent - // via the IM mechanism. - LLNotificationsUtil::add("SystemMessageTip",args); - break; - - case IM_NOTHING_SPECIAL: // p2p IM - // Don't show dialog, just do IM - if (!gAgent.isGodlike() - && gAgent.getRegion()->isPrelude() - && to_id.isNull() ) - { - // do nothing -- don't distract newbies in - // Prelude with global IMs - } -// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0) - else if ( (rlv_handler_t::isEnabled()) && (offline == IM_ONLINE) && ("@version" == message) && - (!is_muted) && ((!accept_im_from_only_friend) || (is_friend)) ) - { - RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(), session_id); - // We won't receive a typing stop message, so do that manually (see comment at the end of LLFloaterIMPanel::sendMsg) - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStop(im_info); - } -// [/RLVa:KB] - else if (offline == IM_ONLINE - && is_do_not_disturb - && !is_muted // Note: Never if muted - && from_id.notNull() //not a system message - && to_id.notNull() //not global message -// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) - && RlvActions::canReceiveIM(from_id)) -// [/RLVa:KB] - { - // now store incoming IM in chat history - buffer = separator_string + message.substr(message_offset); - - LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - script_msg_api(from_id.asString() + ", 0"); - - // add to IM panel, but do not bother the user - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - name, - dialog, - parent_estate_id, - 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); - - if (sAutorespondRepeat || !gIMMgr->hasSession(session_id)) - { - // if the user wants to repeat responses over and over or - // if there is not a panel for this conversation (i.e. it is a new IM conversation - // initiated by the other party) then... - // 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) - send_do_not_disturb_message(msg, from_id, session_id); - } - } - else if (offline == IM_ONLINE - && (is_autorespond || is_autorespond_nonfriends || is_autorespond_muted) - && from_id.notNull() //not a system message - && to_id.notNull() //not global message -// [RLVa:LF] - Same as above: Checked: 2010-11-30 (RLVa-1.3.0) - && RlvActions::canReceiveIM(from_id) && RlvActions::canSendIM(from_id)) -// [/RLVa:LF] - { - buffer = separator_string + message.substr(message_offset); - - LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - if (!is_muted) script_msg_api(from_id.asString() + ", 0"); - - bool send_response = !gIMMgr->hasSession(session_id) || sAutorespondRepeat; - - // add to IM panel, but do not bother the user - gIMMgr->addMessage(session_id, - from_id, - name, - buffer, - name, - dialog, - parent_estate_id, - 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 ); - - if (send_response) - { - // 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; - bool show_autoresponded = false; - LLUUID itemid; - if (is_muted) - { - response = gSavedPerAccountSettings.getString("AutoresponseMutedMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseMutedShow"); - } - else if (is_autorespond_nonfriends) - { - response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); - } - else if (is_autorespond) - { - response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); - } - pack_instant_message( - gMessageSystem, - gAgentID, - FALSE, - gAgentSessionID, - from_id, - my_name, - replace_wildcards(response, from_id, name), - IM_ONLINE, - IM_BUSY_AUTO_RESPONSE, - session_id); - gAgent.sendReliableMessage(); - - autoresponder_finish(show_autoresponded, session_id, from_id, name, itemid, is_muted); - } - } - 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); - } - else if (to_id.isNull()) - { - // Message to everyone from GOD, look up the fullname since - // server always slams name to legacy names - LLAvatarNameCache::get(from_id, boost::bind(god_message_name_cb, _2, chat, message)); - } - else - { - // standard message, not from system - bool mute_im = is_muted; - if (accept_im_from_only_friend && !is_friend && !is_linden) - { - if (!gIMMgr->isNonFriendSessionNotified(session_id)) - { - std::string message = LLTrans::getString("IM_unblock_only_groups_friends"); - gIMMgr->addMessage(session_id, from_id, name, message); - gIMMgr->addNotifiedNonFriendSessionID(session_id); - } - - mute_im = true; - } - - std::string saved; - if(offline == IM_OFFLINE) - { - LLStringUtil::format_map_t args; - args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); - saved = LLTrans::getString("Saved_message", args); - } - else if (!mute_im) script_msg_api(from_id.asString() + ", 0"); - buffer = separator_string + saved + message.substr(message_offset); - - LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - - // Muted nonfriend code moved up - -// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) - // Don't block offline IMs, or IMs from Lindens - if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!RlvActions::canReceiveIM(from_id)) && (!is_linden) ) - { - if (!mute_im) - RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id); - buffer = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); - } -// [/RLVa:KB] - - if (!mute_im || is_linden) - { - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - name, - dialog, - parent_estate_id, - region_id, - position, - true); - chat.mText = std::string("IM: ") + name + separator_string + saved + message.substr(message_offset); - LLFloaterChat::addChat(chat, true, false); - } - else - { - // 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; - LLFloaterChat::addChat(chat, true, true); - - // Autoresponse to muted avatars - if (!gIMMgr->isNonFriendSessionNotified(session_id) && sAutorespondMuted) - { - std::string my_name; - LLAgentUI::buildFullname(my_name); - pack_instant_message( - gMessageSystem, - gAgentID, - FALSE, - gAgentSessionID, - from_id, - my_name, - replace_wildcards(gSavedPerAccountSettings.getString("AutoresponseMutedMessage"), from_id, name), - IM_ONLINE, - IM_BUSY_AUTO_RESPONSE, - session_id); - gAgent.sendReliableMessage(); - autoresponder_finish(gSavedPerAccountSettings.getBOOL("AutoresponseMutedShow"), session_id, from_id, name, gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem") ? static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")) : LLUUID::null, true); - } - } - } - break; - - case IM_TYPING_START: - { - static LLCachedControl sNotifyIncomingMessage(gSavedSettings, "AscentInstantMessageAnnounceIncoming"); - // Don't announce that someone has started messaging, if they're muted or when in busy mode - if (sNotifyIncomingMessage && - !gIMMgr->hasSession(session_id) && - ((accept_im_from_only_friend && (is_friend || is_linden)) || - (!(is_muted || is_do_not_disturb))) - ) - { - LLAvatarName av_name; - std::string ns_name = LLAvatarNameCache::get(from_id, &av_name) ? av_name.getNSName() : name; - - gIMMgr->addMessage(session_id, - from_id, - name, - llformat("%s ", ns_name.c_str()) + LLTrans::getString("IM_announce_incoming"), - name, - IM_NOTHING_SPECIAL, - parent_estate_id, - region_id, - position, - false); - - - // This block is very similar to the one above, but is necessary, since a session is opened to announce incoming message.. - // In order to prevent doubling up on the first response, We neglect to send this if Repeat for each message is on. - if ((is_autorespond_nonfriends || is_autorespond) && !sAutorespondRepeat) - { - std::string my_name; - LLAgentUI::buildFullname(my_name); - std::string response; - bool show_autoresponded = false; - LLUUID itemid; - if (is_autorespond_nonfriends) - { - response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); - } - else if (is_autorespond) - { - response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); - } - pack_instant_message(gMessageSystem, gAgentID, false, gAgentSessionID, from_id, my_name, replace_wildcards(response, from_id, name), IM_ONLINE, IM_BUSY_AUTO_RESPONSE, session_id); - gAgent.sendReliableMessage(); - - autoresponder_finish(show_autoresponded, session_id, from_id, name, itemid, is_muted); - } - } - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStart(im_info); - script_msg_api(from_id.asString() + ", 4"); - } - break; - - case IM_TYPING_STOP: - { - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStop(im_info); - script_msg_api(from_id.asString() + ", 5"); - } - break; - - case IM_MESSAGEBOX: - { - // This is a block, modeless dialog. - //*TODO: Translate - args["MESSAGE"] = message; - LLNotificationsUtil::add("SystemMessageTip", args); - } - break; - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_REQUESTED: - { - LL_INFOS("Messaging") << "Received IM_GROUP_NOTICE message." << LL_ENDL; - // Read the binary bucket for more information. - struct notice_bucket_header_t - { - U8 has_inventory; - U8 asset_type; - LLUUID group_id; - }; - struct notice_bucket_full_t - { - struct notice_bucket_header_t header; - U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE]; - }* notice_bin_bucket; - - // Make sure the binary bucket is big enough to hold the header - // and a null terminated item name. - if ( (binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8)))) - || (binary_bucket[binary_bucket_size - 1] != '\0') ) - { - LL_WARNS("Messaging") << "Malformed group notice binary bucket" << LL_ENDL; - 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. - size_t 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; - LLUUID group_id = notice_bin_bucket->header.group_id; - std::string item_name = ll_safe_string((const char*) notice_bin_bucket->item_name); - - // If there is inventory, give the user the inventory offer. - LLOfferInfo* info = nullptr; - - if (has_inventory) - { - info = new LLOfferInfo(); - - info->mIM = IM_GROUP_NOTICE; - info->mFromID = from_id; - info->mFromGroup = true; - info->mFromObject = false; - info->mTransactionID = session_id; - info->mType = (LLAssetType::EType) asset_type; - info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); - info->mFromName = LLTrans::getString("AGroupMemberNamed", LLSD().with("GROUP_ID", group_id).with("FROM_ID", from_id)); - info->mDesc = item_name; - info->mHost = msg->getSender(); - } - - std::string str(message); - - // Tokenize the string. - // TODO: Support escaped tokens ("||" -> "|") - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("|","",boost::keep_empty_tokens); - tokenizer tokens(str, sep); - tokenizer::iterator iter = tokens.begin(); - - std::string subj(*iter++); - std::string mes(*iter++); - - // Send the notification down the new path. - // 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; - payload["group_id"] = group_id; - payload["inventory_name"] = item_name; - if(info && info->asLLSD()) - { - payload["inventory_offer"] = info->asLLSD(); - } - - LLSD args; - args["SUBJECT"] = subj; - args["MESSAGE"] = mes; - LLDate notice_date = LLDate(timestamp).notNull() ? LLDate(timestamp) : LLDate::now(); - LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).timestamp(notice_date)); - } - - // Also send down the old path for now. - if (IM_GROUP_NOTICE_REQUESTED == dialog) - { - LLGroupActions::showNotice(subj,mes,group_id,has_inventory,item_name,info); - } - else - { - delete info; - } - } - break; - case IM_GROUP_INVITATION: - { - //if (is_do_not_disturb || is_muted) - if (is_muted) return; - if (is_do_not_disturb) - { - LLMessageSystem *msg = gMessageSystem; - send_do_not_disturb_message(msg,from_id); - } - else - { - LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL; - // Read the binary bucket for more information. - struct invite_bucket_t - { - S32 membership_fee; - LLUUID role_id; - }* invite_bucket; - - // Make sure the binary bucket is the correct size. - if (binary_bucket_size != sizeof(invite_bucket_t)) - { - LL_WARNS("Messaging") << "Malformed group invite binary bucket" << LL_ENDL; - break; - } - - invite_bucket = (struct invite_bucket_t*) &binary_bucket[0]; - S32 membership_fee = ntohl(invite_bucket->membership_fee); - // NaCl - Antispam - if (membership_fee > 0 && gSavedSettings.getBOOL("AntiSpamGroupFeeInvites")) - return; - // NaCl End - - LLSD payload; - payload["transaction_id"] = session_id; - payload["group_id"] = from_id; - payload["name"] = name; - payload["message"] = message; - payload["fee"] = membership_fee; - - LLSD args; - args["MESSAGE"] = message; - // we shouldn't pass callback functor since it is registered in LLFunctorRegistration - LLNotificationsUtil::add("JoinGroup", args, payload); - } - } - break; - - case IM_INVENTORY_OFFERED: - case IM_TASK_INVENTORY_OFFERED: - // Someone has offered us some inventory. - { - LLOfferInfo* info = new LLOfferInfo; - if (IM_INVENTORY_OFFERED == dialog) - { - struct offer_agent_bucket_t - { - S8 asset_type; - LLUUID object_id; - }* bucketp; - - 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; - info->mFromObject = FALSE; - } - else // IM_TASK_INVENTORY_OFFERED - { - 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]; - info->mObjectID = LLUUID::null; - info->mFromObject = TRUE; - } - - info->mIM = dialog; - info->mFromID = from_id; - info->mFromGroup = from_group; - info->mTransactionID = session_id; - info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); - - info->mFromName = name; - info->mDesc = message; - info->mHost = msg->getSender(); - //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) - LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID); - fetch_item->startFetch(); - delete fetch_item; - - // Same as closing window - info->forceResponse(IOR_DECLINE); - } - /* Singu Note: Handle this inside inventory_offer_handler so if the user wants to autoaccept offers, they can while busy. - // 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) - // Singu Note: We should use old logic - else if (is_do_not_disturb && dialog != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) - { - // Until throttling is implemented, do not disturb mode should reject inventory instead of silently - // accepting it. SEE SL-39554 - info->forceResponse(IOR_DECLINE); - } - */ - else - { - inventory_offer_handler(info, is_friend, is_owned_by_me); - } - } - break; - - case IM_INVENTORY_ACCEPTED: - { -// args["NAME"] = name; -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open - bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && - (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); - args["NAME"] = (!fRlvFilterName) ? name : RlvStrings::getAnonym(name); -// [/RLVa:KB] - LLNotificationsUtil::add("InventoryAccepted", args); - break; - } - case IM_INVENTORY_DECLINED: - { -// args["NAME"] = name; -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open - bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && - (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); - args["NAME"] = (!fRlvFilterName) ? name : RlvStrings::getAnonym(name); -// [/RLVa:KB] - LLNotificationsUtil::add("InventoryDeclined", args); - break; - } - // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856 - case IM_GROUP_VOTE: - { - LLSD args; - args["NAME"] = name; - args["MESSAGE"] = message; - - LLSD payload; - payload["group_id"] = session_id; - LLNotificationsUtil::add("GroupVote", args, payload); - } - break; - - case IM_GROUP_ELECTION_DEPRECATED: - { - LL_WARNS("Messaging") << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << LL_ENDL; - } - break; - - case IM_FROM_TASK: - { - if (is_do_not_disturb && !is_owned_by_me) - { - return; - } - chat.mText = name + separator_string + message.substr(message_offset); - chat.mFromName = name; - - // 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(); - } - - chat.mSourceType = CHAT_SOURCE_OBJECT; - - // 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; - chat.mSourceType = CHAT_SOURCE_SYSTEM; - } - else script_msg_api(chat.mFromID.asString() + ", 6"); - - // IDEVO Some messages have embedded resident names - message = clean_name_from_task_im(message, from_group); - - LLSD query_string; - query_string["owner"] = from_id; -// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f - if (rlv_handler_t::isEnabled()) - { - // NOTE: the chat message itself will be filtered in LLNearbyChatHandler::processChat() - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && (!from_group) && (RlvUtil::isNearbyAgent(from_id)) ) - { - query_string["rlv_shownames"] = TRUE; - - RlvUtil::filterNames(name); - chat.mFromName = name; - } - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) - { - std::string::size_type idxPos = location.find('/'); - if ( (std::string::npos != idxPos) && (RlvUtil::isNearbyRegion(location.substr(0, idxPos))) ) - location = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); - } - } -// [/RLVa:KB] - query_string["slurl"] = location; - query_string["name"] = name; - if (from_group) - { - query_string["groupowned"] = "true"; - } - -// chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); -// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a - chat.mURL = LLSLURL("objectim", session_id, LLURI::mapToQueryString(query_string)).getSLURLString(); -// [/SL:KB] - chat.mText = name + separator_string + message.substr(message_offset); - - // Note: lie to LLFloaterChat::addChat(), pretending that this is NOT an IM, because - // IMs from objects don't open IM sessions. - LLFloaterChat::addChat(chat, FALSE, FALSE); - } - break; - - case IM_SESSION_SEND: // ad-hoc or group IMs - { - if (!is_linden && is_do_not_disturb) return; - - // Only show messages if we have a session open (which - // should happen after you get an "invitation" -// if ( !gIMMgr->hasSession(session_id) ) -// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c - LLFloaterIMPanel* pIMFloater = gIMMgr->findFloaterBySession(session_id); - if (!pIMFloater) - { - return; - } - - if (from_id != gAgentID && (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM) || gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM))) - { - switch (pIMFloater->getSessionType()) - { - case LLFloaterIMPanel::GROUP_SESSION: // Group chat - if (!RlvActions::canReceiveIM(session_id)) - return; - break; - case LLFloaterIMPanel::ADHOC_SESSION: // Conference chat - if (!RlvActions::canReceiveIM(from_id)) - message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); - break; - default: - RLV_ASSERT(false); - return; - } - } -// [/RLVa:KB] - - // standard message, not from system - std::string saved; - if(offline == IM_OFFLINE) - { - LLStringUtil::format_map_t args; - args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); - saved = LLTrans::getString("Saved_message", args); - } - buffer = separator_string + saved + message.substr(message_offset); - - LL_DEBUGS("Messaging") << "standard message session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - ll_safe_string((char*)binary_bucket), - IM_SESSION_INVITE, - parent_estate_id, - region_id, - position, - true); - - std::string prepend_msg; - if (gAgent.isInGroup(session_id)&& gSavedSettings.getBOOL("OptionShowGroupNameInChatIM")) - { - prepend_msg = '['; - prepend_msg += std::string((char*)binary_bucket); - prepend_msg += "] "; - } - else - { - prepend_msg = std::string("IM: "); - } - chat.mText = prepend_msg + name + separator_string + saved + message.substr(message_offset); - LLFloaterChat::addChat(chat, TRUE, from_id == gAgentID); - - break; - } - case IM_FROM_TASK_AS_ALERT: - if (is_do_not_disturb && !is_owned_by_me) - { - return; - } - { - // Construct a viewer alert for this message. - args["NAME"] = name; - args["MESSAGE"] = message; - LLNotificationsUtil::add("ObjectMessage", args); - } - break; - case IM_BUSY_AUTO_RESPONSE: - if (is_muted) - { - LL_DEBUGS("Messaging") << "Ignoring do-not-disturb response from " << from_id << LL_ENDL; - return; - } - else - { - gIMMgr->addMessage(session_id, from_id, name, separator_string + message.substr(message_offset), name, dialog, parent_estate_id, region_id, position, true); - } - break; - - case IM_LURE_USER: - case IM_TELEPORT_REQUEST: - { -// [RLVa:KB] - Checked: 2013-11-08 (RLVa-1.4.9) - // If we auto-accept the offer/request then this will override DnD status (but we'll still let the other party know later) - bool fRlvAutoAccept = (rlv_handler_t::isEnabled()) && - ( ((IM_LURE_USER == dialog) && (RlvActions::autoAcceptTeleportOffer(from_id))) || - ((IM_TELEPORT_REQUEST == dialog) && (RlvActions::autoAcceptTeleportRequest(from_id))) ); -// [/RLVa:KB] - - bool following = gAgent.getAutoPilotLeaderID() == from_id; - - if (!following && is_muted) - { - return; - } -// else if (!following && is_do_not_disturb) -// [RLVa:KB] - Checked: 2013-11-08 (RLVa-1.4.9) - else if (!following && is_do_not_disturb && !fRlvAutoAccept ) -// [/RLVa:KB] - { - send_do_not_disturb_message(msg, from_id); - } - else - { - 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; - - // Do not parse the (empty) lure bucket for TELEPORT_REQUEST - if (IM_TELEPORT_REQUEST != dialog && 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; - } - } - } - -// [RLVa:KB] - Checked: 2013-11-08 (RLVa-1.4.9) - if (rlv_handler_t::isEnabled()) - { - if ( ((IM_LURE_USER == dialog) && (!RlvActions::canAcceptTpOffer(from_id))) || - ((IM_TELEPORT_REQUEST == dialog) && (!RlvActions::canAcceptTpRequest(from_id))) ) - { - RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLUREREQ_REMOTE)); - if (is_do_not_disturb) - send_do_not_disturb_message(msg, from_id); - return; - } - - // Censor lure message if: 1) restricted from receiving IMs from the sender, or 2) teleport offer and @showloc=n restricted - if ( (!RlvActions::canReceiveIM(from_id)) || ((IM_LURE_USER == dialog) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))) ) - { - message = RlvStrings::getString(RLV_STRING_HIDDEN); - } - } -// [/RLVa:KB] - - LLSD args; - // *TODO: Translate -> [FIRST] [LAST] (maybe) - args["NAME"] = LLAvatarActions::getSLURL(from_id); - 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; - - /* Singu TODO: Figure if we should use these - if (!canUserAccessDstRegion) - { - LLNotification::Params params("TeleportOffered_MaturityBlocked"); - params.substitutions = args; - params.payload = payload; - LLPostponedNotification::add( 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( params, from_id, false); - } - else - */ - { - /* Singu Note: No default constructor for LLNotification::Params - LLNotification::Params params; - if (IM_LURE_USER == dialog) - { - params.name = "TeleportOffered"; - params.functor_name = "TeleportOffered"; - } - else if (IM_TELEPORT_REQUEST == dialog) - { - params.name = "TeleportRequest"; - params.functor_name = "TeleportRequest"; - } - */ - LLNotification::Params params(IM_LURE_USER == dialog ? "TeleportOffered" : "TeleportRequest"); - params.substitutions = args; - params.payload = payload; - - if (following) - { - LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0); - } - else -// [RLVa:KB] - Checked: 20103-11-08 (RLVa-1.4.9) - if ( (rlv_handler_t::isEnabled()) && (fRlvAutoAccept) ) - { - if (IM_LURE_USER == dialog) - gRlvHandler.setCanCancelTp(false); - if (is_do_not_disturb) - send_do_not_disturb_message(msg, from_id); - LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0); - } - else - { - LLNotifications::instance().add(params); - - // - if (IM_LURE_USER == dialog) - gAgent.showLureDestination(LLAvatarActions::getSLURL(from_id), region_handle, pos.mV[VX], pos.mV[VY], pos.mV[VZ]); - script_msg_api(from_id.asString().append(IM_LURE_USER == dialog ? ", 2" : ", 3")); - // - } -// [/RLVa:KB] -// LLNotifications::instance().add(params); - } - } - } - 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"] = name; - 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; - - // 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: - { - LLSD args; - // n.b. this is for URLs sent by the system, not for - // URLs sent by scripts (i.e. llLoadURL) - if (binary_bucket_size <= 0) - { - LL_WARNS("Messaging") << "bad binary_bucket_size: " - << binary_bucket_size - << " - aborting function." << LL_ENDL; - return; - } - - std::string url; - - url.assign((char*)binary_bucket, binary_bucket_size-1); - args["MESSAGE"] = message; - args["URL"] = url; - LLSD payload; - payload["url"] = url; - LLNotificationsUtil::add("GotoURL", args, payload ); - } - break; - - case IM_FRIENDSHIP_OFFERED: - { - LLSD payload; - payload["from_id"] = from_id; - payload["session_id"] = session_id; - payload["online"] = (offline == IM_ONLINE); - payload["sender"] = msg->getSender().getIPandPort(); - - 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]"] = name; - if(message.empty()) - { - //support for frienship offers from clients before July 2008 - LLNotificationsUtil::add("OfferFriendshipNoMessage", args, payload); - } - else - { - args["[MESSAGE]"] = message; - LLNotificationsUtil::add("OfferFriendship", args, payload); - } - } - } - break; - - case IM_FRIENDSHIP_ACCEPTED: - { - // In the case of an offline IM, the formFriendship() may be extraneous - // as the database should already include the relationship. But it - // doesn't hurt for dupes. - LLAvatarTracker::formFriendship(from_id); - - std::vector strings; - strings.push_back(from_id.asString()); - send_generic_message("requestonlinenotification", strings); - - 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)); - } - break; - - case IM_FRIENDSHIP_DECLINED_DEPRECATED: - default: - LL_WARNS("Messaging") << "Instant message calling for unknown dialog " - << (S32)dialog << LL_ENDL; - break; - } - - LLWindow* viewer_window = gViewerWindow->getWindow(); - if (viewer_window && viewer_window->getMinimized() && gSavedSettings.getBOOL("LiruFlashWhenMinimized")) - { - viewer_window->flashIcon(5.f); - } + LLHost sender = msg->getSender(); + + LLIMProcessing::processNewMessage(from_id, + from_group, + to_id, + offline, + dialog, + session_id, + timestamp, + agentName, + message, + parent_estate_id, + region_id, + position, + binary_bucket, + binary_bucket_size, + sender); } void send_do_not_disturb_message(LLMessageSystem* msg, const LLUUID& from_id, const LLUUID& session_id) @@ -3399,9 +2017,8 @@ bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLUUID fid; - LLUUID from_id; LLMessageSystem* msg = gMessageSystem; - switch(option) + switch (option) { case 0: // accept @@ -3434,6 +2051,7 @@ bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) return false; } + static LLNotificationFunctorRegistration callingcard_offer_cb_reg("OfferCallingCard", callingcard_offer_callback); void process_offer_callingcard(LLMessageSystem* msg, void**) @@ -3465,7 +2083,7 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) LLViewerObject* source = gObjectList.findObject(source_id); LLSD args; std::string source_name; - if(source && source->isAvatar()) + if (source && source->isAvatar()) { LLNameValue* nvfirst = source->getNVPair("FirstName"); LLNameValue* nvlast = source->getNVPair("LastName"); @@ -3476,7 +2094,7 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) } } - if(!source_name.empty()) + if (!source_name.empty()) { if (gAgent.isDoNotDisturb() || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat)) @@ -3590,42 +2208,7 @@ void check_translate_chat(const std::string &mesg, LLChat &chat, const bool hist } #endif -// defined in llchatbar.cpp, but not declared in any header -void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); - -void script_msg_api(const std::string& msg) -{ - static const LLCachedControl channel("ScriptMessageAPI"); - if (!channel) return; - static const LLCachedControl key("ScriptMessageAPIKey"); - std::string str; - for (size_t i = 0, keysize = key().size(); i != msg.size(); ++i) - str += msg[i] ^ key()[i%keysize]; - send_chat_from_viewer(LLBase64::encode(reinterpret_cast(str.c_str()), str.size()), CHAT_TYPE_WHISPER, channel); -} - -class AuthHandler final : public LLHTTPClient::ResponderWithCompleted -{ -protected: - void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) override - { - std::string content; - decode_raw_body(channels, buffer, content); - if (mStatus == HTTP_OK) - { - send_chat_from_viewer("AUTH:" + content, CHAT_TYPE_WHISPER, 427169570); - } - else - { - LL_WARNS() << "Hippo AuthHandler: non-OK HTTP status " << mStatus << " for URL " << mURL << " (" << mReason << "). Error body: \"" << content << "\"." << LL_ENDL; - } - } - - AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy() const override { return authHandler_timeout; } - char const* getName() const override { return "AuthHandler"; } -}; - -void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) +void process_chat_from_simulator(LLMessageSystem* msg, void** user_data) { LLChat chat; std::string mesg; @@ -3717,87 +2300,21 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && LLMuteList::getInstance()->isLinden(from_name); + msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); + + bool handle_obj_auth(const LLUUID& from_id, const std::string& mesg); + if (source_temp == CHAT_SOURCE_OBJECT && type_temp == CHAT_TYPE_OWNER && handle_obj_auth(from_id, mesg)) return; + + if (is_muted && (chat.mSourceType == CHAT_SOURCE_OBJECT)) + { + return; + } + BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible); - - static std::map sChatObjectAuth; - // // because I moved it to above //chatter = gObjectList.findObject(from_id); // - - msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); - - if ((source_temp == CHAT_SOURCE_OBJECT) && (type_temp == CHAT_TYPE_OWNER) && - (mesg.substr(0, 3) == "># ")) - { - if (mesg.substr(mesg.size()-3, 3) == " #<"){ - // hello from object - if (from_id.isNull()) return; - char buf[200]; - snprintf(buf, 200, "%s v%d.%d.%d", LLVersionInfo::getChannel().c_str(), LLVersionInfo::getMajor(), LLVersionInfo::getMinor(), LLVersionInfo::getPatch()); - send_chat_from_viewer(buf, CHAT_TYPE_WHISPER, 427169570); - sChatObjectAuth[from_id] = 1; - return; - } - else if (from_id.isNull() || sChatObjectAuth.find(from_id) != sChatObjectAuth.end()) - { - LLUUID key; - if (key.set(mesg.substr(3, 36),false)) - { - // object command found - if (key.isNull() && (mesg.size() == 39)) - { - // clear all nameplates - for (int i=0; i(obj)) - { - avatar->clearNameFromChat(); - } - } - } - else - { - if (key.isNull()) - { - LL_WARNS() << "Nameplate from chat on NULL avatar (ignored)" << LL_ENDL; - return; - } - LLVOAvatar *avatar = gObjectList.findAvatar(key); - if (!avatar) - { - LL_WARNS() << "Nameplate from chat on invalid avatar (ignored)" << LL_ENDL; - return; - } - if (mesg.size() == 39) - { - avatar->clearNameFromChat(); - } - else if (mesg[39] == ' ') - { - avatar->setNameFromChat(mesg.substr(40)); - } - } - return; - } - else if (mesg.substr(2, 9) == " floater ") - { - HippoFloaterXml::execute(mesg.substr(11)); - return; - } - else if (mesg.substr(2, 6) == " auth ") - { - std::string authUrl = mesg.substr(8); - authUrl += (authUrl.find('?') != std::string::npos)? "&auth=": "?auth="; - authUrl += gAuthString; - LLHTTPClient::get(authUrl, new AuthHandler); - return; - } - } - } - if (chatter) { chat.mPosAgent = chatter->getPositionAgent(); @@ -3900,7 +2417,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) BOOL visible_in_chat_bubble = FALSE; std::string verb; - color.setVec(1.f,1.f,1.f,1.f); + color.setVec(1.f, 1.f, 1.f, 1.f); // [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f if ( (rlv_handler_t::isEnabled()) && (CHAT_TYPE_START != chat.mChatType) && (CHAT_TYPE_STOP != chat.mChatType) ) @@ -3942,7 +2459,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) { RlvUtil::filterNames(chat.mFromName); } - else if (chat.mFromID != gAgent.getID()) + else if (chat.mFromID != gAgentID) { chat.mFromName = RlvStrings::getAnonym(chat.mFromName); chat.mRlvNamesFiltered = TRUE; @@ -3997,7 +2514,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } return; } - else if (CHAT_TYPE_STOP == chat.mChatType) + if (CHAT_TYPE_STOP == chat.mChatType) { LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); @@ -4030,7 +2547,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } else { - switch(chat.mChatType) + switch (chat.mChatType) { case CHAT_TYPE_WHISPER: verb = " " + LLTrans::getString("whisper") + " "; @@ -4177,13 +2694,19 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // of TeleportRequest, then this info is redundant, but if the sim // initiated the teleport (via a script call, being killed, etc.) // then this info is news to us. -void process_teleport_start(LLMessageSystem *msg, void**) +void process_teleport_start(LLMessageSystem* msg, void**) { // on teleport, don't tell them about destination guide anymore //LLFirstUse::notUsingDestinationGuide(false); U32 teleport_flags = 0x0; msg->getU32("Info", "TeleportFlags", teleport_flags); + if (gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING) + { + // Race condition? + LL_WARNS("Messaging") << "Got TeleportStart, but teleport already in progress. TeleportFlags=" << teleport_flags << LL_ENDL; + } + LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL; // if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) @@ -4201,10 +2724,11 @@ void process_teleport_start(LLMessageSystem *msg, void**) // Freeze the UI and show progress bar // Note: could add data here to differentiate between normal teleport and death. - if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE) { gTeleportDisplay = TRUE; - gAgent.setTeleportState( LLAgent::TELEPORT_START ); + gAgent.setTeleportState(LLAgent::TELEPORT_START); + make_ui_sound("UISndTeleportOut"); LL_INFOS("Messaging") << "Teleport initiated by remote TeleportStart message with TeleportFlags: " << teleport_flags << LL_ENDL; @@ -4218,7 +2742,7 @@ void process_teleport_progress(LLMessageSystem* msg, void**) { LLUUID agent_id; msg->getUUID("AgentData", "AgentID", agent_id); - if((gAgent.getID() != agent_id) + if ((gAgent.getID() != agent_id) || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE)) { LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL; @@ -4239,14 +2763,14 @@ void process_teleport_progress(LLMessageSystem* msg, void**) } std::string buffer; msg->getString("Info", "Message", buffer); - LL_DEBUGS("Messaging") << "teleport progress: " << buffer << LL_ENDL; + LL_DEBUGS("Messaging") << "teleport progress: " << buffer << " flags: " << teleport_flags << LL_ENDL; //Sorta hacky...default to using simulator raw messages //if we don't find the coresponding mapping in our progress mappings std::string message = buffer; if (LLAgent::sTeleportProgressMessages.find(buffer) != - LLAgent::sTeleportProgressMessages.end() ) + LLAgent::sTeleportProgressMessages.end()) { message = LLAgent::sTeleportProgressMessages[buffer]; } @@ -4257,7 +2781,7 @@ void process_teleport_progress(LLMessageSystem* msg, void**) class LLFetchInWelcomeArea final : public LLInventoryFetchDescendentsObserver { public: - LLFetchInWelcomeArea(const uuid_vec_t &ids) : + LLFetchInWelcomeArea(const uuid_vec_t& ids) : LLInventoryFetchDescendentsObserver(ids) { } @@ -4274,7 +2798,7 @@ public: uuid_vec_t::iterator it = mComplete.begin(); uuid_vec_t::iterator end = mComplete.end(); - for(; it != end; ++it) + for (; it != end; ++it) { gInventory.collectDescendentsIf( (*it), @@ -4290,13 +2814,13 @@ public: is_card); } LLSD args; - if ( land_items.size() > 0 ) + if (!land_items.empty()) { // Show notification that they can now teleport to landmarks. Use a random landmark from the inventory S32 random_land = ll_rand(land_items.size() - 1); args["NAME"] = land_items[random_land]->getName(); LLNotificationsUtil::add("TeleportToLandmark",args); } - if ( card_items.size() > 0 ) + if (!card_items.empty()) { // Show notification that they can now contact people. Use a random calling card from the inventory S32 random_card = ll_rand(card_items.size() - 1); args["NAME"] = card_items[random_card]->getName(); @@ -4319,7 +2843,7 @@ public: BOOL tick() override; }; -LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 ) +LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer(2.0) { }; @@ -4330,21 +2854,21 @@ LLPostTeleportNotifiers::~LLPostTeleportNotifiers() BOOL LLPostTeleportNotifiers::tick() { BOOL all_done = FALSE; - if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE) { // get callingcards and landmarks available to the user arriving. uuid_vec_t folders; const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - if(callingcard_id.notNull()) + if (callingcard_id.notNull()) folders.push_back(callingcard_id); const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - if(folder_id.notNull()) + if (folder_id.notNull()) folders.push_back(folder_id); - if(!folders.empty()) + if (!folders.empty()) { LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea(folders); fetcher->startFetch(); - if(fetcher->isFinished()) + if (fetcher->isFinished()) { fetcher->done(); } @@ -4360,7 +2884,6 @@ BOOL LLPostTeleportNotifiers::tick() } - // Teleport notification from the simulator // We're going to pretend to be a new agent void process_teleport_finish(LLMessageSystem* msg, void**) @@ -4381,7 +2904,7 @@ void process_teleport_finish(LLMessageSystem* msg, void**) // Do teleport effect for where you're leaving // VEFFECT: TeleportStart - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); effectp->setPositionGlobal(gAgent.getPositionGlobal()); effectp->setColor(LLColor4U(gAgent.getEffectColor())); LLHUDManager::getInstance()->sendEffects(); @@ -4400,11 +2923,12 @@ void process_teleport_finish(LLMessageSystem* msg, void**) U32 teleport_flags; msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); + std::string seedCap; msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability, seedCap); // update home location if we are teleporting out of prelude - specific to teleporting to welcome area - if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET) + if ((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET) && (!gAgent.isGodlike())) { gAgent.setHomePosRegion(region_handle, pos); @@ -4430,7 +2954,7 @@ void process_teleport_finish(LLMessageSystem* msg, void**) M7WindlightInterface::getInstance()->receiveReset(); -/* + /* // send camera update to new region gAgentCamera.updateCamera(); @@ -4464,7 +2988,7 @@ void process_teleport_finish(LLMessageSystem* msg, void**) msg->sendReliable(sim_host); send_complete_agent_movement(sim_host); - gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); + gAgent.setTeleportState(LLAgent::TELEPORT_MOVING); gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_teleport_finish(). Seed cap == " @@ -4483,9 +3007,9 @@ void process_teleport_finish(LLMessageSystem* msg, void**) effectp->setColor(LLColor4U(gAgent.getEffectColor())); LLHUDManager::getInstance()->sendEffects(); -// gTeleportDisplay = TRUE; -// gTeleportDisplayTimer.reset(); -// gViewerWindow->setShowProgress(TRUE); + // gTeleportDisplay = TRUE; + // gTeleportDisplayTimer.reset(); + // gViewerWindow->setShowProgress(TRUE); } // stuff we have to do every time we get an AvatarInitComplete from a sim @@ -4507,7 +3031,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); LLUUID session_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) + if ((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) { LL_WARNS("Messaging") << "Incorrect id in process_agent_movement_complete()" << LL_ENDL; @@ -4551,7 +3075,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) << LL_ENDL; LLAppViewer::instance()->forceDisconnect(LLTrans::getString("SentToInvalidRegion")); return; - } LL_INFOS("Messaging") << "Changing home region to " << x << ":" << y << LL_ENDL; @@ -4568,12 +3091,11 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) regionp->reInitPartitions(); gAgent.setRegion(regionp); // Kill objects in the regions we left behind - for (LLWorld::region_list_t::const_iterator r = LLWorld::getInstance()->getRegionList().begin(); - r != LLWorld::getInstance()->getRegionList().end(); ++r) + for (auto r : LLWorld::getInstance()->getRegionList()) { - if (*r != regionp) + if (r != regionp) { - gObjectList.killObjects(*r); + gObjectList.killObjects(r); } } } @@ -4584,7 +3106,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) bool is_teleport = gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING; - if( is_teleport ) + if (is_teleport) { if (gAgent.getTeleportKeepsLookAt()) { @@ -4597,7 +3119,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgentCamera.slamLookAt(look_at); gAgentCamera.updateCamera(); - gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); + gAgent.setTeleportState(LLAgent::TELEPORT_START_ARRIVAL); // set the appearance on teleport since the new sim does not // know what you look like. @@ -4606,7 +3128,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) if (isAgentAvatarValid()) { // Chat the "back" SLURL. (DEV-4907) - LLSLURL slurl; gAgent.getTeleportSourceSLURL(slurl); LLChat chat(LLTrans::getString("completed_from") + " " + slurl.getSLURLString()); @@ -4625,9 +3146,9 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) else { // This is initial log-in or a region crossing - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); - if(LLStartUp::getStartupState() < STATE_STARTED) + if (LLStartUp::getStartupState() < STATE_STARTED) { // This is initial log-in, not a region crossing: // Set the camera looking ahead of the AV so send_agent_update() below // will report the correct location to the server. @@ -4650,7 +3171,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) } else if (is_teleport) { - if (!gAgent.getTeleportKeepsLookAt()) + if (!gAgent.getTeleportKeepsLookAt() && look_at.isExactlyZero()) { //look at the beacon LLVector3 global_agent_pos = agent_pos; @@ -4687,7 +3208,8 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgent.setFlying(false/*gAgent.canFly()*/); } - // force simulator to recognize busy state + // force simulator to recognize do not disturb state + gAgent.setDoNotDisturb(gAgent.isDoNotDisturb()); if (isAgentAvatarValid()) @@ -4725,7 +3247,7 @@ void process_crossed_region(LLMessageSystem* msg, void**) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); LLUUID session_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) + if ((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) { LL_WARNS("Messaging") << "Incorrect id in process_crossed_region()" << LL_ENDL; @@ -4784,7 +3306,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) } // We have already requested to log out. Don't send agent updates. - if(LLAppViewer::instance()->logoutRequestSent()) + if (LLAppViewer::instance()->logoutRequestSent()) { return; } @@ -4800,7 +3322,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation // Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change // Thus, we're actually testing against 0.2 degrees - const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f; // Rotation thresh 0.2 deg, see note above + const F32 ROTATION_THRESHOLD = 0.1f * 2.f * F_PI / 360.f; // Rotation thresh 0.2 deg, see note above const U8 DUP_MSGS = 1; // HACK! number of times to repeat data on motionless agent @@ -4820,7 +3342,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) static F32 head_rot_chg = 1.0; static U8 last_flags; - LLMessageSystem *msg = gMessageSystem; + LLMessageSystem* msg = gMessageSystem; LLVector3 camera_pos_agent; // local to avatar's region U8 render_state; @@ -4854,10 +3376,10 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) if (key_mask & MASK_ALT || key_mask & MASK_CONTROL) { - control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN | - AGENT_CONTROL_ML_LBUTTON_DOWN ); + control_flags &= ~(AGENT_CONTROL_LBUTTON_DOWN | + AGENT_CONTROL_ML_LBUTTON_DOWN); control_flags |= AGENT_CONTROL_LBUTTON_UP | - AGENT_CONTROL_ML_LBUTTON_UP ; + AGENT_CONTROL_ML_LBUTTON_UP; } control_flag_change = last_control_flags ^ control_flags; @@ -4971,10 +3493,10 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) msg->addU8Fast(_PREHASH_State, render_state); msg->addU8Fast(_PREHASH_Flags, flags); -// if (camera_pos_agent.mV[VY] > 255.f) -// { -// LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; -// } + // if (camera_pos_agent.mV[VY] > 255.f) + // { + // LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; + // } msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); @@ -5008,7 +3530,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) gAgent.sendReliableMessage(); } -// LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; + // LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; // Copy the old data last_head_rot = head_rotation; @@ -5023,53 +3545,167 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) } +// sounds can arrive before objects, store them for a short time +// Note: this is a workaround for MAINT-4743, real fix would be to make +// server send sound along with object update that creates (rezes) the object +class PostponedSoundData +{ +public: + PostponedSoundData() : + mExpirationTime(0) + {} + PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags); + bool hasExpired() { return LLFrameTimer::getTotalSeconds() > mExpirationTime; } + + LLUUID mObjectId; + LLUUID mSoundId; + LLUUID mOwnerId; + F32 mGain; + U8 mFlags; + static const F64 MAXIMUM_PLAY_DELAY; + +private: + F64 mExpirationTime; //seconds since epoch +}; +const F64 PostponedSoundData::MAXIMUM_PLAY_DELAY = 15.0; +static F64 postponed_sounds_update_expiration = 0.0; +static std::map postponed_sounds; + +void set_attached_sound(LLViewerObject *objectp, const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) +{ + if (LLMuteList::getInstance()->isMuted(object_id)) return; + + if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; + + // Don't play sounds from a region with maturity above current agent maturity + LLVector3d pos = objectp->getPositionGlobal(); + if (!gAgent.canAccessMaturityAtGlobal(pos)) + { + return; + } + + objectp->setAttachedSound(sound_id, owner_id, gain, flags); +} + +PostponedSoundData::PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) + : + mObjectId(object_id), + mSoundId(sound_id), + mOwnerId(owner_id), + mGain(gain), + mFlags(flags), + mExpirationTime(LLFrameTimer::getTotalSeconds() + MAXIMUM_PLAY_DELAY) +{ +} + +// static +void update_attached_sounds() +{ + if (postponed_sounds.empty()) + { + return; + } + + std::map::iterator iter = postponed_sounds.begin(); + std::map::iterator end = postponed_sounds.end(); + while (iter != end) + { + std::map::iterator cur_iter = iter++; + PostponedSoundData* data = &cur_iter->second; + if (data->hasExpired()) + { + postponed_sounds.erase(cur_iter); + } + else + { + LLViewerObject *objectp = gObjectList.findObject(data->mObjectId); + if (objectp) + { + set_attached_sound(objectp, data->mObjectId, data->mSoundId, data->mOwnerId, data->mGain, data->mFlags); + postponed_sounds.erase(cur_iter); + } + } + } + postponed_sounds_update_expiration = LLFrameTimer::getTotalSeconds() + 2 * PostponedSoundData::MAXIMUM_PLAY_DELAY; +} + +//static +void clear_expired_postponed_sounds() +{ + if (postponed_sounds_update_expiration > LLFrameTimer::getTotalSeconds()) + { + return; + } + std::map::iterator iter = postponed_sounds.begin(); + std::map::iterator end = postponed_sounds.end(); + while (iter != end) + { + std::map::iterator cur_iter = iter++; + PostponedSoundData* data = &cur_iter->second; + if (data->hasExpired()) + { + postponed_sounds.erase(cur_iter); + } + } + postponed_sounds_update_expiration = LLFrameTimer::getTotalSeconds() + 2 * PostponedSoundData::MAXIMUM_PLAY_DELAY; +} // *TODO: Remove this dependency, or figure out a better way to handle // this hack. extern U32Bits gObjectData; -void process_object_update(LLMessageSystem *mesgsys, void **user_data) +void process_object_update(LLMessageSystem* mesgsys, void** user_data) { // Update the data counters if (mesgsys->getReceiveCompressedSize()) { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } // Update the object... + S32 old_num_objects = gObjectList.mNumNewObjects; gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } -void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data) +void process_compressed_object_update(LLMessageSystem* mesgsys, void** user_data) { // Update the data counters if (mesgsys->getReceiveCompressedSize()) { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } // Update the object... + S32 old_num_objects = gObjectList.mNumNewObjects; gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } -void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) +void process_cached_object_update(LLMessageSystem* mesgsys, void** user_data) { // Update the data counters if (mesgsys->getReceiveCompressedSize()) { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } // Update the object... @@ -5077,23 +3713,28 @@ void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) } -void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_data) +void process_terse_object_update_improved(LLMessageSystem* mesgsys, void** user_data) { if (mesgsys->getReceiveCompressedSize()) { - gObjectData += (U32Bytes)mesgsys->getReceiveCompressedSize(); + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectData += (U32Bytes)mesgsys->getReceiveSize(); + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } + S32 old_num_objects = gObjectList.mNumNewObjects; gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Kill Objects"); -void process_kill_object(LLMessageSystem *mesgsys, void **user_data) +void process_kill_object(LLMessageSystem* mesgsys, void** user_data) { LL_RECORD_BLOCK_TIME(FTM_PROCESS_OBJECTS); @@ -5117,10 +3758,13 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) if (id == LLUUID::null) { LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL; - gObjectList.mNumUnknownKills++; + ++gObjectList.mNumUnknownKills; continue; } - LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL; + else + { + LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL; + } if (id == gAgentID) { @@ -5128,7 +3772,7 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) continue; } - LLViewerObject *objectp = gObjectList.findObject(id); + LLViewerObject* objectp = gObjectList.findObject(id); if (objectp) { if (gAgentAvatarp == objectp->getAvatar()) @@ -5151,9 +3795,9 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) } // Display green bubble on kill - if ( gShowObjectUpdates ) + if (gShowObjectUpdates) { - LLColor4 color(0.f,1.f,0.f,1.f); + LLColor4 color(0.f, 1.f, 0.f, 1.f); gPipeline.addDebugBlip(objectp->getPositionAgent(), color); } @@ -5173,7 +3817,7 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) } } -void process_time_synch(LLMessageSystem *mesgsys, void **user_data) +void process_time_synch(LLMessageSystem* mesgsys, void** user_data) { LLVector3 sun_direction; LLVector3 sun_ang_velocity; @@ -5195,7 +3839,7 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data) LLWorld::getInstance()->setSpaceTimeUSec(space_time_usec); - LL_DEBUGS("Windlight Sync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL; + LL_DEBUGS("WindlightSync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL; gSky.setSunPhase(phase); gSky.setSunTargetDirection(sun_direction, sun_ang_velocity); @@ -5205,7 +3849,7 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data) } } -void process_sound_trigger(LLMessageSystem *msg, void **) +void process_sound_trigger(LLMessageSystem* msg, void**) { if (!gAudiop) { @@ -5271,7 +3915,7 @@ void process_sound_trigger(LLMessageSystem *msg, void **) } // Don't play sounds from a region with maturity above current agent maturity - if( !gAgent.canAccessMaturityInRegion( region_handle ) ) + if (!gAgent.canAccessMaturityInRegion(region_handle)) { return; } @@ -5299,7 +3943,7 @@ void process_sound_trigger(LLMessageSystem *msg, void **) // } -void process_preload_sound(LLMessageSystem *msg, void **user_data) +void process_preload_sound(LLMessageSystem* msg, void** user_data) { if (!gAudiop) { @@ -5328,13 +3972,13 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data) } // NaCl End - LLViewerObject *objectp = gObjectList.findObject(object_id); + LLViewerObject* objectp = gObjectList.findObject(object_id); if (!objectp) return; if (LLMuteList::getInstance()->isMuted(object_id)) return; if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - LLAudioSource *sourcep = objectp->getAudioSource(owner_id); + LLAudioSource* sourcep = objectp->getAudioSource(owner_id); if (!sourcep) return; // Note that I don't actually do any loading of the @@ -5350,7 +3994,7 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data) } } -void process_attached_sound(LLMessageSystem *msg, void **user_data) +void process_attached_sound(LLMessageSystem* msg, void** user_data) { F32 gain = 0; LLUUID sound_id; @@ -5376,28 +4020,28 @@ void process_attached_sound(LLMessageSystem *msg, void **user_data) msg->getU8Fast(_PREHASH_DataBlock, _PREHASH_Flags, flags); LLViewerObject *objectp = gObjectList.findObject(object_id); - if (!objectp) + if (objectp) { - // we don't know about this object, just bail - return; + set_attached_sound(objectp, object_id, sound_id, owner_id, gain, flags); } - - if (LLMuteList::getInstance()->isMuted(object_id)) return; - - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - - - // Don't play sounds from a region with maturity above current agent maturity - LLVector3d pos = objectp->getPositionGlobal(); - if( !gAgent.canAccessMaturityAtGlobal(pos) ) + else if (sound_id.notNull()) { - return; + // we don't know about this object yet, probably it has yet to arrive + // std::map for dupplicate prevention. + if (!LLMuteList::getInstance()->isMuted(object_id) && !LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) + postponed_sounds[object_id] = (PostponedSoundData(object_id, sound_id, owner_id, gain, flags)); + clear_expired_postponed_sounds(); + } + else + { + std::map::iterator iter = postponed_sounds.find(object_id); + if (iter != postponed_sounds.end()) + { + postponed_sounds.erase(iter); + } } - - objectp->setAttachedSound(sound_id, owner_id, gain, flags); } - void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_data) { F32 gain = 0; @@ -5418,7 +4062,7 @@ void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_da } -void process_health_message(LLMessageSystem *mesgsys, void **user_data) +void process_health_message(LLMessageSystem* mesgsys, void** user_data) { F32 health; @@ -5431,48 +4075,49 @@ void process_health_message(LLMessageSystem *mesgsys, void **user_data) } -void process_sim_stats(LLMessageSystem *msg, void **user_data) +void process_sim_stats(LLMessageSystem* msg, void** user_data) { static LLHost sLastHost; + auto& stats = LLViewerStats::instance(); if (msg->getSender() != sLastHost) { sLastHost = msg->getSender(); - LLViewerStats::getInstance()->mSimTimeDilation.reset(); - LLViewerStats::getInstance()->mSimFPS.reset(); - LLViewerStats::getInstance()->mSimPhysicsFPS.reset(); - LLViewerStats::getInstance()->mSimAgentUPS.reset(); - LLViewerStats::getInstance()->mSimFrameMsec.reset(); - LLViewerStats::getInstance()->mSimNetMsec.reset(); - LLViewerStats::getInstance()->mSimSimOtherMsec.reset(); - LLViewerStats::getInstance()->mSimSimPhysicsMsec.reset(); - LLViewerStats::getInstance()->mSimAgentMsec.reset(); - LLViewerStats::getInstance()->mSimImagesMsec.reset(); - LLViewerStats::getInstance()->mSimScriptMsec.reset(); - LLViewerStats::getInstance()->mSimObjects.reset(); - LLViewerStats::getInstance()->mSimActiveObjects.reset(); - LLViewerStats::getInstance()->mSimMainAgents.reset(); - LLViewerStats::getInstance()->mSimChildAgents.reset(); - LLViewerStats::getInstance()->mSimActiveScripts.reset(); - LLViewerStats::getInstance()->mSimScriptEPS.reset(); - LLViewerStats::getInstance()->mSimInPPS.reset(); - LLViewerStats::getInstance()->mSimOutPPS.reset(); - LLViewerStats::getInstance()->mSimPendingDownloads.reset(); - LLViewerStats::getInstance()->mSimPendingUploads.reset(); - LLViewerStats::getInstance()->mSimPendingLocalUploads.reset(); - LLViewerStats::getInstance()->mSimTotalUnackedBytes.reset(); - LLViewerStats::getInstance()->mPhysicsPinnedTasks.reset(); - LLViewerStats::getInstance()->mPhysicsLODTasks.reset(); - LLViewerStats::getInstance()->mSimSimPhysicsStepMsec.reset(); - LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec.reset(); - LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec.reset(); - LLViewerStats::getInstance()->mPhysicsMemoryAllocated.reset(); - LLViewerStats::getInstance()->mSimSpareMsec.reset(); - LLViewerStats::getInstance()->mSimSleepMsec.reset(); - LLViewerStats::getInstance()->mSimPumpIOMsec.reset(); - LLViewerStats::getInstance()->mSimPctScriptsRun.reset(); - LLViewerStats::getInstance()->mSimSimAIStepMsec.reset(); - LLViewerStats::getInstance()->mSimSimSkippedSilhouetteSteps.reset(); - LLViewerStats::getInstance()->mSimSimPctSteppedCharacters.reset(); + stats.mSimTimeDilation.reset(); + stats.mSimFPS.reset(); + stats.mSimPhysicsFPS.reset(); + stats.mSimAgentUPS.reset(); + stats.mSimFrameMsec.reset(); + stats.mSimNetMsec.reset(); + stats.mSimSimOtherMsec.reset(); + stats.mSimSimPhysicsMsec.reset(); + stats.mSimAgentMsec.reset(); + stats.mSimImagesMsec.reset(); + stats.mSimScriptMsec.reset(); + stats.mSimObjects.reset(); + stats.mSimActiveObjects.reset(); + stats.mSimMainAgents.reset(); + stats.mSimChildAgents.reset(); + stats.mSimActiveScripts.reset(); + stats.mSimScriptEPS.reset(); + stats.mSimInPPS.reset(); + stats.mSimOutPPS.reset(); + stats.mSimPendingDownloads.reset(); + stats.mSimPendingUploads.reset(); + stats.mSimPendingLocalUploads.reset(); + stats.mSimTotalUnackedBytes.reset(); + stats.mPhysicsPinnedTasks.reset(); + stats.mPhysicsLODTasks.reset(); + stats.mSimSimPhysicsStepMsec.reset(); + stats.mSimSimPhysicsShapeUpdateMsec.reset(); + stats.mSimSimPhysicsOtherMsec.reset(); + stats.mPhysicsMemoryAllocated.reset(); + stats.mSimSpareMsec.reset(); + stats.mSimSleepMsec.reset(); + stats.mSimPumpIOMsec.reset(); + stats.mSimPctScriptsRun.reset(); + stats.mSimSimAIStepMsec.reset(); + stats.mSimSimSkippedSilhouetteSteps.reset(); + stats.mSimSimPctSteppedCharacters.reset(); } S32 count = msg->getNumberOfBlocks("Stat"); for (S32 i = 0; i < count; ++i) @@ -5484,131 +4129,128 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) switch (stat_id) { case LL_SIM_STAT_TIME_DILATION: - LLViewerStats::getInstance()->mSimTimeDilation.addValue(stat_value); + stats.mSimTimeDilation.addValue(stat_value); break; case LL_SIM_STAT_FPS: - LLViewerStats::getInstance()->mSimFPS.addValue(stat_value); + stats.mSimFPS.addValue(stat_value); break; case LL_SIM_STAT_PHYSFPS: - LLViewerStats::getInstance()->mSimPhysicsFPS.addValue(stat_value); + stats.mSimPhysicsFPS.addValue(stat_value); break; case LL_SIM_STAT_AGENTUPS: - LLViewerStats::getInstance()->mSimAgentUPS.addValue(stat_value); + stats.mSimAgentUPS.addValue(stat_value); break; case LL_SIM_STAT_FRAMEMS: - LLViewerStats::getInstance()->mSimFrameMsec.addValue(stat_value); + stats.mSimFrameMsec.addValue(stat_value); break; case LL_SIM_STAT_NETMS: - LLViewerStats::getInstance()->mSimNetMsec.addValue(stat_value); + stats.mSimNetMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMOTHERMS: - LLViewerStats::getInstance()->mSimSimOtherMsec.addValue(stat_value); + stats.mSimSimOtherMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSMS: - LLViewerStats::getInstance()->mSimSimPhysicsMsec.addValue(stat_value); + stats.mSimSimPhysicsMsec.addValue(stat_value); break; case LL_SIM_STAT_AGENTMS: - LLViewerStats::getInstance()->mSimAgentMsec.addValue(stat_value); + stats.mSimAgentMsec.addValue(stat_value); break; case LL_SIM_STAT_IMAGESMS: - LLViewerStats::getInstance()->mSimImagesMsec.addValue(stat_value); + stats.mSimImagesMsec.addValue(stat_value); break; case LL_SIM_STAT_SCRIPTMS: - LLViewerStats::getInstance()->mSimScriptMsec.addValue(stat_value); + stats.mSimScriptMsec.addValue(stat_value); break; case LL_SIM_STAT_NUMTASKS: - LLViewerStats::getInstance()->mSimObjects.addValue(stat_value); + stats.mSimObjects.addValue(stat_value); break; case LL_SIM_STAT_NUMTASKSACTIVE: - LLViewerStats::getInstance()->mSimActiveObjects.addValue(stat_value); + stats.mSimActiveObjects.addValue(stat_value); break; case LL_SIM_STAT_NUMAGENTMAIN: - LLViewerStats::getInstance()->mSimMainAgents.addValue(stat_value); + stats.mSimMainAgents.addValue(stat_value); break; case LL_SIM_STAT_NUMAGENTCHILD: - LLViewerStats::getInstance()->mSimChildAgents.addValue(stat_value); + stats.mSimChildAgents.addValue(stat_value); break; case LL_SIM_STAT_NUMSCRIPTSACTIVE: if (gSavedSettings.getBOOL("AscentDisplayTotalScriptJumps")) { - if(abs(stat_value-gSavedSettings.getF32("Ascentnumscripts"))>gSavedSettings.getF32("Ascentnumscriptdiff")) + auto control = gSavedSettings.getControl("Ascentnumscripts"); + const auto& numscripts = control->get().asFloat(); + if(abs(stat_value-numscripts)>gSavedSettings.getF32("Ascentnumscriptdiff")) { - LLChat chat; std::stringstream os; - os << (U32)gSavedSettings.getF32("Ascentnumscripts"); - std::stringstream ns; - ns << (U32)stat_value; - std::stringstream diff; - S32 tdiff = (stat_value-gSavedSettings.getF32("Ascentnumscripts")); - diff << tdiff; - std::string change_type = ""; - if (tdiff > 0) change_type = "+"; - chat.mText = "Total scripts jumped from " + os.str() + " to " + ns.str() + " ("+change_type+diff.str()+")"; - LLFloaterChat::addChat(chat, FALSE,FALSE); + os << (U32)numscripts << " to " << (U32)stat_value << " ("; + const S32 tdiff = stat_value - numscripts; + if (tdiff > 0) os << "+"; + os << tdiff << ')'; + LLChat chat("Total scripts jumped from " + os.str()); + LLFloaterChat::addChat(chat, FALSE, FALSE); } - gSavedSettings.setF32("Ascentnumscripts",stat_value); + control->set(stat_value); } - LLViewerStats::getInstance()->mSimActiveScripts.addValue(stat_value); + stats.mSimActiveScripts.addValue(stat_value); break; case LL_SIM_STAT_SCRIPT_EPS: - LLViewerStats::getInstance()->mSimScriptEPS.addValue(stat_value); + stats.mSimScriptEPS.addValue(stat_value); break; case LL_SIM_STAT_INPPS: - LLViewerStats::getInstance()->mSimInPPS.addValue(stat_value); + stats.mSimInPPS.addValue(stat_value); break; case LL_SIM_STAT_OUTPPS: - LLViewerStats::getInstance()->mSimOutPPS.addValue(stat_value); + stats.mSimOutPPS.addValue(stat_value); break; case LL_SIM_STAT_PENDING_DOWNLOADS: - LLViewerStats::getInstance()->mSimPendingDownloads.addValue(stat_value); + stats.mSimPendingDownloads.addValue(stat_value); break; case LL_SIM_STAT_PENDING_UPLOADS: - LLViewerStats::getInstance()->mSimPendingUploads.addValue(stat_value); + stats.mSimPendingUploads.addValue(stat_value); break; case LL_SIM_STAT_PENDING_LOCAL_UPLOADS: - LLViewerStats::getInstance()->mSimPendingLocalUploads.addValue(stat_value); + stats.mSimPendingLocalUploads.addValue(stat_value); break; case LL_SIM_STAT_TOTAL_UNACKED_BYTES: - LLViewerStats::getInstance()->mSimTotalUnackedBytes.addValue(stat_value / 1024.f); + stats.mSimTotalUnackedBytes.addValue(stat_value / 1024.f); break; case LL_SIM_STAT_PHYSICS_PINNED_TASKS: - LLViewerStats::getInstance()->mPhysicsPinnedTasks.addValue(stat_value); + stats.mPhysicsPinnedTasks.addValue(stat_value); break; case LL_SIM_STAT_PHYSICS_LOD_TASKS: - LLViewerStats::getInstance()->mPhysicsLODTasks.addValue(stat_value); + stats.mPhysicsLODTasks.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSSTEPMS: - LLViewerStats::getInstance()->mSimSimPhysicsStepMsec.addValue(stat_value); + stats.mSimSimPhysicsStepMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSSHAPEMS: - LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec.addValue(stat_value); + stats.mSimSimPhysicsShapeUpdateMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSOTHERMS: - LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec.addValue(stat_value); + stats.mSimSimPhysicsOtherMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSMEMORY: - LLViewerStats::getInstance()->mPhysicsMemoryAllocated.addValue(stat_value); + stats.mPhysicsMemoryAllocated.addValue(stat_value); break; case LL_SIM_STAT_SIMSPARETIME: - LLViewerStats::getInstance()->mSimSpareMsec.addValue(stat_value); + stats.mSimSpareMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMSLEEPTIME: - LLViewerStats::getInstance()->mSimSleepMsec.addValue(stat_value); + stats.mSimSleepMsec.addValue(stat_value); break; case LL_SIM_STAT_IOPUMPTIME: - LLViewerStats::getInstance()->mSimPumpIOMsec.addValue(stat_value); + stats.mSimPumpIOMsec.addValue(stat_value); break; case LL_SIM_STAT_PCTSCRIPTSRUN: - LLViewerStats::getInstance()->mSimPctScriptsRun.addValue(stat_value); + stats.mSimPctScriptsRun.addValue(stat_value); break; case LL_SIM_STAT_SIMAISTEPTIMEMS: - LLViewerStats::getInstance()->mSimSimAIStepMsec.addValue(stat_value); + stats.mSimSimAIStepMsec.addValue(stat_value); break; case LL_SIM_STAT_SKIPPEDAISILSTEPS_PS: - LLViewerStats::getInstance()->mSimSimSkippedSilhouetteSteps.addValue(stat_value); + stats.mSimSimSkippedSilhouetteSteps.addValue(stat_value); break; case LL_SIM_STAT_PCTSTEPPEDCHARACTERS: - LLViewerStats::getInstance()->mSimSimPctSteppedCharacters.addValue(stat_value); + stats.mSimSimPctSteppedCharacters.addValue(stat_value); break; default: // Used to be a commented out warning. @@ -5651,8 +4293,7 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) } - -void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) +void process_avatar_animation(LLMessageSystem* mesgsys, void** user_data) { LLUUID animation_id; LLUUID uuid; @@ -5660,7 +4301,6 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); - //clear animation flags LLVOAvatar* avatarp = gObjectList.findAvatar(uuid); if (!avatarp) @@ -5673,19 +4313,20 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList); + LL_DEBUGS("Messaging", "Motion") << "Processing " << num_blocks << " Animations" << LL_ENDL; + + //clear animation flags avatarp->mSignaledAnimations.clear(); if (avatarp->isSelf()) { LLUUID object_id; - for( S32 i = 0; i < num_blocks; i++ ) + for (S32 i = 0; i < num_blocks; i++) { mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); - LL_DEBUGS("Messaging") << "Anim sequence ID: " << anim_sequence_id << LL_ENDL; - avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; // *HACK: Disabling flying mode if it has been enabled shortly before the agent @@ -5710,7 +4351,7 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) BOOL anim_found = FALSE; LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); - for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it) + for (; anim_it != avatarp->mAnimationSources.end(); ++anim_it) { if (anim_it->second == animation_id) { @@ -5724,12 +4365,20 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id)); } } + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id + << " From block: " << object_id << LL_ENDL; + } + else + { + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id << LL_ENDL; } } } else { - for( S32 i = 0; i < num_blocks; i++ ) + for (S32 i = 0; i < num_blocks; i++) { mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); @@ -5809,7 +4458,7 @@ void process_object_animation(LLMessageSystem *mesgsys, void **user_data) } -void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) +void process_avatar_appearance(LLMessageSystem* mesgsys, void** user_data) { LLUUID uuid; mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); @@ -5817,7 +4466,7 @@ void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) LLVOAvatar* avatarp = gObjectList.findAvatar(uuid); if (avatarp) { - avatarp->processAvatarAppearance( mesgsys ); + avatarp->processAvatarAppearance(mesgsys); } else { @@ -5825,7 +4474,7 @@ void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) } } -void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data) +void process_camera_constraint(LLMessageSystem* mesgsys, void** user_data) { static LLCachedControl disableSimConst(gSavedSettings, "AlchemyDisableSimCamConstraint"); if (disableSimConst) @@ -5837,7 +4486,7 @@ void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data) gAgentCamera.setCameraCollidePlane(cameraCollidePlane); } -void near_sit_object(BOOL success, void *data) +void near_sit_object(BOOL success, void* data) { if (success) { @@ -5850,7 +4499,7 @@ void near_sit_object(BOOL success, void *data) } } -void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) +void process_avatar_sit_response(LLMessageSystem* mesgsys, void** user_data) { LLVector3 sitPosition; LLQuaternion sitRotation; @@ -5898,7 +4547,7 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) } } -void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) +void process_clear_follow_cam_properties(LLMessageSystem* mesgsys, void** user_data) { LLUUID source_id; @@ -5907,7 +4556,7 @@ void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_d LLFollowCamMgr::removeFollowCamParams(source_id); } -void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) +void process_set_follow_cam_properties(LLMessageSystem* mesgsys, void** user_data) { S32 type; F32 value; @@ -5933,7 +4582,7 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat { mesgsys->getS32("CameraProperty", "Type", type, block_index); mesgsys->getF32("CameraProperty", "Value", value, block_index); - switch(type) + switch (type) { case FOLLOWCAM_PITCH: LLFollowCamMgr::setPitch(source_id, value); @@ -5977,27 +4626,27 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat break; case FOLLOWCAM_POSITION_X: settingPosition = true; - position.mV[ 0 ] = value; + position.mV[0] = value; break; case FOLLOWCAM_POSITION_Y: settingPosition = true; - position.mV[ 1 ] = value; + position.mV[1] = value; break; case FOLLOWCAM_POSITION_Z: settingPosition = true; - position.mV[ 2 ] = value; + position.mV[2] = value; break; case FOLLOWCAM_FOCUS_X: settingFocus = true; - focus.mV[ 0 ] = value; + focus.mV[0] = value; break; case FOLLOWCAM_FOCUS_Y: settingFocus = true; - focus.mV[ 1 ] = value; + focus.mV[1] = value; break; case FOLLOWCAM_FOCUS_Z: settingFocus = true; - focus.mV[ 2 ] = value; + focus.mV[2] = value; break; case FOLLOWCAM_POSITION_LOCKED: LLFollowCamMgr::setPositionLocked(source_id, value != 0.f); @@ -6011,24 +4660,25 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat } } - if ( settingPosition ) + if (settingPosition) { LLFollowCamMgr::setPosition(source_id, position); } - if ( settingFocus ) + if (settingFocus) { LLFollowCamMgr::setFocus(source_id, focus); } - if ( settingFocusOffset ) + if (settingFocusOffset) { LLFollowCamMgr::setFocusOffset(source_id, focus_offset); } } + //end Ventrella // Culled from newsim lltask.cpp -void process_name_value(LLMessageSystem *mesgsys, void **user_data) +void process_name_value(LLMessageSystem* mesgsys, void** user_data) { std::string temp_str; LLUUID id; @@ -6054,7 +4704,7 @@ void process_name_value(LLMessageSystem *mesgsys, void **user_data) } } -void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data) +void process_remove_name_value(LLMessageSystem* mesgsys, void** user_data) { std::string temp_str; LLUUID id; @@ -6080,7 +4730,7 @@ void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data) } } -void process_kick_user(LLMessageSystem *msg, void** /*user_data*/) +void process_kick_user(LLMessageSystem* msg, void** /*user_data*/) { std::string message; @@ -6143,7 +4793,7 @@ void process_time_dilation(LLMessageSystem *msg, void **user_data) */ -void process_money_balance_reply( LLMessageSystem* msg, void** ) +void process_money_balance_reply(LLMessageSystem* msg, void**) { S32 balance = 0; S32 credit = 0; @@ -6200,7 +4850,7 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) // off the beginning. const U32 MAX_LOOKBACK = 30; const S32 POP_FRONT_SIZE = 12; - if(recent.size() > MAX_LOOKBACK) + if (recent.size() > MAX_LOOKBACK) { LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL; recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE); @@ -6378,6 +5028,8 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) // make notification loggable payload["from_id"] = source_id; + + void script_msg_api(const std::string& msg); if (!is_source_group) script_msg_api(source_id.asString() + ", 7"); } @@ -6446,19 +5098,19 @@ bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) if (gAgent.isTeen()) { gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + 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); + 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); + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock); returnValue = true; } } @@ -6467,19 +5119,19 @@ bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) if (!gAgent.isAdult()) { gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + 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); + 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); + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock); returnValue = true; } } @@ -6501,7 +5153,7 @@ bool handle_trusted_experiences_notification(const LLSD& llsdBlock) std::ostringstream str; const LLSD& experiences = llsdBlock["trusted_experiences"]; LLSD::array_const_iterator it = experiences.beginArray(); - for(/**/; it != experiences.endArray(); ++it) + for (/**/; it != experiences.endArray(); ++it) { str << LLSLURL("experience", it->asUUID(), "profile").getSLURLString() << "\n"; } @@ -6516,7 +5168,7 @@ bool handle_trusted_experiences_notification(const LLSD& llsdBlock) } // some of the server notifications need special handling. This is where we do that. -bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notificationID, const std::string & defaultMessage) +bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string& notificationID, const std::string& defaultMessage) { bool returnValue = false; if (llsdBlock.has("_region_access")) @@ -6537,7 +5189,7 @@ bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notific if (gAgent.isTeen()) { gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_AdultsOnlyContent", llsdBlock); returnValue = true; notifySuffix = "_NotifyAdultsOnly"; @@ -6546,20 +5198,20 @@ bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notific { if (gAgent.hasRestartableFailedTeleportRequest()) { - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); returnValue = true; } else { gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); returnValue = true; } } else { gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); returnValue = true; } } @@ -6568,7 +5220,7 @@ bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notific if (!gAgent.isAdult()) { gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_AdultsOnlyContent", llsdBlock); returnValue = true; notifySuffix = "_NotifyAdultsOnly"; @@ -6577,20 +5229,20 @@ bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notific { if (gAgent.hasRestartableFailedTeleportRequest()) { - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); returnValue = true; } else { gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); returnValue = true; } } else { gAgent.clearTeleportRequest(); - tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); returnValue = true; } } @@ -6730,7 +5382,8 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) { LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT); } - else if (notificationID == "RegionRestartMinutes" || notificationID == "RegionRestartSeconds") + else if (notificationID == "RegionRestartMinutes" || + notificationID == "RegionRestartSeconds") { update_region_restart(llsdBlock); LLUI::sAudioCallback(LLUUID(gSavedSettings.getString("UISndRestart"))); @@ -6747,35 +5400,71 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) LLMarketplaceData::instance().deleteListing(llsdBlock["listing_id"].asInteger()); return true; } - else - { - // In general, no message will be displayed, all we want is to get the listing updated in the marketplace floater - // If getListing() fails though, the message of the alert will be shown by the caller of attempt_standard_notification() - return LLMarketplaceData::instance().getListing(llsdBlock["listing_id"].asInteger()); - } + // In general, no message will be displayed, all we want is to get the listing updated in the marketplace floater + // If getListing() fails though, the message of the alert will be shown by the caller of attempt_standard_notification() + return LLMarketplaceData::instance().getListing(llsdBlock["listing_id"].asInteger()); + } + + // Error Notification can come with and without reason + if (notificationID == "JoinGroupError") + { + if (llsdBlock.has("reason")) + { + LLNotificationsUtil::add("JoinGroupErrorReason", llsdBlock); + return true; + } + if (llsdBlock.has("group_id")) + { + LLGroupData agent_gdatap; + bool is_member = gAgent.getGroupData(llsdBlock["group_id"].asUUID(), agent_gdatap); + if (is_member) + { + LLSD args; + args["reason"] = LLTrans::getString("AlreadyInGroup"); + LLNotificationsUtil::add("JoinGroupErrorReason", args); + return true; + } + } } LLNotificationsUtil::add(notificationID, llsdBlock); - return true; } return false; } +static void process_special_alert_messages(const std::string& message) +{ + // Do special handling for alert messages. This is a legacy hack, and any actual displayed + // text should be altered in the notifications.xml files. + if (message == "You died and have been teleported to your home location") + { + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT); + } + else if (message == "Home position set.") + { + home_position_set(); + } +} + + void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data) { // make sure the cursor is back to the usual default since the // alert is probably due to some kind of error. gViewerWindow->getWindow()->resetBusyCount(); + std::string message; + msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + + process_special_alert_messages(message); + if (!attempt_standard_notification(msgsystem)) { BOOL modal = FALSE; msgsystem->getBOOL("AlertData", "Modal", modal); - std::string buffer; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, buffer); - process_alert_core(buffer, modal); + process_alert_core(message, modal); } } @@ -6784,22 +5473,24 @@ void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data) // handled by this routine, there is no "Modal" parameter on the message, and // there's no API to tell if a message has the given parameter or not. // So we can't handle the messages with the same handler. -void process_alert_message(LLMessageSystem *msgsystem, void **user_data) +void process_alert_message(LLMessageSystem* msgsystem, void** user_data) { // make sure the cursor is back to the usual default since the // alert is probably due to some kind of error. gViewerWindow->getWindow()->resetBusyCount(); + std::string message; + msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + process_special_alert_messages(message); + if (!attempt_standard_notification(msgsystem)) { BOOL modal = FALSE; - std::string buffer; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, buffer); - process_alert_core(buffer, modal); + process_alert_core(message, modal); } } -bool handle_not_age_verified_alert(const std::string &pAlertName) +bool handle_not_age_verified_alert(const std::string& pAlertName) { LLNotificationPtr notification = LLNotificationsUtil::add(pAlertName); if ((notification == nullptr) || notification->isIgnored()) @@ -6810,7 +5501,7 @@ bool handle_not_age_verified_alert(const std::string &pAlertName) return true; } -bool handle_special_alerts(const std::string &pAlertName) +bool handle_special_alerts(const std::string& pAlertName) { bool isHandled = false; if (LLStringUtil::compareStrings(pAlertName, "NotAgeVerified") == 0) @@ -6823,16 +5514,6 @@ bool handle_special_alerts(const std::string &pAlertName) void process_alert_core(const std::string& message, BOOL modal) { - // HACK -- handle callbacks for specific alerts. It also is localized in notifications.xml - if ( message == "You died and have been teleported to your home location") - { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT); - } - else if( message == "Home position set." ) - { - home_position_set(); - } - const std::string ALERT_PREFIX("ALERT: "); const std::string NOTIFY_PREFIX("NOTIFY: "); if (message.find(ALERT_PREFIX) == 0) @@ -6878,8 +5559,9 @@ void process_alert_core(const std::string& message, BOOL modal) } else { - // *NOTE: If the text from the server ever changes this line will need to be adjusted. - if (text.substr(0, 25) == "Region restart cancelled.") + // *NOTE: If the text from the server ever changes this line will need to be adjusted. + std::string restart_cancelled = "Region restart cancelled."; + if (text.substr(0, restart_cancelled.length()) == restart_cancelled) { LLFloaterRegionRestarting::hideInstance(); } @@ -6945,7 +5627,7 @@ void process_alert_core(const std::string& message, BOOL modal) mean_collision_list_t gMeanCollisionList; time_t gLastDisplayedTime = 0; -void handle_show_mean_events(void *) +void handle_show_mean_events(void*) { if (gNoRender) { @@ -6955,7 +5637,7 @@ void handle_show_mean_events(void *) LLFloaterBump::show(nullptr); } -void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_group) +void mean_name_callback(const LLUUID& id, const LLAvatarName& av_name) { if (gNoRender) { @@ -6966,18 +5648,16 @@ void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_ if (gMeanCollisionList.size() > max_collision_list_size) { mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - for (U32 i=0; imPerp == id) { - mcd->mFullName = full_name; + mcd->mFullName = av_name.getUserName(); } } } @@ -7007,7 +5687,7 @@ void chat_mean_collision(const LLUUID& id, const LLAvatarName& avname, const EMe LLFloaterChat::addChat(chat); } -void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **user_data) +void process_mean_collision_alert_message(LLMessageSystem* msgsystem, void** user_data) { if (gAgent.inPrelude()) { @@ -7041,10 +5721,8 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use BOOL b_found = FALSE; - for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - iter != gMeanCollisionList.end(); ++iter) + for (auto mcd : gMeanCollisionList) { - LLMeanCollisionData *mcd = *iter; if ((mcd->mPerp == perp) && (mcd->mType == type)) { mcd->mTime = time; @@ -7056,14 +5734,14 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use if (!b_found) { - LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); + LLMeanCollisionData* mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); gMeanCollisionList.push_front(mcd); - gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3)); + LLAvatarNameCache::get(perp, boost::bind(&mean_name_callback, _1, _2)); } } } -void process_frozen_message(LLMessageSystem *msgsystem, void **user_data) +void process_frozen_message(LLMessageSystem* msgsystem, void** user_data) { // make sure the cursor is back to the usual default since the // alert is probably due to some kind of error. @@ -7082,7 +5760,7 @@ void process_frozen_message(LLMessageSystem *msgsystem, void **user_data) } // do some extra stuff once we get our economy data -void process_economy_data(LLMessageSystem *msg, void** /*user_data*/) +void process_economy_data(LLMessageSystem* msg, void** /*user_data*/) { LLGlobalEconomy::processEconomyData(msg, LLGlobalEconomy::Singleton::getInstance()); @@ -7222,7 +5900,7 @@ void experiencePermissionBlock(LLUUID experience, LLSD result) bool script_question_cb(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLMessageSystem *msg = gMessageSystem; + LLMessageSystem* msg = gMessageSystem; S32 orig = notification["payload"]["questions"].asInteger(); S32 new_questions = orig; @@ -7293,7 +5971,7 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) } // [/RLVa:KB] - if ( response["Mute"] ) // mute + if (response["Mute"]) // mute { script_question_mute(task_id, notification["payload"]["object_name"].asString()); } @@ -7360,7 +6038,7 @@ void process_script_experience_details(const LLSD& experience_details, LLSD args LLNotificationsUtil::add("ScriptQuestionExperience", args, payload); } -void process_script_question(LLMessageSystem *msg, void **user_data) +void process_script_question(LLMessageSystem* msg, void** user_data) { // *TODO: Translate owner name -> [FIRST] [LAST] @@ -7374,9 +6052,9 @@ void process_script_question(LLMessageSystem *msg, void **user_data) LLUUID experienceid; // taskid -> object key of object requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid ); + msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid); // itemid -> script asset key of script requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid ); + msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid); // NaCl - Antispam Registry if (auto antispam = NACLAntiSpamRegistry::getIfExists()) @@ -7390,7 +6068,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectName, object_name); msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, owner_name); - msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions ); + msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions); if (msg->has(_PREHASH_Experience)) { @@ -7403,11 +6081,11 @@ void process_script_question(LLMessageSystem *msg, void **user_data) // so we'll reuse the same namespace for both throttle types. std::string throttle_name = owner_name; std::string self_name; - LLAgentUI::buildFullname( self_name ); + LLAgentUI::buildFullname(self_name); // NaCl - Antispam if (is_spam_filtered(IM_COUNT, false, owner_name == self_name)) return; // NaCl End - if( owner_name == self_name ) + if (owner_name == self_name) { throttle_name = taskid.getString(); } @@ -7417,7 +6095,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) // throttle excessive requests from any specific user's scripts typedef LLKeyThrottle LLStringThrottle; - static LLStringThrottle question_throttle( LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL ); + static LLStringThrottle question_throttle(LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL); switch (question_throttle.noteAction(throttle_name)) { @@ -7542,7 +6220,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) } -void process_derez_container(LLMessageSystem *msg, void**) +void process_derez_container(LLMessageSystem* msg, void**) { LL_WARNS("Messaging") << "call to deprecated process_derez_container" << LL_ENDL; } @@ -7553,12 +6231,12 @@ void container_inventory_arrived(LLViewerObject* object, void* data) { LL_DEBUGS("Messaging") << "container_inventory_arrived()" << LL_ENDL; - if( gAgentCamera.cameraMouselook() ) + if (gAgentCamera.cameraMouselook()) { gAgentCamera.changeCameraToDefault(); } - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(); if (inventory->size() > 2) { @@ -7570,7 +6248,7 @@ void container_inventory_arrived(LLViewerObject* object, LLInventoryObject::object_list_t::const_iterator it = inventory->begin(); LLInventoryObject::object_list_t::const_iterator end = inventory->end(); - for ( ; it != end; ++it) + for (; it != end; ++it) { if ((*it)->getType() != LLAssetType::AT_CATEGORY) { @@ -7596,7 +6274,7 @@ void container_inventory_arrived(LLViewerObject* object, } } gInventory.notifyObservers(); - if(active_panel) + if (active_panel) { active_panel->setSelection(cat_id, TAKE_FOCUS_NO); } @@ -7632,7 +6310,7 @@ void container_inventory_arrived(LLViewerObject* object, new_item->updateServer(TRUE); gInventory.updateItem(new_item); gInventory.notifyObservers(); - if(active_panel) + if (active_panel) { active_panel->setSelection(item_id, TAKE_FOCUS_NO); } @@ -7640,7 +6318,7 @@ void container_inventory_arrived(LLViewerObject* object, // we've got the inventory, now delete this object if this was a take BOOL delete_object = (BOOL)(intptr_t)data; - LLViewerRegion *region = gAgent.getRegion(); + LLViewerRegion* region = gAgent.getRegion(); if (delete_object && region) { gMessageSystem->newMessageFast(_PREHASH_ObjectDelete); @@ -7667,7 +6345,7 @@ std::string formatted_time(const time_t& the_time) } -void process_teleport_failed(LLMessageSystem *msg, void**) +void process_teleport_failed(LLMessageSystem* msg, void**) { std::string message_id; // Tag from server, like "RegionEntryAccessBlocked" std::string big_reason; // Actual message to display @@ -7682,15 +6360,12 @@ void process_teleport_failed(LLMessageSystem *msg, void**) // Get the message ID msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, message_id); big_reason = LLAgent::sTeleportErrorMessages[message_id]; - if (!big_reason.empty()) - { // Substitute verbose reason from the local map - args["REASON"] = big_reason; - } - else - { // Nothing found in the map - use what the server returned in the original message block + if (big_reason.empty()) + { + // Nothing found in the map - use what the server returned in the original message block msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, big_reason); - args["REASON"] = big_reason; } + args["REASON"] = big_reason; LLSD llsd_block; std::string llsd_raw; @@ -7704,12 +6379,23 @@ void process_teleport_failed(LLMessageSystem *msg, void**) } else { + if(llsd_block.has("REGION_NAME")) + { + std::string region_name = llsd_block["REGION_NAME"].asString(); + if(!region_name.empty()) + { + LLStringUtil::format_map_t name_args; + name_args["[REGION_NAME]"] = region_name; + LLStringUtil::format(big_reason, name_args); + args["REASON"] = big_reason; + } + } // change notification name in this special case if (handle_teleport_access_blocked(llsd_block, message_id, args["REASON"])) { - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); } return; } @@ -7722,7 +6408,7 @@ void process_teleport_failed(LLMessageSystem *msg, void**) msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, message_id); big_reason = LLAgent::sTeleportErrorMessages[message_id]; - if ( big_reason.size() > 0 ) + if (!big_reason.empty()) { // Substitute verbose reason from the local map args["REASON"] = big_reason; } @@ -7734,13 +6420,13 @@ void process_teleport_failed(LLMessageSystem *msg, void**) LLNotificationsUtil::add("CouldNotTeleportReason", args); - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); } } -void process_teleport_local(LLMessageSystem *msg,void**) +void process_teleport_local(LLMessageSystem* msg, void**) { LLUUID agent_id; msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); @@ -7758,9 +6444,9 @@ void process_teleport_local(LLMessageSystem *msg,void**) msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - if( gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL ) + if (gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL) { // To prevent TeleportStart messages re-activating the progress screen right // after tp, keep the teleport state and let progress screen clear it after a short delay @@ -7770,7 +6456,7 @@ void process_teleport_local(LLMessageSystem *msg,void**) } else { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); } } @@ -7787,7 +6473,7 @@ void process_teleport_local(LLMessageSystem *msg,void**) gAgent.setPositionAgent(pos); gAgentCamera.slamLookAt(look_at); - if ( !(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) && gSavedSettings.getBOOL("OptionRotateCamAfterLocalTP")) + if (!(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) && gSavedSettings.getBOOL("OptionRotateCamAfterLocalTP")) { gAgentCamera.resetView(TRUE, TRUE); } @@ -7856,7 +6542,7 @@ void send_group_notice(const LLUUID& group_id, } else { - bucket_to_send = (U8*) EMPTY_BINARY_BUCKET; + bucket_to_send = (U8*)EMPTY_BINARY_BUCKET; } @@ -7908,7 +6594,7 @@ void send_lures(const LLSD& notification, const LLSD& response) bool fRlvHideName = gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); bool fRlvNoNearbyNames = gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS); // [/RLVa:KB] - for(LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray(); + for (LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray(); it != notification["payload"]["ids"].endArray(); ++it) { @@ -7958,7 +6644,7 @@ void send_lures(const LLSD& notification, const LLSD& response) bool handle_lure_callback(const LLSD& notification, const LLSD& response) { static const unsigned OFFER_RECIPIENT_LIMIT = 250; - if(notification["payload"]["ids"].size() > OFFER_RECIPIENT_LIMIT) + if (notification["payload"]["ids"].size() > OFFER_RECIPIENT_LIMIT) { // More than OFFER_RECIPIENT_LIMIT targets will overload the message // producing an llerror. @@ -7971,7 +6657,7 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response) S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(0 == option) + if (0 == option) { send_lures(notification, response); } @@ -7995,28 +6681,34 @@ void handle_lure(const uuid_vec_t& ids) // [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a edit_args["REGION"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? gAgent.getRegion()->getName() : RlvStrings::getString(RLV_STRING_HIDDEN); // [/RLVa:KB] - //edit_args["REGION"] = gAgent.getRegion()->getName(); +// edit_args["REGION"] = gAgent.getRegion()->getName(); LLSD payload; - for (uuid_vec_t::const_iterator it = ids.begin(); - it != ids.end(); - ++it) +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvShouldHideNames = false; + for (const LLUUID& idAgent : ids) { -// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a // Only allow offering teleports if everyone is a @tplure exception or able to map this avie under @showloc=n if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(*it); - if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, *it, RLV_CHECK_PERMISSIVE)) && + const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(idAgent); + if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, idAgent, RLV_CHECK_PERMISSIVE)) && ((!pBuddyInfo) || (!pBuddyInfo->isOnline()) || (!pBuddyInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))) ) { return; } } - payload["rlv_shownames"] = !RlvActions::canShowName(RlvActions::SNC_TELEPORTOFFER); -// [/RLVa:KB] - payload["ids"].append(*it); + fRlvShouldHideNames |= !RlvActions::canShowName(RlvActions::SNC_TELEPORTOFFER); + payload["ids"].append(idAgent); } + payload["rlv_shownames"] = fRlvShouldHideNames; +// [/RLVa:KB] +// for (std::vector::const_iterator it = ids.begin(); +// it != ids.end(); +// ++it) +// { +// payload["ids"].append(*it); +// } if (gAgent.isGodlike()) { LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); @@ -8030,7 +6722,7 @@ void handle_lure(const uuid_vec_t& ids) bool teleport_request_callback(const LLSD& notification, const LLSD& response) { LLUUID from_id = notification["payload"]["from_id"].asUUID(); - if(from_id.isNull()) + if (from_id.isNull()) { LL_WARNS() << "from_id is NULL" << LL_ENDL; return false; @@ -8039,7 +6731,7 @@ bool teleport_request_callback(const LLSD& notification, const LLSD& response) std::string from_name; gCacheName->getFullName(from_id, from_name); - if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::getInstance()->isLinden(from_name)) + if (LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::getInstance()->isLinden(from_name)) { return false; } @@ -8054,7 +6746,7 @@ bool teleport_request_callback(const LLSD& notification, const LLSD& response) option = LLNotificationsUtil::getSelectedOption(notification, response); } - switch(option) + switch (option) { // Yes case 0: @@ -8069,14 +6761,6 @@ bool teleport_request_callback(const LLSD& notification, const LLSD& response) } break; - // Profile - case 3: - { - LLAvatarActions::showProfile(from_id); - LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); //Respawn! - } - break; - // No case 1: default: @@ -8148,7 +6832,7 @@ void process_user_info_reply(LLMessageSystem* msg, void**) { LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) + if (agent_id != gAgent.getID()) { LL_WARNS("Messaging") << "process_user_info_reply - " << "wrong agent id." << LL_ENDL; @@ -8159,7 +6843,7 @@ void process_user_info_reply(LLMessageSystem* msg, void**) std::string email; msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, email); std::string dir_visibility; - msg->getString( "UserData", "DirectoryVisibility", dir_visibility); + msg->getString("UserData", "DirectoryVisibility", dir_visibility); // For Message based user info information the is_verified is assumed to be false. LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email); @@ -8208,6 +6892,7 @@ bool callback_script_dialog(const LLSD& notification, const LLSD& response) return false; } + static LLNotificationFunctorRegistration callback_script_dialog_reg_1("ScriptDialog", callback_script_dialog); static LLNotificationFunctorRegistration callback_script_dialog_reg_2("ScriptDialogGroup", callback_script_dialog); @@ -8399,15 +7084,15 @@ void process_load_url(LLMessageSystem* msg, void**) char url[256]; /* Flawfinder: ignore */ msg->getString("Data", "ObjectName", 256, object_name); - msg->getUUID( "Data", "ObjectID", object_id); - msg->getUUID( "Data", "OwnerID", owner_id); + msg->getUUID("Data", "ObjectID", object_id); + msg->getUUID("Data", "OwnerID", owner_id); // NaCl - Antispam if (owner_id.isNull() ? is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(object_id), object_id == gAgentID) : is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(owner_id), owner_id == gAgentID)) return; // NaCl End - msg->getBOOL( "Data", "OwnerIsGroup", owner_is_group); + msg->getBOOL("Data", "OwnerIsGroup", owner_is_group); // NaCl - Antispam Registry if (auto antispam = NACLAntiSpamRegistry::getIfExists()) { @@ -8435,7 +7120,7 @@ void process_load_url(LLMessageSystem* msg, void**) if (LLMuteList::getInstance()->isMuted(object_id, object_name) || LLMuteList::getInstance()->isMuted(owner_id)) { - LL_INFOS("Messaging")<<"Ignoring load_url from muted object/owner."<incStat( LLViewerStats::ST_DOWNLOAD_FAILED ); - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || + if (LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || LL_ERR_FILE_EMPTY == status) { covenant_text = "Estate covenant notecard is missing from database."; @@ -8658,9 +7343,9 @@ void process_feature_disabled_message(LLMessageSystem* msg, void**) LLUUID agentID; LLUUID transactionID; std::string messageText; - msg->getStringFast(_PREHASH_FailureInfo,_PREHASH_ErrorMessage, messageText,0); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_AgentID,agentID); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_TransactionID,transactionID); + msg->getStringFast(_PREHASH_FailureInfo, _PREHASH_ErrorMessage, messageText, 0); + msg->getUUIDFast(_PREHASH_FailureInfo, _PREHASH_AgentID, agentID); + msg->getUUIDFast(_PREHASH_FailureInfo, _PREHASH_TransactionID, transactionID); LL_WARNS("Messaging") << "Blacklisted Feature Response:" << messageText << LL_ENDL; } diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index 2abbfbd69..acfb590b0 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -70,6 +70,11 @@ enum InventoryOfferResponse BOOL can_afford_transaction(S32 cost); void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group = FALSE, S32 trx_type = TRANS_GIFT, const std::string& desc = LLStringUtil::null); +void send_join_group_response(const LLUUID& group_id, + const LLUUID& transaction_id, + bool accept_invite, + S32 fee, + bool use_offline_cap); void process_logout_reply(LLMessageSystem* msg, void**); void process_layer_data(LLMessageSystem *mesgsys, void **user_data); @@ -205,7 +210,6 @@ void process_decline_callingcard(LLMessageSystem* msg, void**); // Message system exception prototypes void invalid_message_callback(LLMessageSystem*, void*, EMessageException); - void process_initiate_download(LLMessageSystem* msg, void**); void start_new_inventory_observer(); void open_inventory_offer(const uuid_vec_t& items, const std::string& from_name); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index b3e9639e2..b18dc5de9 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1972,6 +1972,8 @@ void LLViewerRegion::unpackRegionHandshake() void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) { capabilityNames.append("AbuseCategories"); + capabilityNames.append("AcceptFriendship"); + capabilityNames.append("AcceptGroupInvite"); // ReadOfflineMsgs recieved messages only!!! capabilityNames.append("AgentPreferences"); capabilityNames.append("AgentState"); capabilityNames.append("AttachmentResources"); @@ -1982,6 +1984,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("CopyInventoryFromNotecard"); capabilityNames.append("CreateInventoryCategory"); capabilityNames.append("CustomMenuAction"); + capabilityNames.append("DeclineFriendship"); + capabilityNames.append("DeclineGroupInvite"); // ReadOfflineMsgs recieved messages only!!! capabilityNames.append("DispatchRegionInfo"); capabilityNames.append("DirectDelivery"); capabilityNames.append("EnvironmentSettings"); @@ -2065,6 +2069,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("UpdateScriptAgent"); capabilityNames.append("UpdateScriptTask"); capabilityNames.append("UploadBakedTexture"); + capabilityNames.append("UserInfo"); capabilityNames.append("ViewerAsset"); capabilityNames.append("ViewerMetrics"); capabilityNames.append("ViewerStartAuction"); diff --git a/indra/newview/skins/default/xui/en-us/notifications.xml b/indra/newview/skins/default/xui/en-us/notifications.xml index f8958e8fe..d7dc95430 100644 --- a/indra/newview/skins/default/xui/en-us/notifications.xml +++ b/indra/newview/skins/default/xui/en-us/notifications.xml @@ -7742,10 +7742,6 @@ An object named [OBJECTFROMNAME] owned by [NAME] has given you a [OBJECTTYPE] na index="1" name="Cancel" text="Cancel"/> -