/* 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); |
/* 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 |
/* 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) | |||||
{ | |||||
} |
/* 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; | ||||
}; | }; | ||||
} | } |
/* 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() |
/* 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(); | ||||
/* 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); |
/* 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); |
/* 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)) |
/* 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 |
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) { } | |||||
}; | }; | ||||
} | } |
/* 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; |
/* 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 |
/* 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() {} | ||||
}; | }; |
/* 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() | ||||
{ | { | ||||
} | } |
/* 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. | ||||
/* 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() |
/* 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(); |
/* 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)) |
/* 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[]); |
/* 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++]; | |||||
} | |||||
} |
/* 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 |
/* 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 { |
/* 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(); |
/* 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; |
/* 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, |
/* 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; |
/* Copyright 2019 Pierre Ossman for Cendio AB | |||||
* | |||||
* This is free software; you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation; either version 2 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* This software is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with this software; if not, write to the Free Software | |||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||||
* USA. | |||||
*/ | |||||
#ifndef __RFB_CLIPBOARDTYPES_H__ | |||||
#define __RFB_CLIPBOARDTYPES_H__ | |||||
namespace rfb { | |||||
// Formats | |||||
const unsigned int clipboardUTF8 = 1 << 0; | |||||
const unsigned int clipboardRTF = 1 << 1; | |||||
const unsigned int clipboardHTML = 1 << 2; | |||||
const unsigned int clipboardDIB = 1 << 3; | |||||
const unsigned int clipboardFiles = 1 << 4; | |||||
const unsigned int clipboardFormatMask = 0x0000ffff; | |||||
// Actions | |||||
const unsigned int clipboardCaps = 1 << 24; | |||||
const unsigned int clipboardRequest = 1 << 25; | |||||
const unsigned int clipboardPeek = 1 << 26; | |||||
const unsigned int clipboardNotify = 1 << 27; | |||||
const unsigned int clipboardProvide = 1 << 28; | |||||
const unsigned int clipboardActionMask = 0xff000000; | |||||
} | |||||
#endif |
const int pseudoEncodingVMwareCursor = 0x574d5664; | const int 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); | ||||
} | } |
/* 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) | ||||
{ | { |
/* 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 | ||||
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*) | |||||
{ | { | ||||
} | } | ||||
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*) | |||||
{ | { | ||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
void XDesktop::clientCutText(const char* str, int len) { | |||||
void XDesktop::clientCutText(const char* str) { | |||||
} | } | ||||
ScreenSet XDesktop::computeScreenLayout() | ScreenSet XDesktop::computeScreenLayout() |
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); | ||||
/* 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); | |||||
} |
/* 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 |
/* 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) |
/* 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); |
/* 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) |
/* 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); | ||||
/* 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; | |||||
} | |||||
} | |||||
} |
/* 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 | ||||
} | } |
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 ////////////////////// | ||||
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(); |
} | } | ||||
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; |
// 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(); |
/* 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; | |||||
} | } | ||||
/* 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; |
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. | ||||
. | . |
/* 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; | ||||
/* 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); | ||||
/* 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); | |||||
} | } | ||||
/* 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 | ||||