diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index d0fb586459..e93ba83434 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -18,9 +18,6 @@ #include // std headers // external library headers -#include -#include -#include // other Linden headers #include "llerror.h" #include "llstring.h" @@ -64,7 +61,9 @@ public: // Pass it a callback to our connect() method, so it can send events // from a particular LLEventPump to the plugin without having to know // this class or method name. - mListener(new LLLeapListener(boost::bind(&LLLeapImpl::connect, this, _1, _2))) + mListener(new LLLeapListener( + [this](LLEventPump& pump, const std::string& listener) + { return connect(pump, listener); })) { // Rule out unpopulated Params block if (! cparams.executable.isProvided()) @@ -93,7 +92,7 @@ public: } // Listen for child "termination" right away to catch launch errors. - mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::bad_launch, this, _1)); + mDonePump.listen("LLLeap", [this](const LLSD& data){ return bad_launch(data); }); // Okay, launch child. // Get a modifiable copy of params block to set files and postend. @@ -113,7 +112,7 @@ public: // Okay, launch apparently worked. Change our mDonePump listener. mDonePump.stopListening("LLLeap"); - mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::done, this, _1)); + mDonePump.listen("LLLeap", [this](const LLSD& data){ return done(data); }); // Child might pump large volumes of data through either stdout or // stderr. Don't bother copying all that data into notification event. @@ -128,13 +127,9 @@ public: // Listening on stdout is stateful. In general, we're either waiting // for the length prefix or waiting for the specified length of data. - // We address that with two different listener methods -- one of which - // is blocked at any given time. + mReadPrefix = true; mStdoutConnection = childout.getPump() - .listen("prefix", boost::bind(&LLLeapImpl::rstdout, this, _1)); - mStdoutDataConnection = childout.getPump() - .listen("data", boost::bind(&LLLeapImpl::rstdoutData, this, _1)); - mBlocker.reset(new LLEventPump::Blocker(mStdoutDataConnection)); + .listen("LLLeap", [this](const LLSD& data){ return rstdout(data); }); // Log anything sent up through stderr. When a typical program // encounters an error, it writes its error message to stderr and @@ -142,7 +137,7 @@ public: // interpreter behaves that way. More generally, though, a plugin // author can log whatever s/he wants to the viewer log using stderr. mStderrConnection = childerr.getPump() - .listen("LLLeap", boost::bind(&LLLeapImpl::rstderr, this, _1)); + .listen("LLLeap", [this](const LLSD& data){ return rstderr(data); }); // For our lifespan, intercept any LL_ERRS so we can notify plugin mRecorder = LLError::addGenericRecorder( @@ -255,120 +250,120 @@ public: return false; } - // Initial state of stateful listening on child stdout: wait for a length - // prefix, followed by ':'. - bool rstdout(const LLSD& data) + // Stateful listening on child stdout: + // wait for a length prefix, followed by ':'. + bool rstdout(const LLSD&) { LLProcess::ReadPipe& childout(mChild->getReadPipe(LLProcess::STDOUT)); - // It's possible we got notified of a couple digit characters without - // seeing the ':' -- unlikely, but still. Until we see ':', keep - // waiting. - if (childout.contains(':')) + while (childout.size()) { - std::istream& childstream(childout.get_istream()); - // Saw ':', read length prefix and store in mExpect. - size_t expect; - childstream >> expect; - int colon(childstream.get()); - if (colon != ':') + /*----------------- waiting for length prefix ------------------*/ + if (mReadPrefix) { - // Protocol failure. Clear out the rest of the pending data in - // childout (well, up to a max length) to log what was wrong. - LLProcess::ReadPipe::size_type - readlen((std::min)(childout.size(), LLProcess::ReadPipe::size_type(80))); - bad_protocol(STRINGIZE(expect << char(colon) << childout.read(readlen))); - } - else - { - // Saw length prefix, saw colon, life is good. Now wait for - // that length of data to arrive. - mExpect = expect; - LL_DEBUGS("LLLeap") << "got length, waiting for " - << mExpect << " bytes of data" << LL_ENDL; - // Block calls to this method; resetting mBlocker unblocks - // calls to the other method. - mBlocker.reset(new LLEventPump::Blocker(mStdoutConnection)); - // Go check if we've already received all the advertised data. - if (childout.size()) + // It's possible we got notified of a couple digit characters without + // seeing the ':' -- unlikely, but still. Until we see ':', keep + // waiting. + if (! childout.contains(':')) { - LLSD updata(data); - updata["len"] = LLSD::Integer(childout.size()); - rstdoutData(updata); + if (childout.contains('\n')) + { + // Since this is the initial listening state, this is where we'd + // arrive if the child isn't following protocol at all -- say + // because the user specified 'ls' or some darn thing. + bad_protocol(childout.getline()); + } + // Either way, stop looping. + break; } - } - } - else if (childout.contains('\n')) - { - // Since this is the initial listening state, this is where we'd - // arrive if the child isn't following protocol at all -- say - // because the user specified 'ls' or some darn thing. - bad_protocol(childout.getline()); - } - return false; - } - // State in which we listen on stdout for the specified length of data to - // arrive. - bool rstdoutData(const LLSD& data) - { - LLProcess::ReadPipe& childout(mChild->getReadPipe(LLProcess::STDOUT)); - // Until we've accumulated the promised length of data, keep waiting. - if (childout.size() >= mExpect) - { - // Ready to rock and roll. - LL_DEBUGS("LLLeap") << "needed " << mExpect << " bytes, got " - << childout.size() << ", parsing LLSD" << LL_ENDL; - LLSD data; -#if 1 - // specifically require notation LLSD from child - LLPointer parser(new LLSDNotationParser()); - S32 parse_status(parser->parse(childout.get_istream(), data, mExpect)); - if (parse_status == LLSDParser::PARSE_FAILURE) -#else - // SL-18330: accept any valid LLSD serialization format from child - // Unfortunately this runs into trouble we have not yet debugged. - bool parse_status(LLSDSerialize::deserialize(data, childout.get_istream(), mExpect)); - if (! parse_status) -#endif - { - bad_protocol("unparseable LLSD data"); - } - else if (! (data.isMap() && data["pump"].isString() && data.has("data"))) - { - // we got an LLSD object, but it lacks required keys - bad_protocol("missing 'pump' or 'data'"); + // Saw ':', read length prefix and store in mExpect. + std::istream& childstream(childout.get_istream()); + size_t expect; + childstream >> expect; + int colon(childstream.get()); + if (colon != ':') + { + // Protocol failure. Clear out the rest of the pending data in + // childout (well, up to a max length) to log what was wrong. + LLProcess::ReadPipe::size_type + readlen((std::min)(childout.size(), + LLProcess::ReadPipe::size_type(80))); + bad_protocol(stringize(expect, char(colon), childout.read(readlen))); + break; + } + else + { + // Saw length prefix, saw colon, life is good. Now wait for + // that length of data to arrive. + mExpect = expect; + LL_DEBUGS("LLLeap") << "got length, waiting for " + << mExpect << " bytes of data" << LL_ENDL; + // Transition to "read data" mode and loop back to check + // if we've already received all the advertised data. + mReadPrefix = false; + continue; + } } + /*----------------- saw prefix, wait for data ------------------*/ else { - try + // Until we've accumulated the promised length of data, keep waiting. + if (childout.size() < mExpect) { - // The LLSD object we got from our stream contains the - // keys we need. - LLEventPumps::instance().obtain(data["pump"]).post(data["data"]); + break; } - catch (const std::exception& err) + + // We have the data we were told to expect! Ready to rock and roll. + LL_DEBUGS("LLLeap") << "needed " << mExpect << " bytes, got " + << childout.size() << ", parsing LLSD" << LL_ENDL; + LLSD data; +#if 1 + // specifically require notation LLSD from child + LLPointer parser(new LLSDNotationParser()); + S32 parse_status(parser->parse(childout.get_istream(), data, mExpect)); + if (parse_status == LLSDParser::PARSE_FAILURE) +#else + // SL-18330: accept any valid LLSD serialization format from child + // Unfortunately this runs into trouble we have not yet debugged. + bool parse_status(LLSDSerialize::deserialize(data, childout.get_istream(), mExpect)); + if (! parse_status) +#endif { - // No plugin should be allowed to crash the viewer by - // driving an exception -- intentionally or not. - LOG_UNHANDLED_EXCEPTION(stringize("handling request ", data)); - // Whether or not the plugin added a "reply" key to the - // request, send a reply. We happen to know who originated - // this request, and the reply LLEventPump of interest. - // Not our problem if the plugin ignores the reply event. - data["reply"] = mReplyPump.getName(); - sendReply(llsd::map("error", - stringize(LLError::Log::classname(err), ": ", err.what())), - data); + bad_protocol("unparseable LLSD data"); + break; } - // Block calls to this method; resetting mBlocker unblocks - // calls to the other method. - mBlocker.reset(new LLEventPump::Blocker(mStdoutDataConnection)); - // Go check for any more pending events in the buffer. - if (childout.size()) + else if (! (data.isMap() && data["pump"].isString() && data.has("data"))) { - LLSD updata(data); - data["len"] = LLSD::Integer(childout.size()); - rstdout(updata); + // we got an LLSD object, but it lacks required keys + bad_protocol("missing 'pump' or 'data'"); + break; + } + else + { + try + { + // The LLSD object we got from our stream contains the + // keys we need. + LLEventPumps::instance().obtain(data["pump"]).post(data["data"]); + } + catch (const std::exception& err) + { + // No plugin should be allowed to crash the viewer by + // driving an exception -- intentionally or not. + LOG_UNHANDLED_EXCEPTION(stringize("handling request ", data)); + // Whether or not the plugin added a "reply" key to the + // request, send a reply. We happen to know who originated + // this request, and the reply LLEventPump of interest. + // Not our problem if the plugin ignores the reply event. + data["reply"] = mReplyPump.getName(); + sendReply(llsd::map("error", + stringize(LLError::Log::classname(err), ": ", err.what())), + data); + } + // Transition to "read prefix" mode and go check for any + // more pending events in the buffer. + mReadPrefix = true; + continue; } } } @@ -453,7 +448,8 @@ private: // child's stdin, suitably enriched with the pump name on which it was // received. return pump.listen(listener, - boost::bind(&LLLeapImpl::wstdin, this, pump.getName(), _1)); + [this, name=pump.getName()](const LLSD& data) + { return wstdin(name, data); }); } std::string mDesc; @@ -461,11 +457,11 @@ private: LLEventStream mReplyPump; LLProcessPtr mChild; LLTempBoundListener - mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection; - std::unique_ptr mBlocker; + mStdinConnection, mStdoutConnection, mStderrConnection; LLProcess::ReadPipe::size_type mExpect; LLError::RecorderPtr mRecorder; std::unique_ptr mListener; + bool mReadPrefix; }; // These must follow the declaration of LLLeapImpl, so they may as well be last. diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp index a8714ba7d0..2d0db0280e 100644 --- a/indra/llui/llemojihelper.cpp +++ b/indra/llui/llemojihelper.cpp @@ -103,20 +103,34 @@ void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, c if (mHelperHandle.isDead()) { LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER); + // Try to prevent failed build of emoji picker from killing the viewer. + if(!pHelperFloater) + { + LL_WARNS() << "Cannot show emoji helper, reason unknown." << LL_ENDL; + return; + } + // mHelperHandle = pHelperFloater->getHandle(); mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())[0]); }, std::placeholders::_2)); } setHostCtrl(hostctrl_p); mEmojiCommitCb = cb; - S32 floater_x, floater_y; - if (!hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView)) + S32 floater_x=0, floater_y=0;// initialise to avoid warnings + if (hostctrl_p && !hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView))// another unchecked pointer access { - LL_ERRS() << "Cannot show emoji helper for non-floater controls." << LL_ENDL; + LL_WARNS() << "Cannot show emoji helper for non-floater controls." << LL_ENDL; // Is this really worth crashing over? return; } LLFloater* pHelperFloater = mHelperHandle.get(); + // Be a bit paranoid - the previous code should have ensured this or returned. + if (!pHelperFloater) + { + LL_WARNS() << "Helper floater unexpectedly null." << LL_ENDL; + return; + } + // LLRect rect = pHelperFloater->getRect(); S32 left = floater_x - HELPER_FLOATER_OFFSET_X; S32 top = floater_y - HELPER_FLOATER_OFFSET_Y + rect.getHeight(); diff --git a/indra/newview/fspanellogin.cpp b/indra/newview/fspanellogin.cpp index 222b5dbd4e..b645b3430d 100644 --- a/indra/newview/fspanellogin.cpp +++ b/indra/newview/fspanellogin.cpp @@ -250,8 +250,11 @@ FSPanelLogin::FSPanelLogin(const LLRect &rect, LLTextBox* grid_mgr_help_text = getChild("grid_login_text"); grid_mgr_help_text->setClickedCallback(onClickGridMgrHelp, NULL); +#ifdef OPENSIM LLTextBox* grid_builder_text = getChild("grid_builder_text"); grid_builder_text->setClickedCallback(onClickGridBuilder, NULL); + grid_builder_text->setVisible(true); +#endif LLSLURL start_slurl(LLStartUp::getStartSLURL()); // The StartSLURL might have been set either by an explicit command-line diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 825e48fb33..8a6e4a286b 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -156,6 +156,7 @@ #include "llviewershadermgr.h" #include "NACLantispam.h" #include "../llcrashlogger/llcrashlogger.h" +#include #if LL_WINDOWS #include #endif @@ -5272,38 +5273,13 @@ void LLPanelPreferenceSkins::refreshPreviewImage() // // Backup Settings -// copied from llxfer_file.cpp - Hopefully this will be part of LLFile some day -Zi -// added a safeguard so the destination file is only created when the source file exists -Zi -S32 copy_prefs_file(const std::string& from, const std::string& to) +static void copy_prefs_file(const std::string& from, const std::string& to) { - LL_WARNS() << "copying " << from << " to " << to << LL_ENDL; - S32 rv = 0; - LLFILE* in = LLFile::fopen(from, "rb"); /*Flawfinder: ignore*/ - if(!in) - { - LL_WARNS() << "couldn't open source file " << from << " - copy aborted." << LL_ENDL; - return -1; - } + LL_INFOS() << "Copying " << from << " to " << to << LL_ENDL; - LLFILE* out = LLFile::fopen(to, "wb"); /*Flawfinder: ignore*/ - if(!out) - { - fclose(in); - LL_WARNS() << "couldn't open destination file " << to << " - copy aborted." << LL_ENDL; - return -1; - } - - S32 read = 0; - const S32 COPY_BUFFER_SIZE = 16384; - U8 buffer[COPY_BUFFER_SIZE]; - while(((read = fread(buffer, 1, sizeof(buffer), in)) > 0) - && (fwrite(buffer, 1, read, out) == (U32)read)); /* Flawfinder : ignore */ - if(ferror(in) || ferror(out)) rv = -2; - - if(in) fclose(in); - if(out) fclose(out); - - return rv; + std::error_code ec; + if (!std::filesystem::copy_file(from, to, ec) || ec) + LL_WARNS() << "Couldn't copy file: " << ec.message() << LL_ENDL; } static LLPanelInjector t_pref_backup("panel_preference_backup"); diff --git a/indra/newview/skins/default/xui/en/panel_fs_login.xml b/indra/newview/skins/default/xui/en/panel_fs_login.xml index 52500edb4f..eb071fed6a 100644 --- a/indra/newview/skins/default/xui/en/panel_fs_login.xml +++ b/indra/newview/skins/default/xui/en/panel_fs_login.xml @@ -187,7 +187,8 @@ height="16" name="grid_builder_text" left="5" - width="190"> + width="190" + visible="false"> + Click to add more grids + width="250" + visible="false"> + Click to add more grids