mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2025-02-09 23:19:26 +01:00
Chromeclip (#69)
* Initial binary clipboard support * Rename -DLP_Clip_Types to -DLP_ClipTypes * Better handling of websocket frames * Copy-paste bug in SSE2 scaling to under 0.5x * Remove old text clipboard * Bind text to binary clipboard * Move binclip clear to probing phase * Off-by-one in sse2 scaling * Add a clarifying log message for INCR clipboard transfers * WIP: Update novnc commit * Fix CentOS pipeline * webpack fix * Update novnc commit * Change some DLP defaults * update novnc commit Co-authored-by: Lauri Kasanen <cand@gmx.com> Co-authored-by: matt <matt@kasmweb.com>
This commit is contained in:
parent
e6d1b8c3c8
commit
5b28a168d0
@ -284,74 +284,26 @@ void SConnection::setEncodings(int nEncodings, const rdr::S32* encodings)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SMsgHandler::setEncodings(nEncodings, encodings);
|
SMsgHandler::setEncodings(nEncodings, encodings);
|
||||||
|
|
||||||
if (cp.supportsExtendedClipboard) {
|
|
||||||
rdr::U32 sizes[] = { 0 };
|
|
||||||
writer()->writeClipboardCaps(rfb::clipboardUTF8 |
|
|
||||||
rfb::clipboardRequest |
|
|
||||||
rfb::clipboardPeek |
|
|
||||||
rfb::clipboardNotify |
|
|
||||||
rfb::clipboardProvide,
|
|
||||||
sizes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConnection::clientCutText(const char* str, int len)
|
void SConnection::clearBinaryClipboard()
|
||||||
{
|
{
|
||||||
hasLocalClipboard = false;
|
binaryClipboard.clear();
|
||||||
|
|
||||||
strFree(clientClipboard);
|
|
||||||
clientClipboard = NULL;
|
|
||||||
|
|
||||||
clientClipboard = latin1ToUTF8(str);
|
|
||||||
|
|
||||||
handleClipboardAnnounce(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConnection::handleClipboardRequest(rdr::U32 flags)
|
void SConnection::addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
||||||
|
const rdr::U32 len)
|
||||||
{
|
{
|
||||||
if (!(flags & rfb::clipboardUTF8))
|
binaryClipboard_t bin;
|
||||||
return;
|
strncpy(bin.mime, mime, sizeof(bin.mime));
|
||||||
if (!hasLocalClipboard)
|
bin.mime[sizeof(bin.mime) - 1] = '\0';
|
||||||
return;
|
|
||||||
handleClipboardRequest();
|
bin.data.resize(len);
|
||||||
|
memcpy(&bin.data[0], data, len);
|
||||||
|
|
||||||
|
binaryClipboard.push_back(bin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConnection::handleClipboardPeek(rdr::U32 flags)
|
|
||||||
{
|
|
||||||
if (!hasLocalClipboard)
|
|
||||||
return;
|
|
||||||
if (cp.clipboardFlags() & rfb::clipboardNotify)
|
|
||||||
writer()->writeClipboardNotify(rfb::clipboardUTF8);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SConnection::handleClipboardNotify(rdr::U32 flags)
|
|
||||||
{
|
|
||||||
strFree(clientClipboard);
|
|
||||||
clientClipboard = NULL;
|
|
||||||
|
|
||||||
if (flags & rfb::clipboardUTF8) {
|
|
||||||
handleClipboardAnnounce(true);
|
|
||||||
hasLocalClipboard = false;
|
|
||||||
} else {
|
|
||||||
handleClipboardAnnounce(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SConnection::handleClipboardProvide(rdr::U32 flags,
|
|
||||||
const size_t* lengths,
|
|
||||||
const rdr::U8* const* data)
|
|
||||||
{
|
|
||||||
if (!(flags & rfb::clipboardUTF8))
|
|
||||||
return;
|
|
||||||
|
|
||||||
strFree(clientClipboard);
|
|
||||||
clientClipboard = NULL;
|
|
||||||
|
|
||||||
clientClipboard = convertLF((const char*)data[0], lengths[0]);
|
|
||||||
|
|
||||||
handleClipboardData(clientClipboard, strlen(clientClipboard));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SConnection::supportsQEMUKeyEvent()
|
void SConnection::supportsQEMUKeyEvent()
|
||||||
{
|
{
|
||||||
@ -445,56 +397,13 @@ void SConnection::enableContinuousUpdates(bool enable,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConnection::handleClipboardRequest()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SConnection::handleClipboardAnnounce(bool available)
|
void SConnection::handleClipboardAnnounce(bool available)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConnection::handleClipboardData(const char* data, int len)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SConnection::requestClipboard()
|
|
||||||
{
|
|
||||||
if (clientClipboard != NULL) {
|
|
||||||
handleClipboardData(clientClipboard, strlen(clientClipboard));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cp.supportsExtendedClipboard &&
|
|
||||||
(cp.clipboardFlags() & rfb::clipboardRequest))
|
|
||||||
writer()->writeClipboardRequest(rfb::clipboardUTF8);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SConnection::announceClipboard(bool available)
|
void SConnection::announceClipboard(bool available)
|
||||||
{
|
{
|
||||||
hasLocalClipboard = available;
|
hasLocalClipboard = available;
|
||||||
|
|
||||||
if (cp.supportsExtendedClipboard &&
|
|
||||||
(cp.clipboardFlags() & rfb::clipboardNotify))
|
|
||||||
writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
|
|
||||||
else {
|
|
||||||
if (available)
|
|
||||||
handleClipboardRequest();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SConnection::sendClipboardData(const char* data, int len)
|
|
||||||
{
|
|
||||||
if (cp.supportsExtendedClipboard &&
|
|
||||||
(cp.clipboardFlags() & rfb::clipboardProvide)) {
|
|
||||||
CharArray filtered(convertCRLF(data));
|
|
||||||
size_t sizes[1] = { strlen(filtered.buf) + 1 };
|
|
||||||
const rdr::U8* data[1] = { (const rdr::U8*)filtered.buf };
|
|
||||||
writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data);
|
|
||||||
} else {
|
|
||||||
CharArray latin1(utf8ToLatin1(data));
|
|
||||||
|
|
||||||
writer()->writeServerCutText(latin1.buf, strlen(latin1.buf));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConnection::writeFakeColourMap(void)
|
void SConnection::writeFakeColourMap(void)
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <rdr/OutStream.h>
|
#include <rdr/OutStream.h>
|
||||||
#include <rfb/SMsgHandler.h>
|
#include <rfb/SMsgHandler.h>
|
||||||
#include <rfb/SecurityServer.h>
|
#include <rfb/SecurityServer.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace rfb {
|
namespace rfb {
|
||||||
|
|
||||||
@ -73,14 +74,9 @@ namespace rfb {
|
|||||||
|
|
||||||
virtual void setEncodings(int nEncodings, const rdr::S32* encodings);
|
virtual void setEncodings(int nEncodings, const rdr::S32* encodings);
|
||||||
|
|
||||||
virtual void clientCutText(const char* str, int len);
|
virtual void clearBinaryClipboard();
|
||||||
|
virtual void addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
||||||
virtual void handleClipboardRequest(rdr::U32 flags);
|
const rdr::U32 len);
|
||||||
virtual void handleClipboardPeek(rdr::U32 flags);
|
|
||||||
virtual void handleClipboardNotify(rdr::U32 flags);
|
|
||||||
virtual void handleClipboardProvide(rdr::U32 flags,
|
|
||||||
const size_t* lengths,
|
|
||||||
const rdr::U8* const* data);
|
|
||||||
|
|
||||||
virtual void supportsQEMUKeyEvent();
|
virtual void supportsQEMUKeyEvent();
|
||||||
|
|
||||||
@ -127,25 +123,11 @@ namespace rfb {
|
|||||||
virtual void enableContinuousUpdates(bool enable,
|
virtual void enableContinuousUpdates(bool enable,
|
||||||
int x, int y, int w, int h);
|
int x, int y, int w, int h);
|
||||||
|
|
||||||
// handleClipboardRequest() is called whenever the client requests
|
|
||||||
// the server to send over its clipboard data. It will only be
|
|
||||||
// called after the server has first announced a clipboard change
|
|
||||||
// via announceClipboard().
|
|
||||||
virtual void handleClipboardRequest();
|
|
||||||
|
|
||||||
// handleClipboardAnnounce() is called to indicate a change in the
|
// handleClipboardAnnounce() is called to indicate a change in the
|
||||||
// clipboard on the client. Call requestClipboard() to access the
|
// clipboard on the client. Call requestClipboard() to access the
|
||||||
// actual data.
|
// actual data.
|
||||||
virtual void handleClipboardAnnounce(bool available);
|
virtual void handleClipboardAnnounce(bool available);
|
||||||
|
|
||||||
// handleClipboardData() is called when the client has sent over
|
|
||||||
// the clipboard data as a result of a previous call to
|
|
||||||
// requestClipboard(). Note that this function might never be
|
|
||||||
// called if the clipboard data was no longer available when the
|
|
||||||
// client received the request.
|
|
||||||
virtual void handleClipboardData(const char* data, int len);
|
|
||||||
|
|
||||||
|
|
||||||
virtual void add_changed_all() {}
|
virtual void add_changed_all() {}
|
||||||
|
|
||||||
// setAccessRights() allows a security package to limit the access rights
|
// setAccessRights() allows a security package to limit the access rights
|
||||||
@ -166,22 +148,11 @@ namespace rfb {
|
|||||||
|
|
||||||
// Other methods
|
// Other methods
|
||||||
|
|
||||||
// requestClipboard() will result in a request to the client to
|
|
||||||
// transfer its clipboard data. A call to handleClipboardData()
|
|
||||||
// will be made once the data is available.
|
|
||||||
virtual void requestClipboard();
|
|
||||||
|
|
||||||
// announceClipboard() informs the client of changes to the
|
// announceClipboard() informs the client of changes to the
|
||||||
// clipboard on the server. The client may later request the
|
// clipboard on the server. The client may later request the
|
||||||
// clipboard data via handleClipboardRequest().
|
// clipboard data via handleClipboardRequest().
|
||||||
virtual void announceClipboard(bool available);
|
virtual void announceClipboard(bool available);
|
||||||
|
|
||||||
// sendClipboardData() transfers the clipboard data to the client
|
|
||||||
// and should be called whenever the client has requested the
|
|
||||||
// clipboard via handleClipboardRequest().
|
|
||||||
virtual void sendClipboardData(const char* data, int len);
|
|
||||||
|
|
||||||
|
|
||||||
// authenticated() returns true if the client has authenticated
|
// authenticated() returns true if the client has authenticated
|
||||||
// successfully.
|
// successfully.
|
||||||
bool authenticated() { return (state_ == RFBSTATE_INITIALISATION ||
|
bool authenticated() { return (state_ == RFBSTATE_INITIALISATION ||
|
||||||
@ -221,12 +192,19 @@ namespace rfb {
|
|||||||
|
|
||||||
rdr::S32 getPreferredEncoding() { return preferredEncoding; }
|
rdr::S32 getPreferredEncoding() { return preferredEncoding; }
|
||||||
|
|
||||||
|
struct binaryClipboard_t {
|
||||||
|
char mime[32];
|
||||||
|
std::vector<unsigned char> data;
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setState(stateEnum s) { state_ = s; }
|
void setState(stateEnum s) { state_ = s; }
|
||||||
|
|
||||||
void setReader(SMsgReader *r) { reader_ = r; }
|
void setReader(SMsgReader *r) { reader_ = r; }
|
||||||
void setWriter(SMsgWriter *w) { writer_ = w; }
|
void setWriter(SMsgWriter *w) { writer_ = w; }
|
||||||
|
|
||||||
|
std::vector<binaryClipboard_t> binaryClipboard;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void writeFakeColourMap(void);
|
void writeFakeColourMap(void);
|
||||||
|
|
||||||
|
@ -78,23 +78,13 @@ namespace rfb {
|
|||||||
// the relevant RFB protocol messages from clients.
|
// the relevant RFB protocol messages from clients.
|
||||||
// See InputHandler for method signatures.
|
// See InputHandler for method signatures.
|
||||||
|
|
||||||
// handleClipboardRequest() is called whenever a client requests
|
|
||||||
// the server to send over its clipboard data. It will only be
|
|
||||||
// called after the server has first announced a clipboard change
|
|
||||||
// via VNCServer::announceClipboard().
|
|
||||||
virtual void handleClipboardRequest() {}
|
|
||||||
|
|
||||||
// handleClipboardAnnounce() is called to indicate a change in the
|
// handleClipboardAnnounce() is called to indicate a change in the
|
||||||
// clipboard on a client. Call VNCServer::requestClipboard() to
|
// clipboard on a client. Call VNCServer::requestClipboard() to
|
||||||
// access the actual data.
|
// access the actual data.
|
||||||
virtual void handleClipboardAnnounce(bool __unused_attr available) {}
|
virtual void handleClipboardAnnounce(bool __unused_attr available) {}
|
||||||
|
|
||||||
// handleClipboardData() is called when a client has sent over
|
virtual void handleClipboardAnnounceBinary(const unsigned __unused_attr num,
|
||||||
// the clipboard data as a result of a previous call to
|
const char __unused_attr mimes[][32]) {}
|
||||||
// VNCServer::requestClipboard(). Note that this function might
|
|
||||||
// never be called if the clipboard data was no longer available
|
|
||||||
// when the client received the request.
|
|
||||||
virtual void handleClipboardData(const char* __unused_attr data, int len __unused_attr) {}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~SDesktop() {}
|
virtual ~SDesktop() {}
|
||||||
|
@ -64,26 +64,16 @@ void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings)
|
|||||||
supportsQEMUKeyEvent();
|
supportsQEMUKeyEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgHandler::handleClipboardCaps(rdr::U32 flags, const rdr::U32* lengths)
|
void SMsgHandler::handleClipboardAnnounceBinary(const unsigned, const char mimes[][32])
|
||||||
{
|
|
||||||
cp.setClipboardCaps(flags, lengths);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMsgHandler::handleClipboardRequest(rdr::U32 flags)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgHandler::handleClipboardPeek(rdr::U32 flags)
|
void SMsgHandler::clearBinaryClipboard()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgHandler::handleClipboardNotify(rdr::U32 flags)
|
void SMsgHandler::addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
||||||
{
|
const rdr::U32 len)
|
||||||
}
|
|
||||||
|
|
||||||
void SMsgHandler::handleClipboardProvide(rdr::U32 flags,
|
|
||||||
const size_t* lengths,
|
|
||||||
const rdr::U8* const* data)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,14 +54,10 @@ namespace rfb {
|
|||||||
virtual void enableContinuousUpdates(bool enable,
|
virtual void enableContinuousUpdates(bool enable,
|
||||||
int x, int y, int w, int h) = 0;
|
int x, int y, int w, int h) = 0;
|
||||||
|
|
||||||
virtual void handleClipboardCaps(rdr::U32 flags,
|
virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
|
||||||
const rdr::U32* lengths);
|
virtual void clearBinaryClipboard();
|
||||||
virtual void handleClipboardRequest(rdr::U32 flags);
|
virtual void addBinaryClipboard(const char mime[], const rdr::U8 *data,
|
||||||
virtual void handleClipboardPeek(rdr::U32 flags);
|
const rdr::U32 len);
|
||||||
virtual void handleClipboardNotify(rdr::U32 flags);
|
|
||||||
virtual void handleClipboardProvide(rdr::U32 flags,
|
|
||||||
const size_t* lengths,
|
|
||||||
const rdr::U8* const* data);
|
|
||||||
|
|
||||||
virtual void sendStats(const bool toClient = true) = 0;
|
virtual void sendStats(const bool toClient = true) = 0;
|
||||||
virtual void handleFrameStats(rdr::U32 all, rdr::U32 render) = 0;
|
virtual void handleFrameStats(rdr::U32 all, rdr::U32 render) = 0;
|
||||||
|
@ -35,8 +35,6 @@ using namespace rfb;
|
|||||||
|
|
||||||
static LogWriter vlog("SMsgReader");
|
static LogWriter vlog("SMsgReader");
|
||||||
|
|
||||||
static IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
|
|
||||||
|
|
||||||
SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_)
|
SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_)
|
||||||
: handler(handler_), is(is_)
|
: handler(handler_), is(is_)
|
||||||
{
|
{
|
||||||
@ -83,6 +81,9 @@ void SMsgReader::readMsg()
|
|||||||
case msgTypeFrameStats:
|
case msgTypeFrameStats:
|
||||||
readFrameStats();
|
readFrameStats();
|
||||||
break;
|
break;
|
||||||
|
case msgTypeBinaryClipboard:
|
||||||
|
readBinaryClipboard();
|
||||||
|
break;
|
||||||
case msgTypeKeyEvent:
|
case msgTypeKeyEvent:
|
||||||
readKeyEvent();
|
readKeyEvent();
|
||||||
break;
|
break;
|
||||||
@ -240,109 +241,54 @@ void SMsgReader::readClientCutText()
|
|||||||
readExtendedClipboard(slen);
|
readExtendedClipboard(slen);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (len > (size_t)maxCutText) {
|
|
||||||
is->skip(len);
|
is->skip(len);
|
||||||
vlog.error("Cut text too long (%d bytes) - ignoring", len);
|
vlog.error("Client sent old cuttext msg, ignoring");
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
void SMsgReader::readBinaryClipboard()
|
||||||
|
{
|
||||||
|
const rdr::U8 num = is->readU8();
|
||||||
|
rdr::U8 i, valid = 0;
|
||||||
|
char tmpmimes[num][32];
|
||||||
|
|
||||||
|
handler->clearBinaryClipboard();
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
const rdr::U8 mimelen = is->readU8();
|
||||||
|
if (mimelen > 32 - 1) {
|
||||||
|
vlog.error("Mime too long (%u)", mimelen);
|
||||||
}
|
}
|
||||||
CharArray ca(len+1);
|
|
||||||
ca.buf[len] = 0;
|
char mime[mimelen + 1];
|
||||||
|
mime[mimelen] = '\0';
|
||||||
|
is->readBytes(mime, mimelen);
|
||||||
|
|
||||||
|
strncpy(tmpmimes[valid], mime, 32);
|
||||||
|
tmpmimes[valid][31] = '\0';
|
||||||
|
|
||||||
|
const rdr::U32 len = is->readU32();
|
||||||
|
CharArray ca(len);
|
||||||
is->readBytes(ca.buf, len);
|
is->readBytes(ca.buf, len);
|
||||||
handler->clientCutText(ca.buf, len);
|
|
||||||
|
if (rfb::Server::DLP_ClipAcceptMax && len > (unsigned) rfb::Server::DLP_ClipAcceptMax) {
|
||||||
|
vlog.info("DLP: refused to receive binary clipboard, too large");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
vlog.debug("Received binary clipboard, type %s, %u bytes", mime, len);
|
||||||
|
|
||||||
|
handler->addBinaryClipboard(mime, (rdr::U8 *) ca.buf, len);
|
||||||
|
valid++;
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->handleClipboardAnnounceBinary(valid, tmpmimes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgReader::readExtendedClipboard(rdr::S32 len)
|
void SMsgReader::readExtendedClipboard(rdr::S32 len)
|
||||||
{
|
{
|
||||||
rdr::U32 flags;
|
|
||||||
rdr::U32 action;
|
|
||||||
|
|
||||||
if (len < 4)
|
if (len < 4)
|
||||||
throw Exception("Invalid extended clipboard message");
|
throw Exception("Invalid extended clipboard message");
|
||||||
if (len > maxCutText) {
|
vlog.error("Client sent old cuttext msg, ignoring");
|
||||||
vlog.error("Extended clipboard message too long (%d bytes) - ignoring", len);
|
|
||||||
is->skip(len);
|
is->skip(len);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
flags = is->readU32();
|
|
||||||
action = flags & clipboardActionMask;
|
|
||||||
|
|
||||||
if (action & clipboardCaps) {
|
|
||||||
int i;
|
|
||||||
size_t num;
|
|
||||||
rdr::U32 lengths[16];
|
|
||||||
|
|
||||||
num = 0;
|
|
||||||
for (i = 0;i < 16;i++) {
|
|
||||||
if (flags & (1 << i))
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len < (rdr::S32)(4 + 4*num))
|
|
||||||
throw Exception("Invalid extended clipboard message");
|
|
||||||
|
|
||||||
num = 0;
|
|
||||||
for (i = 0;i < 16;i++) {
|
|
||||||
if (flags & (1 << i))
|
|
||||||
lengths[num++] = is->readU32();
|
|
||||||
}
|
|
||||||
|
|
||||||
handler->handleClipboardCaps(flags, lengths);
|
|
||||||
} else if (action == clipboardProvide) {
|
|
||||||
rdr::ZlibInStream zis;
|
|
||||||
|
|
||||||
int i;
|
|
||||||
size_t num;
|
|
||||||
size_t lengths[16];
|
|
||||||
rdr::U8* buffers[16];
|
|
||||||
|
|
||||||
zis.setUnderlying(is, len - 4);
|
|
||||||
|
|
||||||
num = 0;
|
|
||||||
for (i = 0;i < 16;i++) {
|
|
||||||
if (!(flags & 1 << i))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
lengths[num] = zis.readU32();
|
|
||||||
if (lengths[num] > (size_t)maxCutText) {
|
|
||||||
vlog.error("Extended clipboard data too long (%d bytes) - ignoring",
|
|
||||||
(unsigned)lengths[num]);
|
|
||||||
zis.skip(lengths[num]);
|
|
||||||
flags &= ~(1 << i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffers[num] = new rdr::U8[lengths[num]];
|
|
||||||
zis.readBytes(buffers[num], lengths[num]);
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
|
|
||||||
zis.flushUnderlying();
|
|
||||||
zis.setUnderlying(NULL, 0);
|
|
||||||
|
|
||||||
handler->handleClipboardProvide(flags, lengths, buffers);
|
|
||||||
|
|
||||||
num = 0;
|
|
||||||
for (i = 0;i < 16;i++) {
|
|
||||||
if (!(flags & 1 << i))
|
|
||||||
continue;
|
|
||||||
delete [] buffers[num++];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (action) {
|
|
||||||
case clipboardRequest:
|
|
||||||
handler->handleClipboardRequest(flags);
|
|
||||||
break;
|
|
||||||
case clipboardPeek:
|
|
||||||
handler->handleClipboardPeek(flags);
|
|
||||||
break;
|
|
||||||
case clipboardNotify:
|
|
||||||
handler->handleClipboardNotify(flags);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw Exception("Invalid extended clipboard action");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgReader::readRequestStats()
|
void SMsgReader::readRequestStats()
|
||||||
|
@ -58,6 +58,7 @@ namespace rfb {
|
|||||||
void readExtendedClipboard(rdr::S32 len);
|
void readExtendedClipboard(rdr::S32 len);
|
||||||
void readRequestStats();
|
void readRequestStats();
|
||||||
void readFrameStats();
|
void readFrameStats();
|
||||||
|
void readBinaryClipboard();
|
||||||
|
|
||||||
void readQEMUMessage();
|
void readQEMUMessage();
|
||||||
void readQEMUKeyEvent();
|
void readQEMUKeyEvent();
|
||||||
|
@ -85,118 +85,21 @@ void SMsgWriter::writeBell()
|
|||||||
endMsg();
|
endMsg();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMsgWriter::writeServerCutText(const char* str, int len)
|
void SMsgWriter::writeBinaryClipboard(const std::vector<SConnection::binaryClipboard_t> &b)
|
||||||
{
|
{
|
||||||
startMsg(msgTypeServerCutText);
|
startMsg(msgTypeBinaryClipboard);
|
||||||
os->pad(3);
|
|
||||||
os->writeU32(len);
|
|
||||||
os->writeBytes(str, len);
|
|
||||||
endMsg();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMsgWriter::writeClipboardCaps(rdr::U32 caps,
|
os->writeU8(b.size());
|
||||||
const rdr::U32* lengths)
|
rdr::U8 i;
|
||||||
{
|
for (i = 0; i < b.size(); i++) {
|
||||||
size_t i, count;
|
const rdr::U8 mimelen = strlen(b[i].mime);
|
||||||
|
os->writeU8(mimelen);
|
||||||
|
os->writeBytes(b[i].mime, mimelen);
|
||||||
|
|
||||||
if (!cp->supportsExtendedClipboard)
|
os->writeU32(b[i].data.size());
|
||||||
throw Exception("Client does not support extended clipboard");
|
os->writeBytes(&b[i].data[0], b[i].data.size());
|
||||||
|
|
||||||
count = 0;
|
|
||||||
for (i = 0;i < 16;i++) {
|
|
||||||
if (caps & (1 << i))
|
|
||||||
count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startMsg(msgTypeServerCutText);
|
|
||||||
os->pad(3);
|
|
||||||
os->writeS32(-(4 + 4 * count));
|
|
||||||
|
|
||||||
os->writeU32(caps | clipboardCaps);
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
for (i = 0;i < 16;i++) {
|
|
||||||
if (caps & (1 << i))
|
|
||||||
os->writeU32(lengths[count++]);
|
|
||||||
}
|
|
||||||
|
|
||||||
endMsg();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMsgWriter::writeClipboardRequest(rdr::U32 flags)
|
|
||||||
{
|
|
||||||
if (!cp->supportsExtendedClipboard)
|
|
||||||
throw Exception("Client does not support extended clipboard");
|
|
||||||
if (!(cp->clipboardFlags() & clipboardRequest))
|
|
||||||
throw Exception("Client does not support clipboard \"request\" action");
|
|
||||||
|
|
||||||
startMsg(msgTypeServerCutText);
|
|
||||||
os->pad(3);
|
|
||||||
os->writeS32(-4);
|
|
||||||
os->writeU32(flags | clipboardRequest);
|
|
||||||
endMsg();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMsgWriter::writeClipboardPeek(rdr::U32 flags)
|
|
||||||
{
|
|
||||||
if (!cp->supportsExtendedClipboard)
|
|
||||||
throw Exception("Client does not support extended clipboard");
|
|
||||||
if (!(cp->clipboardFlags() & clipboardPeek))
|
|
||||||
throw Exception("Client does not support clipboard \"peek\" action");
|
|
||||||
|
|
||||||
startMsg(msgTypeServerCutText);
|
|
||||||
os->pad(3);
|
|
||||||
os->writeS32(-4);
|
|
||||||
os->writeU32(flags | clipboardPeek);
|
|
||||||
endMsg();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMsgWriter::writeClipboardNotify(rdr::U32 flags)
|
|
||||||
{
|
|
||||||
if (!cp->supportsExtendedClipboard)
|
|
||||||
throw Exception("Client does not support extended clipboard");
|
|
||||||
if (!(cp->clipboardFlags() & clipboardNotify))
|
|
||||||
throw Exception("Client does not support clipboard \"notify\" action");
|
|
||||||
|
|
||||||
startMsg(msgTypeServerCutText);
|
|
||||||
os->pad(3);
|
|
||||||
os->writeS32(-4);
|
|
||||||
os->writeU32(flags | clipboardNotify);
|
|
||||||
endMsg();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SMsgWriter::writeClipboardProvide(rdr::U32 flags,
|
|
||||||
const size_t* lengths,
|
|
||||||
const rdr::U8* const* data)
|
|
||||||
{
|
|
||||||
rdr::MemOutStream mos;
|
|
||||||
rdr::ZlibOutStream zos;
|
|
||||||
|
|
||||||
int i, count;
|
|
||||||
|
|
||||||
if (!cp->supportsExtendedClipboard)
|
|
||||||
throw Exception("Client does not support extended clipboard");
|
|
||||||
if (!(cp->clipboardFlags() & clipboardProvide))
|
|
||||||
throw Exception("Client does not support clipboard \"provide\" action");
|
|
||||||
|
|
||||||
zos.setUnderlying(&mos);
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
for (i = 0;i < 16;i++) {
|
|
||||||
if (!(flags & (1 << i)))
|
|
||||||
continue;
|
|
||||||
zos.writeU32(lengths[count]);
|
|
||||||
zos.writeBytes(data[count], lengths[count]);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
zos.flush();
|
|
||||||
|
|
||||||
startMsg(msgTypeServerCutText);
|
|
||||||
os->pad(3);
|
|
||||||
os->writeS32(-(4 + mos.length()));
|
|
||||||
os->writeU32(flags | clipboardProvide);
|
|
||||||
os->writeBytes(mos.data(), mos.length());
|
|
||||||
endMsg();
|
endMsg();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
#include <rdr/types.h>
|
#include <rdr/types.h>
|
||||||
#include <rfb/encodings.h>
|
#include <rfb/encodings.h>
|
||||||
#include <rfb/ScreenSet.h>
|
#include <rfb/ScreenSet.h>
|
||||||
|
#include <rfb/SConnection.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace rdr { class OutStream; }
|
namespace rdr { class OutStream; }
|
||||||
|
|
||||||
@ -54,14 +56,8 @@ namespace rfb {
|
|||||||
|
|
||||||
// writeBell() and writeServerCutText() do the obvious thing.
|
// writeBell() and writeServerCutText() do the obvious thing.
|
||||||
void writeBell();
|
void writeBell();
|
||||||
void writeServerCutText(const char* str, int len);
|
|
||||||
|
|
||||||
void writeClipboardCaps(rdr::U32 caps, const rdr::U32* lengths);
|
void writeBinaryClipboard(const std::vector<SConnection::binaryClipboard_t> &b);
|
||||||
void writeClipboardRequest(rdr::U32 flags);
|
|
||||||
void writeClipboardPeek(rdr::U32 flags);
|
|
||||||
void writeClipboardNotify(rdr::U32 flags);
|
|
||||||
void writeClipboardProvide(rdr::U32 flags, const size_t* lengths,
|
|
||||||
const rdr::U8* const* data);
|
|
||||||
|
|
||||||
void writeStats(const char* str, int len);
|
void writeStats(const char* str, int len);
|
||||||
|
|
||||||
|
@ -149,15 +149,15 @@ rfb::IntParameter rfb::Server::webpVideoQuality
|
|||||||
rfb::IntParameter rfb::Server::DLP_ClipSendMax
|
rfb::IntParameter rfb::Server::DLP_ClipSendMax
|
||||||
("DLP_ClipSendMax",
|
("DLP_ClipSendMax",
|
||||||
"Limit clipboard bytes to send to clients in one transaction",
|
"Limit clipboard bytes to send to clients in one transaction",
|
||||||
10000, 0, INT_MAX);
|
0, 0, INT_MAX);
|
||||||
rfb::IntParameter rfb::Server::DLP_ClipAcceptMax
|
rfb::IntParameter rfb::Server::DLP_ClipAcceptMax
|
||||||
("DLP_ClipAcceptMax",
|
("DLP_ClipAcceptMax",
|
||||||
"Limit clipboard bytes to receive from clients in one transaction",
|
"Limit clipboard bytes to receive from clients in one transaction",
|
||||||
10000, 0, INT_MAX);
|
0, 0, INT_MAX);
|
||||||
rfb::IntParameter rfb::Server::DLP_ClipDelay
|
rfb::IntParameter rfb::Server::DLP_ClipDelay
|
||||||
("DLP_ClipDelay",
|
("DLP_ClipDelay",
|
||||||
"This many milliseconds must pass between clipboard actions",
|
"This many milliseconds must pass between clipboard actions",
|
||||||
1000, 0, INT_MAX);
|
0, 0, INT_MAX);
|
||||||
rfb::IntParameter rfb::Server::DLP_KeyRateLimit
|
rfb::IntParameter rfb::Server::DLP_KeyRateLimit
|
||||||
("DLP_KeyRateLimit",
|
("DLP_KeyRateLimit",
|
||||||
"Reject keyboard presses over this many per second",
|
"Reject keyboard presses over this many per second",
|
||||||
@ -171,6 +171,10 @@ rfb::StringParameter rfb::Server::DLP_Region
|
|||||||
("DLP_Region",
|
("DLP_Region",
|
||||||
"Black out anything outside this region",
|
"Black out anything outside this region",
|
||||||
"");
|
"");
|
||||||
|
rfb::StringParameter rfb::Server::DLP_Clip_Types
|
||||||
|
("DLP_ClipTypes",
|
||||||
|
"Allowed binary clipboard mimetypes",
|
||||||
|
"text/html,image/png");
|
||||||
|
|
||||||
rfb::BoolParameter rfb::Server::DLP_RegionAllowClick
|
rfb::BoolParameter rfb::Server::DLP_RegionAllowClick
|
||||||
("DLP_RegionAllowClick",
|
("DLP_RegionAllowClick",
|
||||||
|
@ -50,6 +50,7 @@ namespace rfb {
|
|||||||
static IntParameter DLP_KeyRateLimit;
|
static IntParameter DLP_KeyRateLimit;
|
||||||
static StringParameter DLP_ClipLog;
|
static StringParameter DLP_ClipLog;
|
||||||
static StringParameter DLP_Region;
|
static StringParameter DLP_Region;
|
||||||
|
static StringParameter DLP_Clip_Types;
|
||||||
static BoolParameter DLP_RegionAllowClick;
|
static BoolParameter DLP_RegionAllowClick;
|
||||||
static BoolParameter DLP_RegionAllowRelease;
|
static BoolParameter DLP_RegionAllowRelease;
|
||||||
static IntParameter jpegVideoQuality;
|
static IntParameter jpegVideoQuality;
|
||||||
|
@ -57,7 +57,8 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
|
|||||||
inProcessMessages(false),
|
inProcessMessages(false),
|
||||||
pendingSyncFence(false), syncFence(false), fenceFlags(0),
|
pendingSyncFence(false), syncFence(false), fenceFlags(0),
|
||||||
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
|
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
|
||||||
losslessTimer(this), kbdLogTimer(this), server(server_), updates(false),
|
losslessTimer(this), kbdLogTimer(this), binclipTimer(this),
|
||||||
|
server(server_), updates(false),
|
||||||
updateRenderedCursor(false), removeRenderedCursor(false),
|
updateRenderedCursor(false), removeRenderedCursor(false),
|
||||||
continuousUpdates(false), encodeManager(this, &server_->encCache),
|
continuousUpdates(false), encodeManager(this, &server_->encCache),
|
||||||
needsPermCheck(false), pointerEventTime(0),
|
needsPermCheck(false), pointerEventTime(0),
|
||||||
@ -413,18 +414,6 @@ static void keylog(unsigned keysym, const char *client) {
|
|||||||
flushKeylog(client);
|
flushKeylog(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::requestClipboardOrClose()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (!(accessRights & AccessCutText)) return;
|
|
||||||
if (!rfb::Server::acceptCutText) return;
|
|
||||||
if (state() != RFBSTATE_NORMAL) return;
|
|
||||||
requestClipboard();
|
|
||||||
} catch(rdr::Exception& e) {
|
|
||||||
close(e.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VNCSConnectionST::announceClipboardOrClose(bool available)
|
void VNCSConnectionST::announceClipboardOrClose(bool available)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -437,29 +426,51 @@ void VNCSConnectionST::announceClipboardOrClose(bool available)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::sendClipboardDataOrClose(const char* data)
|
void VNCSConnectionST::clearBinaryClipboardData()
|
||||||
|
{
|
||||||
|
clearBinaryClipboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VNCSConnectionST::sendBinaryClipboardDataOrClose(const char* mime,
|
||||||
|
const unsigned char *data,
|
||||||
|
const unsigned len)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (!(accessRights & AccessCutText)) return;
|
if (!(accessRights & AccessCutText)) return;
|
||||||
if (!rfb::Server::sendCutText) return;
|
if (!rfb::Server::sendCutText) return;
|
||||||
if (msSince(&lastClipboardOp) < (unsigned) rfb::Server::DLP_ClipDelay) {
|
if (rfb::Server::DLP_ClipSendMax && len > (unsigned) rfb::Server::DLP_ClipSendMax) {
|
||||||
vlog.info("DLP: client %s: refused to send clipboard, too soon",
|
vlog.info("DLP: client %s: refused to send binary clipboard, too large",
|
||||||
sock->getPeerAddress());
|
sock->getPeerAddress());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int len = strlen(data);
|
|
||||||
const int origlen = len;
|
cliplog((const char *) data, len, len, "sent", sock->getPeerAddress());
|
||||||
if (rfb::Server::DLP_ClipSendMax && len > rfb::Server::DLP_ClipSendMax)
|
|
||||||
len = rfb::Server::DLP_ClipSendMax;
|
|
||||||
cliplog(data, len, origlen, "sent", sock->getPeerAddress());
|
|
||||||
if (state() != RFBSTATE_NORMAL) return;
|
if (state() != RFBSTATE_NORMAL) return;
|
||||||
sendClipboardData(data, len);
|
|
||||||
gettimeofday(&lastClipboardOp, NULL);
|
addBinaryClipboard(mime, data, len);
|
||||||
|
binclipTimer.start(100);
|
||||||
} catch(rdr::Exception& e) {
|
} catch(rdr::Exception& e) {
|
||||||
close(e.str());
|
close(e.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNCSConnectionST::getBinaryClipboardData(const char* mime, const unsigned char **data,
|
||||||
|
unsigned *len)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < binaryClipboard.size(); i++) {
|
||||||
|
if (!strcmp(binaryClipboard[i].mime, mime)) {
|
||||||
|
*data = &binaryClipboard[i].data[0];
|
||||||
|
*len = binaryClipboard[i].data.size();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vlog.error("Binary clipboard data for mime %s not found", mime);
|
||||||
|
*data = (const unsigned char *) "";
|
||||||
|
*len = 1;
|
||||||
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::setDesktopNameOrClose(const char *name)
|
void VNCSConnectionST::setDesktopNameOrClose(const char *name)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -1014,12 +1025,6 @@ void VNCSConnectionST::enableContinuousUpdates(bool enable,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::handleClipboardRequest()
|
|
||||||
{
|
|
||||||
if (!(accessRights & AccessCutText)) return;
|
|
||||||
server->handleClipboardRequest(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VNCSConnectionST::handleClipboardAnnounce(bool available)
|
void VNCSConnectionST::handleClipboardAnnounce(bool available)
|
||||||
{
|
{
|
||||||
if (!(accessRights & AccessCutText)) return;
|
if (!(accessRights & AccessCutText)) return;
|
||||||
@ -1027,25 +1032,13 @@ void VNCSConnectionST::handleClipboardAnnounce(bool available)
|
|||||||
server->handleClipboardAnnounce(this, available);
|
server->handleClipboardAnnounce(this, available);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::handleClipboardData(const char* data, int len)
|
void VNCSConnectionST::handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32])
|
||||||
{
|
{
|
||||||
if (!(accessRights & AccessCutText)) return;
|
if (!(accessRights & AccessCutText)) return;
|
||||||
if (!rfb::Server::acceptCutText) return;
|
if (!rfb::Server::acceptCutText) return;
|
||||||
if (msSince(&lastClipboardOp) < (unsigned) rfb::Server::DLP_ClipDelay) {
|
server->handleClipboardAnnounceBinary(this, num, mimes);
|
||||||
vlog.info("DLP: client %s: refused to receive clipboard, too soon",
|
|
||||||
sock->getPeerAddress());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const int origlen = len;
|
|
||||||
if (rfb::Server::DLP_ClipAcceptMax && len > rfb::Server::DLP_ClipAcceptMax)
|
|
||||||
len = rfb::Server::DLP_ClipAcceptMax;
|
|
||||||
cliplog(data, len, origlen, "received", sock->getPeerAddress());
|
|
||||||
|
|
||||||
gettimeofday(&lastClipboardOp, NULL);
|
|
||||||
server->handleClipboardData(this, data, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// supportsLocalCursor() is called whenever the status of
|
// supportsLocalCursor() is called whenever the status of
|
||||||
// cp.supportsLocalCursor has changed. If the client does now support local
|
// cp.supportsLocalCursor has changed. If the client does now support local
|
||||||
// cursor, we make sure that the old server-side rendered cursor is cleaned up
|
// cursor, we make sure that the old server-side rendered cursor is cleaned up
|
||||||
@ -1089,6 +1082,8 @@ bool VNCSConnectionST::handleTimeout(Timer* t)
|
|||||||
writeFramebufferUpdate();
|
writeFramebufferUpdate();
|
||||||
else if (t == &kbdLogTimer)
|
else if (t == &kbdLogTimer)
|
||||||
flushKeylog(sock->getPeerAddress());
|
flushKeylog(sock->getPeerAddress());
|
||||||
|
else if (t == &binclipTimer)
|
||||||
|
writeBinaryClipboard();
|
||||||
} catch (rdr::Exception& e) {
|
} catch (rdr::Exception& e) {
|
||||||
close(e.str());
|
close(e.str());
|
||||||
}
|
}
|
||||||
@ -1446,6 +1441,18 @@ void VNCSConnectionST::writeDataUpdate()
|
|||||||
requested.clear();
|
requested.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNCSConnectionST::writeBinaryClipboard()
|
||||||
|
{
|
||||||
|
if (msSince(&lastClipboardOp) < (unsigned) rfb::Server::DLP_ClipDelay) {
|
||||||
|
vlog.info("DLP: client %s: refused to send binary clipboard, too soon",
|
||||||
|
sock->getPeerAddress());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer()->writeBinaryClipboard(binaryClipboard);
|
||||||
|
|
||||||
|
gettimeofday(&lastClipboardOp, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
|
void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
|
||||||
{
|
{
|
||||||
|
@ -77,9 +77,12 @@ namespace rfb {
|
|||||||
void bellOrClose();
|
void bellOrClose();
|
||||||
void setDesktopNameOrClose(const char *name);
|
void setDesktopNameOrClose(const char *name);
|
||||||
void setLEDStateOrClose(unsigned int state);
|
void setLEDStateOrClose(unsigned int state);
|
||||||
void requestClipboardOrClose();
|
|
||||||
void announceClipboardOrClose(bool available);
|
void announceClipboardOrClose(bool available);
|
||||||
void sendClipboardDataOrClose(const char* data);
|
void clearBinaryClipboardData();
|
||||||
|
void sendBinaryClipboardDataOrClose(const char* mime, const unsigned char *data,
|
||||||
|
const unsigned len);
|
||||||
|
void getBinaryClipboardData(const char* mime, const unsigned char **data,
|
||||||
|
unsigned *len);
|
||||||
|
|
||||||
// checkIdleTimeout() returns the number of milliseconds left until the
|
// checkIdleTimeout() returns the number of milliseconds left until the
|
||||||
// idle timeout expires. If it has expired, the connection is closed and
|
// idle timeout expires. If it has expired, the connection is closed and
|
||||||
@ -212,9 +215,8 @@ namespace rfb {
|
|||||||
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
|
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
|
||||||
virtual void enableContinuousUpdates(bool enable,
|
virtual void enableContinuousUpdates(bool enable,
|
||||||
int x, int y, int w, int h);
|
int x, int y, int w, int h);
|
||||||
virtual void handleClipboardRequest();
|
|
||||||
virtual void handleClipboardAnnounce(bool available);
|
virtual void handleClipboardAnnounce(bool available);
|
||||||
virtual void handleClipboardData(const char* data, int len);
|
virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
|
||||||
virtual void supportsLocalCursor();
|
virtual void supportsLocalCursor();
|
||||||
virtual void supportsFence();
|
virtual void supportsFence();
|
||||||
virtual void supportsContinuousUpdates();
|
virtual void supportsContinuousUpdates();
|
||||||
@ -260,6 +262,8 @@ namespace rfb {
|
|||||||
void writeNoDataUpdate();
|
void writeNoDataUpdate();
|
||||||
void writeDataUpdate();
|
void writeDataUpdate();
|
||||||
|
|
||||||
|
void writeBinaryClipboard();
|
||||||
|
|
||||||
void screenLayoutChange(rdr::U16 reason);
|
void screenLayoutChange(rdr::U16 reason);
|
||||||
void setCursor();
|
void setCursor();
|
||||||
void setCursorPos();
|
void setCursorPos();
|
||||||
@ -282,6 +286,7 @@ namespace rfb {
|
|||||||
Timer congestionTimer;
|
Timer congestionTimer;
|
||||||
Timer losslessTimer;
|
Timer losslessTimer;
|
||||||
Timer kbdLogTimer;
|
Timer kbdLogTimer;
|
||||||
|
Timer binclipTimer;
|
||||||
|
|
||||||
VNCServerST* server;
|
VNCServerST* server;
|
||||||
SimpleUpdateTracker updates;
|
SimpleUpdateTracker updates;
|
||||||
|
@ -52,22 +52,11 @@ namespace rfb {
|
|||||||
// getPixelBuffer() returns a pointer to the PixelBuffer object.
|
// getPixelBuffer() returns a pointer to the PixelBuffer object.
|
||||||
virtual PixelBuffer* getPixelBuffer() const = 0;
|
virtual PixelBuffer* getPixelBuffer() const = 0;
|
||||||
|
|
||||||
// requestClipboard() will result in a request to a client to
|
|
||||||
// transfer its clipboard data. A call to
|
|
||||||
// SDesktop::handleClipboardData() will be made once the data is
|
|
||||||
// available.
|
|
||||||
virtual void requestClipboard() = 0;
|
|
||||||
|
|
||||||
// announceClipboard() informs all clients of changes to the
|
// announceClipboard() informs all clients of changes to the
|
||||||
// clipboard on the server. A client may later request the
|
// clipboard on the server. A client may later request the
|
||||||
// clipboard data via SDesktop::handleClipboardRequest().
|
// clipboard data via SDesktop::handleClipboardRequest().
|
||||||
virtual void announceClipboard(bool available) = 0;
|
virtual void announceClipboard(bool available) = 0;
|
||||||
|
|
||||||
// sendClipboardData() transfers the clipboard data to a client
|
|
||||||
// and should be called whenever a client has requested the
|
|
||||||
// clipboard via SDesktop::handleClipboardRequest().
|
|
||||||
virtual void sendClipboardData(const char* data) = 0;
|
|
||||||
|
|
||||||
// bell() tells the server that it should make all clients make a bell sound.
|
// bell() tells the server that it should make all clients make a bell sound.
|
||||||
virtual void bell() = 0;
|
virtual void bell() = 0;
|
||||||
|
|
||||||
|
@ -518,14 +518,6 @@ void VNCServerST::setScreenLayout(const ScreenSet& layout)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCServerST::requestClipboard()
|
|
||||||
{
|
|
||||||
if (clipboardClient == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
clipboardClient->requestClipboard();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VNCServerST::announceClipboard(bool available)
|
void VNCServerST::announceClipboard(bool available)
|
||||||
{
|
{
|
||||||
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
||||||
@ -541,20 +533,31 @@ void VNCServerST::announceClipboard(bool available)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCServerST::sendClipboardData(const char* data)
|
void VNCServerST::sendBinaryClipboardData(const char* mime, const unsigned char *data,
|
||||||
|
const unsigned len)
|
||||||
{
|
{
|
||||||
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
||||||
|
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
|
||||||
if (strchr(data, '\r') != NULL)
|
|
||||||
throw Exception("Invalid carriage return in clipboard data");
|
|
||||||
|
|
||||||
for (ci = clipboardRequestors.begin();
|
|
||||||
ci != clipboardRequestors.end(); ci = ci_next) {
|
|
||||||
ci_next = ci; ci_next++;
|
ci_next = ci; ci_next++;
|
||||||
(*ci)->sendClipboardDataOrClose(data);
|
(*ci)->sendBinaryClipboardDataOrClose(mime, data, len);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
clipboardRequestors.clear();
|
void VNCServerST::getBinaryClipboardData(const char* mime, const unsigned char **data,
|
||||||
|
unsigned *len)
|
||||||
|
{
|
||||||
|
if (!clipboardClient)
|
||||||
|
return;
|
||||||
|
clipboardClient->getBinaryClipboardData(mime, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VNCServerST::clearBinaryClipboardData()
|
||||||
|
{
|
||||||
|
std::list<VNCSConnectionST*>::iterator ci, ci_next;
|
||||||
|
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
|
||||||
|
ci_next = ci; ci_next++;
|
||||||
|
(*ci)->clearBinaryClipboardData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCServerST::bell()
|
void VNCServerST::bell()
|
||||||
@ -1198,13 +1201,6 @@ bool VNCServerST::getComparerState()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCServerST::handleClipboardRequest(VNCSConnectionST* client)
|
|
||||||
{
|
|
||||||
clipboardRequestors.push_back(client);
|
|
||||||
if (clipboardRequestors.size() == 1)
|
|
||||||
desktop->handleClipboardRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client,
|
void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client,
|
||||||
bool available)
|
bool available)
|
||||||
{
|
{
|
||||||
@ -1218,11 +1214,10 @@ void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client,
|
|||||||
desktop->handleClipboardAnnounce(available);
|
desktop->handleClipboardAnnounce(available);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VNCServerST::handleClipboardData(VNCSConnectionST* client,
|
void VNCServerST::handleClipboardAnnounceBinary(VNCSConnectionST* client,
|
||||||
const char* data, int len)
|
const unsigned num,
|
||||||
|
const char mimes[][32])
|
||||||
{
|
{
|
||||||
if (client != clipboardClient)
|
clipboardClient = client;
|
||||||
return;
|
desktop->handleClipboardAnnounceBinary(num, mimes);
|
||||||
desktop->handleClipboardData(data, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,9 +96,12 @@ namespace rfb {
|
|||||||
virtual void setPixelBuffer(PixelBuffer* pb);
|
virtual void setPixelBuffer(PixelBuffer* pb);
|
||||||
virtual void setScreenLayout(const ScreenSet& layout);
|
virtual void setScreenLayout(const ScreenSet& layout);
|
||||||
virtual PixelBuffer* getPixelBuffer() const { if (DLPRegion.enabled && blackedpb) return blackedpb; else return pb; }
|
virtual PixelBuffer* getPixelBuffer() const { if (DLPRegion.enabled && blackedpb) return blackedpb; else return pb; }
|
||||||
virtual void requestClipboard();
|
|
||||||
virtual void announceClipboard(bool available);
|
virtual void announceClipboard(bool available);
|
||||||
virtual void sendClipboardData(const char* data);
|
virtual void clearBinaryClipboardData();
|
||||||
|
virtual void sendBinaryClipboardData(const char* mime, const unsigned char *data,
|
||||||
|
const unsigned len);
|
||||||
|
virtual void getBinaryClipboardData(const char *mime, const unsigned char **ptr,
|
||||||
|
unsigned *len);
|
||||||
virtual void add_changed(const Region ®ion);
|
virtual void add_changed(const Region ®ion);
|
||||||
virtual void add_copied(const Region &dest, const Point &delta);
|
virtual void add_copied(const Region &dest, const Point &delta);
|
||||||
virtual void setCursor(int width, int height, const Point& hotspot,
|
virtual void setCursor(int width, int height, const Point& hotspot,
|
||||||
@ -191,9 +194,9 @@ namespace rfb {
|
|||||||
|
|
||||||
void setAPIMessager(network::GetAPIMessager *msgr) { apimessager = msgr; }
|
void setAPIMessager(network::GetAPIMessager *msgr) { apimessager = msgr; }
|
||||||
|
|
||||||
void handleClipboardRequest(VNCSConnectionST* client);
|
|
||||||
void handleClipboardAnnounce(VNCSConnectionST* client, bool available);
|
void handleClipboardAnnounce(VNCSConnectionST* client, bool available);
|
||||||
void handleClipboardData(VNCSConnectionST* client, const char* data, int len);
|
void handleClipboardAnnounceBinary(VNCSConnectionST* client, const unsigned num,
|
||||||
|
const char mimes[][32]);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ namespace rfb {
|
|||||||
// kasm
|
// kasm
|
||||||
const int msgTypeStats = 178;
|
const int msgTypeStats = 178;
|
||||||
const int msgTypeRequestFrameStats = 179;
|
const int msgTypeRequestFrameStats = 179;
|
||||||
|
const int msgTypeBinaryClipboard = 180;
|
||||||
|
|
||||||
const int msgTypeServerFence = 248;
|
const int msgTypeServerFence = 248;
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ namespace rfb {
|
|||||||
// kasm
|
// kasm
|
||||||
const int msgTypeRequestStats = 178;
|
const int msgTypeRequestStats = 178;
|
||||||
const int msgTypeFrameStats = 179;
|
const int msgTypeFrameStats = 179;
|
||||||
|
//const int msgTypeBinaryClipboard = 180;
|
||||||
|
|
||||||
const int msgTypeClientFence = 248;
|
const int msgTypeClientFence = 248;
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ void SSE2_halve(const uint8_t *oldpx,
|
|||||||
|
|
||||||
uint8_t * const dst = newpx + newstride * (y / 2) * 4;
|
uint8_t * const dst = newpx + newstride * (y / 2) * 4;
|
||||||
|
|
||||||
for (x = 0; x < srcw; x += 4) {
|
for (x = 0; x < srcw - 3; x += 4) {
|
||||||
__m128i lo, hi, a, b, c, d;
|
__m128i lo, hi, a, b, c, d;
|
||||||
lo = _mm_loadu_si128((__m128i *) &row0[x * 4]);
|
lo = _mm_loadu_si128((__m128i *) &row0[x * 4]);
|
||||||
hi = _mm_loadu_si128((__m128i *) &row1[x * 4]);
|
hi = _mm_loadu_si128((__m128i *) &row1[x * 4]);
|
||||||
@ -141,7 +141,7 @@ void SSE2_scale(const uint8_t *oldpx,
|
|||||||
const __m128i vertmul = _mm_set1_epi16(top);
|
const __m128i vertmul = _mm_set1_epi16(top);
|
||||||
const __m128i vertmul2 = _mm_set1_epi16(bot);
|
const __m128i vertmul2 = _mm_set1_epi16(bot);
|
||||||
|
|
||||||
for (x = 0; x < tgtw; x += 2) {
|
for (x = 0; x < tgtw - 1; x += 2) {
|
||||||
const float nx[2] = {
|
const float nx[2] = {
|
||||||
x * invdiff,
|
x * invdiff,
|
||||||
(x + 1) * invdiff,
|
(x + 1) * invdiff,
|
||||||
|
2
kasmweb
2
kasmweb
@ -1 +1 @@
|
|||||||
Subproject commit a4cf38902911e9ff07e9d3eb7909c5ba932a5089
|
Subproject commit 0bd38139494ef1bbaf580c2f4892c7be3a291b19
|
@ -176,15 +176,6 @@ XserverDesktop::queryConnection(network::Socket* sock,
|
|||||||
return rfb::VNCServerST::PENDING;
|
return rfb::VNCServerST::PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XserverDesktop::requestClipboard()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
server->requestClipboard();
|
|
||||||
} catch (rdr::Exception& e) {
|
|
||||||
vlog.error("XserverDesktop::requestClipboard: %s",e.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void XserverDesktop::announceClipboard(bool available)
|
void XserverDesktop::announceClipboard(bool available)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -194,12 +185,34 @@ void XserverDesktop::announceClipboard(bool available)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XserverDesktop::sendClipboardData(const char* data)
|
void XserverDesktop::clearBinaryClipboardData()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
server->sendClipboardData(data);
|
server->clearBinaryClipboardData();
|
||||||
} catch (rdr::Exception& e) {
|
} catch (rdr::Exception& e) {
|
||||||
vlog.error("XserverDesktop::sendClipboardData: %s",e.str());
|
vlog.error("XserverDesktop::clearBinaryClipboardData: %s",e.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XserverDesktop::sendBinaryClipboardData(const char* mime,
|
||||||
|
const unsigned char *data,
|
||||||
|
const unsigned len)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
server->sendBinaryClipboardData(mime, data, len);
|
||||||
|
} catch (rdr::Exception& e) {
|
||||||
|
vlog.error("XserverDesktop::sendBinaryClipboardData: %s",e.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XserverDesktop::getBinaryClipboardData(const char* mime,
|
||||||
|
const unsigned char **data,
|
||||||
|
unsigned *len)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
server->getBinaryClipboardData(mime, data, len);
|
||||||
|
} catch (rdr::Exception& e) {
|
||||||
|
vlog.error("XserverDesktop::getBinaryClipboardData: %s",e.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,19 +485,14 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XserverDesktop::handleClipboardRequest()
|
|
||||||
{
|
|
||||||
vncHandleClipboardRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
void XserverDesktop::handleClipboardAnnounce(bool available)
|
void XserverDesktop::handleClipboardAnnounce(bool available)
|
||||||
{
|
{
|
||||||
vncHandleClipboardAnnounce(available);
|
vncHandleClipboardAnnounce(available);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XserverDesktop::handleClipboardData(const char* data_, int len)
|
void XserverDesktop::handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32])
|
||||||
{
|
{
|
||||||
vncHandleClipboardData(data_, len);
|
vncHandleClipboardAnnounceBinary(num, mimes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XserverDesktop::grabRegion(const rfb::Region& region)
|
void XserverDesktop::grabRegion(const rfb::Region& region)
|
||||||
|
@ -62,7 +62,11 @@ public:
|
|||||||
void refreshScreenLayout();
|
void refreshScreenLayout();
|
||||||
void requestClipboard();
|
void requestClipboard();
|
||||||
void announceClipboard(bool available);
|
void announceClipboard(bool available);
|
||||||
void sendClipboardData(const char* data);
|
void clearBinaryClipboardData();
|
||||||
|
void sendBinaryClipboardData(const char* mime, const unsigned char *data,
|
||||||
|
const unsigned len);
|
||||||
|
void getBinaryClipboardData(const char *mime, const unsigned char **ptr,
|
||||||
|
unsigned *len);
|
||||||
void bell();
|
void bell();
|
||||||
void setLEDState(unsigned int state);
|
void setLEDState(unsigned int state);
|
||||||
void setDesktopName(const char* name);
|
void setDesktopName(const char* name);
|
||||||
@ -94,9 +98,8 @@ public:
|
|||||||
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
|
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
|
||||||
virtual unsigned int setScreenLayout(int fb_width, int fb_height,
|
virtual unsigned int setScreenLayout(int fb_width, int fb_height,
|
||||||
const rfb::ScreenSet& layout);
|
const rfb::ScreenSet& layout);
|
||||||
virtual void handleClipboardRequest();
|
|
||||||
virtual void handleClipboardAnnounce(bool available);
|
virtual void handleClipboardAnnounce(bool available);
|
||||||
virtual void handleClipboardData(const char* data, int len);
|
virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
|
||||||
|
|
||||||
// rfb::PixelBuffer callbacks
|
// rfb::PixelBuffer callbacks
|
||||||
virtual void grabRegion(const rfb::Region& r);
|
virtual void grabRegion(const rfb::Region& r);
|
||||||
|
@ -295,17 +295,22 @@ Allow click releases inside the blacked-out region.
|
|||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
.B \-DLP_ClipSendMax \fIbytes\fP
|
.B \-DLP_ClipSendMax \fIbytes\fP
|
||||||
Limit clipboard bytes to send to clients in one transaction. Default 10,000.
|
Limit clipboard bytes to send to clients in one transaction. Default 0.
|
||||||
0 disables the limit, use \fBSendCutText\fP to disable clipboard sending entirely.
|
0 disables the limit, use \fBSendCutText\fP to disable clipboard sending entirely.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
.B \-DLP_ClipAcceptMax \fIbytes\fP
|
.B \-DLP_ClipAcceptMax \fIbytes\fP
|
||||||
Limit clipboard bytes to receive from clients in one transaction. Default 10,000.
|
Limit clipboard bytes to receive from clients in one transaction. Default 0.
|
||||||
0 disables the limit, use \fBAcceptCutText\fP to disable clipboard receiving entirely.
|
0 disables the limit, use \fBAcceptCutText\fP to disable clipboard receiving entirely.
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
.B \-DLP_ClipDelay \fIms\fP
|
.B \-DLP_ClipDelay \fIms\fP
|
||||||
This many milliseconds must pass between clipboard actions. Default 1000.
|
This many milliseconds must pass between clipboard actions. Default 0, 0 disables the limit.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.B \-DLP_ClipTypes \fIa,b\fP
|
||||||
|
Allowed binary clipboard mimetypes, separated by commas. Default
|
||||||
|
chromium/x-web-custom-data,text/html,image/png
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
.B \-DLP_KeyRateLimit \fIkeys-per-second\fP
|
.B \-DLP_KeyRateLimit \fIkeys-per-second\fP
|
||||||
|
@ -18,10 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <rfb/Configuration.h>
|
#include <rfb/Configuration.h>
|
||||||
#include <rfb/Logger_stdio.h>
|
#include <rfb/Logger_stdio.h>
|
||||||
@ -64,6 +66,8 @@ int vncFbstride[MAXSCREENS];
|
|||||||
|
|
||||||
int vncInetdSock = -1;
|
int vncInetdSock = -1;
|
||||||
|
|
||||||
|
static std::vector<dlp_mimetype_t> dlp_mimetypes;
|
||||||
|
|
||||||
struct CaseInsensitiveCompare {
|
struct CaseInsensitiveCompare {
|
||||||
bool operator() (const std::string &a, const std::string &b) const {
|
bool operator() (const std::string &a, const std::string &b) const {
|
||||||
return strcasecmp(a.c_str(), b.c_str()) < 0;
|
return strcasecmp(a.c_str(), b.c_str()) < 0;
|
||||||
@ -147,6 +151,38 @@ static void parseOverrideList(const char *text, ParamSet &out)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void parseClipTypes()
|
||||||
|
{
|
||||||
|
char *str = strdup(Server::DLP_Clip_Types);
|
||||||
|
char * const origstr = str;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
char *cur = strsep(&str, ",");
|
||||||
|
if (!cur)
|
||||||
|
break;
|
||||||
|
if (!cur[0])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Hardcoded filters
|
||||||
|
if (!strcmp(cur, "TEXT") ||
|
||||||
|
!strcmp(cur, "STRING") ||
|
||||||
|
strstr(cur, "text/plain") ||
|
||||||
|
!strcmp(cur, "UTF8_STRING"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct dlp_mimetype_t m;
|
||||||
|
strncpy(m.mime, cur, sizeof(m.mime));
|
||||||
|
m.mime[sizeof(m.mime) - 1] = '\0';
|
||||||
|
|
||||||
|
dlp_mimetypes.push_back(m);
|
||||||
|
|
||||||
|
vlog.debug("Adding DLP binary mime type %s", m.mime);
|
||||||
|
}
|
||||||
|
vlog.debug("Total %u binary mime types", dlp_mimetypes.size());
|
||||||
|
|
||||||
|
free(origstr);
|
||||||
|
}
|
||||||
|
|
||||||
void vncExtensionInit(void)
|
void vncExtensionInit(void)
|
||||||
{
|
{
|
||||||
if (vncExtGeneration == vncGetServerGeneration()) {
|
if (vncExtGeneration == vncGetServerGeneration()) {
|
||||||
@ -163,6 +199,8 @@ void vncExtensionInit(void)
|
|||||||
|
|
||||||
vncAddExtension();
|
vncAddExtension();
|
||||||
|
|
||||||
|
if (!initialised)
|
||||||
|
parseClipTypes();
|
||||||
vncSelectionInit();
|
vncSelectionInit();
|
||||||
|
|
||||||
vlog.info("VNC extension running!");
|
vlog.info("VNC extension running!");
|
||||||
@ -315,22 +353,30 @@ void vncUpdateDesktopName(void)
|
|||||||
desktop[scr]->setDesktopName(desktopName);
|
desktop[scr]->setDesktopName(desktopName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vncRequestClipboard(void)
|
|
||||||
{
|
|
||||||
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
|
||||||
desktop[scr]->requestClipboard();
|
|
||||||
}
|
|
||||||
|
|
||||||
void vncAnnounceClipboard(int available)
|
void vncAnnounceClipboard(int available)
|
||||||
{
|
{
|
||||||
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
||||||
desktop[scr]->announceClipboard(available);
|
desktop[scr]->announceClipboard(available);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vncSendClipboardData(const char* data)
|
void vncSendBinaryClipboardData(const char* mime, const unsigned char *data,
|
||||||
|
const unsigned len)
|
||||||
{
|
{
|
||||||
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
||||||
desktop[scr]->sendClipboardData(data);
|
desktop[scr]->sendBinaryClipboardData(mime, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vncGetBinaryClipboardData(const char *mime, const unsigned char **ptr,
|
||||||
|
unsigned *len)
|
||||||
|
{
|
||||||
|
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
||||||
|
desktop[scr]->getBinaryClipboardData(mime, ptr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vncClearBinaryClipboardData()
|
||||||
|
{
|
||||||
|
for (int scr = 0; scr < vncGetScreenCount(); scr++)
|
||||||
|
desktop[scr]->clearBinaryClipboardData();
|
||||||
}
|
}
|
||||||
|
|
||||||
int vncConnectClient(const char *addr)
|
int vncConnectClient(const char *addr)
|
||||||
@ -486,3 +532,13 @@ int vncOverrideParam(const char *nameAndValue)
|
|||||||
|
|
||||||
return rfb::Configuration::setParam(nameAndValue);
|
return rfb::Configuration::setParam(nameAndValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned dlp_num_mimetypes()
|
||||||
|
{
|
||||||
|
return dlp_mimetypes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dlp_get_mimetype(const unsigned i)
|
||||||
|
{
|
||||||
|
return dlp_mimetypes[i].mime;
|
||||||
|
}
|
||||||
|
@ -45,6 +45,13 @@ int vncNotifyQueryConnect(void);
|
|||||||
extern void* vncFbptr[];
|
extern void* vncFbptr[];
|
||||||
extern int vncFbstride[];
|
extern int vncFbstride[];
|
||||||
|
|
||||||
|
struct dlp_mimetype_t {
|
||||||
|
char mime[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned dlp_num_mimetypes();
|
||||||
|
const char *dlp_get_mimetype(const unsigned i);
|
||||||
|
|
||||||
extern int vncInetdSock;
|
extern int vncInetdSock;
|
||||||
|
|
||||||
void vncExtensionInit(void);
|
void vncExtensionInit(void);
|
||||||
@ -60,9 +67,12 @@ int vncGetSendPrimary(void);
|
|||||||
|
|
||||||
void vncUpdateDesktopName(void);
|
void vncUpdateDesktopName(void);
|
||||||
|
|
||||||
void vncRequestClipboard(void);
|
|
||||||
void vncAnnounceClipboard(int available);
|
void vncAnnounceClipboard(int available);
|
||||||
void vncSendClipboardData(const char* data);
|
void vncClearBinaryClipboardData();
|
||||||
|
void vncSendBinaryClipboardData(const char* mime, const unsigned char *data,
|
||||||
|
const unsigned len);
|
||||||
|
void vncGetBinaryClipboardData(const char *mime, const unsigned char **ptr,
|
||||||
|
unsigned *len);
|
||||||
|
|
||||||
int vncConnectClient(const char *addr);
|
int vncConnectClient(const char *addr);
|
||||||
|
|
||||||
|
@ -43,6 +43,14 @@
|
|||||||
|
|
||||||
static Atom xaPRIMARY, xaCLIPBOARD;
|
static Atom xaPRIMARY, xaCLIPBOARD;
|
||||||
static Atom xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT, xaUTF8_STRING;
|
static Atom xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT, xaUTF8_STRING;
|
||||||
|
static Atom xaINCR;
|
||||||
|
static Atom *xaBinclips;
|
||||||
|
static unsigned xaHtmlIndex, xaPngIndex;
|
||||||
|
static Bool htmlPngPresent;
|
||||||
|
|
||||||
|
static unsigned *mimeIndexesFromClient;
|
||||||
|
static unsigned numMimesFromClient;
|
||||||
|
static Bool textFromClient;
|
||||||
|
|
||||||
static WindowPtr pWindow;
|
static WindowPtr pWindow;
|
||||||
static Window wid;
|
static Window wid;
|
||||||
@ -66,8 +74,7 @@ static int vncCreateSelectionWindow(void);
|
|||||||
static int vncOwnSelection(Atom selection);
|
static int vncOwnSelection(Atom selection);
|
||||||
static int vncConvertSelection(ClientPtr client, Atom selection,
|
static int vncConvertSelection(ClientPtr client, Atom selection,
|
||||||
Atom target, Atom property,
|
Atom target, Atom property,
|
||||||
Window requestor, CARD32 time,
|
Window requestor, CARD32 time);
|
||||||
const char* data, int len);
|
|
||||||
static int vncProcConvertSelection(ClientPtr client);
|
static int vncProcConvertSelection(ClientPtr client);
|
||||||
static void vncSelectionRequest(Atom selection, Atom target);
|
static void vncSelectionRequest(Atom selection, Atom target);
|
||||||
static int vncProcSendEvent(ClientPtr client);
|
static int vncProcSendEvent(ClientPtr client);
|
||||||
@ -90,6 +97,32 @@ void vncSelectionInit(void)
|
|||||||
xaTEXT = MakeAtom("TEXT", 4, TRUE);
|
xaTEXT = MakeAtom("TEXT", 4, TRUE);
|
||||||
xaUTF8_STRING = MakeAtom("UTF8_STRING", 11, TRUE);
|
xaUTF8_STRING = MakeAtom("UTF8_STRING", 11, TRUE);
|
||||||
|
|
||||||
|
xaINCR = MakeAtom("INCR", 4, TRUE);
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
mimeIndexesFromClient = calloc(dlp_num_mimetypes(), sizeof(unsigned));
|
||||||
|
numMimesFromClient = 0;
|
||||||
|
textFromClient = FALSE;
|
||||||
|
xaBinclips = calloc(dlp_num_mimetypes(), sizeof(Atom));
|
||||||
|
htmlPngPresent = FALSE;
|
||||||
|
Bool htmlfound = FALSE, pngfound = FALSE;
|
||||||
|
for (i = 0; i < dlp_num_mimetypes(); i++) {
|
||||||
|
const char *cur = dlp_get_mimetype(i);
|
||||||
|
xaBinclips[i] = MakeAtom(cur, strlen(cur), TRUE);
|
||||||
|
|
||||||
|
if (!strcmp(cur, "text/html")) {
|
||||||
|
xaHtmlIndex = i;
|
||||||
|
htmlfound = TRUE;
|
||||||
|
}
|
||||||
|
if (!strcmp(cur, "image/png")) {
|
||||||
|
xaPngIndex = i;
|
||||||
|
pngfound = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (htmlfound && pngfound)
|
||||||
|
htmlPngPresent = TRUE;
|
||||||
|
|
||||||
/* There are no hooks for when these are internal windows, so
|
/* There are no hooks for when these are internal windows, so
|
||||||
* override the relevant handlers. */
|
* override the relevant handlers. */
|
||||||
origProcConvertSelection = ProcVector[X_ConvertSelection];
|
origProcConvertSelection = ProcVector[X_ConvertSelection];
|
||||||
@ -103,7 +136,7 @@ void vncSelectionInit(void)
|
|||||||
FatalError("Add VNC ClientStateCallback failed\n");
|
FatalError("Add VNC ClientStateCallback failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void vncHandleClipboardRequest(void)
|
static void vncHandleClipboardRequest(void)
|
||||||
{
|
{
|
||||||
if (activeSelection == None) {
|
if (activeSelection == None) {
|
||||||
LOG_DEBUG("Got request for local clipboard although no clipboard is active");
|
LOG_DEBUG("Got request for local clipboard although no clipboard is active");
|
||||||
@ -161,24 +194,55 @@ void vncHandleClipboardAnnounce(int available)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vncHandleClipboardData(const char* data, int len)
|
void vncHandleClipboardAnnounceBinary(const unsigned num, const char mimes[][32])
|
||||||
{
|
{
|
||||||
struct VncDataTarget* next;
|
if (num) {
|
||||||
|
|
||||||
LOG_DEBUG("Got remote clipboard data, sending to X11 clients");
|
|
||||||
|
|
||||||
while (vncDataTargetHead != NULL) {
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
LOG_DEBUG("Remote binary clipboard announced, grabbing local ownership");
|
||||||
|
|
||||||
|
if (vncGetSetPrimary()) {
|
||||||
|
rc = vncOwnSelection(xaPRIMARY);
|
||||||
|
if (rc != Success)
|
||||||
|
LOG_ERROR("Could not set PRIMARY selection");
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = vncOwnSelection(xaCLIPBOARD);
|
||||||
|
if (rc != Success)
|
||||||
|
LOG_ERROR("Could not set CLIPBOARD selection");
|
||||||
|
|
||||||
|
unsigned i, valid = 0;
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
unsigned j;
|
||||||
|
for (j = 0; j < dlp_num_mimetypes(); j++) {
|
||||||
|
if (!strcmp(dlp_get_mimetype(j), mimes[i])) {
|
||||||
|
mimeIndexesFromClient[valid] = j;
|
||||||
|
valid++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(mimes[i], "text/plain"))
|
||||||
|
textFromClient = TRUE;
|
||||||
|
}
|
||||||
|
numMimesFromClient = valid;
|
||||||
|
LOG_DEBUG("Client sent %u mimes, %u were valid", num, valid);
|
||||||
|
} else {
|
||||||
|
struct VncDataTarget* next;
|
||||||
|
numMimesFromClient = 0;
|
||||||
|
textFromClient = FALSE;
|
||||||
|
|
||||||
|
if (pWindow == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOG_DEBUG("Remote binary clipboard lost, removing local ownership");
|
||||||
|
|
||||||
|
DeleteWindowFromAnySelections(pWindow);
|
||||||
|
|
||||||
|
/* Abort any pending transfer */
|
||||||
|
while (vncDataTargetHead != NULL) {
|
||||||
xEvent event;
|
xEvent event;
|
||||||
|
|
||||||
rc = vncConvertSelection(vncDataTargetHead->client,
|
|
||||||
vncDataTargetHead->selection,
|
|
||||||
vncDataTargetHead->target,
|
|
||||||
vncDataTargetHead->property,
|
|
||||||
vncDataTargetHead->requestor,
|
|
||||||
vncDataTargetHead->time,
|
|
||||||
data, len);
|
|
||||||
if (rc != Success) {
|
|
||||||
event.u.u.type = SelectionNotify;
|
event.u.u.type = SelectionNotify;
|
||||||
event.u.selectionNotify.time = vncDataTargetHead->time;
|
event.u.selectionNotify.time = vncDataTargetHead->time;
|
||||||
event.u.selectionNotify.requestor = vncDataTargetHead->requestor;
|
event.u.selectionNotify.requestor = vncDataTargetHead->requestor;
|
||||||
@ -186,12 +250,12 @@ void vncHandleClipboardData(const char* data, int len)
|
|||||||
event.u.selectionNotify.target = vncDataTargetHead->target;
|
event.u.selectionNotify.target = vncDataTargetHead->target;
|
||||||
event.u.selectionNotify.property = None;
|
event.u.selectionNotify.property = None;
|
||||||
WriteEventsToClient(vncDataTargetHead->client, 1, &event);
|
WriteEventsToClient(vncDataTargetHead->client, 1, &event);
|
||||||
}
|
|
||||||
|
|
||||||
next = vncDataTargetHead->next;
|
next = vncDataTargetHead->next;
|
||||||
free(vncDataTargetHead);
|
free(vncDataTargetHead);
|
||||||
vncDataTargetHead = next;
|
vncDataTargetHead = next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vncCreateSelectionWindow(void)
|
static int vncCreateSelectionWindow(void)
|
||||||
@ -277,10 +341,22 @@ static int vncOwnSelection(Atom selection)
|
|||||||
return Success;
|
return Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bool clientHasBinaryAtom(const Atom target, unsigned *which)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < numMimesFromClient; i++) {
|
||||||
|
if (xaBinclips[mimeIndexesFromClient[i]] == target) {
|
||||||
|
*which = mimeIndexesFromClient[i];
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static int vncConvertSelection(ClientPtr client, Atom selection,
|
static int vncConvertSelection(ClientPtr client, Atom selection,
|
||||||
Atom target, Atom property,
|
Atom target, Atom property,
|
||||||
Window requestor, CARD32 time,
|
Window requestor, CARD32 time)
|
||||||
const char* data, int len)
|
|
||||||
{
|
{
|
||||||
Selection *pSel;
|
Selection *pSel;
|
||||||
WindowPtr pWin;
|
WindowPtr pWin;
|
||||||
@ -290,13 +366,8 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
|
|||||||
|
|
||||||
xEvent event;
|
xEvent event;
|
||||||
|
|
||||||
if (data == NULL) {
|
|
||||||
LOG_DEBUG("Selection request for %s (type %s)",
|
LOG_DEBUG("Selection request for %s (type %s)",
|
||||||
NameForAtom(selection), NameForAtom(target));
|
NameForAtom(selection), NameForAtom(target));
|
||||||
} else {
|
|
||||||
LOG_DEBUG("Sending data for selection request for %s (type %s)",
|
|
||||||
NameForAtom(selection), NameForAtom(target));
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = dixLookupSelection(&pSel, selection, client, DixGetAttrAccess);
|
rc = dixLookupSelection(&pSel, selection, client, DixGetAttrAccess);
|
||||||
if (rc != Success)
|
if (rc != Success)
|
||||||
@ -315,14 +386,23 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
|
|||||||
realProperty = target;
|
realProperty = target;
|
||||||
|
|
||||||
/* FIXME: MULTIPLE target */
|
/* FIXME: MULTIPLE target */
|
||||||
|
unsigned binatomidx;
|
||||||
|
|
||||||
if (target == xaTARGETS) {
|
if (target == xaTARGETS) {
|
||||||
Atom targets[] = { xaTARGETS, xaTIMESTAMP,
|
Atom targets[5 + numMimesFromClient];
|
||||||
xaSTRING, xaTEXT, xaUTF8_STRING };
|
targets[0] = xaTARGETS;
|
||||||
|
targets[1] = xaTIMESTAMP;
|
||||||
|
targets[2] = xaSTRING;
|
||||||
|
targets[3] = xaTEXT;
|
||||||
|
targets[4] = xaUTF8_STRING;
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < numMimesFromClient; i++)
|
||||||
|
targets[5 + i] = xaBinclips[mimeIndexesFromClient[i]];
|
||||||
|
|
||||||
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
|
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
|
||||||
XA_ATOM, 32, PropModeReplace,
|
XA_ATOM, 32, PropModeReplace,
|
||||||
sizeof(targets)/sizeof(targets[0]),
|
5 + numMimesFromClient,
|
||||||
targets, TRUE);
|
targets, TRUE);
|
||||||
if (rc != Success)
|
if (rc != Success)
|
||||||
return rc;
|
return rc;
|
||||||
@ -333,37 +413,22 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
|
|||||||
TRUE);
|
TRUE);
|
||||||
if (rc != Success)
|
if (rc != Success)
|
||||||
return rc;
|
return rc;
|
||||||
} else {
|
} else if (clientHasBinaryAtom(target, &binatomidx)) {
|
||||||
if (data == NULL) {
|
const unsigned char *data;
|
||||||
struct VncDataTarget* vdt;
|
unsigned len;
|
||||||
|
vncGetBinaryClipboardData(dlp_get_mimetype(binatomidx), &data, &len);
|
||||||
|
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
|
||||||
|
xaBinclips[binatomidx], 8, PropModeReplace,
|
||||||
|
len, (unsigned char *) data, TRUE);
|
||||||
|
if (rc != Success)
|
||||||
|
return rc;
|
||||||
|
} else if (textFromClient) {
|
||||||
|
const unsigned char *data;
|
||||||
|
unsigned len;
|
||||||
|
vncGetBinaryClipboardData("text/plain", &data, &len);
|
||||||
|
|
||||||
if ((target != xaSTRING) && (target != xaTEXT) &&
|
|
||||||
(target != xaUTF8_STRING))
|
|
||||||
return BadMatch;
|
|
||||||
|
|
||||||
vdt = calloc(1, sizeof(struct VncDataTarget));
|
|
||||||
if (vdt == NULL)
|
|
||||||
return BadAlloc;
|
|
||||||
|
|
||||||
vdt->client = client;
|
|
||||||
vdt->selection = selection;
|
|
||||||
vdt->target = target;
|
|
||||||
vdt->property = property;
|
|
||||||
vdt->requestor = requestor;
|
|
||||||
vdt->time = time;
|
|
||||||
|
|
||||||
vdt->next = vncDataTargetHead;
|
|
||||||
vncDataTargetHead = vdt;
|
|
||||||
|
|
||||||
LOG_DEBUG("Requesting clipboard data from client");
|
|
||||||
|
|
||||||
vncRequestClipboard();
|
|
||||||
|
|
||||||
return Success;
|
|
||||||
} else {
|
|
||||||
if ((target == xaSTRING) || (target == xaTEXT)) {
|
if ((target == xaSTRING) || (target == xaTEXT)) {
|
||||||
char* latin1;
|
char* latin1;
|
||||||
|
|
||||||
latin1 = vncUTF8ToLatin1(data, (size_t)-1);
|
latin1 = vncUTF8ToLatin1(data, (size_t)-1);
|
||||||
if (latin1 == NULL)
|
if (latin1 == NULL)
|
||||||
return BadAlloc;
|
return BadAlloc;
|
||||||
@ -379,13 +444,16 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
|
|||||||
} else if (target == xaUTF8_STRING) {
|
} else if (target == xaUTF8_STRING) {
|
||||||
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
|
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
|
||||||
xaUTF8_STRING, 8, PropModeReplace,
|
xaUTF8_STRING, 8, PropModeReplace,
|
||||||
len, data, TRUE);
|
len, (char *) data, TRUE);
|
||||||
if (rc != Success)
|
if (rc != Success)
|
||||||
return rc;
|
return rc;
|
||||||
} else {
|
} else {
|
||||||
return BadMatch;
|
return BadMatch;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
LOG_ERROR("Text clipboard paste requested, but client sent no text");
|
||||||
|
|
||||||
|
return BadMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.u.u.type = SelectionNotify;
|
event.u.u.type = SelectionNotify;
|
||||||
@ -424,7 +492,7 @@ static int vncProcConvertSelection(ClientPtr client)
|
|||||||
pSel->window == wid) {
|
pSel->window == wid) {
|
||||||
rc = vncConvertSelection(client, stuff->selection,
|
rc = vncConvertSelection(client, stuff->selection,
|
||||||
stuff->target, stuff->property,
|
stuff->target, stuff->property,
|
||||||
stuff->requestor, stuff->time, NULL, 0);
|
stuff->requestor, stuff->time);
|
||||||
if (rc != Success) {
|
if (rc != Success) {
|
||||||
xEvent event;
|
xEvent event;
|
||||||
|
|
||||||
@ -483,6 +551,21 @@ static Bool vncHasAtom(Atom atom, const Atom list[], size_t size)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Bool vncHasBinaryClipboardAtom(const Atom list[], size_t size)
|
||||||
|
{
|
||||||
|
size_t i, b;
|
||||||
|
const unsigned num = dlp_num_mimetypes();
|
||||||
|
|
||||||
|
for (i = 0;i < size;i++) {
|
||||||
|
for (b = 0; b < num; b++) {
|
||||||
|
if (list[i] == xaBinclips[b])
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void vncHandleSelection(Atom selection, Atom target,
|
static void vncHandleSelection(Atom selection, Atom target,
|
||||||
Atom property, Atom requestor,
|
Atom property, Atom requestor,
|
||||||
TimeStamp time)
|
TimeStamp time)
|
||||||
@ -502,6 +585,9 @@ static void vncHandleSelection(Atom selection, Atom target,
|
|||||||
if (target != property)
|
if (target != property)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (prop->type == xaINCR)
|
||||||
|
LOG_INFO("Incremental clipboard transfer denied, too large");
|
||||||
|
|
||||||
if (target == xaTARGETS) {
|
if (target == xaTARGETS) {
|
||||||
if (prop->format != 32)
|
if (prop->format != 32)
|
||||||
return;
|
return;
|
||||||
@ -510,16 +596,36 @@ static void vncHandleSelection(Atom selection, Atom target,
|
|||||||
|
|
||||||
if (probing) {
|
if (probing) {
|
||||||
if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size) ||
|
if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size) ||
|
||||||
vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size)) {
|
vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size) ||
|
||||||
|
vncHasBinaryClipboardAtom((const Atom*)prop->data, prop->size)) {
|
||||||
LOG_DEBUG("Compatible format found, notifying clients");
|
LOG_DEBUG("Compatible format found, notifying clients");
|
||||||
|
vncClearBinaryClipboardData();
|
||||||
activeSelection = selection;
|
activeSelection = selection;
|
||||||
vncAnnounceClipboard(TRUE);
|
vncAnnounceClipboard(TRUE);
|
||||||
|
vncHandleClipboardRequest();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size))
|
if (vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size))
|
||||||
vncSelectionRequest(selection, xaUTF8_STRING);
|
vncSelectionRequest(selection, xaUTF8_STRING);
|
||||||
else if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size))
|
else if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size))
|
||||||
vncSelectionRequest(selection, xaSTRING);
|
vncSelectionRequest(selection, xaSTRING);
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
Bool skiphtml = FALSE;
|
||||||
|
if (htmlPngPresent &&
|
||||||
|
vncHasAtom(xaBinclips[xaHtmlIndex], (const Atom*)prop->data, prop->size) &&
|
||||||
|
vncHasAtom(xaBinclips[xaPngIndex], (const Atom*)prop->data, prop->size))
|
||||||
|
skiphtml = TRUE;
|
||||||
|
|
||||||
|
for (i = 0; i < dlp_num_mimetypes(); i++) {
|
||||||
|
if (skiphtml && i == xaHtmlIndex)
|
||||||
|
continue;
|
||||||
|
if (vncHasAtom(xaBinclips[i], (const Atom*)prop->data, prop->size)) {
|
||||||
|
vncSelectionRequest(selection, xaBinclips[i]);
|
||||||
|
//break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (target == xaSTRING) {
|
} else if (target == xaSTRING) {
|
||||||
char* filtered;
|
char* filtered;
|
||||||
@ -539,10 +645,10 @@ static void vncHandleSelection(Atom selection, Atom target,
|
|||||||
if (utf8 == NULL)
|
if (utf8 == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG_DEBUG("Sending clipboard to clients (%d bytes)",
|
LOG_DEBUG("Sending text part of binary clipboard to clients (%d bytes)",
|
||||||
(int)strlen(utf8));
|
(int)strlen(utf8));
|
||||||
|
|
||||||
vncSendClipboardData(utf8);
|
vncSendBinaryClipboardData("text/plain", utf8, strlen(utf8));
|
||||||
|
|
||||||
vncStrFree(utf8);
|
vncStrFree(utf8);
|
||||||
} else if (target == xaUTF8_STRING) {
|
} else if (target == xaUTF8_STRING) {
|
||||||
@ -557,12 +663,31 @@ static void vncHandleSelection(Atom selection, Atom target,
|
|||||||
if (filtered == NULL)
|
if (filtered == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG_DEBUG("Sending clipboard to clients (%d bytes)",
|
LOG_DEBUG("Sending text part of binary clipboard to clients (%d bytes)",
|
||||||
(int)strlen(filtered));
|
(int)strlen(filtered));
|
||||||
|
|
||||||
vncSendClipboardData(filtered);
|
vncSendBinaryClipboardData("text/plain", filtered, strlen(filtered));
|
||||||
|
|
||||||
vncStrFree(filtered);
|
vncStrFree(filtered);
|
||||||
|
} else {
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
if (prop->format != 8)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < dlp_num_mimetypes(); i++) {
|
||||||
|
if (target == xaBinclips[i]) {
|
||||||
|
if (prop->type != xaBinclips[i])
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOG_DEBUG("Sending binary clipboard to clients (%d bytes)",
|
||||||
|
prop->size);
|
||||||
|
|
||||||
|
vncSendBinaryClipboardData(dlp_get_mimetype(i), prop->data, prop->size);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,9 +24,8 @@ extern "C" {
|
|||||||
|
|
||||||
void vncSelectionInit(void);
|
void vncSelectionInit(void);
|
||||||
|
|
||||||
void vncHandleClipboardRequest(void);
|
|
||||||
void vncHandleClipboardAnnounce(int available);
|
void vncHandleClipboardAnnounce(int available);
|
||||||
void vncHandleClipboardData(const char* data, int len);
|
void vncHandleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user