diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 21f9faa410..0f69fb7fa0 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -115,28 +115,28 @@ else (USESYSTEMLIBS) elseif (DARWIN) set(BOOST_CONTEXT_LIBRARY optimized boost_context-mt${addrsfx} - debug boost_context-mt${addrsfx}-d) + debug boost_context-mt${addrsfx}) set(BOOST_FIBER_LIBRARY optimized boost_fiber-mt${addrsfx} - debug boost_fiber-mt${addrsfx}-d) + debug boost_fiber-mt${addrsfx}) set(BOOST_FILESYSTEM_LIBRARY optimized boost_filesystem-mt${addrsfx} - debug boost_filesystem-mt${addrsfx}-d) + debug boost_filesystem-mt${addrsfx}) set(BOOST_PROGRAM_OPTIONS_LIBRARY optimized boost_program_options-mt${addrsfx} - debug boost_program_options-mt${addrsfx}-d) + debug boost_program_options-mt${addrsfx}) set(BOOST_REGEX_LIBRARY optimized boost_regex-mt${addrsfx} - debug boost_regex-mt${addrsfx}-d) + debug boost_regex-mt${addrsfx}) set(BOOST_SIGNALS_LIBRARY optimized boost_signals-mt${addrsfx} - debug boost_signals-mt${addrsfx}-d) + debug boost_signals-mt${addrsfx}) set(BOOST_SYSTEM_LIBRARY optimized boost_system-mt${addrsfx} - debug boost_system-mt${addrsfx}-d) + debug boost_system-mt${addrsfx}) set(BOOST_THREAD_LIBRARY optimized boost_thread-mt${addrsfx} - debug boost_thread-mt${addrsfx}-d) + debug boost_thread-mt${addrsfx}) set(BOOST_WAVE_LIBRARY optimized boost_wave-mt${addrsfx} debug boost_wave-mt${addrsfx}-gd) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1c6b356f6a..470ffff2c3 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -857,6 +857,7 @@ set(viewer_SOURCE_FILES llxmlrpctransaction.cpp noise.cpp particleeditor.cpp + permissionstracker.cpp piemenu.cpp pieseparator.cpp pieslice.cpp @@ -1630,6 +1631,7 @@ set(viewer_HEADER_FILES macmain.h noise.h particleeditor.h + permissionstracker.h piemenu.h pieseparator.h pieslice.h diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index cc81d718c3..32c568aee0 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.5.5 +6.5.6 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 3e38e6e38f..3683854765 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -21918,6 +21918,30 @@ Change of this parameter will affect the layout of buttons in notification toast Boolean Value 0 + + CefVerboseLog + + Comment + Enable/disable CEF verbose loggingk + Persist + 1 + Type + Boolean + Value + 0 + + ResetUIScaleOnFirstRun + + Comment + Resets the UI scale factor on first run due to changed display scaling behavior + Persist + 1 + Type + Boolean + Value + 1 + Backup + 0 360CaptureUseInterestListCap @@ -21996,30 +22020,19 @@ Change of this parameter will affect the layout of buttons in notification toast Value 3 - CefVerboseLog - - Comment - Enable/disable CEF verbose loggingk - Persist - 1 - Type - Boolean - Value - 0 - - ResetUIScaleOnFirstRun - - Comment - Resets the UI scale factor on first run due to changed display scaling behavior - Persist - 1 - Type - Boolean - Value - 1 - Backup - 0 - + MFAHash + + Comment + Override MFA state hash for authentication + Persist + 0 + Type + String + Value + + Backup + 0 + FSShowServerVersionChangeNotice Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 9b4fc7afc3..bb1e3b8a26 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3705,6 +3705,11 @@ bool LLAppViewer::initWindow() return true; } +bool LLAppViewer::isUpdaterMissing() +{ + return mUpdaterNotFound; +} + void LLAppViewer::writeDebugInfo(bool isStatic) { #if LL_WINDOWS && LL_BUGSPLAT diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index a32f7a743f..2143d81e1e 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -98,7 +98,7 @@ public: bool quitRequested() { return mQuitRequested; } bool logoutRequestSent() { return mLogoutRequestSent; } bool isSecondInstance() { return mSecondInstance; } - bool isUpdaterMissing() { return mUpdaterNotFound; } + bool isUpdaterMissing(); // In use by tests void writeDebugInfo(bool isStatic=true); diff --git a/indra/newview/llfollowcam.cpp b/indra/newview/llfollowcam.cpp index c2ea3b07c1..4a65e8c2dc 100644 --- a/indra/newview/llfollowcam.cpp +++ b/indra/newview/llfollowcam.cpp @@ -29,6 +29,8 @@ #include "llfollowcam.h" #include "llagent.h" +#include "permissionstracker.h" + //------------------------------------------------------- // constants //------------------------------------------------------- @@ -829,11 +831,13 @@ void LLFollowCamMgr::setCameraActive( const LLUUID& source, bool active ) if (found_it != mParamStack.end()) { mParamStack.erase(found_it); + PermissionsTracker::instance().removePermissionsEntry(source, PermissionsTracker::PERM_FOLLOWCAM); } // put on top of stack if(active) { mParamStack.push_back(params); + PermissionsTracker::instance().addPermissionsEntry(source, PermissionsTracker::PERM_FOLLOWCAM); } } @@ -843,6 +847,8 @@ void LLFollowCamMgr::removeFollowCamParams(const LLUUID& source) LLFollowCamParams* params = getParamsForID(source); mParamMap.erase(source); delete params; + + PermissionsTracker::instance().removePermissionsEntry(source, PermissionsTracker::PERM_FOLLOWCAM); } bool LLFollowCamMgr::isScriptedCameraSource(const LLUUID& source) diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 7b41a7320c..3b694803ad 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -61,6 +61,7 @@ #include "lltrans.h" #include +#include #include const S32 LOGIN_MAX_RETRIES = 0; // Viewer should not autmatically retry login @@ -239,8 +240,9 @@ void LLLoginInstance::constructAuthParams(LLPointer user_credentia request_params["id0"] = mSerialNumber; request_params["host_id"] = gSavedSettings.getString("HostID"); request_params["extended_errors"] = true; // request message_id and message_args + request_params["token"] = ""; - // log request_params _before_ adding the credentials + // log request_params _before_ adding the credentials or sensitive MFA hash data LL_DEBUGS("LLLogin") << "Login parameters: " << LLSDOStreamer(request_params) << LL_ENDL; // Copy the credentials into the request after logging the rest @@ -253,6 +255,33 @@ void LLLoginInstance::constructAuthParams(LLPointer user_credentia request_params[it->first] = it->second; } + std::string mfa_hash = gSavedSettings.getString("MFAHash"); //non-persistent to enable testing + std::string grid(LLGridManager::getInstance()->getGridId()); + std::string user_id = user_credential->userID(); + if (gSecAPIHandler) + { + if (mfa_hash.empty()) + { + // normal execution, mfa_hash was not set from debug setting so load from protected store + LLSD data_map = gSecAPIHandler->getProtectedData("mfa_hash", grid); + if (data_map.isMap() && data_map.has(user_id)) + { + mfa_hash = data_map[user_id].asString(); + } + } + else + { + // SL-16888 the mfa_hash is being overridden for testing so save it for consistency for future login requests + gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, mfa_hash); + } + } + else + { + LL_WARNS() << "unable to access protected store for mfa_hash" << LL_ENDL; + } + + request_params["mfa_hash"] = mfa_hash; + // Specify desired timeout/retry options LLSD http_params; F32 srv_timeout = llclamp(gSavedSettings.getF32("LoginSRVTimeout"), LOGIN_SRV_TIMEOUT_MIN, LOGIN_SRV_TIMEOUT_MAX); @@ -265,6 +294,11 @@ void LLLoginInstance::constructAuthParams(LLPointer user_credentia mRequestData["params"] = request_params; mRequestData["options"] = requested_options; mRequestData["http_params"] = http_params; +//#if LL_RELEASE_FOR_DOWNLOAD +// mRequestData["wait_for_updater"] = !gSavedSettings.getBOOL("CmdLineSkipUpdater") && !LLAppViewer::instance()->isUpdaterMissing(); +//#else + mRequestData["wait_for_updater"] = false; +//#endif } bool LLLoginInstance::handleLoginEvent(const LLSD& event) @@ -420,6 +454,38 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) boost::bind(&LLLoginInstance::syncWithUpdater, this, resp, _1, _2)); } } + else if(reason_response == "mfa_challenge") + { + LL_DEBUGS("LLLogin") << " MFA challenge" << LL_ENDL; + + if (gViewerWindow) + { + gViewerWindow->setShowProgress(FALSE, FALSE); + } + + LLSD args(llsd::map( "MESSAGE", LLTrans::getString(response["message_id"]) )); + LLSD payload; + LLNotificationsUtil::add("PromptMFAToken", args, payload, [=](LLSD const & notif, LLSD const & response) { + bool continue_clicked = response["continue"].asBoolean(); + std::string token = response["token"].asString(); + LL_DEBUGS("LLLogin") << "PromptMFAToken: response: " << response << " continue_clicked" << continue_clicked << LL_ENDL; + + // strip out whitespace - SL-17034/BUG-231938 + token = boost::regex_replace(token, boost::regex("\\s"), ""); + + if (continue_clicked && !token.empty()) + { + LL_INFOS("LLLogin") << "PromptMFAToken: token submitted" << LL_ENDL; + + // Set the request data to true and retry login. + mRequestData["params"]["token"] = token; + reconnect(); + } else { + LL_INFOS("LLLogin") << "PromptMFAToken: no token, attemptComplete" << LL_ENDL; + attemptComplete(); + } + }); + } else if( reason_response == "key" || reason_response == "presence" || reason_response == "connect" diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index 95ad1e79ba..03d7068c7c 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -485,6 +485,9 @@ public: const std::string& data_id, const std::string& map_elem)=0; + // ensure protected store's map is written to storage + virtual void syncProtectedMap() = 0; + public: virtual LLPointer createCredential(const std::string& grid, const LLSD& identifier, diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 72c7c9cde2..63e97d1ad7 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -1621,6 +1621,11 @@ void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type, } } +void LLSecAPIBasicHandler::syncProtectedMap() +{ + // TODO - consider unifing these functions + _writeProtectedData(); +} // // Create a credential object from an identifier and authenticator. credentials are // per credential name (was: grid). diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index df53e01524..47fa724996 100644 --- a/indra/newview/llsechandler_basic.h +++ b/indra/newview/llsechandler_basic.h @@ -278,6 +278,9 @@ public: const std::string& data_id, const std::string& map_elem); + // ensure protected store's map is written to storage + virtual void syncProtectedMap(); + // credential management routines virtual LLPointer createCredential(const std::string& credName, diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index cc8100235c..9328cded00 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -141,6 +141,7 @@ #include "llproxy.h" #include "llproductinforequest.h" #include "llqueryflags.h" +#include "llsecapi.h" #include "llselectmgr.h" #include "llsky.h" #include "llstatview.h" @@ -1732,10 +1733,10 @@ bool idle_startup() } else { - if (reason_response != "tos") + if (reason_response != "tos" && reason_response != "mfa_challenge") { - // Don't pop up a notification in the TOS case because - // LLFloaterTOS::onCancel() already scolded the user. + // Don't pop up a notification in the TOS or MFA cases because + // the specialized floater has already scolded the user. std::string error_code; if(response.has("errorcode")) { @@ -3247,8 +3248,31 @@ void show_release_notes_if_required() && gSavedSettings.getBOOL("UpdaterShowReleaseNotes") && !gSavedSettings.getBOOL("FirstLoginThisInstall")) { - LLSD info(LLAppViewer::instance()->getViewerInfo()); - LLWeb::loadURLInternal(info["VIEWER_RELEASE_NOTES_URL"]); + +#if LL_RELEASE_FOR_DOWNLOAD + if (!gSavedSettings.getBOOL("CmdLineSkipUpdater") + && !LLAppViewer::instance()->isUpdaterMissing()) + { + // Instantiate a "relnotes" listener which assumes any arriving event + // is the release notes URL string. Since "relnotes" is an + // LLEventMailDrop, this listener will be invoked whether or not the + // URL has already been posted. If so, it will fire immediately; + // otherwise it will fire whenever the URL is (later) posted. Either + // way, it will display the release notes as soon as the URL becomes + // available. + LLEventPumps::instance().obtain("relnotes").listen( + "showrelnotes", + [](const LLSD& url) { + LLWeb::loadURLInternal(url.asString()); + return false; + }); + } + else +#endif // LL_RELEASE_FOR_DOWNLOAD + { + LLSD info(LLAppViewer::instance()->getViewerInfo()); + LLWeb::loadURLInternal(info["VIEWER_RELEASE_NOTES_URL"]); + } release_notes_shown = true; } } @@ -4703,6 +4727,17 @@ bool process_login_success_response(U32 &first_sim_size_x, U32 &first_sim_size_y LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); } + + // Only save mfa_hash for future logins if the user wants their info remembered. + if(response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser") && gSavedSettings.getBOOL("RememberPassword")) + { + std::string grid(LLGridManager::getInstance()->getGridId()); + std::string user_id(gUserCredential->userID()); + gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]); + // TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically + gSecAPIHandler->syncProtectedMap(); + } + // OpenSim legacy economy support #ifdef OPENSIM if (!LLGridManager::instance().isInSecondLife()) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 916712ecb8..f022779a09 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -166,6 +166,7 @@ #include "lltexturecache.h" #include "llvovolume.h" #include "particleeditor.h" +#include "permissionstracker.h" using namespace LLAvatarAppearanceDefines; @@ -5424,6 +5425,9 @@ void handle_reset_camera_angles() // Camera focus and offset with CTRL/SHIFT + Scroll wheel gSavedSettings.getControl("FocusOffsetRearView")->resetToDefault(); gSavedSettings.getControl("CameraOffsetRearView")->resetToDefault(); + + // warn the user if there is a scripted followcam active that might stop a camera reset + PermissionsTracker::instance().warnFollowcam(); } // diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index e4eea0a510..d7b64bc5c1 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -150,6 +150,7 @@ #include "llfloaterbump.h" #include "llfloaterreg.h" #include "llfriendcard.h" +#include "permissionstracker.h" // Permissions Tracker #include "tea.h" // #include "NACLantispam.h" #include "chatbar_as_cmdline.h" @@ -4733,6 +4734,8 @@ void process_object_properties(LLMessageSystem *msg, void**user_data) { explorer->requestNameCallback(msg); } + + PermissionsTracker::instance().objectPropertiesCallback(msg); } // area search diff --git a/indra/newview/permissionstracker.cpp b/indra/newview/permissionstracker.cpp new file mode 100644 index 0000000000..db01feee27 --- /dev/null +++ b/indra/newview/permissionstracker.cpp @@ -0,0 +1,274 @@ +/** + * @file permissionstracker.cpp + * @brief Permissions Tracker implementation - Initially it's only tracking + * camera control permissions, to warn users about attachments or seats that + * took camera control permissions and might interfere with resetting the + * camera view. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2022, Zi Ree @ Second Life + * + * 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 "llagentdata.h" // for gAgentID anf gAgentSessionID +#include "llnotificationsutil.h" +#include "llslurl.h" +#include "lltrans.h" +#include "llviewermenu.h" // for handle_object_edit() +#include "llviewerregion.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" // for gObjectList +#include "llvoavatarself.h" // for gAgentAvatarp +#include "llworld.h" + +#include "permissionstracker.h" + +#define PERMISSION_ENTRY_EXPIRY_TIME 3600.0 + +PermissionsTracker::PermissionsTracker() +: LLSingleton() +{ +} + +PermissionsTracker::~PermissionsTracker() +{ +} + +void PermissionsTracker::addPermissionsEntry(const LLUUID& source_id, PermissionsTracker::PERM_TYPE permission_type) +{ + // find out if this is a new entry in the list + if (mPermissionsList.find(source_id) == mPermissionsList.end()) + { + LL_DEBUGS("PermissionsTracker") << "Creating list entry for source " << source_id << LL_ENDL; + mPermissionsList[source_id].objectName = LLTrans::getString("LoadingData"); + + // find out if the object is still in reach + LLViewerObject* vo = gObjectList.findObject(source_id); + if (!vo) + { + mPermissionsList[source_id].objectName = LLTrans::getString("ObjectOutOfRange"); + } + else + { + mPermissionsList[source_id].attachmentID = vo->getAttachmentItemID(); + LL_DEBUGS("PermissionsTracker") << "Requesting ObjectProperties for source " << source_id << LL_ENDL; + + // remember which object names we already requested + mRequestedIDs.push_back(source_id); + + // send a request out to get this object's details + LLMessageSystem* msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_ObjectSelect); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgentID); + msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, vo->getLocalID()); + msg->sendReliable(gAgentAvatarp->getRegion()->getHost()); + + msg->newMessageFast(_PREHASH_ObjectDeselect); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgentID); + msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, vo->getLocalID()); + msg->sendReliable(gAgentAvatarp->getRegion()->getHost()); + } + } + + LL_DEBUGS("PermissionsTracker") << "Adding permission type " << permission_type << " to source " << source_id << LL_ENDL; + mPermissionsList[source_id].type |= permission_type; + mPermissionsList[source_id].time = LLDate(LLTimer::getTotalSeconds()); + + purgePermissionsEntries(); +} + +void PermissionsTracker::removePermissionsEntry(const LLUUID& source_id, PermissionsTracker::PERM_TYPE permission_type) +{ + if (mPermissionsList.find(source_id) == mPermissionsList.end()) + { + LL_DEBUGS("PermissionsTracker") << "Could not find list entry for source " << source_id << LL_ENDL; + return; + } + + LL_DEBUGS("PermissionsTracker") << "Removing permissions type " << permission_type << " from source " << source_id << LL_ENDL; + mPermissionsList[source_id].type &= ~permission_type; + mPermissionsList[source_id].time = LLDate(LLTimer::getTotalSeconds()); + + purgePermissionsEntries(); +} + +void PermissionsTracker::purgePermissionsEntries() +{ + F64 expiry_time = LLDate(LLTimer::getTotalSeconds()).secondsSinceEpoch() - PERMISSION_ENTRY_EXPIRY_TIME; + + auto it = mPermissionsList.begin(); + while (it != mPermissionsList.end()) + { + if (it->second.type == PERM_TYPE::PERM_NONE && it->second.time.secondsSinceEpoch() < expiry_time) + { + LL_DEBUGS("PermissionsTracker") << "Erasing list entry for source " << it->first << LL_ENDL; + it = mPermissionsList.erase(it); + } + else + { + ++it; + } + } +} + +void PermissionsTracker::warnFollowcam() +{ + std::string followcamList; + for (auto entry : mPermissionsList) + { + if (entry.second.type & PermissionsTracker::PERM_FOLLOWCAM) + { + if (entry.second.attachmentID.notNull()) + { + std::string attachment_point = "???"; + gAgentAvatarp->getAttachedPointName(entry.second.attachmentID, attachment_point); + + LLSD args; + args["ATTACHMENT_POINT"] = attachment_point; + + std::string verb = "select?name=" + LLURI::escape(entry.second.objectName); + followcamList += LLSLURL("inventory", entry.second.attachmentID, verb.c_str()).getSLURLString() + " " + + LLTrans::getString("WornOnAttachmentPoint", args) + "\n"; + } + else + { + followcamList += LLSLURL("objectim", entry.first, "").getSLURLString() + + "?name=" + LLURI::escape(entry.second.objectName) + + "&owner=" + entry.second.ownerID.asString(); + + LLSD args; + std::string slurl = args["slurl"].asString(); + if (slurl.empty()) + { + LLViewerRegion* region = LLWorld::instance().getRegionFromPosAgent(gAgentAvatarp->getPositionAgent()); + if(region) + { + LLSLURL region_slurl(region->getName(), gAgentAvatarp->getPositionAgent()); + slurl = region_slurl.getLocationString(); + } + } + + followcamList += "&slurl=" + LLURI::escape(slurl) + "\n"; + } + } + } + + if (followcamList.empty()) + { + return; + } + + LLSD args; + args["SOURCES"] = followcamList; + LLNotificationsUtil::add("WarnScriptedCamera", args); +} + +void PermissionsTracker::objectPropertiesCallback(LLMessageSystem* msg) +{ + LL_DEBUGS("PermissionsTracker") << "Received ObjectProperties message." << LL_ENDL; + + // if we weren't looking for any IDs, ignore this callback + if (mRequestedIDs.empty()) + { + LL_DEBUGS("PermissionsTracker") << "No objects in request list." << LL_ENDL; + return; + } + + // we might have received more than one answer in one block + S32 num = msg->getNumberOfBlocksFast(_PREHASH_ObjectData); + for (S32 index = 0; index < num; ++index) + { + LLUUID source_id; + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id, index); + + auto iter = std::find(mRequestedIDs.begin(), mRequestedIDs.end(), source_id); + // if this is one of the objects we were looking for, process the data + if (iter != mRequestedIDs.end()) + { + // get the name of the object + std::string object_name; + msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, object_name, index); + + LLUUID object_owner; + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, object_owner, index); + + LL_DEBUGS("PermissionsTracker") << "Received object name " << object_name + << " and owner " << object_owner.asString() << " for source " << source_id << LL_ENDL; + + // remove the object from the lookup list and add it to the known names list + mRequestedIDs.erase(iter); + + mPermissionsList[source_id].objectName = object_name; + mPermissionsList[source_id].ownerID = object_owner; + + LLAvatarName avatar_name; + if (LLAvatarNameCache::get(object_owner, &avatar_name)) + { + LL_DEBUGS("PermissionsTracker") << "Found cached entry for owner " << object_owner.asString() + << ": " << avatar_name.getCompleteName() << LL_ENDL; + mPermissionsList[source_id].ownerName = avatar_name.getCompleteName(); + } + else + { + if (mAvatarNameCacheConnections.find(object_owner) != mAvatarNameCacheConnections.end()) + { + boost::signals2::connection cb_connection = LLAvatarNameCache::get(object_owner, boost::bind(&PermissionsTracker::avatarNameCallback, this, _1, _2)); + mAvatarNameCacheConnections.insert(std::make_pair(object_owner, cb_connection)); + + LL_DEBUGS("PermissionsTracker") << "Requesting avatar name for owner " << object_owner.asString() << LL_ENDL; + } + } + } + } +} + +void PermissionsTracker::avatarNameCallback(const LLUUID& avatar_id, const LLAvatarName& avatar_name) +{ + LL_DEBUGS("PermissionsTracker") << "Received avatar name " << avatar_name.getCompleteName() << LL_ENDL; + + auto iter = mAvatarNameCacheConnections.find(avatar_id); + if (iter != mAvatarNameCacheConnections.end()) + { + if (iter->second.connected()) + { + iter->second.disconnect(); + } + mAvatarNameCacheConnections.erase(iter); + } + + for (auto entry : mPermissionsList) + { + if (entry.second.ownerID == avatar_id) + { + LL_DEBUGS("PermissionsTracker") << "Saved avatar name " << avatar_name.getCompleteName()<< " for source " << entry.first.asString() << LL_ENDL; + entry.second.ownerName = avatar_name.getCompleteName(); + } + } +} diff --git a/indra/newview/permissionstracker.h b/indra/newview/permissionstracker.h new file mode 100644 index 0000000000..0072d564e6 --- /dev/null +++ b/indra/newview/permissionstracker.h @@ -0,0 +1,86 @@ +/** + * @file permissionstracker.h + * @brief Permissions Tracker declaration + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2022, Zi Ree @ Second Life + * + * 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 PERMISSIONSTRACKER_H +#define PERMISSIONSTRACKER_H + +#include "llfloater.h" +#include "llsingleton.h" + +// -------------------------------------------------------------------------- +// PermissionsTracker: holds a list of requested script permissions to be +// referred to e.g. when trying to reset the camera view and a script is +// holding a follow cam which micht prevent it from working. +// -------------------------------------------------------------------------- + +class PermissionsTracker +: public LLSingleton +{ + LLSINGLETON(PermissionsTracker); + ~PermissionsTracker(); + + public: + enum PERM_TYPE + { + PERM_NONE = 0, + PERM_FOLLOWCAM = 1, + }; + + struct PermissionsEntry + { + LLUUID ownerID; // agent who owns the requesting object + LLUUID attachmentID; // attachment ID in inventory for attached objects + std::string ownerName; + std::string objectName; + LLDate time; // time when the permission was granted + U32 type; // what kind of permissions were granted + }; + + std::map mPermissionsList; // UUID of the requesting object + + void addPermissionsEntry( + const LLUUID& source_id, + PermissionsTracker::PERM_TYPE permission_type); // called in llviewermessage.cpp + + void removePermissionsEntry( + const LLUUID& source_id, + PermissionsTracker::PERM_TYPE permission_type); // called in llviewermessage.cpp + + void purgePermissionsEntries(); + + void objectPropertiesCallback(LLMessageSystem* msg); + void avatarNameCallback(const LLUUID& avatar_id, const LLAvatarName& av_name); + + void warnFollowcam(); // Warn the user if a script is holding followcam parameters + + std::vector mRequestedIDs; // list of object IDs we requested named for + + typedef std::map avatar_name_cache_connection_map_t; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; +}; + +#endif // PERMISSIONSTRACKER_H diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml index 4c40e9417e..862b75daf8 100644 --- a/indra/newview/skins/default/xui/de/notifications.xml +++ b/indra/newview/skins/default/xui/de/notifications.xml @@ -4839,8 +4839,15 @@ Bitte kopieren Sie diese in Ihr Inventar und versuchen Sie es erneut. Test-Ergebnis für gip-Level 6 Datei-Komprimierung für [FILE] mit Größe [SIZE] KB: Packen: [PACK_TIME]s [PSIZE]KB Entpacken: [UNPACK_TIME]s [USIZE]KB - fail - + fail + + + [MESSAGE] +
+