SYNERGY 512 SonarCloud vulnerabilities in Synergy-Core (#6971)

* SYNERGY-512 SonarCloud vulnerabilities in Synergy-Core
* Fix all vulnerablilities from SonarCloud besides TLS
* Update ChangeLog

* SYNERGY-512 SonarCloud vulnerabilities in Synergy-Core
* Fix SonarCloud messages(Code Smells level)

* SYNERGY-512 SonarCloud vulnerabilities in Synergy-Core
* Fix build on Linux based systems

* SYNERGY-512 SonarCloud vulnerabilities in Synergy-Core
* Fix Sonar messages

* SYNERGY-512 SonarCloud vulnerabilities in Synergy-Core
* Fix Sonar messages

* SYNERGY-512 SonarCloud vulnerabilities in Synergy-Core
* Fix Sonar messages

* SYNERGY-512 SonarCloud vulnerabilities in Synergy-Core
* Resolve comment issues

* SYNERGY-512 SonarCloud vulnerabilities in Synergy-Core
* Fix comments

Co-authored-by: Andrii Batyiev <andrii-external@symless.com>
This commit is contained in:
Andrey Batyiev 2021-04-06 13:02:25 +03:00 committed by GitHub
parent 3c2810a3e0
commit ad1fd9c1af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 136 additions and 163 deletions

View file

@ -33,6 +33,7 @@ Bug fixes:
- #6946 Add build stage to filename - #6946 Add build stage to filename
- #6950 Synergy client doesn't save the server address when rebooted - #6950 Synergy client doesn't save the server address when rebooted
- #6951 Fix issue creating standard version for Raspberry Pi - #6951 Fix issue creating standard version for Raspberry Pi
- #6971 Fix vulnerabilities from SonarCloud
Enhancements: Enhancements:
- #6912 Removes UI for Screen Saver Sync and Files Drag and Drop - #6912 Removes UI for Screen Saver Sync and Files Drag and Drop

View file

@ -22,6 +22,7 @@
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
#include <QProcess> #include <QProcess>
#include <QFile>
#endif #endif
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
@ -48,20 +49,6 @@ QString hash(const QString& string)
return hash.toHex(); return hash.toHex();
} }
QString getFirstMacAddress()
{
QString mac;
foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces())
{
mac = interface.hardwareAddress();
if (mac.size() != 0)
{
break;
}
}
return mac;
}
qProcessorArch getProcessorArch() qProcessorArch getProcessorArch()
{ {
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
@ -90,26 +77,3 @@ qProcessorArch getProcessorArch()
return kProcessorArchUnknown; return kProcessorArchUnknown;
} }
QString getOSInformation()
{
QString result;
#if defined(Q_OS_LINUX)
result = "Linux";
try {
QStringList arguments;
arguments.append("/etc/os-release");
CommandProcess cp("/bin/cat", arguments);
QString output = cp.run();
QRegExp resultRegex(".*PRETTY_NAME=\"([^\"]+)\".*");
if (resultRegex.exactMatch(output)) {
result = resultRegex.cap(1);
}
} catch (...) {
}
#endif
return result;
}

View file

@ -26,6 +26,4 @@
void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData); void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData);
QString hash(const QString& string); QString hash(const QString& string);
QString getFirstMacAddress();
qProcessorArch getProcessorArch(); qProcessorArch getProcessorArch();
QString getOSInformation();

View file

@ -720,7 +720,7 @@ ArchMultithreadPosix::doThreadFunc(ArchThread thread)
lockMutex(m_threadMutex); lockMutex(m_threadMutex);
unlockMutex(m_threadMutex); unlockMutex(m_threadMutex);
void* result = NULL; void* result = nullptr;
try { try {
// go // go
result = (*thread->m_func)(thread->m_userData); result = (*thread->m_func)(thread->m_userData);
@ -728,6 +728,8 @@ ArchMultithreadPosix::doThreadFunc(ArchThread thread)
catch (XThreadCancel&) { catch (XThreadCancel&) {
// client called cancel() // client called cancel()
// set base value
result = nullptr;
} }
catch (...) { catch (...) {
// note -- don't catch (...) to avoid masking bugs // note -- don't catch (...) to avoid masking bugs

View file

@ -69,6 +69,7 @@ XBase::format(const char* /*id*/, const char* fmt, ...) const throw()
} }
catch (...) { catch (...) {
// ignore // ignore
result.clear();
} }
va_end(args); va_end(args);

View file

@ -44,7 +44,7 @@ public:
SecureSocket& operator=(SecureSocket &&) =delete; SecureSocket& operator=(SecureSocket &&) =delete;
// ISocket overrides // ISocket overrides
void close(); void close() override;
// IDataSocket overrides // IDataSocket overrides
virtual void connect(const NetworkAddress&); virtual void connect(const NetworkAddress&);

View file

@ -28,6 +28,7 @@
#include "mt/Mutex.h" #include "mt/Mutex.h"
#include "arch/Arch.h" #include "arch/Arch.h"
#include "arch/XArch.h" #include "arch/XArch.h"
#include "base/Log.h"
#include "base/IEventQueue.h" #include "base/IEventQueue.h"
// //
@ -57,6 +58,7 @@ TCPListenSocket::~TCPListenSocket()
} }
catch (...) { catch (...) {
// ignore // ignore
LOG((CLOG_WARN "error while closing TCP socket"));
} }
delete m_mutex; delete m_mutex;
} }

View file

@ -47,7 +47,7 @@ TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
try { try {
m_socket = ARCH->newSocket(family, IArchNetwork::kSTREAM); m_socket = ARCH->newSocket(family, IArchNetwork::kSTREAM);
} }
catch (XArchNetwork& e) { catch (const XArchNetwork& e) {
throw XSocketCreate(e.what()); throw XSocketCreate(e.what());
} }
@ -64,7 +64,7 @@ TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
m_flushed(&m_mutex, true), m_flushed(&m_mutex, true),
m_socketMultiplexer(socketMultiplexer) m_socketMultiplexer(socketMultiplexer)
{ {
assert(m_socket != NULL); assert(m_socket != nullptr);
LOG((CLOG_DEBUG "Opening new socket: %08X", m_socket)); LOG((CLOG_DEBUG "Opening new socket: %08X", m_socket));
@ -77,10 +77,11 @@ TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer,
TCPSocket::~TCPSocket() TCPSocket::~TCPSocket()
{ {
try { try {
// warning virtual function in destructor is very danger practice
close(); close();
} }
catch (...) { catch (...) {
// ignore LOG((CLOG_DEBUG "error while TCP socket destruction"));
} }
} }
@ -90,10 +91,10 @@ TCPSocket::bind(const NetworkAddress& addr)
try { try {
ARCH->bindSocket(m_socket, addr.getAddress()); ARCH->bindSocket(m_socket, addr.getAddress());
} }
catch (XArchNetworkAddressInUse& e) { catch (const XArchNetworkAddressInUse& e) {
throw XSocketAddressInUse(e.what()); throw XSocketAddressInUse(e.what());
} }
catch (XArchNetwork& e) { catch (const XArchNetwork& e) {
throw XSocketBind(e.what()); throw XSocketBind(e.what());
} }
} }
@ -104,7 +105,7 @@ TCPSocket::close()
LOG((CLOG_DEBUG "Closing socket: %08X", m_socket)); LOG((CLOG_DEBUG "Closing socket: %08X", m_socket));
// remove ourself from the multiplexer // remove ourself from the multiplexer
setJob(NULL); setJob(nullptr);
Lock lock(&m_mutex); Lock lock(&m_mutex);
@ -115,13 +116,13 @@ TCPSocket::close()
onDisconnected(); onDisconnected();
// close the socket // close the socket
if (m_socket != NULL) { if (m_socket != nullptr) {
ArchSocket socket = m_socket; ArchSocket socket = m_socket;
m_socket = NULL; m_socket = nullptr;
try { try {
ARCH->closeSocket(socket); ARCH->closeSocket(socket);
} }
catch (XArchNetwork& e) { catch (const XArchNetwork& e) {
// ignore, there's not much we can do // ignore, there's not much we can do
LOG((CLOG_WARN "error closing socket: %s", e.what())); LOG((CLOG_WARN "error closing socket: %s", e.what()));
} }
@ -143,7 +144,7 @@ TCPSocket::read(void* buffer, UInt32 n)
if (n > size) { if (n > size) {
n = size; n = size;
} }
if (buffer != NULL && n != 0) { if (buffer != nullptr && n != 0) {
memcpy(buffer, m_inputBuffer.peek(n), n); memcpy(buffer, m_inputBuffer.peek(n), n);
} }
m_inputBuffer.pop(n); m_inputBuffer.pop(n);
@ -209,8 +210,9 @@ TCPSocket::shutdownInput()
try { try {
ARCH->closeSocketForRead(m_socket); ARCH->closeSocketForRead(m_socket);
} }
catch (XArchNetwork&) { catch (const XArchNetwork& e) {
// ignore // ignore, there's not much we can do
LOG((CLOG_WARN "error closing socket: %s", e.what()));
} }
// shutdown buffer for reading // shutdown buffer for reading
@ -236,8 +238,9 @@ TCPSocket::shutdownOutput()
try { try {
ARCH->closeSocketForWrite(m_socket); ARCH->closeSocketForWrite(m_socket);
} }
catch (XArchNetwork&) { catch (const XArchNetwork& e) {
// ignore // ignore, there's not much we can do
LOG((CLOG_WARN "error closing socket: %s", e.what()));
} }
// shutdown buffer for writing // shutdown buffer for writing
@ -281,7 +284,7 @@ TCPSocket::connect(const NetworkAddress& addr)
Lock lock(&m_mutex); Lock lock(&m_mutex);
// fail on attempts to reconnect // fail on attempts to reconnect
if (m_socket == NULL || m_connected) { if (m_socket == nullptr || m_connected) {
sendConnectionFailedEvent("busy"); sendConnectionFailedEvent("busy");
return; return;
} }
@ -296,7 +299,7 @@ TCPSocket::connect(const NetworkAddress& addr)
m_writable = true; m_writable = true;
} }
} }
catch (XArchNetwork& e) { catch (const XArchNetwork& e) {
throw XSocketConnect(e.what()); throw XSocketConnect(e.what());
} }
} }
@ -317,13 +320,14 @@ TCPSocket::init()
// mouse motion messages are much less useful if they're delayed. // mouse motion messages are much less useful if they're delayed.
ARCH->setNoDelayOnSocket(m_socket, true); ARCH->setNoDelayOnSocket(m_socket, true);
} }
catch (XArchNetwork& e) { catch (const XArchNetwork& e) {
try { try {
ARCH->closeSocket(m_socket); ARCH->closeSocket(m_socket);
m_socket = NULL; m_socket = nullptr;
} }
catch (XArchNetwork&) { catch (const XArchNetwork& e) {
// ignore // ignore, there's not much we can do
LOG((CLOG_WARN "error closing socket: %s", e.what()));
} }
throw XSocketCreate(e.what()); throw XSocketCreate(e.what());
} }
@ -392,7 +396,7 @@ void
TCPSocket::setJob(ISocketMultiplexerJob* job) TCPSocket::setJob(ISocketMultiplexerJob* job)
{ {
// multiplexer will delete the old job // multiplexer will delete the old job
if (job == NULL) { if (job == nullptr) {
m_socketMultiplexer->removeSocket(this); m_socketMultiplexer->removeSocket(this);
} }
else { else {
@ -405,13 +409,13 @@ TCPSocket::newJob()
{ {
// note -- must have m_mutex locked on entry // note -- must have m_mutex locked on entry
if (m_socket == NULL) { if (m_socket == nullptr) {
return NULL; return nullptr;
} }
else if (!m_connected) { else if (!m_connected) {
assert(!m_readable); assert(!m_readable);
if (!(m_readable || m_writable)) { if (!(m_readable || m_writable)) {
return NULL; return nullptr;
} }
return new TSocketMultiplexerMethodJob<TCPSocket>( return new TSocketMultiplexerMethodJob<TCPSocket>(
this, &TCPSocket::serviceConnecting, this, &TCPSocket::serviceConnecting,
@ -419,7 +423,7 @@ TCPSocket::newJob()
} }
else { else {
if (!(m_readable || (m_writable && (m_outputBuffer.getSize() > 0)))) { if (!(m_readable || (m_writable && (m_outputBuffer.getSize() > 0)))) {
return NULL; return nullptr;
} }
return new TSocketMultiplexerMethodJob<TCPSocket>( return new TSocketMultiplexerMethodJob<TCPSocket>(
this, &TCPSocket::serviceConnected, this, &TCPSocket::serviceConnected,
@ -439,7 +443,7 @@ TCPSocket::sendConnectionFailedEvent(const char* msg)
void void
TCPSocket::sendEvent(Event::Type type) TCPSocket::sendEvent(Event::Type type)
{ {
m_events->addEvent(Event(type, getEventTarget(), NULL)); m_events->addEvent(Event(type, getEventTarget(), nullptr));
} }
void void
@ -516,7 +520,7 @@ TCPSocket::serviceConnecting(ISocketMultiplexerJob* job,
// connection may have failed or succeeded // connection may have failed or succeeded
ARCH->throwErrorOnSocket(m_socket); ARCH->throwErrorOnSocket(m_socket);
} }
catch (XArchNetwork& e) { catch (const XArchNetwork& e) {
sendConnectionFailedEvent(e.what()); sendConnectionFailedEvent(e.what());
onDisconnected(); onDisconnected();
return newJob(); return newJob();
@ -592,5 +596,9 @@ TCPSocket::serviceConnected(ISocketMultiplexerJob* job,
} }
} }
return result == kBreak ? NULL : result == kNew ? newJob() : job; if (result == kBreak) {
return nullptr;
}
return result == kNew ? newJob() : job;
} }

View file

@ -30,6 +30,7 @@
#include "base/Stopwatch.h" #include "base/Stopwatch.h"
#include "common/stdvector.h" #include "common/stdvector.h"
#include <algorithm>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <X11/Xatom.h> #include <X11/Xatom.h>
@ -70,7 +71,6 @@ XWindowsClipboard::XWindowsClipboard(Display* display,
m_selection = XInternAtom(m_display, "CLIPBOARD", False); m_selection = XInternAtom(m_display, "CLIPBOARD", False);
break; break;
case kClipboardSelection:
default: default:
m_selection = XA_PRIMARY; m_selection = XA_PRIMARY;
break; break;
@ -126,12 +126,10 @@ XWindowsClipboard::addRequest(Window owner, Window requestor,
if (owner == m_window) { if (owner == m_window) {
LOG((CLOG_DEBUG1 "request for clipboard %d, target %s by 0x%08x (property=%s)", m_selection, XWindowsUtil::atomToString(m_display, target).c_str(), requestor, XWindowsUtil::atomToString(m_display, property).c_str())); LOG((CLOG_DEBUG1 "request for clipboard %d, target %s by 0x%08x (property=%s)", m_selection, XWindowsUtil::atomToString(m_display, target).c_str(), requestor, XWindowsUtil::atomToString(m_display, property).c_str()));
if (wasOwnedAtTime(time)) { if (wasOwnedAtTime(time)) {
if (target == m_atomMultiple) { if (target == m_atomMultiple && property != None) {
// add a multiple request. property may not be None // add a multiple request. property may not be None
// according to ICCCM. // according to ICCCM.
if (property != None) { success = insertMultipleReply(requestor, time, property);
success = insertMultipleReply(requestor, time, property);
}
} }
else { else {
addSimpleRequest(requestor, target, time, property); addSimpleRequest(requestor, target, time, property);
@ -178,7 +176,7 @@ XWindowsClipboard::addSimpleRequest(Window requestor,
} }
else { else {
IXWindowsClipboardConverter* converter = getConverter(target); IXWindowsClipboardConverter* converter = getConverter(target);
if (converter != NULL) { if (converter != nullptr) {
IClipboard::EFormat clipboardFormat = converter->getFormat(); IClipboard::EFormat clipboardFormat = converter->getFormat();
if (m_added[clipboardFormat]) { if (m_added[clipboardFormat]) {
try { try {
@ -188,6 +186,7 @@ XWindowsClipboard::addSimpleRequest(Window requestor,
} }
catch (...) { catch (...) {
// ignore -- cannot convert // ignore -- cannot convert
LOG((CLOG_WARN "error while converting clipboard data"));
} }
} }
} }
@ -406,7 +405,7 @@ XWindowsClipboard::clearConverters()
IXWindowsClipboardConverter* IXWindowsClipboardConverter*
XWindowsClipboard::getConverter(Atom target, bool onlyIfNotAdded) const XWindowsClipboard::getConverter(Atom target, bool onlyIfNotAdded) const
{ {
IXWindowsClipboardConverter* converter = NULL; IXWindowsClipboardConverter* converter = nullptr;
for (ConverterList::const_iterator index = m_converters.begin(); for (ConverterList::const_iterator index = m_converters.begin();
index != m_converters.end(); ++index) { index != m_converters.end(); ++index) {
converter = *index; converter = *index;
@ -414,17 +413,15 @@ XWindowsClipboard::getConverter(Atom target, bool onlyIfNotAdded) const
break; break;
} }
} }
if (converter == NULL) { if (converter == nullptr) {
LOG((CLOG_DEBUG1 " no converter for target %s", XWindowsUtil::atomToString(m_display, target).c_str())); LOG((CLOG_DEBUG1 " no converter for target %s", XWindowsUtil::atomToString(m_display, target).c_str()));
return NULL; return nullptr;
} }
// optionally skip already handled targets // optionally skip already handled targets
if (onlyIfNotAdded) { if (onlyIfNotAdded && m_added[converter->getFormat()]) {
if (m_added[converter->getFormat()]) { LOG((CLOG_DEBUG1 " skipping handled format %d", converter->getFormat()));
LOG((CLOG_DEBUG1 " skipping handled format %d", converter->getFormat())); return nullptr;
return NULL;
}
} }
return converter; return converter;
@ -519,7 +516,7 @@ XWindowsClipboard::icccmFillCache()
} }
XWindowsUtil::convertAtomProperty(data); XWindowsUtil::convertAtomProperty(data);
const Atom* targets = reinterpret_cast<const Atom*>(data.data()); // TODO: Safe? auto targets = static_cast<const Atom*>(static_cast<const void*>(data.data()));
const UInt32 numTargets = data.size() / sizeof(Atom); const UInt32 numTargets = data.size() / sizeof(Atom);
LOG((CLOG_DEBUG " available targets: %s", XWindowsUtil::atomsToString(m_display, targets, numTargets).c_str())); LOG((CLOG_DEBUG " available targets: %s", XWindowsUtil::atomsToString(m_display, targets, numTargets).c_str()));
@ -572,8 +569,8 @@ bool
XWindowsClipboard::icccmGetSelection(Atom target, XWindowsClipboard::icccmGetSelection(Atom target,
Atom* actualTarget, String* data) const Atom* actualTarget, String* data) const
{ {
assert(actualTarget != NULL); assert(actualTarget != nullptr);
assert(data != NULL); assert(data != nullptr);
// request data conversion // request data conversion
CICCCMGetClipboard getter(m_window, m_time, m_atomData); CICCCMGetClipboard getter(m_window, m_time, m_atomData);
@ -597,7 +594,7 @@ XWindowsClipboard::icccmGetTime() const
String data; String data;
if (icccmGetSelection(m_atomTimestamp, &actualTarget, &data) && if (icccmGetSelection(m_atomTimestamp, &actualTarget, &data) &&
actualTarget == m_atomInteger) { actualTarget == m_atomInteger) {
Time time = *reinterpret_cast<const Time*>(data.data()); Time time = *static_cast<const Time*>(static_cast<const void*>(data.data()));
LOG((CLOG_DEBUG1 "got ICCCM time %d", time)); LOG((CLOG_DEBUG1 "got ICCCM time %d", time));
return time; return time;
} }
@ -735,8 +732,7 @@ XWindowsClipboard::motifFillCache()
// format list is after static item structure elements // format list is after static item structure elements
const SInt32 numFormats = item.m_numFormats - item.m_numDeletedFormats; const SInt32 numFormats = item.m_numFormats - item.m_numDeletedFormats;
const SInt32* formats = reinterpret_cast<const SInt32*>(item.m_size + auto formats = static_cast<const SInt32*>(static_cast<const void*>(item.m_size + data.data()));
static_cast<const char*>(data.data()));
// get the available formats // get the available formats
typedef std::map<Atom, String> MotifFormatMap; typedef std::map<Atom, String> MotifFormatMap;
@ -832,7 +828,7 @@ XWindowsClipboard::motifGetSelection(const MotifClipFormat* format,
Window root = RootWindow(m_display, DefaultScreen(m_display)); Window root = RootWindow(m_display, DefaultScreen(m_display));
return XWindowsUtil::getWindowProperty(m_display, root, return XWindowsUtil::getWindowProperty(m_display, root,
target, data, target, data,
actualTarget, NULL, False); actualTarget, nullptr, False);
} }
IClipboard::Time IClipboard::Time
@ -862,7 +858,7 @@ XWindowsClipboard::insertMultipleReply(Window requestor,
// data is a list of atom pairs: target, property // data is a list of atom pairs: target, property
XWindowsUtil::convertAtomProperty(data); XWindowsUtil::convertAtomProperty(data);
const Atom* targets = reinterpret_cast<const Atom*>(data.data()); auto targets = static_cast<const Atom*>(static_cast<const void*>(data.data()));
const UInt32 numTargets = data.size() / sizeof(Atom); const UInt32 numTargets = data.size() / sizeof(Atom);
// add replies for each target // add replies for each target
@ -894,7 +890,7 @@ XWindowsClipboard::insertMultipleReply(Window requestor,
void void
XWindowsClipboard::insertReply(Reply* reply) XWindowsClipboard::insertReply(Reply* reply)
{ {
assert(reply != NULL); assert(reply != nullptr);
// note -- we must respond to requests in order if requestor,target,time // note -- we must respond to requests in order if requestor,target,time
// are the same, otherwise we can use whatever order we like with one // are the same, otherwise we can use whatever order we like with one
@ -995,7 +991,7 @@ XWindowsClipboard::pushReplies(ReplyMap::iterator& mapIndex,
bool bool
XWindowsClipboard::sendReply(Reply* reply) XWindowsClipboard::sendReply(Reply* reply)
{ {
assert(reply != NULL); assert(reply != nullptr);
// bail out immediately if reply is done // bail out immediately if reply is done
if (reply->m_done) { if (reply->m_done) {
@ -1083,68 +1079,75 @@ XWindowsClipboard::sendReply(Reply* reply)
} }
} }
// send notification if we haven't yet // notification already sended
if (!reply->m_replied) { if (!reply->m_replied) {
LOG((CLOG_DEBUG1 "clipboard: sending notify to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property)); return false;
reply->m_replied = true;
// dump every property on the requestor window to the debug2 }
// log. we've seen what appears to be a bug in lesstif and
// knowing the properties may help design a workaround, if LOG((CLOG_DEBUG1 "clipboard: sending notify to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property));
// it becomes necessary. reply->m_replied = true;
if (CLOG->getFilter() >= kDEBUG2) {
XWindowsUtil::ErrorLock lock(m_display); // nothing to log
int n; if (CLOG->getFilter() < kDEBUG2) {
Atom* props = XListProperties(m_display, reply->m_requestor, &n); sendNotify(reply->m_requestor, m_selection,
LOG((CLOG_DEBUG2 "properties of 0x%08x:", reply->m_requestor)); reply->m_target, reply->m_property,
for (int i = 0; i < n; ++i) { static_cast<unsigned int>(reply->m_time));
Atom target;
String data; // wait for delete notify
char* name = XGetAtomName(m_display, props[i]); return false;
if (!XWindowsUtil::getWindowProperty(m_display,
reply->m_requestor, }
props[i], &data, &target, NULL, False)) {
LOG((CLOG_DEBUG2 " %s: <can't read property>", name)); // dump every property on the requestor window to the debug2
} // log. we've seen what appears to be a bug in lesstif and
else { // knowing the properties may help design a workaround, if
// if there are any non-ascii characters in string // it becomes necessary.
// then print the binary data. XWindowsUtil::ErrorLock lock(m_display);
static const char* hex = "0123456789abcdef"; int n;
String::size_type j = 0; Atom* props = XListProperties(m_display, reply->m_requestor, &n);
while (j < data.size()) { LOG((CLOG_DEBUG2 "properties of 0x%08x:", reply->m_requestor));
if (data[j] < 32 || data[j] > 126) { for (int i = 0; i < n; ++i) {
String tmp; Atom target;
tmp.reserve(data.size() * 3); String data;
for (j = 0; j < data.size(); ++j) { char* name = XGetAtomName(m_display, props[i]);
unsigned char v = (unsigned char)data[j]; if (!XWindowsUtil::getWindowProperty(m_display,
tmp += hex[v >> 16]; reply->m_requestor,
tmp += hex[v & 15]; props[i], &data, &target, nullptr, False)) {
tmp += ' '; LOG((CLOG_DEBUG2 " %s: <can't read property>", name));
} }
data = tmp; else {
break; // convert to hex if contains non ascii symbols
} if (std::find_if(data.begin(), data.end(),
++j; [](const unsigned char& c) { return c < 32 || c > 126; }) != data.end()) {
} const String hex_digits = "0123456789abcdef";
char* type = XGetAtomName(m_display, target); String tmp;
LOG((CLOG_DEBUG2 " %s (%s): %s", name, type, data.c_str())); tmp.reserve(data.length() * 3);
if (type != NULL) { std::for_each(data.begin(), data.end(), [hex_digits, &tmp](const unsigned char& c)
XFree(type); {
} tmp += hex_digits[c >> 16];
} tmp += hex_digits[c & 15];
if (name != NULL) { tmp += ' ';
XFree(name); });
} data = tmp;
} }
if (props != NULL) { char* type = XGetAtomName(m_display, target);
XFree(props); LOG((CLOG_DEBUG2 " %s (%s): %s", name, type, data.c_str()));
if (type != nullptr) {
XFree(type);
} }
} }
if (name != nullptr) {
sendNotify(reply->m_requestor, m_selection, XFree(name);
reply->m_target, reply->m_property, }
reply->m_time);
} }
if (props != nullptr) {
XFree(props);
}
sendNotify(reply->m_requestor, m_selection,
reply->m_target, reply->m_property,
reply->m_time);
// wait for delete notify // wait for delete notify
return false; return false;
@ -1224,7 +1227,7 @@ XWindowsClipboard::wasOwnedAtTime(::Time time) const
Atom Atom
XWindowsClipboard::getTargetsData(String& data, int* format) const XWindowsClipboard::getTargetsData(String& data, int* format) const
{ {
assert(format != NULL); assert(format != nullptr);
// add standard targets // add standard targets
XWindowsUtil::appendAtomData(data, m_atomTargets); XWindowsUtil::appendAtomData(data, m_atomTargets);
@ -1249,7 +1252,7 @@ XWindowsClipboard::getTargetsData(String& data, int* format) const
Atom Atom
XWindowsClipboard::getTimestampData(String& data, int* format) const XWindowsClipboard::getTimestampData(String& data, int* format) const
{ {
assert(format != NULL); assert(format != nullptr);
checkCache(); checkCache();
XWindowsUtil::appendTimeData(data, m_timeOwned); XWindowsUtil::appendTimeData(data, m_timeOwned);
@ -1271,8 +1274,6 @@ XWindowsClipboard::CICCCMGetClipboard::CICCCMGetClipboard(
m_failed(false), m_failed(false),
m_done(false), m_done(false),
m_reading(false), m_reading(false),
m_data(NULL),
m_actualTarget(NULL),
m_error(false) m_error(false)
{ {
// do nothing // do nothing
@ -1287,8 +1288,8 @@ bool
XWindowsClipboard::CICCCMGetClipboard::readClipboard(Display* display, XWindowsClipboard::CICCCMGetClipboard::readClipboard(Display* display,
Atom selection, Atom target, Atom* actualTarget, String* data) Atom selection, Atom target, Atom* actualTarget, String* data)
{ {
assert(actualTarget != NULL); assert(actualTarget != nullptr);
assert(data != NULL); assert(data != nullptr);
LOG((CLOG_DEBUG1 "request selection=%s, target=%s, window=%x", XWindowsUtil::atomToString(display, selection).c_str(), XWindowsUtil::atomToString(display, target).c_str(), m_requestor)); LOG((CLOG_DEBUG1 "request selection=%s, target=%s, window=%x", XWindowsUtil::atomToString(display, selection).c_str(), XWindowsUtil::atomToString(display, target).c_str(), m_requestor));
@ -1438,7 +1439,7 @@ XWindowsClipboard::CICCCMGetClipboard::processEvent(
Atom target; Atom target;
const String::size_type oldSize = m_data->size(); const String::size_type oldSize = m_data->size();
if (!XWindowsUtil::getWindowProperty(display, m_requestor, if (!XWindowsUtil::getWindowProperty(display, m_requestor,
m_property, m_data, &target, NULL, True)) { m_property, m_data, &target, nullptr, True)) {
// unable to read property // unable to read property
m_failed = true; m_failed = true;
return true; return true;
@ -1448,11 +1449,7 @@ XWindowsClipboard::CICCCMGetClipboard::processEvent(
// selection owner is busted. if the INCR property has no size // selection owner is busted. if the INCR property has no size
// then the selection owner is busted. // then the selection owner is busted.
if (target == m_atomIncr) { if (target == m_atomIncr) {
if (m_incr) { if (m_incr || m_data->size() == oldSize) {
m_failed = true;
m_error = true;
}
else if (m_data->size() == oldSize) {
m_failed = true; m_failed = true;
m_error = true; m_error = true;
} }

View file

@ -172,11 +172,11 @@ private:
bool m_reading; bool m_reading;
// the converted selection data // the converted selection data
String* m_data; String* m_data = nullptr;
// the actual type of the data. if this is None then the // the actual type of the data. if this is None then the
// selection owner cannot convert to the requested type. // selection owner cannot convert to the requested type.
Atom* m_actualTarget; Atom* m_actualTarget = nullptr;
public: public:
// true iff the selection owner didn't follow ICCCM conventions // true iff the selection owner didn't follow ICCCM conventions