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

#include <string.h> #include <string.h>


#include <rfb/Exception.h> #include <rfb/Exception.h>
#include <rfb/clipboardTypes.h>
#include <rfb/fenceTypes.h> #include <rfb/fenceTypes.h>
#include <rfb/CMsgReader.h> #include <rfb/CMsgReader.h>
#include <rfb/CMsgWriter.h> #include <rfb/CMsgWriter.h>
firstUpdate(true), pendingUpdate(false), continuousUpdates(false), firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
forceNonincremental(true), forceNonincremental(true),
framebuffer(NULL), decoder(this), framebuffer(NULL), decoder(this),
serverClipboard(NULL)
serverClipboard(NULL), hasLocalClipboard(false)
{ {
} }




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

strFree(serverClipboard); strFree(serverClipboard);
serverClipboard = NULL; serverClipboard = NULL;


handleClipboardAnnounce(true); 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() void CConnection::authSuccess()
{ {
} }
handleClipboardData(serverClipboard); handleClipboardData(serverClipboard);
return; return;
} }

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


void CConnection::announceClipboard(bool available) 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) 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() void CConnection::refreshFramebuffer()


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

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



virtual void serverCutText(const char* str); 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 // Methods to be overridden in a derived class


DecodeManager decoder; DecodeManager decoder;


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

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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
{ {
server.setLEDState(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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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. * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
* *
* This is free software; you can redistribute it and/or modify * This is free software; you can redistribute it and/or modify
// The following methods are called as corresponding messages are read. A // The following methods are called as corresponding messages are read. A
// derived class should override these methods as desired. Note that for // derived class should override these methods as desired. Note that for
// the setDesktopSize(), setExtendedDesktopSize(), setPixelFormat(), // 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 setDesktopSize(int w, int h);
virtual void setExtendedDesktopSize(unsigned reason, unsigned result, virtual void setExtendedDesktopSize(unsigned reason, unsigned result,


virtual void setLEDState(unsigned int state); 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; ServerParams server;
}; };
} }

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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>


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

#include <rfb/msgTypes.h>
#include <rfb/clipboardTypes.h>
#include <rfb/Exception.h> #include <rfb/Exception.h>
#include <rfb/LogWriter.h> #include <rfb/LogWriter.h>
#include <rfb/util.h> #include <rfb/util.h>


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


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

using namespace rfb; using namespace rfb;


CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_) CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_)
{ {
is->skip(3); is->skip(3);
rdr::U32 len = is->readU32(); 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); is->skip(len);
vlog.error("cut text too long (%d bytes) - ignoring",len); vlog.error("cut text too long (%d bytes) - ignoring",len);
return; return;
handler->serverCutText(filtered.buf); 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() void CMsgReader::readFence()
{ {
rdr::U32 flags; rdr::U32 flags;

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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
void readSetColourMapEntries(); void readSetColourMapEntries();
void readBell(); void readBell();
void readServerCutText(); void readServerCutText();
void readExtendedClipboard(rdr::S32 len);
void readFence(); void readFence();
void readEndOfContinuousUpdates(); void readEndOfContinuousUpdates();



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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* USA. * USA.
*/ */
#include <stdio.h> #include <stdio.h>

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

#include <rfb/msgTypes.h> #include <rfb/msgTypes.h>
#include <rfb/fenceTypes.h> #include <rfb/fenceTypes.h>
#include <rfb/qemuTypes.h> #include <rfb/qemuTypes.h>
#include <rfb/clipboardTypes.h>
#include <rfb/Exception.h> #include <rfb/Exception.h>
#include <rfb/PixelFormat.h> #include <rfb/PixelFormat.h>
#include <rfb/Rect.h> #include <rfb/Rect.h>
endMsg(); 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) void CMsgWriter::startMsg(int type)
{ {
os->writeU8(type); os->writeU8(type);

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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by


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

void writeClientCutText(const char* str); 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: protected:
void startMsg(int type); void startMsg(int type);
void endMsg(); void endMsg();

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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
#include <rfb/Exception.h> #include <rfb/Exception.h>
#include <rfb/encodings.h> #include <rfb/encodings.h>
#include <rfb/ledStates.h> #include <rfb/ledStates.h>
#include <rfb/clipboardTypes.h>
#include <rfb/ClientParams.h> #include <rfb/ClientParams.h>


using namespace rfb; using namespace rfb;
ledState_(ledUnknown) ledState_(ledUnknown)
{ {
setName(""); setName("");

cursor_ = new Cursor(0, 0, Point(), NULL); 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() ClientParams::~ClientParams()
ledState_ = 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 bool ClientParams::supportsLocalCursor() const
{ {
if (supportsEncoding(pseudoEncodingCursorWithAlpha)) if (supportsEncoding(pseudoEncodingCursorWithAlpha))

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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
unsigned int ledState() { return ledState_; } unsigned int ledState() { return ledState_; }
void setLEDState(unsigned int state); 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 // Wrappers to check for functionality rather than specific
// encodings // encodings
bool supportsLocalCursor() const; bool supportsLocalCursor() const;
Cursor* cursor_; Cursor* cursor_;
std::set<rdr::S32> encodings_; std::set<rdr::S32> encodings_;
unsigned int ledState_; unsigned int ledState_;
rdr::U32 clipFlags;
rdr::U32 clipSizes[16];
}; };
} }
#endif #endif

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

#include <string.h> #include <string.h>
#include <rfb/Exception.h> #include <rfb/Exception.h>
#include <rfb/Security.h> #include <rfb/Security.h>
#include <rfb/clipboardTypes.h>
#include <rfb/msgTypes.h> #include <rfb/msgTypes.h>
#include <rfb/fenceTypes.h> #include <rfb/fenceTypes.h>
#include <rfb/SMsgReader.h> #include <rfb/SMsgReader.h>
is(0), os(0), reader_(0), writer_(0), is(0), os(0), reader_(0), writer_(0),
ssecurity(0), state_(RFBSTATE_UNINITIALISED), ssecurity(0), state_(RFBSTATE_UNINITIALISED),
preferredEncoding(encodingRaw), preferredEncoding(encodingRaw),
clientClipboard(NULL)
clientClipboard(NULL), hasLocalClipboard(false)
{ {
defaultMajorVersion = 3; defaultMajorVersion = 3;
defaultMinorVersion = 8; defaultMinorVersion = 8;
} }


SMsgHandler::setEncodings(nEncodings, 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) void SConnection::clientCutText(const char* str)
handleClipboardAnnounce(true); 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() void SConnection::supportsQEMUKeyEvent()
{ {
writer()->writeQEMUKeyEvent(); writer()->writeQEMUKeyEvent();
handleClipboardData(clientClipboard); handleClipboardData(clientClipboard);
return; return;
} }

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


void SConnection::announceClipboard(bool available) 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) 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) void SConnection::writeFakeColourMap(void)

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



virtual void clientCutText(const char* str); 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(); virtual void supportsQEMUKeyEvent();




AccessRights accessRights; AccessRights accessRights;


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

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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
supportsQEMUKeyEvent(); 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() void SMsgHandler::supportsLocalCursor()
{ {
} }

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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by


// The following methods are called as corresponding messages are read. A // The following methods are called as corresponding messages are read. A
// derived class should override these methods as desired. Note that for // 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); virtual void clientInit(bool shared);


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,
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 // InputHandler interface
// The InputHandler methods will be called for the corresponding messages. // The InputHandler methods will be called for the corresponding messages.



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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* USA. * USA.
*/ */
#include <stdio.h> #include <stdio.h>

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

#include <rfb/msgTypes.h> #include <rfb/msgTypes.h>
#include <rfb/qemuTypes.h> #include <rfb/qemuTypes.h>
#include <rfb/clipboardTypes.h>
#include <rfb/Exception.h> #include <rfb/Exception.h>
#include <rfb/util.h> #include <rfb/util.h>
#include <rfb/SMsgHandler.h> #include <rfb/SMsgHandler.h>
void SMsgReader::readClientCutText() void SMsgReader::readClientCutText()
{ {
is->skip(3); 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); is->skip(len);
vlog.error("Cut text too long (%d bytes) - ignoring", len); vlog.error("Cut text too long (%d bytes) - ignoring", len);
return; return;
handler->clientCutText(filtered.buf); 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() void SMsgReader::readQEMUMessage()
{ {
int subType = is->readU8(); int subType = is->readU8();

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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
void readKeyEvent(); void readKeyEvent();
void readPointerEvent(); void readPointerEvent();
void readClientCutText(); void readClientCutText();
void readExtendedClipboard(rdr::S32 len);


void readQEMUMessage(); void readQEMUMessage();
void readQEMUKeyEvent(); void readQEMUKeyEvent();

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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* USA. * USA.
*/ */
#include <stdio.h> #include <stdio.h>

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

#include <rfb/msgTypes.h> #include <rfb/msgTypes.h>
#include <rfb/fenceTypes.h> #include <rfb/fenceTypes.h>
#include <rfb/clipboardTypes.h>
#include <rfb/Exception.h> #include <rfb/Exception.h>
#include <rfb/ClientParams.h> #include <rfb/ClientParams.h>
#include <rfb/UpdateTracker.h> #include <rfb/UpdateTracker.h>
endMsg(); 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[]) void SMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
{ {
if (!client->supportsEncoding(pseudoEncodingFence)) if (!client->supportsEncoding(pseudoEncodingFence))

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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
const rdr::U16 green[], const rdr::U16 green[],
const rdr::U16 blue[]); const rdr::U16 blue[]);


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

void writeServerCutText(const char* str); 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. // writeFence() sends a new fence request or response to the client.
void writeFence(rdr::U32 flags, unsigned len, const char data[]); void writeFence(rdr::U32 flags, unsigned len, const char data[]);



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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
ledState_(ledUnknown) ledState_(ledUnknown)
{ {
setName(""); setName("");

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

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


ServerParams::~ServerParams() ServerParams::~ServerParams()
{ {
ledState_ = 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

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* 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 * This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
unsigned int ledState() { return ledState_; } unsigned int ledState() { return ledState_; }
void setLEDState(unsigned int state); void setLEDState(unsigned int state);


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

bool supportsQEMUKeyEvent; bool supportsQEMUKeyEvent;
bool supportsSetDesktopSize; bool supportsSetDesktopSize;
bool supportsFence; bool supportsFence;
char* name_; char* name_;
Cursor* cursor_; Cursor* cursor_;
unsigned int ledState_; unsigned int ledState_;
rdr::U32 clipFlags;
rdr::U32 clipSizes[16];
}; };
} }
#endif #endif

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

/* 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

const int pseudoEncodingVMwareCursor = 0x574d5664; const int pseudoEncodingVMwareCursor = 0x574d5664;
const int pseudoEncodingVMwareLEDState = 0x574d5668; const int pseudoEncodingVMwareLEDState = 0x574d5668;


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

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

+ 5
- 0
vncviewer/vncviewer.man View File

Default is on. Default is on.
. .
.TP .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 .B \-SendClipboard
Send clipboard changes to the server. Default is on. Send clipboard changes to the server. Default is on.
. .

Loading…
Cancel
Save