Browse Source

Support extended clipboard transfers

Implements support in both client and server for the extended
clipboard format first seen in UltraVNC. Currently only implements
text handling, but that is still an improvement as it extends the
clipboard from ISO 8859-1 to full Unicode.
tags/v1.9.90
Pierre Ossman 8 years ago
parent
commit
0ff2655456

+ 86
- 5
common/rfb/CConnection.cxx View File

@@ -21,6 +21,7 @@
#include <string.h>

#include <rfb/Exception.h>
#include <rfb/clipboardTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/CMsgReader.h>
#include <rfb/CMsgWriter.h>
@@ -53,7 +54,7 @@ CConnection::CConnection()
firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
forceNonincremental(true),
framebuffer(NULL), decoder(this),
serverClipboard(NULL)
serverClipboard(NULL), hasLocalClipboard(false)
{
}

@@ -467,6 +468,8 @@ void CConnection::dataRect(const Rect& r, int encoding)

void CConnection::serverCutText(const char* str)
{
hasLocalClipboard = false;

strFree(serverClipboard);
serverClipboard = NULL;

@@ -475,6 +478,67 @@ void CConnection::serverCutText(const char* str)
handleClipboardAnnounce(true);
}

void CConnection::handleClipboardCaps(rdr::U32 flags,
const rdr::U32* lengths)
{
rdr::U32 sizes[] = { 0 };

CMsgHandler::handleClipboardCaps(flags, lengths);

writer()->writeClipboardCaps(rfb::clipboardUTF8 |
rfb::clipboardRequest |
rfb::clipboardPeek |
rfb::clipboardNotify |
rfb::clipboardProvide,
sizes);
}

void CConnection::handleClipboardRequest(rdr::U32 flags)
{
if (!(flags & rfb::clipboardUTF8))
return;
if (!hasLocalClipboard)
return;
handleClipboardRequest();
}

void CConnection::handleClipboardPeek(rdr::U32 flags)
{
if (!hasLocalClipboard)
return;
if (server.clipboardFlags() & rfb::clipboardNotify)
writer()->writeClipboardNotify(rfb::clipboardUTF8);
}

void CConnection::handleClipboardNotify(rdr::U32 flags)
{
strFree(serverClipboard);
serverClipboard = NULL;

if (flags & rfb::clipboardUTF8) {
hasLocalClipboard = false;
handleClipboardAnnounce(true);
} else {
handleClipboardAnnounce(false);
}
}

void CConnection::handleClipboardProvide(rdr::U32 flags,
const size_t* lengths,
const rdr::U8* const* data)
{
if (!(flags & rfb::clipboardUTF8))
return;

strFree(serverClipboard);
serverClipboard = NULL;

serverClipboard = convertLF((const char*)data[0], lengths[0]);

// FIXME: Should probably verify that this data was actually requested
handleClipboardData(serverClipboard);
}

void CConnection::authSuccess()
{
}
@@ -506,19 +570,35 @@ void CConnection::requestClipboard()
handleClipboardData(serverClipboard);
return;
}

if (server.clipboardFlags() & rfb::clipboardRequest)
writer()->writeClipboardRequest(rfb::clipboardUTF8);
}

void CConnection::announceClipboard(bool available)
{
if (available)
handleClipboardRequest();
hasLocalClipboard = available;

if (server.clipboardFlags() & rfb::clipboardNotify)
writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
else {
if (available)
handleClipboardRequest();
}
}

void CConnection::sendClipboardData(const char* data)
{
CharArray latin1(utf8ToLatin1(data));
if (server.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()->writeClientCutText(latin1.buf);
writer()->writeClientCutText(latin1.buf);
}
}

void CConnection::refreshFramebuffer()
@@ -656,6 +736,7 @@ void CConnection::updateEncodings()

encodings.push_back(pseudoEncodingDesktopName);
encodings.push_back(pseudoEncodingLastRect);
encodings.push_back(pseudoEncodingExtendedClipboard);
encodings.push_back(pseudoEncodingContinuousUpdates);
encodings.push_back(pseudoEncodingFence);
encodings.push_back(pseudoEncodingQEMUKeyEvent);

+ 10
- 0
common/rfb/CConnection.h View File

@@ -111,6 +111,15 @@ namespace rfb {

virtual void serverCutText(const char* str);

virtual void handleClipboardCaps(rdr::U32 flags,
const rdr::U32* lengths);
virtual void handleClipboardRequest(rdr::U32 flags);
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);


// Methods to be overridden in a derived class

@@ -277,6 +286,7 @@ namespace rfb {
DecodeManager decoder;

char* serverClipboard;
bool hasLocalClipboard;
};
}
#endif

+ 24
- 1
common/rfb/CMsgHandler.cxx View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2011 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -98,3 +98,26 @@ void CMsgHandler::setLEDState(unsigned int state)
{
server.setLEDState(state);
}

void CMsgHandler::handleClipboardCaps(rdr::U32 flags, const rdr::U32* lengths)
{
server.setClipboardCaps(flags, lengths);
}

void CMsgHandler::handleClipboardRequest(rdr::U32 flags)
{
}

void CMsgHandler::handleClipboardPeek(rdr::U32 flags)
{
}

void CMsgHandler::handleClipboardNotify(rdr::U32 flags)
{
}

void CMsgHandler::handleClipboardProvide(rdr::U32 flags,
const size_t* lengths,
const rdr::U8* const* data)
{
}

+ 13
- 3
common/rfb/CMsgHandler.h View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2011 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
@@ -42,8 +42,9 @@ namespace rfb {
// The following methods are called as corresponding messages are read. A
// derived class should override these methods as desired. Note that for
// the setDesktopSize(), setExtendedDesktopSize(), setPixelFormat(),
// setName() and serverInit() methods, a derived class should call on to
// CMsgHandler's methods to set the members of "server" appropriately.
// setName(), serverInit() and clipboardCaps methods, a derived class
// should call on to CMsgHandler's methods to set the members of "server"
// appropriately.

virtual void setDesktopSize(int w, int h);
virtual void setExtendedDesktopSize(unsigned reason, unsigned result,
@@ -74,6 +75,15 @@ namespace rfb {

virtual void setLEDState(unsigned int state);

virtual void handleClipboardCaps(rdr::U32 flags,
const rdr::U32* lengths);
virtual void handleClipboardRequest(rdr::U32 flags);
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);

ServerParams server;
};
}

+ 109
- 3
common/rfb/CMsgReader.cxx View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2017 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,8 +20,11 @@
#include <assert.h>
#include <stdio.h>

#include <rfb/msgTypes.h>
#include <rdr/InStream.h>
#include <rdr/ZlibInStream.h>

#include <rfb/msgTypes.h>
#include <rfb/clipboardTypes.h>
#include <rfb/Exception.h>
#include <rfb/LogWriter.h>
#include <rfb/util.h>
@@ -30,6 +33,8 @@

static rfb::LogWriter vlog("CMsgReader");

static rfb::IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);

using namespace rfb;

CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_)
@@ -152,7 +157,15 @@ void CMsgReader::readServerCutText()
{
is->skip(3);
rdr::U32 len = is->readU32();
if (len > 256*1024) {

if (len & 0x80000000) {
rdr::S32 slen = len;
slen = -slen;
readExtendedClipboard(slen);
return;
}

if (len > (size_t)maxCutText) {
is->skip(len);
vlog.error("cut text too long (%d bytes) - ignoring",len);
return;
@@ -163,6 +176,99 @@ void CMsgReader::readServerCutText()
handler->serverCutText(filtered.buf);
}

void CMsgReader::readExtendedClipboard(rdr::S32 len)
{
rdr::U32 flags;
rdr::U32 action;

if (len < 4)
throw Exception("Invalid extended clipboard message");
if (len > maxCutText) {
vlog.error("Extended clipboard message too long (%d bytes) - ignoring", 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.removeUnderlying();

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 CMsgReader::readFence()
{
rdr::U32 flags;

+ 2
- 1
common/rfb/CMsgReader.h View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2014 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -53,6 +53,7 @@ namespace rfb {
void readSetColourMapEntries();
void readBell();
void readServerCutText();
void readExtendedClipboard(rdr::S32 len);
void readFence();
void readEndOfContinuousUpdates();


+ 104
- 1
common/rfb/CMsgWriter.cxx View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2014 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,10 +17,15 @@
* USA.
*/
#include <stdio.h>

#include <rdr/OutStream.h>
#include <rdr/MemOutStream.h>
#include <rdr/ZlibOutStream.h>

#include <rfb/msgTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/qemuTypes.h>
#include <rfb/clipboardTypes.h>
#include <rfb/Exception.h>
#include <rfb/PixelFormat.h>
#include <rfb/Rect.h>
@@ -194,6 +199,104 @@ void CMsgWriter::writeClientCutText(const char* str)
endMsg();
}

void CMsgWriter::writeClipboardCaps(rdr::U32 caps,
const rdr::U32* lengths)
{
size_t i, count;

if (!(server->clipboardFlags() & clipboardCaps))
throw Exception("Server does not support clipboard \"caps\" action");

count = 0;
for (i = 0;i < 16;i++) {
if (caps & (1 << i))
count++;
}

startMsg(msgTypeClientCutText);
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 CMsgWriter::writeClipboardRequest(rdr::U32 flags)
{
if (!(server->clipboardFlags() & clipboardRequest))
throw Exception("Server does not support clipboard \"request\" action");

startMsg(msgTypeClientCutText);
os->pad(3);
os->writeS32(-4);
os->writeU32(flags | clipboardRequest);
endMsg();
}

void CMsgWriter::writeClipboardPeek(rdr::U32 flags)
{
if (!(server->clipboardFlags() & clipboardPeek))
throw Exception("Server does not support clipboard \"peek\" action");

startMsg(msgTypeClientCutText);
os->pad(3);
os->writeS32(-4);
os->writeU32(flags | clipboardPeek);
endMsg();
}

void CMsgWriter::writeClipboardNotify(rdr::U32 flags)
{
if (!(server->clipboardFlags() & clipboardNotify))
throw Exception("Server does not support clipboard \"notify\" action");

startMsg(msgTypeClientCutText);
os->pad(3);
os->writeS32(-4);
os->writeU32(flags | clipboardNotify);
endMsg();
}

void CMsgWriter::writeClipboardProvide(rdr::U32 flags,
const size_t* lengths,
const rdr::U8* const* data)
{
rdr::MemOutStream mos;
rdr::ZlibOutStream zos;

int i, count;

if (!(server->clipboardFlags() & clipboardProvide))
throw Exception("Server 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(msgTypeClientCutText);
os->pad(3);
os->writeS32(-(4 + mos.length()));
os->writeU32(flags | clipboardProvide);
os->writeBytes(mos.data(), mos.length());
endMsg();
}

void CMsgWriter::startMsg(int type)
{
os->writeU8(type);

+ 9
- 1
common/rfb/CMsgWriter.h View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2014 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -55,8 +55,16 @@ namespace rfb {

void writeKeyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
void writePointerEvent(const Point& pos, int buttonMask);

void writeClientCutText(const char* str);

void writeClipboardCaps(rdr::U32 caps, const rdr::U32* lengths);
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);

protected:
void startMsg(int type);
void endMsg();

+ 22
- 1
common/rfb/ClientParams.cxx View File

@@ -1,6 +1,6 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
* Copyright 2014-2018 Pierre Ossman for Cendio AB
* Copyright 2014-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
#include <rfb/Exception.h>
#include <rfb/encodings.h>
#include <rfb/ledStates.h>
#include <rfb/clipboardTypes.h>
#include <rfb/ClientParams.h>

using namespace rfb;
@@ -32,7 +33,13 @@ ClientParams::ClientParams()
ledState_(ledUnknown)
{
setName("");

cursor_ = new Cursor(0, 0, Point(), NULL);

clipFlags = clipboardUTF8 | clipboardRTF | clipboardHTML |
clipboardRequest | clipboardNotify | clipboardProvide;
memset(clipSizes, 0, sizeof(clipSizes));
clipSizes[0] = 20 * 1024 * 1024;
}

ClientParams::~ClientParams()
@@ -136,6 +143,20 @@ void ClientParams::setLEDState(unsigned int state)
ledState_ = state;
}

void ClientParams::setClipboardCaps(rdr::U32 flags, const rdr::U32* lengths)
{
int i, num;

clipFlags = flags;

num = 0;
for (i = 0;i < 16;i++) {
if (!(flags & (1 << i)))
continue;
clipSizes[i] = lengths[num++];
}
}

bool ClientParams::supportsLocalCursor() const
{
if (supportsEncoding(pseudoEncodingCursorWithAlpha))

+ 6
- 1
common/rfb/ClientParams.h View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2014-2018 Pierre Ossman for Cendio AB
* Copyright 2014-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -84,6 +84,9 @@ namespace rfb {
unsigned int ledState() { return ledState_; }
void setLEDState(unsigned int state);

rdr::U32 clipboardFlags() const { return clipFlags; }
void setClipboardCaps(rdr::U32 flags, const rdr::U32* lengths);

// Wrappers to check for functionality rather than specific
// encodings
bool supportsLocalCursor() const;
@@ -108,6 +111,8 @@ namespace rfb {
Cursor* cursor_;
std::set<rdr::S32> encodings_;
unsigned int ledState_;
rdr::U32 clipFlags;
rdr::U32 clipSizes[16];
};
}
#endif

+ 78
- 5
common/rfb/SConnection.cxx View File

@@ -20,6 +20,7 @@
#include <string.h>
#include <rfb/Exception.h>
#include <rfb/Security.h>
#include <rfb/clipboardTypes.h>
#include <rfb/msgTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/SMsgReader.h>
@@ -53,7 +54,7 @@ SConnection::SConnection()
is(0), os(0), reader_(0), writer_(0),
ssecurity(0), state_(RFBSTATE_UNINITIALISED),
preferredEncoding(encodingRaw),
clientClipboard(NULL)
clientClipboard(NULL), hasLocalClipboard(false)
{
defaultMajorVersion = 3;
defaultMinorVersion = 8;
@@ -299,6 +300,16 @@ void SConnection::setEncodings(int nEncodings, const rdr::S32* encodings)
}

SMsgHandler::setEncodings(nEncodings, encodings);

if (client.supportsEncoding(pseudoEncodingExtendedClipboard)) {
rdr::U32 sizes[] = { 0 };
writer()->writeClipboardCaps(rfb::clipboardUTF8 |
rfb::clipboardRequest |
rfb::clipboardPeek |
rfb::clipboardNotify |
rfb::clipboardProvide,
sizes);
}
}

void SConnection::clientCutText(const char* str)
@@ -311,6 +322,49 @@ void SConnection::clientCutText(const char* str)
handleClipboardAnnounce(true);
}

void SConnection::handleClipboardRequest(rdr::U32 flags)
{
if (!(flags & rfb::clipboardUTF8))
return;
if (!hasLocalClipboard)
return;
handleClipboardRequest();
}

void SConnection::handleClipboardPeek(rdr::U32 flags)
{
if (!hasLocalClipboard)
return;
if (client.clipboardFlags() & rfb::clipboardNotify)
writer()->writeClipboardNotify(rfb::clipboardUTF8);
}

void SConnection::handleClipboardNotify(rdr::U32 flags)
{
strFree(clientClipboard);
clientClipboard = NULL;

if (flags & rfb::clipboardUTF8)
handleClipboardAnnounce(true);
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);
}

void SConnection::supportsQEMUKeyEvent()
{
writer()->writeQEMUKeyEvent();
@@ -440,19 +494,38 @@ void SConnection::requestClipboard()
handleClipboardData(clientClipboard);
return;
}

if (client.supportsEncoding(pseudoEncodingExtendedClipboard) &&
(client.clipboardFlags() & rfb::clipboardRequest))
writer()->writeClipboardRequest(rfb::clipboardUTF8);
}

void SConnection::announceClipboard(bool available)
{
if (available)
handleClipboardRequest();
hasLocalClipboard = available;

if (client.supportsEncoding(pseudoEncodingExtendedClipboard) &&
(client.clipboardFlags() & rfb::clipboardNotify))
writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
else {
if (available)
handleClipboardRequest();
}
}

void SConnection::sendClipboardData(const char* data)
{
CharArray latin1(utf8ToLatin1(data));
if (client.supportsEncoding(pseudoEncodingExtendedClipboard) &&
(client.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);
writer()->writeServerCutText(latin1.buf);
}
}

void SConnection::writeFakeColourMap(void)

+ 8
- 0
common/rfb/SConnection.h View File

@@ -82,6 +82,13 @@ namespace rfb {

virtual void clientCutText(const char* str);

virtual void handleClipboardRequest(rdr::U32 flags);
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();


@@ -247,6 +254,7 @@ namespace rfb {
AccessRights accessRights;

char* clientClipboard;
bool hasLocalClipboard;
};
}
#endif

+ 24
- 1
common/rfb/SMsgHandler.cxx View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2011 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -64,6 +64,29 @@ void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings)
supportsQEMUKeyEvent();
}

void SMsgHandler::handleClipboardCaps(rdr::U32 flags, const rdr::U32* lengths)
{
client.setClipboardCaps(flags, lengths);
}

void SMsgHandler::handleClipboardRequest(rdr::U32 flags)
{
}

void SMsgHandler::handleClipboardPeek(rdr::U32 flags)
{
}

void SMsgHandler::handleClipboardNotify(rdr::U32 flags)
{
}

void SMsgHandler::handleClipboardProvide(rdr::U32 flags,
const size_t* lengths,
const rdr::U8* const* data)
{
}

void SMsgHandler::supportsLocalCursor()
{
}

+ 12
- 3
common/rfb/SMsgHandler.h View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2011 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,8 +40,8 @@ namespace rfb {

// The following methods are called as corresponding messages are read. A
// derived class should override these methods as desired. Note that for
// the setPixelFormat(), and setEncodings() methods, a derived class must
// call on to SMsgHandler's methods.
// the setPixelFormat(), setEncodings() and clipboardCaps() methods, a
// derived class must call on to SMsgHandler's methods.

virtual void clientInit(bool shared);

@@ -54,6 +54,15 @@ namespace rfb {
virtual void enableContinuousUpdates(bool enable,
int x, int y, int w, int h) = 0;

virtual void handleClipboardCaps(rdr::U32 flags,
const rdr::U32* lengths);
virtual void handleClipboardRequest(rdr::U32 flags);
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);

// InputHandler interface
// The InputHandler methods will be called for the corresponding messages.


+ 107
- 5
common/rfb/SMsgReader.cxx View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2014 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,9 +17,13 @@
* USA.
*/
#include <stdio.h>

#include <rdr/InStream.h>
#include <rdr/ZlibInStream.h>

#include <rfb/msgTypes.h>
#include <rfb/qemuTypes.h>
#include <rfb/clipboardTypes.h>
#include <rfb/Exception.h>
#include <rfb/util.h>
#include <rfb/SMsgHandler.h>
@@ -203,11 +207,16 @@ void SMsgReader::readPointerEvent()
void SMsgReader::readClientCutText()
{
is->skip(3);
int len = is->readU32();
if (len < 0) {
throw Exception("Cut text too long.");
rdr::U32 len = is->readU32();

if (len & 0x80000000) {
rdr::S32 slen = len;
slen = -slen;
readExtendedClipboard(slen);
return;
}
if (len > maxCutText) {

if (len > (size_t)maxCutText) {
is->skip(len);
vlog.error("Cut text too long (%d bytes) - ignoring", len);
return;
@@ -218,6 +227,99 @@ void SMsgReader::readClientCutText()
handler->clientCutText(filtered.buf);
}

void SMsgReader::readExtendedClipboard(rdr::S32 len)
{
rdr::U32 flags;
rdr::U32 action;

if (len < 4)
throw Exception("Invalid extended clipboard message");
if (len > maxCutText) {
vlog.error("Extended clipboard message too long (%d bytes) - ignoring", 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.removeUnderlying();

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::readQEMUMessage()
{
int subType = is->readU8();

+ 2
- 1
common/rfb/SMsgReader.h View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2014 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@ namespace rfb {
void readKeyEvent();
void readPointerEvent();
void readClientCutText();
void readExtendedClipboard(rdr::S32 len);

void readQEMUMessage();
void readQEMUKeyEvent();

+ 112
- 1
common/rfb/SMsgWriter.cxx View File

@@ -1,6 +1,6 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
* Copyright 2009-2017 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,9 +18,14 @@
* USA.
*/
#include <stdio.h>

#include <rdr/OutStream.h>
#include <rdr/MemOutStream.h>
#include <rdr/ZlibOutStream.h>

#include <rfb/msgTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/clipboardTypes.h>
#include <rfb/Exception.h>
#include <rfb/ClientParams.h>
#include <rfb/UpdateTracker.h>
@@ -93,6 +98,112 @@ void SMsgWriter::writeServerCutText(const char* str)
endMsg();
}

void SMsgWriter::writeClipboardCaps(rdr::U32 caps,
const rdr::U32* lengths)
{
size_t i, count;

if (!client->supportsEncoding(pseudoEncodingExtendedClipboard))
throw Exception("Client does not support extended clipboard");

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 (!client->supportsEncoding(pseudoEncodingExtendedClipboard))
throw Exception("Client does not support extended clipboard");
if (!(client->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 (!client->supportsEncoding(pseudoEncodingExtendedClipboard))
throw Exception("Client does not support extended clipboard");
if (!(client->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 (!client->supportsEncoding(pseudoEncodingExtendedClipboard))
throw Exception("Client does not support extended clipboard");
if (!(client->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 (!client->supportsEncoding(pseudoEncodingExtendedClipboard))
throw Exception("Client does not support extended clipboard");
if (!(client->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();
}

void SMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
{
if (!client->supportsEncoding(pseudoEncodingFence))

+ 10
- 2
common/rfb/SMsgWriter.h View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2014 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -54,10 +54,18 @@ namespace rfb {
const rdr::U16 green[],
const rdr::U16 blue[]);

// writeBell() and writeServerCutText() do the obvious thing.
// writeBell() does the obvious thing.
void writeBell();

void writeServerCutText(const char* str);

void writeClipboardCaps(rdr::U32 caps, const rdr::U32* lengths);
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);

// writeFence() sends a new fence request or response to the client.
void writeFence(rdr::U32 flags, unsigned len, const char data[]);


+ 19
- 1
common/rfb/ServerParams.cxx View File

@@ -1,6 +1,6 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
* Copyright 2014-2018 Pierre Ossman for Cendio AB
* Copyright 2014-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,7 +32,11 @@ ServerParams::ServerParams()
ledState_(ledUnknown)
{
setName("");

cursor_ = new Cursor(0, 0, Point(), NULL);

clipFlags = 0;
memset(clipSizes, 0, sizeof(clipSizes));
}

ServerParams::~ServerParams()
@@ -82,3 +86,17 @@ void ServerParams::setLEDState(unsigned int state)
{
ledState_ = state;
}

void ServerParams::setClipboardCaps(rdr::U32 flags, const rdr::U32* lengths)
{
int i, num;

clipFlags = flags;

num = 0;
for (i = 0;i < 16;i++) {
if (!(flags & (1 << i)))
continue;
clipSizes[i] = lengths[num++];
}
}

+ 6
- 1
common/rfb/ServerParams.h View File

@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2014-2018 Pierre Ossman for Cendio AB
* Copyright 2014-2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -69,6 +69,9 @@ namespace rfb {
unsigned int ledState() { return ledState_; }
void setLEDState(unsigned int state);

rdr::U32 clipboardFlags() const { return clipFlags; }
void setClipboardCaps(rdr::U32 flags, const rdr::U32* lengths);

bool supportsQEMUKeyEvent;
bool supportsSetDesktopSize;
bool supportsFence;
@@ -84,6 +87,8 @@ namespace rfb {
char* name_;
Cursor* cursor_;
unsigned int ledState_;
rdr::U32 clipFlags;
rdr::U32 clipSizes[16];
};
}
#endif

+ 41
- 0
common/rfb/clipboardTypes.h View File

@@ -0,0 +1,41 @@
/* Copyright 2019 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifndef __RFB_CLIPBOARDTYPES_H__
#define __RFB_CLIPBOARDTYPES_H__

namespace rfb {

// Formats
const unsigned int clipboardUTF8 = 1 << 0;
const unsigned int clipboardRTF = 1 << 1;
const unsigned int clipboardHTML = 1 << 2;
const unsigned int clipboardDIB = 1 << 3;
const unsigned int clipboardFiles = 1 << 4;

const unsigned int clipboardFormatMask = 0x0000ffff;

// Actions
const unsigned int clipboardCaps = 1 << 24;
const unsigned int clipboardRequest = 1 << 25;
const unsigned int clipboardPeek = 1 << 26;
const unsigned int clipboardNotify = 1 << 27;
const unsigned int clipboardProvide = 1 << 28;

const unsigned int clipboardActionMask = 0xff000000;
}
#endif

+ 3
- 0
common/rfb/encodings.h View File

@@ -63,6 +63,9 @@ namespace rfb {
const int pseudoEncodingVMwareCursor = 0x574d5664;
const int pseudoEncodingVMwareLEDState = 0x574d5668;

// UltraVNC-specific
const int pseudoEncodingExtendedClipboard = 0xC0A1E5CE;

int encodingNum(const char* name);
const char* encodingName(int num);
}

+ 5
- 0
vncviewer/vncviewer.man View File

@@ -182,6 +182,11 @@ Set the primary selection as well as the clipboard selection.
Default is on.
.
.TP
.B \-MaxCutText \fIbytes\fP
The maximum size of a clipboard update that will be accepted from a server.
Default is \fB262144\fP.
.
.TP
.B \-SendClipboard
Send clipboard changes to the server. Default is on.
.

Loading…
Cancel
Save