#include <string.h>
#include <rfb/Exception.h>
+#include <rfb/clipboardTypes.h>
#include <rfb/fenceTypes.h>
#include <rfb/CMsgReader.h>
#include <rfb/CMsgWriter.h>
firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
forceNonincremental(true),
framebuffer(NULL), decoder(this),
- serverClipboard(NULL)
+ serverClipboard(NULL), hasLocalClipboard(false)
{
}
void CConnection::serverCutText(const char* str)
{
+ hasLocalClipboard = false;
+
strFree(serverClipboard);
serverClipboard = NULL;
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()
{
}
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()
encodings.push_back(pseudoEncodingDesktopName);
encodings.push_back(pseudoEncodingLastRect);
+ encodings.push_back(pseudoEncodingExtendedClipboard);
encodings.push_back(pseudoEncodingContinuousUpdates);
encodings.push_back(pseudoEncodingFence);
encodings.push_back(pseudoEncodingQEMUKeyEvent);
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
DecodeManager decoder;
char* serverClipboard;
+ bool hasLocalClipboard;
};
}
#endif
/* 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
{
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)
+{
+}
/* 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
// 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,
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;
};
}
/* 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
#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>
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_)
{
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;
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;
/* 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
void readSetColourMapEntries();
void readBell();
void readServerCutText();
+ void readExtendedClipboard(rdr::S32 len);
void readFence();
void readEndOfContinuousUpdates();
/* 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
* 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>
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);
/* 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
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();
/* 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
#include <rfb/Exception.h>
#include <rfb/encodings.h>
#include <rfb/ledStates.h>
+#include <rfb/clipboardTypes.h>
#include <rfb/ClientParams.h>
using namespace rfb;
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()
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))
/* 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
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;
Cursor* cursor_;
std::set<rdr::S32> encodings_;
unsigned int ledState_;
+ rdr::U32 clipFlags;
+ rdr::U32 clipSizes[16];
};
}
#endif
#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>
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;
}
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)
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();
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)
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();
AccessRights accessRights;
char* clientClipboard;
+ bool hasLocalClipboard;
};
}
#endif
/* 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
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()
{
}
/* 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
// 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);
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.
/* 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
* 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>
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;
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();
/* 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
void readKeyEvent();
void readPointerEvent();
void readClientCutText();
+ void readExtendedClipboard(rdr::S32 len);
void readQEMUMessage();
void readQEMUKeyEvent();
/* 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
* 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>
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))
/* 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
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[]);
/* 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
ledState_(ledUnknown)
{
setName("");
+
cursor_ = new Cursor(0, 0, Point(), NULL);
+
+ clipFlags = 0;
+ memset(clipSizes, 0, sizeof(clipSizes));
}
ServerParams::~ServerParams()
{
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++];
+ }
+}
/* 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
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;
char* name_;
Cursor* cursor_;
unsigned int ledState_;
+ rdr::U32 clipFlags;
+ rdr::U32 clipSizes[16];
};
}
#endif
--- /dev/null
+/* 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
const int pseudoEncodingVMwareCursor = 0x574d5664;
const int pseudoEncodingVMwareLEDState = 0x574d5668;
+ // UltraVNC-specific
+ const int pseudoEncodingExtendedClipboard = 0xC0A1E5CE;
+
int encodingNum(const char* name);
const char* encodingName(int num);
}
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.
.