Ansariel 2024-06-10 23:46:12 +02:00
commit 6f866e682d
6 changed files with 141 additions and 150 deletions

View File

@ -18,9 +18,6 @@
#include <algorithm>
// std headers
// external library headers
#include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/tokenizer.hpp>
// 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<LLSDParser> 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<LLSDParser> 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<LLEventPump::Blocker> mBlocker;
mStdinConnection, mStdoutConnection, mStderrConnection;
LLProcess::ReadPipe::size_type mExpect;
LLError::RecorderPtr mRecorder;
std::unique_ptr<LLLeapListener> mListener;
bool mReadPrefix;
};
// These must follow the declaration of LLLeapImpl, so they may as well be last.

View File

@ -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);
// <FS:Beq> 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;
}
// </FS:Beq>
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;// <FS:Beq/> initialise to avoid warnings
if (hostctrl_p && !hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView))// <FS:Beq/> 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; // <FS:Beq/> Is this really worth crashing over?
return;
}
LLFloater* pHelperFloater = mHelperHandle.get();
// <FS:Beq> Be a bit paranoid - the previous code should have ensured this or returned.
if (!pHelperFloater)
{
LL_WARNS() << "Helper floater unexpectedly null." << LL_ENDL;
return;
}
// </FS:Beq>
LLRect rect = pHelperFloater->getRect();
S32 left = floater_x - HELPER_FLOATER_OFFSET_X;
S32 top = floater_y - HELPER_FLOATER_OFFSET_Y + rect.getHeight();

View File

@ -250,8 +250,11 @@ FSPanelLogin::FSPanelLogin(const LLRect &rect,
LLTextBox* grid_mgr_help_text = getChild<LLTextBox>("grid_login_text");
grid_mgr_help_text->setClickedCallback(onClickGridMgrHelp, NULL);
#ifdef OPENSIM
LLTextBox* grid_builder_text = getChild<LLTextBox>("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

View File

@ -156,6 +156,7 @@
#include "llviewershadermgr.h"
#include "NACLantispam.h"
#include "../llcrashlogger/llcrashlogger.h"
#include <filesystem>
#if LL_WINDOWS
#include <VersionHelpers.h>
#endif
@ -5272,38 +5273,13 @@ void LLPanelPreferenceSkins::refreshPreviewImage()
// </FS:PP>
// <FS:Zi> 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<FSPanelPreferenceBackup> t_pref_backup("panel_preference_backup");

View File

@ -187,7 +187,8 @@
height="16"
name="grid_builder_text"
left="5"
width="190">
width="190"
visible="false">
+ Click to add more grids
</text>
<text

View File

@ -291,7 +291,8 @@
name="grid_builder_text"
valign="center"
left="45"
width="250">
width="250"
visible="false">
+ Click to add more grids
</text>
</layout_panel>