Browse Source

Merge branch 'exclipboard' of https://github.com/CendioOssman/tigervnc

tags/v1.9.90
Pierre Ossman 4 years ago
parent
commit
5b8a629661
54 changed files with 2192 additions and 433 deletions
  1. 128
    2
      common/rfb/CConnection.cxx
  2. 48
    1
      common/rfb/CConnection.h
  3. 24
    1
      common/rfb/CMsgHandler.cxx
  4. 14
    4
      common/rfb/CMsgHandler.h
  5. 112
    6
      common/rfb/CMsgReader.cxx
  6. 2
    1
      common/rfb/CMsgReader.h
  7. 111
    2
      common/rfb/CMsgWriter.cxx
  8. 10
    2
      common/rfb/CMsgWriter.h
  9. 22
    1
      common/rfb/ClientParams.cxx
  10. 6
    1
      common/rfb/ClientParams.h
  11. 1
    2
      common/rfb/InputHandler.h
  12. 120
    2
      common/rfb/SConnection.cxx
  13. 48
    1
      common/rfb/SConnection.h
  14. 20
    0
      common/rfb/SDesktop.h
  15. 24
    1
      common/rfb/SMsgHandler.cxx
  16. 12
    3
      common/rfb/SMsgHandler.h
  17. 110
    8
      common/rfb/SMsgReader.cxx
  18. 2
    1
      common/rfb/SMsgReader.h
  19. 119
    2
      common/rfb/SMsgWriter.cxx
  20. 11
    3
      common/rfb/SMsgWriter.h
  21. 19
    1
      common/rfb/ServerParams.cxx
  22. 6
    1
      common/rfb/ServerParams.h
  23. 55
    23
      common/rfb/VNCSConnectionST.cxx
  24. 7
    3
      common/rfb/VNCSConnectionST.h
  25. 16
    3
      common/rfb/VNCServer.h
  26. 66
    10
      common/rfb/VNCServerST.cxx
  27. 11
    3
      common/rfb/VNCServerST.h
  28. 41
    0
      common/rfb/clipboardTypes.h
  29. 3
    0
      common/rfb/encodings.h
  30. 440
    0
      common/rfb/util.cxx
  31. 21
    0
      common/rfb/util.h
  32. 2
    2
      tests/decperf.cxx
  33. 2
    2
      tests/encperf.cxx
  34. 1
    1
      unix/x0vncserver/XDesktop.cxx
  35. 1
    1
      unix/x0vncserver/XDesktop.h
  36. 33
    1
      unix/xserver/hw/vnc/RFBGlue.cc
  37. 8
    1
      unix/xserver/hw/vnc/RFBGlue.h
  38. 41
    13
      unix/xserver/hw/vnc/XserverDesktop.cc
  39. 7
    3
      unix/xserver/hw/vnc/XserverDesktop.h
  40. 15
    3
      unix/xserver/hw/vnc/vncExtInit.cc
  41. 4
    2
      unix/xserver/hw/vnc/vncExtInit.h
  42. 229
    113
      unix/xserver/hw/vnc/vncSelection.c
  43. 4
    2
      unix/xserver/hw/vnc/vncSelection.h
  44. 15
    5
      vncviewer/CConn.cxx
  45. 4
    2
      vncviewer/CConn.h
  46. 16
    6
      vncviewer/DesktopWindow.cxx
  47. 5
    3
      vncviewer/DesktopWindow.h
  48. 82
    81
      vncviewer/Viewport.cxx
  49. 10
    7
      vncviewer/Viewport.h
  50. 5
    0
      vncviewer/vncviewer.man
  51. 49
    84
      win/rfb_win32/Clipboard.cxx
  52. 5
    1
      win/rfb_win32/Clipboard.h
  53. 19
    9
      win/rfb_win32/SDisplay.cxx
  54. 6
    3
      win/rfb_win32/SDisplay.h

+ 128
- 2
common/rfb/CConnection.cxx View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-2017 Pierre Ossman for Cendio AB
* Copyright 2011-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 <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>
formatChange(false), encodingChange(false), formatChange(false), encodingChange(false),
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), hasLocalClipboard(false)
{ {
} }


reader_ = 0; reader_ = 0;
delete writer_; delete writer_;
writer_ = 0; writer_ = 0;
strFree(serverClipboard);
} }


void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_) void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
decoder.decodeRect(r, encoding, framebuffer); decoder.decodeRect(r, encoding, framebuffer);
} }


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

strFree(serverClipboard);
serverClipboard = NULL;

serverClipboard = latin1ToUTF8(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() void CConnection::authSuccess()
{ {
} }
assert(false); assert(false);
} }


void CConnection::handleClipboardRequest()
{
}

void CConnection::handleClipboardAnnounce(bool available)
{
}

void CConnection::handleClipboardData(const char* data)
{
}

void CConnection::requestClipboard()
{
if (serverClipboard != NULL) {
handleClipboardData(serverClipboard);
return;
}

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

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

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

void CConnection::sendClipboardData(const char* 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);
}
}

void CConnection::refreshFramebuffer() void CConnection::refreshFramebuffer()
{ {
forceNonincremental = true; forceNonincremental = true;


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);

+ 48
- 1
common/rfb/CConnection.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-2017 Pierre Ossman for Cendio AB
* Copyright 2011-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
virtual void framebufferUpdateEnd(); virtual void framebufferUpdateEnd();
virtual void dataRect(const Rect& r, int encoding); virtual void dataRect(const Rect& r, int encoding);


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


// sure the pixel buffer has been updated once this call returns. // sure the pixel buffer has been updated once this call returns.
virtual void resizeFramebuffer(); virtual void resizeFramebuffer();


// handleClipboardRequest() is called whenever the server requests
// the client to send over its clipboard data. It will only be
// called after the client has first announced a clipboard change
// via announceClipboard().
virtual void handleClipboardRequest();

// handleClipboardAnnounce() is called to indicate a change in the
// clipboard on the server. Call requestClipboard() to access the
// actual data.
virtual void handleClipboardAnnounce(bool available);

// handleClipboardData() is called when the server has sent over
// the clipboard data as a result of a previous call to
// requestClipboard(). Note that this function might never be
// called if the clipboard data was no longer available when the
// server received the request.
virtual void handleClipboardData(const char* data);



// Other methods // Other methods


// requestClipboard() will result in a request to the server to
// transfer its clipboard data. A call to handleClipboardData()
// will be made once the data is available.
virtual void requestClipboard();

// announceClipboard() informs the server of changes to the
// clipboard on the client. The server may later request the
// clipboard data via handleClipboardRequest().
virtual void announceClipboard(bool available);

// sendClipboardData() transfers the clipboard data to the server
// and should be called whenever the server has requested the
// clipboard via handleClipboardRequest().
virtual void sendClipboardData(const char* data);

// refreshFramebuffer() forces a complete refresh of the entire // refreshFramebuffer() forces a complete refresh of the entire
// framebuffer // framebuffer
void refreshFramebuffer(); void refreshFramebuffer();


ModifiablePixelBuffer* framebuffer; ModifiablePixelBuffer* framebuffer;
DecodeManager decoder; DecodeManager decoder;

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)
{
}

+ 14
- 4
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 setColourMapEntries(int firstColour, int nColours, virtual void setColourMapEntries(int firstColour, int nColours,
rdr::U16* rgbs) = 0; rdr::U16* rgbs) = 0;
virtual void bell() = 0; virtual void bell() = 0;
virtual void serverCutText(const char* str, rdr::U32 len) = 0;
virtual void serverCutText(const char* str) = 0;


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;
}; };
} }

+ 112
- 6
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;
} }
CharArray ca(len+1);
ca.buf[len] = 0;
CharArray ca(len);
is->readBytes(ca.buf, len); is->readBytes(ca.buf, len);
handler->serverCutText(ca.buf, len);
CharArray filtered(convertLF(ca.buf, len));
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()

+ 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();



+ 111
- 2
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>
} }




void CMsgWriter::writeClientCutText(const char* str, rdr::U32 len)
void CMsgWriter::writeClientCutText(const char* str)
{ {
size_t len;

if (strchr(str, '\r') != NULL)
throw Exception("Invalid carriage return in clipboard data");

len = strlen(str);
startMsg(msgTypeClientCutText); startMsg(msgTypeClientCutText);
os->pad(3); os->pad(3);
os->writeU32(len); os->writeU32(len);
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);

+ 10
- 2
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, rdr::U32 len);

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);

+ 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

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

bool __unused_attr down) { } bool __unused_attr down) { }
virtual void pointerEvent(const Point& __unused_attr pos, virtual void pointerEvent(const Point& __unused_attr pos,
int __unused_attr buttonMask) { } int __unused_attr buttonMask) { }
virtual void clientCutText(const char* __unused_attr str,
int __unused_attr len) { }
virtual void clientCutText(const char* __unused_attr str) { }
}; };


} }

+ 120
- 2
common/rfb/SConnection.cxx View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011 Pierre Ossman for Cendio AB
* Copyright 2011-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 <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>
: readyForSetColourMapEntries(false), : readyForSetColourMapEntries(false),
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), hasLocalClipboard(false)
{ {
defaultMajorVersion = 3; defaultMajorVersion = 3;
defaultMinorVersion = 8; defaultMinorVersion = 8;
reader_ = 0; reader_ = 0;
delete writer_; delete writer_;
writer_ = 0; writer_ = 0;
strFree(clientClipboard);
} }


void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_) void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
} }


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)
{
strFree(clientClipboard);
clientClipboard = NULL;

clientClipboard = latin1ToUTF8(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() void SConnection::supportsQEMUKeyEvent()
{ {
} }


void SConnection::handleClipboardRequest()
{
}

void SConnection::handleClipboardAnnounce(bool available)
{
}

void SConnection::handleClipboardData(const char* data)
{
}

void SConnection::requestClipboard()
{
if (clientClipboard != NULL) {
handleClipboardData(clientClipboard);
return;
}

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

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

void SConnection::writeFakeColourMap(void) void SConnection::writeFakeColourMap(void)
{ {
int i; int i;

+ 48
- 1
common/rfb/SConnection.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011 Pierre Ossman for Cendio AB
* Copyright 2011-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


virtual void setEncodings(int nEncodings, const rdr::S32* encodings); virtual void setEncodings(int nEncodings, const rdr::S32* encodings);


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();



// Methods to be overridden in a derived class // Methods to be overridden in a derived class


// versionReceived() indicates that the version number has just been read // versionReceived() indicates that the version number has just been read
virtual void enableContinuousUpdates(bool enable, virtual void enableContinuousUpdates(bool enable,
int x, int y, int w, int h); int x, int y, int w, int h);


// handleClipboardRequest() is called whenever the client requests
// the server to send over its clipboard data. It will only be
// called after the server has first announced a clipboard change
// via announceClipboard().
virtual void handleClipboardRequest();

// handleClipboardAnnounce() is called to indicate a change in the
// clipboard on the client. Call requestClipboard() to access the
// actual data.
virtual void handleClipboardAnnounce(bool available);

// handleClipboardData() is called when the client has sent over
// the clipboard data as a result of a previous call to
// requestClipboard(). Note that this function might never be
// called if the clipboard data was no longer available when the
// client received the request.
virtual void handleClipboardData(const char* data);


// Other methods // Other methods


// requestClipboard() will result in a request to the client to
// transfer its clipboard data. A call to handleClipboardData()
// will be made once the data is available.
virtual void requestClipboard();

// announceClipboard() informs the client of changes to the
// clipboard on the server. The client may later request the
// clipboard data via handleClipboardRequest().
virtual void announceClipboard(bool available);

// sendClipboardData() transfers the clipboard data to the client
// and should be called whenever the client has requested the
// clipboard via handleClipboardRequest().
virtual void sendClipboardData(const char* data);

// setAccessRights() allows a security package to limit the access rights // setAccessRights() allows a security package to limit the access rights
// of a SConnection to the server. How the access rights are treated // of a SConnection to the server. How the access rights are treated
// is up to the derived class. // is up to the derived class.
stateEnum state_; stateEnum state_;
rdr::S32 preferredEncoding; rdr::S32 preferredEncoding;
AccessRights accessRights; AccessRights accessRights;

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

+ 20
- 0
common/rfb/SDesktop.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* 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
// pointerEvent(), keyEvent() and clientCutText() are called in response to // pointerEvent(), keyEvent() and clientCutText() are called in response to
// the relevant RFB protocol messages from clients. // the relevant RFB protocol messages from clients.
// See InputHandler for method signatures. // See InputHandler for method signatures.

// handleClipboardRequest() is called whenever a client requests
// the server to send over its clipboard data. It will only be
// called after the server has first announced a clipboard change
// via VNCServer::announceClipboard().
virtual void handleClipboardRequest() {}

// handleClipboardAnnounce() is called to indicate a change in the
// clipboard on a client. Call VNCServer::requestClipboard() to
// access the actual data.
virtual void handleClipboardAnnounce(bool __unused_attr available) {}

// handleClipboardData() is called when a client has sent over
// the clipboard data as a result of a previous call to
// VNCServer::requestClipboard(). Note that this function might
// never be called if the clipboard data was no longer available
// when the client received the request.
virtual void handleClipboardData(const char* __unused_attr data) {}

protected: protected:
virtual ~SDesktop() {} virtual ~SDesktop() {}
}; };

+ 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.



+ 110
- 8
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;
} }
CharArray ca(len+1);
ca.buf[len] = 0;
CharArray ca(len);
is->readBytes(ca.buf, len); is->readBytes(ca.buf, len);
handler->clientCutText(ca.buf, len);
CharArray filtered(convertLF(ca.buf, len));
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()

+ 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();

+ 119
- 2
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::writeServerCutText(const char* str, int len)
void SMsgWriter::writeServerCutText(const char* str)
{ {
size_t len;

if (strchr(str, '\r') != NULL)
throw Exception("Invalid carriage return in clipboard data");

len = strlen(str);
startMsg(msgTypeServerCutText); startMsg(msgTypeServerCutText);
os->pad(3); os->pad(3);
os->writeU32(len); os->writeU32(len);
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))

+ 11
- 3
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, int len);

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

+ 55
- 23
common/rfb/VNCSConnectionST.cxx View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2018 Pierre Ossman for Cendio AB
* Copyright 2009-2019 Pierre Ossman for Cendio AB
* Copyright 2018 Peter Astrand for Cendio AB * Copyright 2018 Peter Astrand 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
} }
} }


void VNCSConnectionST::serverCutTextOrClose(const char *str, int len)
void VNCSConnectionST::setDesktopNameOrClose(const char *name)
{ {
try { try {
if (!accessCheck(AccessCutText)) return;
if (!rfb::Server::sendCutText) return;
if (state() == RFBSTATE_NORMAL)
writer()->writeServerCutText(str, len);
setDesktopName(name);
writeFramebufferUpdate();
} catch(rdr::Exception& e) { } catch(rdr::Exception& e) {
close(e.str()); close(e.str());
} }
} }



void VNCSConnectionST::setDesktopNameOrClose(const char *name)
void VNCSConnectionST::setCursorOrClose()
{ {
try { try {
setDesktopName(name);
setCursor();
writeFramebufferUpdate(); writeFramebufferUpdate();
} catch(rdr::Exception& e) { } catch(rdr::Exception& e) {
close(e.str()); close(e.str());
} }
} }



void VNCSConnectionST::setCursorOrClose()
void VNCSConnectionST::setLEDStateOrClose(unsigned int state)
{ {
try { try {
setCursor();
setLEDState(state);
writeFramebufferUpdate(); writeFramebufferUpdate();
} catch(rdr::Exception& e) { } catch(rdr::Exception& e) {
close(e.str()); close(e.str());
} }
} }


void VNCSConnectionST::requestClipboardOrClose()
{
try {
if (!accessCheck(AccessCutText)) return;
if (!rfb::Server::acceptCutText) return;
if (state() != RFBSTATE_NORMAL) return;
requestClipboard();
} catch(rdr::Exception& e) {
close(e.str());
}
}


void VNCSConnectionST::setLEDStateOrClose(unsigned int state)
void VNCSConnectionST::announceClipboardOrClose(bool available)
{ {
try { try {
setLEDState(state);
writeFramebufferUpdate();
if (!accessCheck(AccessCutText)) return;
if (!rfb::Server::sendCutText) return;
if (state() != RFBSTATE_NORMAL) return;
announceClipboard(available);
} catch(rdr::Exception& e) { } catch(rdr::Exception& e) {
close(e.str()); close(e.str());
} }
} }


void VNCSConnectionST::sendClipboardDataOrClose(const char* data)
{
try {
if (!accessCheck(AccessCutText)) return;
if (!rfb::Server::sendCutText) return;
if (state() != RFBSTATE_NORMAL) return;
sendClipboardData(data);
} catch(rdr::Exception& e) {
close(e.str());
}
}


bool VNCSConnectionST::getComparerState() bool VNCSConnectionST::getComparerState()
{ {
server->keyEvent(keysym, keycode, down); server->keyEvent(keysym, keycode, down);
} }


void VNCSConnectionST::clientCutText(const char* str, int len)
{
if (!accessCheck(AccessCutText)) return;
if (!rfb::Server::acceptCutText) return;
server->clientCutText(str, len);
}

void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental) void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
{ {
Rect safeRect; Rect safeRect;
} }
} }


void VNCSConnectionST::handleClipboardRequest()
{
if (!accessCheck(AccessCutText)) return;
server->handleClipboardRequest(this);
}

void VNCSConnectionST::handleClipboardAnnounce(bool available)
{
if (!accessCheck(AccessCutText)) return;
if (!rfb::Server::acceptCutText) return;
server->handleClipboardAnnounce(this, available);
}

void VNCSConnectionST::handleClipboardData(const char* data)
{
if (!accessCheck(AccessCutText)) return;
if (!rfb::Server::acceptCutText) return;
server->handleClipboardData(this, data);
}

// supportsLocalCursor() is called whenever the status of // supportsLocalCursor() is called whenever the status of
// client.supportsLocalCursor() has changed. If the client does now support local // client.supportsLocalCursor() has changed. If the client does now support local
// cursor, we make sure that the old server-side rendered cursor is cleaned up // cursor, we make sure that the old server-side rendered cursor is cleaned up
writer()->writeLEDState(); writer()->writeLEDState();
} }



bool VNCSConnectionST::handleTimeout(Timer* t) bool VNCSConnectionST::handleTimeout(Timer* t)
{ {
try { try {

+ 7
- 3
common/rfb/VNCSConnectionST.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2016 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 screenLayoutChangeOrClose(rdr::U16 reason); void screenLayoutChangeOrClose(rdr::U16 reason);
void setCursorOrClose(); void setCursorOrClose();
void bellOrClose(); void bellOrClose();
void serverCutTextOrClose(const char *str, int len);
void setDesktopNameOrClose(const char *name); void setDesktopNameOrClose(const char *name);
void setLEDStateOrClose(unsigned int state); void setLEDStateOrClose(unsigned int state);
void approveConnectionOrClose(bool accept, const char* reason); void approveConnectionOrClose(bool accept, const char* reason);
void requestClipboardOrClose();
void announceClipboardOrClose(bool available);
void sendClipboardDataOrClose(const char* data);


// The following methods never throw exceptions // The following methods never throw exceptions


virtual void setPixelFormat(const PixelFormat& pf); virtual void setPixelFormat(const PixelFormat& pf);
virtual void pointerEvent(const Point& pos, int buttonMask); virtual void pointerEvent(const Point& pos, int buttonMask);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
virtual void clientCutText(const char* str, int len);
virtual void framebufferUpdateRequest(const Rect& r, bool incremental); virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
virtual void setDesktopSize(int fb_width, int fb_height, virtual void setDesktopSize(int fb_width, int fb_height,
const ScreenSet& layout); const ScreenSet& layout);
virtual void fence(rdr::U32 flags, unsigned len, const char data[]); virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
virtual void enableContinuousUpdates(bool enable, virtual void enableContinuousUpdates(bool enable,
int x, int y, int w, int h); int x, int y, int w, int h);
virtual void handleClipboardRequest();
virtual void handleClipboardAnnounce(bool available);
virtual void handleClipboardData(const char* data);
virtual void supportsLocalCursor(); virtual void supportsLocalCursor();
virtual void supportsFence(); virtual void supportsFence();
virtual void supportsContinuousUpdates(); virtual void supportsContinuousUpdates();

+ 16
- 3
common/rfb/VNCServer.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* 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
// getPixelBuffer() returns a pointer to the PixelBuffer object. // getPixelBuffer() returns a pointer to the PixelBuffer object.
virtual const PixelBuffer* getPixelBuffer() const = 0; virtual const PixelBuffer* getPixelBuffer() const = 0;


// serverCutText() tells the server that the cut text has changed. This
// will normally be sent to all clients.
virtual void serverCutText(const char* str, int len) = 0;
// requestClipboard() will result in a request to a client to
// transfer its clipboard data. A call to
// SDesktop::handleClipboardData() will be made once the data is
// available.
virtual void requestClipboard() = 0;

// announceClipboard() informs all clients of changes to the
// clipboard on the server. A client may later request the
// clipboard data via SDesktop::handleClipboardRequest().
virtual void announceClipboard(bool available) = 0;

// sendClipboardData() transfers the clipboard data to a client
// and should be called whenever a client has requested the
// clipboard via SDesktop::handleClipboardRequest().
virtual void sendClipboardData(const char* data) = 0;


// bell() tells the server that it should make all clients make a bell sound. // bell() tells the server that it should make all clients make a bell sound.
virtual void bell() = 0; virtual void bell() = 0;

+ 66
- 10
common/rfb/VNCServerST.cxx View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2018 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
VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
: blHosts(&blacklist), desktop(desktop_), desktopStarted(false), : blHosts(&blacklist), desktop(desktop_), desktopStarted(false),
blockCounter(0), pb(0), ledState(ledUnknown), blockCounter(0), pb(0), ledState(ledUnknown),
name(strDup(name_)), pointerClient(0), comparer(0),
cursor(new Cursor(0, 0, Point(), NULL)),
name(strDup(name_)), pointerClient(0), clipboardClient(0),
comparer(0), cursor(new Cursor(0, 0, Point(), NULL)),
renderedCursorInvalid(false), renderedCursorInvalid(false),
keyRemapper(&KeyRemapper::defInstance), keyRemapper(&KeyRemapper::defInstance),
idleTimer(this), disconnectTimer(this), connectTimer(this), idleTimer(this), disconnectTimer(this), connectTimer(this),
if ((*ci)->getSock() == sock) { if ((*ci)->getSock() == sock) {
clients.remove(*ci); clients.remove(*ci);


// - Release the cursor if this client owns it
// - Remove any references to it
if (pointerClient == *ci) if (pointerClient == *ci)
pointerClient = NULL; pointerClient = NULL;
if (clipboardClient == *ci)
clipboardClient = NULL;
clipboardRequestors.remove(*ci);


// Adjust the exit timers // Adjust the exit timers
connectTimer.stop(); connectTimer.stop();
} }
} }


void VNCServerST::bell()
void VNCServerST::requestClipboard()
{
if (clipboardClient == NULL)
return;

clipboardClient->requestClipboard();
}

void VNCServerST::announceClipboard(bool available)
{ {
std::list<VNCSConnectionST*>::iterator ci, ci_next; std::list<VNCSConnectionST*>::iterator ci, ci_next;

if (available)
clipboardClient = NULL;

clipboardRequestors.clear();

for (ci = clients.begin(); ci != clients.end(); ci = ci_next) { for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
ci_next = ci; ci_next++; ci_next = ci; ci_next++;
(*ci)->bellOrClose();
(*ci)->announceClipboard(available);
}
}

void VNCServerST::sendClipboardData(const char* data)
{
std::list<VNCSConnectionST*>::iterator ci, ci_next;

if (strchr(data, '\r') != NULL)
throw Exception("Invalid carriage return in clipboard data");

for (ci = clipboardRequestors.begin();
ci != clipboardRequestors.end(); ci = ci_next) {
ci_next = ci; ci_next++;
(*ci)->sendClipboardData(data);
} }

clipboardRequestors.clear();
} }


void VNCServerST::serverCutText(const char* str, int len)
void VNCServerST::bell()
{ {
std::list<VNCSConnectionST*>::iterator ci, ci_next; std::list<VNCSConnectionST*>::iterator ci, ci_next;
for (ci = clients.begin(); ci != clients.end(); ci = ci_next) { for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
ci_next = ci; ci_next++; ci_next = ci; ci_next++;
(*ci)->serverCutTextOrClose(str, len);
(*ci)->bellOrClose();
} }
} }


desktop->pointerEvent(pos, buttonMask); desktop->pointerEvent(pos, buttonMask);
} }


void VNCServerST::clientCutText(const char* str, int len)
void VNCServerST::handleClipboardRequest(VNCSConnectionST* client)
{ {
desktop->clientCutText(str, len);
clipboardRequestors.push_back(client);
if (clipboardRequestors.size() == 1)
desktop->handleClipboardRequest();
}

void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client,
bool available)
{
if (available)
clipboardClient = client;
else {
if (client != clipboardClient)
return;
clipboardClient = NULL;
}
desktop->handleClipboardAnnounce(available);
}

void VNCServerST::handleClipboardData(VNCSConnectionST* client,
const char* data)
{
if (client != clipboardClient)
return;
desktop->handleClipboardData(data);
} }


unsigned int VNCServerST::setDesktopSize(VNCSConnectionST* requester, unsigned int VNCServerST::setDesktopSize(VNCSConnectionST* requester,

+ 11
- 3
common/rfb/VNCServerST.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2016 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
virtual void setPixelBuffer(PixelBuffer* pb); virtual void setPixelBuffer(PixelBuffer* pb);
virtual void setScreenLayout(const ScreenSet& layout); virtual void setScreenLayout(const ScreenSet& layout);
virtual const PixelBuffer* getPixelBuffer() const { return pb; } virtual const PixelBuffer* getPixelBuffer() const { return pb; }
virtual void serverCutText(const char* str, int len);

virtual void requestClipboard();
virtual void announceClipboard(bool available);
virtual void sendClipboardData(const char* data);


virtual void approveConnection(network::Socket* sock, bool accept, virtual void approveConnection(network::Socket* sock, bool accept,
const char* reason); const char* reason);
// Event handlers // Event handlers
void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
void pointerEvent(VNCSConnectionST* client, const Point& pos, int buttonMask); void pointerEvent(VNCSConnectionST* client, const Point& pos, int buttonMask);
void clientCutText(const char* str, int len);

void handleClipboardRequest(VNCSConnectionST* client);
void handleClipboardAnnounce(VNCSConnectionST* client, bool available);
void handleClipboardData(VNCSConnectionST* client, const char* data);


unsigned int setDesktopSize(VNCSConnectionST* requester, unsigned int setDesktopSize(VNCSConnectionST* requester,
int fb_width, int fb_height, int fb_width, int fb_height,


std::list<VNCSConnectionST*> clients; std::list<VNCSConnectionST*> clients;
VNCSConnectionST* pointerClient; VNCSConnectionST* pointerClient;
VNCSConnectionST* clipboardClient;
std::list<VNCSConnectionST*> clipboardRequestors;
std::list<network::Socket*> closingSockets; std::list<network::Socket*> closingSockets;


ComparingUpdateTracker* comparer; ComparingUpdateTracker* comparer;

+ 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);
} }

+ 440
- 0
common/rfb/util.cxx View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-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
delete [] s; delete [] s;
} }


void strFree(wchar_t* s) {
delete [] s;
}



bool strSplit(const char* src, const char limiter, char** out1, char** out2, bool fromEnd) { bool strSplit(const char* src, const char limiter, char** out1, char** out2, bool fromEnd) {
CharArray out1old, out2old; CharArray out1old, out2old;
dest[src ? destlen-1 : 0] = 0; dest[src ? destlen-1 : 0] = 0;
} }


char* convertLF(const char* src, size_t bytes)
{
char* buffer;
size_t sz;

char* out;
const char* in;
size_t in_len;

// Always include space for a NULL
sz = 1;

// Compute output size
in = src;
in_len = bytes;
while ((*in != '\0') && (in_len > 0)) {
if (*in != '\r') {
sz++;
in++;
in_len--;
continue;
}

if ((in_len == 0) || (*(in+1) != '\n'))
sz++;

in++;
in_len--;
}

// Alloc
buffer = new char[sz];
memset(buffer, 0, sz);

// And convert
out = buffer;
in = src;
in_len = bytes;
while ((*in != '\0') && (in_len > 0)) {
if (*in != '\r') {
*out++ = *in++;
in_len--;
continue;
}

if ((in_len == 0) || (*(in+1) != '\n'))
*out++ = '\n';

in++;
in_len--;
}

return buffer;
}

char* convertCRLF(const char* src, size_t bytes)
{
char* buffer;
size_t sz;

char* out;
const char* in;
size_t in_len;

// Always include space for a NULL
sz = 1;

// Compute output size
in = src;
in_len = bytes;
while ((*in != '\0') && (in_len > 0)) {
sz++;

if (*in == '\r') {
if ((in_len == 0) || (*(in+1) != '\n'))
sz++;
} else if (*in == '\n') {
if ((in == src) || (*(in-1) != '\r'))
sz++;
}

in++;
in_len--;
}

// Alloc
buffer = new char[sz];
memset(buffer, 0, sz);

// And convert
out = buffer;
in = src;
in_len = bytes;
while ((*in != '\0') && (in_len > 0)) {
if (*in == '\n') {
if ((in == src) || (*(in-1) != '\r'))
*out++ = '\r';
}

*out = *in;

if (*in == '\r') {
if ((in_len == 0) || (*(in+1) != '\n')) {
out++;
*out = '\n';
}
}

out++;
in++;
in_len--;
}

return buffer;
}

size_t ucs4ToUTF8(unsigned src, char* dst) {
if (src < 0x80) {
*dst++ = src;
*dst++ = '\0';
return 1;
} else if (src < 0x800) {
*dst++ = 0xc0 | (src >> 6);
*dst++ = 0x80 | (src & 0x3f);
*dst++ = '\0';
return 2;
} else if (src < 0x10000) {
*dst++ = 0xe0 | (src >> 12);
*dst++ = 0x80 | ((src >> 6) & 0x3f);
*dst++ = 0x80 | (src & 0x3f);
*dst++ = '\0';
return 3;
} else if (src < 0x110000) {
*dst++ = 0xf0 | (src >> 18);
*dst++ = 0x80 | ((src >> 12) & 0x3f);
*dst++ = 0x80 | ((src >> 6) & 0x3f);
*dst++ = 0x80 | (src & 0x3f);
*dst++ = '\0';
return 4;
} else {
return ucs4ToUTF8(0xfffd, dst);
}
}

size_t utf8ToUCS4(const char* src, size_t max, unsigned* dst) {
size_t count, consumed;

*dst = 0xfffd;

if (max == 0)
return 0;

consumed = 1;

if ((*src & 0x80) == 0) {
*dst = *src;
count = 0;
} else if ((*src & 0xe0) == 0xc0) {
*dst = *src & 0x1f;
count = 1;
} else if ((*src & 0xf0) == 0xe0) {
*dst = *src & 0x0f;
count = 2;
} else if ((*src & 0xf8) == 0xf0) {
*dst = *src & 0x07;
count = 3;
} else {
// Invalid sequence, consume all continuation characters
src++;
max--;
while ((max-- > 0) && ((*src++ & 0xc0) == 0x80))
consumed++;
return consumed;
}

src++;
max--;

while (count--) {
// Invalid or truncated sequence?
if ((max == 0) || ((*src & 0xc0) != 0x80)) {
*dst = 0xfffd;
return consumed;
}

*dst <<= 6;
*dst |= *src & 0x3f;

src++;
max--;
}

return consumed;
}

size_t ucs4ToUTF16(unsigned src, wchar_t* dst) {
if ((src < 0xd800) || ((src >= 0xe000) && (src < 0x10000))) {
*dst++ = src;
*dst++ = L'\0';
return 1;
} else if (src < 0x110000) {
*dst++ = 0xd800 | ((src >> 10) & 0x07ff);
*dst++ = 0xdc00 | (src & 0x07ff);
*dst++ = L'\0';
return 2;
} else {
return ucs4ToUTF16(0xfffd, dst);
}
}

size_t utf16ToUCS4(const wchar_t* src, size_t max, unsigned* dst) {
*dst = 0xfffd;

if (max == 0)
return 0;

if ((*src < 0xd800) || (*src >= 0xe000)) {
*dst = *src;
return 1;
}

if (*src & 0x0400) {
size_t consumed;

// Invalid sequence, consume all continuation characters
consumed = 0;
while ((max > 0) && (*src & 0x0400)) {
src++;
max--;
consumed++;
}

return consumed;
}

*dst = *src++;
max--;

// Invalid or truncated sequence?
if ((max == 0) || ((*src & 0xfc00) != 0xdc00)) {
*dst = 0xfffd;
return 1;
}

*dst = 0x10000 | ((*dst & 0x03ff) << 10);
*dst |= *src & 0x3ff;

return 2;
}

char* latin1ToUTF8(const char* src, size_t bytes) {
char* buffer;
size_t sz;

char* out;
const char* in;
size_t in_len;

// Always include space for a NULL
sz = 1;

// Compute output size
in = src;
in_len = bytes;
while ((*in != '\0') && (in_len > 0)) {
char buf[5];
sz += ucs4ToUTF8(*in, buf);
in++;
in_len--;
}

// Alloc
buffer = new char[sz];
memset(buffer, 0, sz);

// And convert
out = buffer;
in = src;
in_len = bytes;
while ((*in != '\0') && (in_len > 0)) {
out += ucs4ToUTF8(*in, out);
in++;
in_len--;
}

return buffer;
}

char* utf8ToLatin1(const char* src, size_t bytes) {
char* buffer;
size_t sz;

char* out;
const char* in;
size_t in_len;

// Always include space for a NULL
sz = 1;

// Compute output size
in = src;
in_len = bytes;
while ((*in != '\0') && (in_len > 0)) {
size_t len;
unsigned ucs;

len = utf8ToUCS4(in, in_len, &ucs);
in += len;
in_len -= len;
sz++;
}

// Alloc
buffer = new char[sz];
memset(buffer, 0, sz);

// And convert
out = buffer;
in = src;
in_len = bytes;
while ((*in != '\0') && (in_len > 0)) {
size_t len;
unsigned ucs;

len = utf8ToUCS4(in, in_len, &ucs);
in += len;
in_len -= len;

if (ucs > 0xff)
*out++ = '?';
else
*out++ = (unsigned char)ucs;
}

return buffer;
}

char* utf16ToUTF8(const wchar_t* src, size_t units)
{
char* buffer;
size_t sz;

char* out;
const wchar_t* in;
size_t in_len;

// Always include space for a NULL
sz = 1;

// Compute output size
in = src;
in_len = units;
while ((*in != '\0') && (in_len > 0)) {
size_t len;
unsigned ucs;
char buf[5];

len = utf16ToUCS4(in, in_len, &ucs);
in += len;
in_len -= len;

sz += ucs4ToUTF8(ucs, buf);
}

// Alloc
buffer = new char[sz];
memset(buffer, 0, sz);

// And convert
out = buffer;
in = src;
in_len = units;
while ((*in != '\0') && (in_len > 0)) {
size_t len;
unsigned ucs;

len = utf16ToUCS4(in, in_len, &ucs);
in += len;
in_len -= len;

out += ucs4ToUTF8(ucs, out);
}

return buffer;
}

wchar_t* utf8ToUTF16(const char* src, size_t bytes)
{
wchar_t* buffer;
size_t sz;

wchar_t* out;
const char* in;
size_t in_len;

// Always include space for a NULL
sz = 1;

// Compute output size
in = src;
in_len = bytes;
while ((*in != '\0') && (in_len > 0)) {
size_t len;
unsigned ucs;
wchar_t buf[3];

len = utf8ToUCS4(in, in_len, &ucs);
in += len;
in_len -= len;

sz += ucs4ToUTF16(ucs, buf);
}

// Alloc
buffer = new wchar_t[sz];
memset(buffer, 0, sz);

// And convert
out = buffer;
in = src;
in_len = bytes;
while ((*in != '\0') && (in_len > 0)) {
size_t len;
unsigned ucs;

len = utf8ToUCS4(in, in_len, &ucs);
in += len;
in_len -= len;

out += ucs4ToUTF16(ucs, out);
}

return buffer;
}

unsigned msBetween(const struct timeval *first, unsigned msBetween(const struct timeval *first,
const struct timeval *second) const struct timeval *second)
{ {

+ 21
- 0
common/rfb/util.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-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


char* strDup(const char* s); char* strDup(const char* s);
void strFree(char* s); void strFree(char* s);
void strFree(wchar_t* s);


// Returns true if split successful. Returns false otherwise. // Returns true if split successful. Returns false otherwise.
// ALWAYS *copies* first part of string to out1 buffer. // ALWAYS *copies* first part of string to out1 buffer.
// Copies src to dest, up to specified length-1, and guarantees termination // Copies src to dest, up to specified length-1, and guarantees termination
void strCopy(char* dest, const char* src, int destlen); void strCopy(char* dest, const char* src, int destlen);


// Makes sure line endings are in a certain format

char* convertLF(const char* src, size_t bytes = (size_t)-1);
char* convertCRLF(const char* src, size_t bytes = (size_t)-1);

// Convertions between various Unicode formats. The returned strings are
// always null terminated and must be freed using strFree().

size_t ucs4ToUTF8(unsigned src, char* dst);
size_t utf8ToUCS4(const char* src, size_t max, unsigned* dst);

size_t ucs4ToUTF16(unsigned src, wchar_t* dst);
size_t utf16ToUCS4(const wchar_t* src, size_t max, unsigned* dst);

char* latin1ToUTF8(const char* src, size_t bytes = (size_t)-1);
char* utf8ToLatin1(const char* src, size_t bytes = (size_t)-1);

char* utf16ToUTF8(const wchar_t* src, size_t units = (size_t)-1);
wchar_t* utf8ToUTF16(const char* src, size_t bytes = (size_t)-1);


// HELPER functions for timeout handling // HELPER functions for timeout handling



+ 2
- 2
tests/decperf.cxx View File

virtual void framebufferUpdateEnd(); virtual void framebufferUpdateEnd();
virtual void setColourMapEntries(int, int, rdr::U16*); virtual void setColourMapEntries(int, int, rdr::U16*);
virtual void bell(); virtual void bell();
virtual void serverCutText(const char*, rdr::U32);
virtual void serverCutText(const char*);


public: public:
double cpuTime; double cpuTime;
{ {
} }


void CConn::serverCutText(const char*, rdr::U32)
void CConn::serverCutText(const char*)
{ {
} }



+ 2
- 2
tests/encperf.cxx View File

virtual void dataRect(const rfb::Rect&, int); virtual void dataRect(const rfb::Rect&, int);
virtual void setColourMapEntries(int, int, rdr::U16*); virtual void setColourMapEntries(int, int, rdr::U16*);
virtual void bell(); virtual void bell();
virtual void serverCutText(const char*, rdr::U32);
virtual void serverCutText(const char*);


public: public:
double decodeTime; double decodeTime;
{ {
} }


void CConn::serverCutText(const char*, rdr::U32)
void CConn::serverCutText(const char*)
{ {
} }



+ 1
- 1
unix/x0vncserver/XDesktop.cxx View File

#endif #endif
} }


void XDesktop::clientCutText(const char* str, int len) {
void XDesktop::clientCutText(const char* str) {
} }


ScreenSet XDesktop::computeScreenLayout() ScreenSet XDesktop::computeScreenLayout()

+ 1
- 1
unix/x0vncserver/XDesktop.h View File

virtual void pointerEvent(const rfb::Point& pos, int buttonMask); virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym); KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down); virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down);
virtual void clientCutText(const char* str, int len);
virtual void clientCutText(const char* str);
virtual unsigned int setScreenLayout(int fb_width, int fb_height, virtual unsigned int setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout); const rfb::ScreenSet& layout);



+ 33
- 1
unix/xserver/hw/vnc/RFBGlue.cc View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-2015 Pierre Ossman for Cendio AB
* Copyright 2011-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
} }
return 0; return 0;
} }

char* vncConvertLF(const char* src, size_t bytes)
{
try {
return convertLF(src, bytes);
} catch (...) {
return NULL;
}
}

char* vncLatin1ToUTF8(const char* src, size_t bytes)
{
try {
return latin1ToUTF8(src, bytes);
} catch (...) {
return NULL;
}
}

char* vncUTF8ToLatin1(const char* src, size_t bytes)
{
try {
return utf8ToLatin1(src, bytes);
} catch (...) {
return NULL;
}
}

void vncStrFree(char* str)
{
strFree(str);
}

+ 8
- 1
unix/xserver/hw/vnc/RFBGlue.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-2015 Pierre Ossman for Cendio AB
* Copyright 2011-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
int vncGetSocketPort(int fd); int vncGetSocketPort(int fd);
int vncIsTCPPortUsed(int port); int vncIsTCPPortUsed(int port);


char* vncConvertLF(const char* src, size_t bytes);

char* vncLatin1ToUTF8(const char* src, size_t bytes);
char* vncUTF8ToLatin1(const char* src, size_t bytes);

void vncStrFree(char* str);

#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

+ 41
- 13
unix/xserver/hw/vnc/XserverDesktop.cc 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
* Copyright 2014 Brian P. Hinz * Copyright 2014 Brian P. Hinz
* *
* This is free software; you can redistribute it and/or modify * This is free software; you can redistribute it and/or modify
queryConnectTimer.start(queryConnectTimeout * 1000); queryConnectTimer.start(queryConnectTimeout * 1000);
} }


void XserverDesktop::bell()
void XserverDesktop::requestClipboard()
{ {
server->bell();
try {
server->requestClipboard();
} catch (rdr::Exception& e) {
vlog.error("XserverDesktop::requestClipboard: %s",e.str());
}
} }


void XserverDesktop::setLEDState(unsigned int state)
void XserverDesktop::announceClipboard(bool available)
{ {
server->setLEDState(state);
try {
server->announceClipboard(available);
} catch (rdr::Exception& e) {
vlog.error("XserverDesktop::announceClipboard: %s",e.str());
}
} }


void XserverDesktop::serverCutText(const char* str, int len)
void XserverDesktop::sendClipboardData(const char* data)
{ {
try { try {
server->serverCutText(str, len);
server->sendClipboardData(data);
} catch (rdr::Exception& e) { } catch (rdr::Exception& e) {
vlog.error("XserverDesktop::serverCutText: %s",e.str());
vlog.error("XserverDesktop::sendClipboardData: %s",e.str());
} }
} }


void XserverDesktop::bell()
{
server->bell();
}

void XserverDesktop::setLEDState(unsigned int state)
{
server->setLEDState(state);
}

void XserverDesktop::setDesktopName(const char* name) void XserverDesktop::setDesktopName(const char* name)
{ {
try { try {
vncPointerButtonAction(buttonMask); vncPointerButtonAction(buttonMask);
} }


void XserverDesktop::clientCutText(const char* str, int len)
{
vncClientCutText(str, len);
}

unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height, unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout) const rfb::ScreenSet& layout)
{ {
return result; return result;
} }


void XserverDesktop::handleClipboardRequest()
{
vncHandleClipboardRequest();
}

void XserverDesktop::handleClipboardAnnounce(bool available)
{
vncHandleClipboardAnnounce(available);
}

void XserverDesktop::handleClipboardData(const char* data_)
{
vncHandleClipboardData(data_);
}

void XserverDesktop::grabRegion(const rfb::Region& region) void XserverDesktop::grabRegion(const rfb::Region& region)
{ {
if (directFbptr) if (directFbptr)

+ 7
- 3
unix/xserver/hw/vnc/XserverDesktop.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2009-2015 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 unblockUpdates(); void unblockUpdates();
void setFramebuffer(int w, int h, void* fbptr, int stride); void setFramebuffer(int w, int h, void* fbptr, int stride);
void refreshScreenLayout(); void refreshScreenLayout();
void requestClipboard();
void announceClipboard(bool available);
void sendClipboardData(const char* data);
void bell(); void bell();
void setLEDState(unsigned int state); void setLEDState(unsigned int state);
void serverCutText(const char* str, int len);
void setDesktopName(const char* name); void setDesktopName(const char* name);
void setCursor(int width, int height, int hotX, int hotY, void setCursor(int width, int height, int hotX, int hotY,
const unsigned char *rgbaData); const unsigned char *rgbaData);
const char* userName); const char* userName);
virtual void pointerEvent(const rfb::Point& pos, int buttonMask); virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
virtual void clientCutText(const char* str, int len);
virtual unsigned int setScreenLayout(int fb_width, int fb_height, virtual unsigned int setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout); const rfb::ScreenSet& layout);
virtual void handleClipboardRequest();
virtual void handleClipboardAnnounce(bool available);
virtual void handleClipboardData(const char* data);


// rfb::PixelBuffer callbacks // rfb::PixelBuffer callbacks
virtual void grabRegion(const rfb::Region& r); virtual void grabRegion(const rfb::Region& r);

+ 15
- 3
unix/xserver/hw/vnc/vncExtInit.cc View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-2015 Pierre Ossman for Cendio AB
* Copyright 2011-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
desktop[scr]->setDesktopName(desktopName); desktop[scr]->setDesktopName(desktopName);
} }


void vncServerCutText(const char *text, size_t len)
void vncRequestClipboard(void)
{ {
for (int scr = 0; scr < vncGetScreenCount(); scr++) for (int scr = 0; scr < vncGetScreenCount(); scr++)
desktop[scr]->serverCutText(text, len);
desktop[scr]->requestClipboard();
}

void vncAnnounceClipboard(int available)
{
for (int scr = 0; scr < vncGetScreenCount(); scr++)
desktop[scr]->announceClipboard(available);
}

void vncSendClipboardData(const char* data)
{
for (int scr = 0; scr < vncGetScreenCount(); scr++)
desktop[scr]->sendClipboardData(data);
} }


int vncConnectClient(const char *addr) int vncConnectClient(const char *addr)

+ 4
- 2
unix/xserver/hw/vnc/vncExtInit.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-2015 Pierre Ossman for Cendio AB
* Copyright 2011-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 vncUpdateDesktopName(void); void vncUpdateDesktopName(void);


void vncServerCutText(const char *text, size_t len);
void vncRequestClipboard(void);
void vncAnnounceClipboard(int available);
void vncSendClipboardData(const char* data);


int vncConnectClient(const char *addr); int vncConnectClient(const char *addr);



+ 229
- 113
unix/xserver/hw/vnc/vncSelection.c View File

/* Copyright 2016 Pierre Ossman for Cendio AB
/* Copyright 2016-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
static WindowPtr pWindow; static WindowPtr pWindow;
static Window wid; static Window wid;


static char* clientCutText;
static int clientCutTextLen;
static Bool probing;
static Atom activeSelection = None;

struct VncDataTarget {
ClientPtr client;
Atom selection;
Atom target;
Atom property;
Window requestor;
CARD32 time;
struct VncDataTarget* next;
};

static struct VncDataTarget* vncDataTargetHead;


static int vncCreateSelectionWindow(void); static int vncCreateSelectionWindow(void);
static int vncOwnSelection(Atom selection); static int vncOwnSelection(Atom selection);
static int vncConvertSelection(ClientPtr client, Atom selection,
Atom target, Atom property,
Window requestor, CARD32 time,
const char* data);
static int vncProcConvertSelection(ClientPtr client); static int vncProcConvertSelection(ClientPtr client);
static void vncSelectionRequest(Atom selection, Atom target);
static int vncProcSendEvent(ClientPtr client); static int vncProcSendEvent(ClientPtr client);
static void vncSelectionCallback(CallbackListPtr *callbacks, static void vncSelectionCallback(CallbackListPtr *callbacks,
void * data, void * args); void * data, void * args);
static void vncClientStateCallback(CallbackListPtr * l,
void * d, void * p);


static int (*origProcConvertSelection)(ClientPtr); static int (*origProcConvertSelection)(ClientPtr);
static int (*origProcSendEvent)(ClientPtr); static int (*origProcSendEvent)(ClientPtr);


if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0)) if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0))
FatalError("Add VNC SelectionCallback failed\n"); FatalError("Add VNC SelectionCallback failed\n");
if (!AddCallback(&ClientStateCallback, vncClientStateCallback, 0))
FatalError("Add VNC ClientStateCallback failed\n");
} }


void vncClientCutText(const char* str, int len)
void vncHandleClipboardRequest(void)
{ {
int rc;

if (clientCutText != NULL)
free(clientCutText);

clientCutText = malloc(len);
if (clientCutText == NULL) {
LOG_ERROR("Could not allocate clipboard buffer");
DeleteWindowFromAnySelections(pWindow);
if (activeSelection == None) {
LOG_DEBUG("Got request for local clipboard although no clipboard is active");
return; return;
} }


memcpy(clientCutText, str, len);
clientCutTextLen = len;
LOG_DEBUG("Got request for local clipboard, re-probing formats");

probing = FALSE;
vncSelectionRequest(activeSelection, xaTARGETS);
}

void vncHandleClipboardAnnounce(int available)
{
if (available) {
int rc;

LOG_DEBUG("Remote clipboard announced, grabbing local ownership");

if (vncGetSetPrimary()) {
rc = vncOwnSelection(xaPRIMARY);
if (rc != Success)
LOG_ERROR("Could not set PRIMARY selection");
}


if (vncGetSetPrimary()) {
rc = vncOwnSelection(xaPRIMARY);
rc = vncOwnSelection(xaCLIPBOARD);
if (rc != Success) if (rc != Success)
LOG_ERROR("Could not set PRIMARY selection");
LOG_ERROR("Could not set CLIPBOARD selection");
} else {
struct VncDataTarget* next;

if (pWindow == NULL)
return;

LOG_DEBUG("Remote clipboard lost, removing local ownership");

DeleteWindowFromAnySelections(pWindow);

/* Abort any pending transfer */
while (vncDataTargetHead != NULL) {
xEvent event;

event.u.u.type = SelectionNotify;
event.u.selectionNotify.time = vncDataTargetHead->time;
event.u.selectionNotify.requestor = vncDataTargetHead->requestor;
event.u.selectionNotify.selection = vncDataTargetHead->selection;
event.u.selectionNotify.target = vncDataTargetHead->target;
event.u.selectionNotify.property = None;
WriteEventsToClient(vncDataTargetHead->client, 1, &event);

next = vncDataTargetHead->next;
free(vncDataTargetHead);
vncDataTargetHead = next;
}
} }
}


rc = vncOwnSelection(xaCLIPBOARD);
if (rc != Success)
LOG_ERROR("Could not set CLIPBOARD selection");
void vncHandleClipboardData(const char* data)
{
struct VncDataTarget* next;

LOG_DEBUG("Got remote clipboard data, sending to X11 clients");

while (vncDataTargetHead != NULL) {
int rc;
xEvent event;

rc = vncConvertSelection(vncDataTargetHead->client,
vncDataTargetHead->selection,
vncDataTargetHead->target,
vncDataTargetHead->property,
vncDataTargetHead->requestor,
vncDataTargetHead->time,
data);
if (rc != Success) {
event.u.u.type = SelectionNotify;
event.u.selectionNotify.time = vncDataTargetHead->time;
event.u.selectionNotify.requestor = vncDataTargetHead->requestor;
event.u.selectionNotify.selection = vncDataTargetHead->selection;
event.u.selectionNotify.target = vncDataTargetHead->target;
event.u.selectionNotify.property = None;
WriteEventsToClient(vncDataTargetHead->client, 1, &event);
}

next = vncDataTargetHead->next;
free(vncDataTargetHead);
vncDataTargetHead = next;
}
} }


static int vncCreateSelectionWindow(void) static int vncCreateSelectionWindow(void)


static int vncConvertSelection(ClientPtr client, Atom selection, static int vncConvertSelection(ClientPtr client, Atom selection,
Atom target, Atom property, Atom target, Atom property,
Window requestor, CARD32 time)
Window requestor, CARD32 time,
const char* data)
{ {
Selection *pSel; Selection *pSel;
WindowPtr pWin; WindowPtr pWin;


xEvent event; xEvent event;


LOG_DEBUG("Selection request for %s (type %s)",
NameForAtom(selection), NameForAtom(target));
if (data == NULL) {
LOG_DEBUG("Selection request for %s (type %s)",
NameForAtom(selection), NameForAtom(target));
} else {
LOG_DEBUG("Sending data for selection request for %s (type %s)",
NameForAtom(selection), NameForAtom(target));
}


rc = dixLookupSelection(&pSel, selection, client, DixGetAttrAccess); rc = dixLookupSelection(&pSel, selection, client, DixGetAttrAccess);
if (rc != Success) if (rc != Success)
TRUE); TRUE);
if (rc != Success) if (rc != Success)
return rc; return rc;
} else if ((target == xaSTRING) || (target == xaTEXT)) {
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
XA_STRING, 8, PropModeReplace,
clientCutTextLen, clientCutText,
TRUE);
if (rc != Success)
return rc;
} else if (target == xaUTF8_STRING) {
unsigned char* buffer;
unsigned char* out;
size_t len;

const unsigned char* in;
size_t in_len;

buffer = malloc(clientCutTextLen*2);
if (buffer == NULL)
return BadAlloc;

out = buffer;
len = 0;
in = clientCutText;
in_len = clientCutTextLen;
while (in_len > 0) {
if (*in & 0x80) {
*out++ = 0xc0 | (*in >> 6);
*out++ = 0x80 | (*in & 0x3f);
len += 2;
in++;
in_len--;
} else {
if (data == NULL) {
struct VncDataTarget* vdt;

if ((target != xaSTRING) && (target != xaTEXT) &&
(target != xaUTF8_STRING))
return BadMatch;

vdt = calloc(1, sizeof(struct VncDataTarget));
if (vdt == NULL)
return BadAlloc;

vdt->client = client;
vdt->selection = selection;
vdt->target = target;
vdt->property = property;
vdt->requestor = requestor;
vdt->time = time;

vdt->next = vncDataTargetHead;
vncDataTargetHead = vdt;

LOG_DEBUG("Requesting clipboard data from client");

vncRequestClipboard();

return Success;
} else {
if ((target == xaSTRING) || (target == xaTEXT)) {
char* latin1;

latin1 = vncUTF8ToLatin1(data, (size_t)-1);
if (latin1 == NULL)
return BadAlloc;

rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
XA_STRING, 8, PropModeReplace,
strlen(latin1), latin1, TRUE);

vncStrFree(latin1);

if (rc != Success)
return rc;
} else if (target == xaUTF8_STRING) {
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
xaUTF8_STRING, 8, PropModeReplace,
strlen(data), data, TRUE);
if (rc != Success)
return rc;
} else { } else {
*out++ = *in++;
len++;
in_len--;
return BadMatch;
} }
} }

rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
xaUTF8_STRING, 8, PropModeReplace,
len, buffer, TRUE);
free(buffer);
if (rc != Success)
return rc;
} else {
return BadMatch;
} }


event.u.u.type = SelectionNotify; event.u.u.type = SelectionNotify;
pSel->window == wid) { pSel->window == wid) {
rc = vncConvertSelection(client, stuff->selection, rc = vncConvertSelection(client, stuff->selection,
stuff->target, stuff->property, stuff->target, stuff->property,
stuff->requestor, stuff->time);
stuff->requestor, stuff->time, NULL);
if (rc != Success) { if (rc != Success) {
xEvent event; xEvent event;


if (prop->type != XA_ATOM) if (prop->type != XA_ATOM)
return; return;


if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size))
vncSelectionRequest(selection, xaSTRING);
else if (vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size))
vncSelectionRequest(selection, xaUTF8_STRING);
if (probing) {
if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size) ||
vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size)) {
LOG_DEBUG("Compatible format found, notifying clients");
activeSelection = selection;
vncAnnounceClipboard(TRUE);
}
} else {
if (vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size))
vncSelectionRequest(selection, xaUTF8_STRING);
else if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size))
vncSelectionRequest(selection, xaSTRING);
}
} else if (target == xaSTRING) { } else if (target == xaSTRING) {
char* filtered;
char* utf8;

if (prop->format != 8) if (prop->format != 8)
return; return;
if (prop->type != xaSTRING) if (prop->type != xaSTRING)
return; return;


vncServerCutText(prop->data, prop->size);
} else if (target == xaUTF8_STRING) {
unsigned char* buffer;
unsigned char* out;
size_t len;
filtered = vncConvertLF(prop->data, prop->size);
if (filtered == NULL)
return;

utf8 = vncLatin1ToUTF8(filtered, (size_t)-1);
vncStrFree(filtered);
if (utf8 == NULL)
return;

LOG_DEBUG("Sending clipboard to clients (%d bytes)",
(int)strlen(utf8));


const unsigned char* in;
size_t in_len;
vncSendClipboardData(utf8);

vncStrFree(utf8);
} else if (target == xaUTF8_STRING) {
char *filtered;


if (prop->format != 8) if (prop->format != 8)
return; return;
if (prop->type != xaUTF8_STRING) if (prop->type != xaUTF8_STRING)
return; return;


buffer = malloc(prop->size);
if (buffer == NULL)
filtered = vncConvertLF(prop->data, prop->size);
if (filtered == NULL)
return; return;


out = buffer;
len = 0;
in = prop->data;
in_len = prop->size;
while (in_len > 0) {
if ((*in & 0x80) == 0x00) {
*out++ = *in++;
len++;
in_len--;
} else if ((*in & 0xe0) == 0xc0) {
unsigned ucs;
ucs = (*in++ & 0x1f) << 6;
in_len--;
if (in_len > 0) {
ucs |= (*in++ & 0x3f);
in_len--;
}
if (ucs <= 0xff)
*out++ = ucs;
else
*out++ = '?';
len++;
} else {
*out++ = '?';
len++;
do {
in++;
in_len--;
} while ((in_len > 0) && ((*in & 0xc0) == 0x80));
}
}
LOG_DEBUG("Sending clipboard to clients (%d bytes)",
(int)strlen(filtered));


vncServerCutText((const char*)buffer, len);
vncSendClipboardData(filtered);


free(buffer);
vncStrFree(filtered);
} }
} }


{ {
SelectionInfoRec *info = (SelectionInfoRec *) args; SelectionInfoRec *info = (SelectionInfoRec *) args;


if (info->selection->selection == activeSelection) {
LOG_DEBUG("Local clipboard lost, notifying clients");
activeSelection = None;
vncAnnounceClipboard(FALSE);
}

if (info->kind != SelectionSetOwner) if (info->kind != SelectionSetOwner)
return; return;
if (info->client == serverClient) if (info->client == serverClient)
!vncGetSendPrimary()) !vncGetSendPrimary())
return; return;


LOG_DEBUG("Got clipboard notification, probing for formats");

probing = TRUE;
vncSelectionRequest(info->selection->selection, xaTARGETS); vncSelectionRequest(info->selection->selection, xaTARGETS);
} }

static void vncClientStateCallback(CallbackListPtr * l,
void * d, void * p)
{
ClientPtr client = ((NewClientInfoRec*)p)->client;
if (client->clientState == ClientStateGone) {
struct VncDataTarget** nextPtr = &vncDataTargetHead;
for (struct VncDataTarget* cur = vncDataTargetHead; cur; cur = *nextPtr) {
if (cur->client == client) {
*nextPtr = cur->next;
free(cur);
continue;
}
nextPtr = &cur->next;
}
}
}

+ 4
- 2
unix/xserver/hw/vnc/vncSelection.h View File

/* Copyright 2016 Pierre Ossman for Cendio AB
/* Copyright 2016-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 vncSelectionInit(void); void vncSelectionInit(void);


void vncClientCutText(const char* str, int len);
void vncHandleClipboardRequest(void);
void vncHandleClipboardAnnounce(int available);
void vncHandleClipboardData(const char* data);


#ifdef __cplusplus #ifdef __cplusplus
} }

+ 15
- 5
vncviewer/CConn.cxx View File

fl_beep(); fl_beep();
} }


void CConn::serverCutText(const char* str, rdr::U32 len)
{
desktop->serverCutText(str, len);
}

void CConn::dataRect(const Rect& r, int encoding) void CConn::dataRect(const Rect& r, int encoding)
{ {
sock->inStream().startTiming(); sock->inStream().startTiming();
desktop->setLEDState(state); desktop->setLEDState(state);
} }


void CConn::handleClipboardRequest()
{
desktop->handleClipboardRequest();
}

void CConn::handleClipboardAnnounce(bool available)
{
desktop->handleClipboardAnnounce(available);
}

void CConn::handleClipboardData(const char* data)
{
desktop->handleClipboardData(data);
}



////////////////////// Internal methods ////////////////////// ////////////////////// Internal methods //////////////////////



+ 4
- 2
vncviewer/CConn.h View File



void bell(); void bell();


void serverCutText(const char* str, rdr::U32 len);

void framebufferUpdateStart(); void framebufferUpdateStart();
void framebufferUpdateEnd(); void framebufferUpdateEnd();
void dataRect(const rfb::Rect& r, int encoding); void dataRect(const rfb::Rect& r, int encoding);


void setLEDState(unsigned int state); void setLEDState(unsigned int state);


virtual void handleClipboardRequest();
virtual void handleClipboardAnnounce(bool available);
virtual void handleClipboardData(const char* data);

private: private:


void resizeFramebuffer(); void resizeFramebuffer();

+ 16
- 6
vncviewer/DesktopWindow.cxx View File

} }




void DesktopWindow::serverCutText(const char* str, rdr::U32 len)
{
viewport->serverCutText(str, len);
}


void DesktopWindow::setCursor(int width, int height, void DesktopWindow::setCursor(int width, int height,
const rfb::Point& hotspot, const rfb::Point& hotspot,
const rdr::U8* data) const rdr::U8* data)
} }




void DesktopWindow::handleClipboardRequest()
{
viewport->handleClipboardRequest();
}

void DesktopWindow::handleClipboardAnnounce(bool available)
{
viewport->handleClipboardAnnounce(available);
}

void DesktopWindow::handleClipboardData(const char* data)
{
viewport->handleClipboardData(data);
}


void DesktopWindow::resize(int x, int y, int w, int h) void DesktopWindow::resize(int x, int y, int w, int h)
{ {
bool resizing; bool resizing;

+ 5
- 3
vncviewer/DesktopWindow.h View File

// Resize the current framebuffer, but retain the contents // Resize the current framebuffer, but retain the contents
void resizeFramebuffer(int new_w, int new_h); void resizeFramebuffer(int new_w, int new_h);


// Incoming clipboard from server
void serverCutText(const char* str, rdr::U32 len);

// New image for the locally rendered cursor // New image for the locally rendered cursor
void setCursor(int width, int height, const rfb::Point& hotspot, void setCursor(int width, int height, const rfb::Point& hotspot,
const rdr::U8* data); const rdr::U8* data);
// Change client LED state // Change client LED state
void setLEDState(unsigned int state); void setLEDState(unsigned int state);


// Clipboard events
void handleClipboardRequest();
void handleClipboardAnnounce(bool available);
void handleClipboardData(const char* data);

// Fl_Window callback methods // Fl_Window callback methods
virtual void show(); virtual void show();
virtual void draw(); virtual void draw();

+ 82
- 81
vncviewer/Viewport.cxx View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-2014 Pierre Ossman for Cendio AB
* Copyright 2011-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
altGrArmed(false), altGrArmed(false),
#endif #endif
firstLEDState(true), firstLEDState(true),
pendingServerCutText(NULL), pendingClientCutText(NULL),
pendingServerClipboard(false), pendingClientClipboard(false),
menuCtrlKey(false), menuAltKey(false), cursor(NULL) menuCtrlKey(false), menuAltKey(false), cursor(NULL)
{ {
#if !defined(WIN32) && !defined(__APPLE__) #if !defined(WIN32) && !defined(__APPLE__)
delete cursor; delete cursor;
} }


clearPendingClipboard();

// FLTK automatically deletes all child widgets, so we shouldn't touch // FLTK automatically deletes all child widgets, so we shouldn't touch
// them ourselves here // them ourselves here
} }
damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height()); damage(FL_DAMAGE_USER1, r.tl.x + x(), r.tl.y + y(), r.width(), r.height());
} }


void Viewport::serverCutText(const char* str, rdr::U32 len)
{
char *buffer;
int size, ret;

clearPendingClipboard();

if (!acceptClipboard)
return;

size = fl_utf8froma(NULL, 0, str, len);
if (size <= 0)
return;

size++;

buffer = new char[size];

ret = fl_utf8froma(buffer, size, str, len);
assert(ret < size);

vlog.debug("Got clipboard data (%d bytes)", (int)strlen(buffer));

if (!hasFocus()) {
pendingServerCutText = buffer;
return;
}

// RFB doesn't have separate selection and clipboard concepts, so we
// dump the data into both variants.
#if !defined(WIN32) && !defined(__APPLE__)
if (setPrimary)
Fl::copy(buffer, ret, 0);
#endif
Fl::copy(buffer, ret, 1);

delete [] buffer;
}

static const char * dotcursor_xpm[] = { static const char * dotcursor_xpm[] = {
"5 5 2 1", "5 5 2 1",
". c #000000", ". c #000000",
window()->cursor(cursor, cursorHotspot.x, cursorHotspot.y); window()->cursor(cursor, cursorHotspot.x, cursorHotspot.y);
} }


void Viewport::handleClipboardRequest()
{
Fl::paste(*this, clipboardSource);
}

void Viewport::handleClipboardAnnounce(bool available)
{
if (!acceptClipboard)
return;

if (available)
vlog.debug("Got notification of new clipboard on server");
else
vlog.debug("Clipboard is no longer available on server");

if (!available) {
pendingServerClipboard = false;
return;
}

pendingClientClipboard = false;

if (!hasFocus()) {
pendingServerClipboard = true;
return;
}

cc->requestClipboard();
}

void Viewport::handleClipboardData(const char* data)
{
size_t len;

if (!hasFocus())
return;

len = strlen(data);

vlog.debug("Got clipboard data (%d bytes)", (int)len);

// RFB doesn't have separate selection and clipboard concepts, so we
// dump the data into both variants.
#if !defined(WIN32) && !defined(__APPLE__)
if (setPrimary)
Fl::copy(data, len, 0);
#endif
Fl::copy(data, len, 1);
}


void Viewport::setLEDState(unsigned int state) void Viewport::setLEDState(unsigned int state)
{ {


int Viewport::handle(int event) int Viewport::handle(int event)
{ {
char *buffer;
int ret;
char *filtered;
int buttonMask, wheelMask; int buttonMask, wheelMask;
DownMap::const_iterator iter; DownMap::const_iterator iter;


switch (event) { switch (event) {
case FL_PASTE: case FL_PASTE:
buffer = new char[Fl::event_length() + 1];

clearPendingClipboard();

// This is documented as to ASCII, but actually does to 8859-1
ret = fl_utf8toa(Fl::event_text(), Fl::event_length(), buffer,
Fl::event_length() + 1);
assert(ret < (Fl::event_length() + 1));
filtered = convertLF(Fl::event_text(), Fl::event_length());


if (!hasFocus()) {
pendingClientCutText = buffer;
return 1;
}

vlog.debug("Sending clipboard data (%d bytes)", (int)strlen(buffer));
vlog.debug("Sending clipboard data (%d bytes)", (int)strlen(filtered));


try { try {
cc->writer()->writeClientCutText(buffer, ret);
cc->sendClipboardData(filtered);
} catch (rdr::Exception& e) { } catch (rdr::Exception& e) {
vlog.error("%s", e.str()); vlog.error("%s", e.str());
exit_vncviewer(e.str()); exit_vncviewer(e.str());
} }


delete [] buffer;
strFree(filtered);


return 1; return 1;


return; return;
#endif #endif


Fl::paste(*self, source);
}
self->clipboardSource = source;


self->pendingServerClipboard = false;


void Viewport::clearPendingClipboard()
{
delete [] pendingServerCutText;
pendingServerCutText = NULL;
delete [] pendingClientCutText;
pendingClientCutText = NULL;
if (!self->hasFocus()) {
self->pendingClientClipboard = true;
// Clear any older client clipboard from the server
self->cc->announceClipboard(false);
return;
}

try {
self->cc->announceClipboard(true);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(e.str());
}
} }




void Viewport::flushPendingClipboard() void Viewport::flushPendingClipboard()
{ {
if (pendingServerCutText) {
size_t len = strlen(pendingServerCutText);
#if !defined(WIN32) && !defined(__APPLE__)
if (setPrimary)
Fl::copy(pendingServerCutText, len, 0);
#endif
Fl::copy(pendingServerCutText, len, 1);
if (pendingServerClipboard) {
try {
cc->requestClipboard();
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
exit_vncviewer(e.str());
}
} }
if (pendingClientCutText) {
size_t len = strlen(pendingClientCutText);
vlog.debug("Sending pending clipboard data (%d bytes)", (int)len);
if (pendingClientClipboard) {
try { try {
cc->writer()->writeClientCutText(pendingClientCutText, len);
cc->announceClipboard(true);
} catch (rdr::Exception& e) { } catch (rdr::Exception& e) {
vlog.error("%s", e.str()); vlog.error("%s", e.str());
exit_vncviewer(e.str()); exit_vncviewer(e.str());
} }
} }


clearPendingClipboard();
pendingServerClipboard = false;
pendingClientClipboard = false;
} }





+ 10
- 7
vncviewer/Viewport.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright 2011-2019 Pierre Ossman <ossman@cendio.se> 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
// Flush updates to screen // Flush updates to screen
void updateWindow(); void updateWindow();


// Incoming clipboard from server
void serverCutText(const char* str, rdr::U32 len);

// New image for the locally rendered cursor // New image for the locally rendered cursor
void setCursor(int width, int height, const rfb::Point& hotspot, void setCursor(int width, int height, const rfb::Point& hotspot,
const rdr::U8* data); const rdr::U8* data);


void draw(Surface* dst); void draw(Surface* dst);


// Clipboard events
void handleClipboardRequest();
void handleClipboardAnnounce(bool available);
void handleClipboardData(const char* data);

// Fl_Widget callback methods // Fl_Widget callback methods


void draw(); void draw();


static void handleClipboardChange(int source, void *data); static void handleClipboardChange(int source, void *data);


void clearPendingClipboard();
void flushPendingClipboard(); void flushPendingClipboard();


void handlePointerEvent(const rfb::Point& pos, int buttonMask); void handlePointerEvent(const rfb::Point& pos, int buttonMask);


bool firstLEDState; bool firstLEDState;


const char* pendingServerCutText;
const char* pendingClientCutText;
bool pendingServerClipboard;
bool pendingClientClipboard;

int clipboardSource;


rdr::U32 menuKeySym; rdr::U32 menuKeySym;
int menuKeyCode, menuKeyFLTK; int menuKeyCode, menuKeyFLTK;

+ 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.
. .

+ 49
- 84
win/rfb_win32/Clipboard.cxx View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2012-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


static LogWriter vlog("Clipboard"); static LogWriter vlog("Clipboard");



//
// -=- CR/LF handlers
//

char*
dos2unix(const char* text) {
int len = strlen(text)+1;
char* unix = new char[strlen(text)+1];
int i, j=0;
for (i=0; i<len; i++) {
if (text[i] != '\x0d')
unix[j++] = text[i];
}
return unix;
}

char*
unix2dos(const char* text) {
int len = strlen(text)+1;
char* dos = new char[strlen(text)*2+1];
int i, j=0;
for (i=0; i<len; i++) {
if (text[i] == '\x0a')
dos[j++] = '\x0d';
dos[j++] = text[i];
}
return dos;
}


//
// -=- ISO-8859-1 (Latin 1) filter (in-place)
//

void
removeNonISOLatin1Chars(char* text) {
int len = strlen(text);
int i=0, j=0;
for (; i<len; i++) {
if (((text[i] >= 1) && (text[i] <= 127)) ||
((text[i] >= 160) && (text[i] <= 255)))
text[j++] = text[i];
}
text[j] = 0;
}

// //
// -=- Clipboard object // -=- Clipboard object
// //
} else { } else {
vlog.debug("local clipboard changed by %p", owner); vlog.debug("local clipboard changed by %p", owner);


// Open the clipboard
if (OpenClipboard(getHandle())) {
// Get the clipboard data
HGLOBAL cliphandle = GetClipboardData(CF_TEXT);
if (cliphandle) {
char* clipdata = (char*) GlobalLock(cliphandle);

// Notify clients
if (notifier) {
if (!clipdata) {
notifier->notifyClipboardChanged(0, 0);
} else {
CharArray unix_text;
unix_text.buf = dos2unix(clipdata);
removeNonISOLatin1Chars(unix_text.buf);
notifier->notifyClipboardChanged(unix_text.buf, strlen(unix_text.buf));
}
} else {
vlog.debug("no clipboard notifier registered");
}

// Release the buffer and close the clipboard
GlobalUnlock(cliphandle);
}

CloseClipboard();
}
if (notifier == NULL)
vlog.debug("no clipboard notifier registered");
else
notifier->notifyClipboardChanged(IsClipboardFormatAvailable(CF_UNICODETEXT));
} }
} }
if (next_window) if (next_window)
return MsgWindow::processMessage(msg, wParam, lParam); return MsgWindow::processMessage(msg, wParam, lParam);
}; };


char*
Clipboard::getClipText() {
HGLOBAL cliphandle;
wchar_t* clipdata;
CharArray utf8;

// Open the clipboard
if (!OpenClipboard(getHandle()))
return NULL;

// Get the clipboard data
cliphandle = GetClipboardData(CF_UNICODETEXT);
if (!cliphandle) {
CloseClipboard();
return NULL;
}

clipdata = (wchar_t*) GlobalLock(cliphandle);
if (!clipdata) {
CloseClipboard();
return NULL;
}

// Convert it to UTF-8
utf8.replaceBuf(utf16ToUTF8(clipdata));

// Release the buffer and close the clipboard
GlobalUnlock(cliphandle);
CloseClipboard();

return convertLF(utf8.buf);
}

void void
Clipboard::setClipText(const char* text) { Clipboard::setClipText(const char* text) {
HANDLE clip_handle = 0; HANDLE clip_handle = 0;
if (!OpenClipboard(getHandle())) if (!OpenClipboard(getHandle()))
throw rdr::SystemException("unable to open Win32 clipboard", GetLastError()); throw rdr::SystemException("unable to open Win32 clipboard", GetLastError());


// - Pre-process the supplied clipboard text into DOS format
CharArray dos_text;
dos_text.buf = unix2dos(text);
removeNonISOLatin1Chars(dos_text.buf);
int dos_text_len = strlen(dos_text.buf);
// - Convert the supplied clipboard text into UTF-16 format with CRLF
CharArray filtered(convertCRLF(text));
wchar_t* utf16;
utf16 = utf8ToUTF16(filtered.buf);


// - Allocate global memory for the data // - Allocate global memory for the data
clip_handle = ::GlobalAlloc(GMEM_MOVEABLE, dos_text_len+1);
clip_handle = ::GlobalAlloc(GMEM_MOVEABLE, (wcslen(utf16) + 1) * 2);


char* data = (char*) GlobalLock(clip_handle);
memcpy(data, dos_text.buf, dos_text_len+1);
data[dos_text_len] = 0;
wchar_t* data = (wchar_t*) GlobalLock(clip_handle);
wcscpy(data, utf16);
GlobalUnlock(clip_handle); GlobalUnlock(clip_handle);


strFree(utf16);

// - Next, we must clear out any existing data // - Next, we must clear out any existing data
if (!EmptyClipboard()) if (!EmptyClipboard())
throw rdr::SystemException("unable to empty Win32 clipboard", GetLastError()); throw rdr::SystemException("unable to empty Win32 clipboard", GetLastError());


// - Set the new clipboard data // - Set the new clipboard data
if (!SetClipboardData(CF_TEXT, clip_handle))
if (!SetClipboardData(CF_UNICODETEXT, clip_handle))
throw rdr::SystemException("unable to set Win32 clipboard", GetLastError()); throw rdr::SystemException("unable to set Win32 clipboard", GetLastError());
clip_handle = 0; clip_handle = 0;



+ 5
- 1
win/rfb_win32/Clipboard.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2016-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
// -=- Abstract base class for callback recipients // -=- Abstract base class for callback recipients
class Notifier { class Notifier {
public: public:
virtual void notifyClipboardChanged(const char* text, int len) = 0;
virtual void notifyClipboardChanged(bool available) = 0;
virtual ~Notifier() {}; virtual ~Notifier() {};
}; };


// - Set the notifier to use // - Set the notifier to use
void setNotifier(Notifier* cbn) {notifier = cbn;} void setNotifier(Notifier* cbn) {notifier = cbn;}


// - Get the clipboard contents
char* getClipText();

// - Set the clipboard contents // - Set the clipboard contents
void setClipText(const char* text); void setClipText(const char* text);



+ 19
- 9
win/rfb_win32/SDisplay.cxx View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-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 SDisplay::handleClipboardRequest() {
CharArray data(clipboard->getClipText());
server->sendClipboardData(data.buf);
}

void SDisplay::handleClipboardAnnounce(bool available) {
// FIXME: Wait for an application to actually request it
if (available)
server->requestClipboard();
}

void SDisplay::handleClipboardData(const char* data) {
clipboard->setClipText(data);
}


void SDisplay::pointerEvent(const Point& pos, int buttonmask) { void SDisplay::pointerEvent(const Point& pos, int buttonmask) {
if (pb->getRect().contains(pos)) { if (pb->getRect().contains(pos)) {
Point screenPos = pos.translate(screenRect.tl); Point screenPos = pos.translate(screenRect.tl);
return false; return false;
} }


void SDisplay::clientCutText(const char* text, int len) {
CharArray clip_sz(len+1);
memcpy(clip_sz.buf, text, len);
clip_sz.buf[len] = 0;
clipboard->setClipText(clip_sz.buf);
}



void void
SDisplay::notifyClipboardChanged(const char* text, int len) {
SDisplay::notifyClipboardChanged(bool available) {
vlog.debug("clipboard text changed"); vlog.debug("clipboard text changed");
if (server) if (server)
server->serverCutText(text, len);
server->announceClipboard(available);
} }





+ 6
- 3
win/rfb_win32/SDisplay.h View File

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-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
virtual void terminate(); virtual void terminate();
virtual void queryConnection(network::Socket* sock, virtual void queryConnection(network::Socket* sock,
const char* userName); const char* userName);
virtual void handleClipboardRequest();
virtual void handleClipboardAnnounce(bool available);
virtual void handleClipboardData(const char* data);
virtual void pointerEvent(const Point& pos, int buttonmask); virtual void pointerEvent(const Point& pos, int buttonmask);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down); virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
virtual void clientCutText(const char* str, int len);


// -=- Clipboard
// -=- Clipboard events
virtual void notifyClipboardChanged(const char* text, int len);
virtual void notifyClipboardChanged(bool available);


// -=- Display events // -=- Display events

Loading…
Cancel
Save