diff --git a/README.md b/README.md
index a618547..65d84f4 100644
--- a/README.md
+++ b/README.md
@@ -42,9 +42,9 @@ Future Goals:
#### Debian-based
```sh
-wget -qO- https://github.com/kasmtech/KasmVNC/releases/download/v0.9.2-beta/kasmvncserver_ubuntu_bionic_0.9.2_amd64.deb
+wget https://github.com/kasmtech/KasmVNC/releases/download/v0.9.2-beta/kasmvncserver_ubuntu_bionic_0.9.2_amd64.deb
-sudo dpkg -i kasmvncserver_0.9.1~beta-1_amd64.deb
+sudo dpkg -i kasmvncserver_*.deb
sudo apt-get -f install
# We provide an example script to run KasmVNC at #
diff --git a/common/network/websocket.c b/common/network/websocket.c
index 47ac11d..6270b49 100644
--- a/common/network/websocket.c
+++ b/common/network/websocket.c
@@ -111,7 +111,7 @@ static const char *parse_get(const char * const in, const char * const opt, unsi
return "";
}
-static void percent_decode(const char *src, char *dst) {
+static void percent_decode(const char *src, char *dst, const uint8_t filter) {
while (1) {
if (!*src)
break;
@@ -127,7 +127,32 @@ static void percent_decode(const char *src, char *dst) {
hex[2] = '\0';
src += 2;
- *dst++ = strtol(hex, NULL, 16);
+ *dst = strtol(hex, NULL, 16);
+
+ if (filter) {
+ // Avoid directory traversal
+ if (*dst == '/')
+ *dst = '_';
+ }
+
+ dst++;
+ }
+ }
+
+ *dst = '\0';
+}
+
+static void percent_encode(const char *src, char *dst) {
+ while (1) {
+ if (!*src)
+ break;
+ if (isalnum(*src) || *src == '.' || *src == ',') {
+ *dst++ = *src++;
+ } else {
+ *dst++ = '%';
+ sprintf(dst, "%02X", *src);
+ dst += 2;
+ src++;
}
}
@@ -746,6 +771,7 @@ def:
static void dirlisting(ws_ctx_t *ws_ctx, const char fullpath[], const char path[]) {
char buf[4096];
+ char enc[PATH_MAX * 3 + 1];
unsigned i;
// Redirect?
@@ -779,11 +805,13 @@ static void dirlisting(ws_ctx_t *ws_ctx, const char fullpath[], const char path[
if (!strcmp(names[i]->d_name, ".") || !strcmp(names[i]->d_name, ".."))
continue;
+ percent_encode(names[i]->d_name, enc);
+
if (names[i]->d_type == DT_DIR)
- sprintf(buf, "
%s/", names[i]->d_name,
+ sprintf(buf, "%s/", enc,
names[i]->d_name);
else
- sprintf(buf, "%s", names[i]->d_name,
+ sprintf(buf, "%s", enc,
names[i]->d_name);
ws_send(ws_ctx, buf, strlen(buf));
@@ -822,13 +850,15 @@ static void servefile(ws_ctx_t *ws_ctx, const char *in) {
len = strlen(path);
}
- wserr("Requested file '%s'\n", path);
- sprintf(fullpath, "%s/%s", settings.httpdir, path);
+ percent_decode(path, buf, 1);
+
+ wserr("Requested file '%s'\n", buf);
+ sprintf(fullpath, "%s/%s", settings.httpdir, buf);
DIR *dir = opendir(fullpath);
if (dir) {
closedir(dir);
- dirlisting(ws_ctx, fullpath, path);
+ dirlisting(ws_ctx, fullpath, buf);
return;
}
@@ -976,14 +1006,14 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
if (len) {
memcpy(buf, param, len);
buf[len] = '\0';
- percent_decode(buf, decname);
+ percent_decode(buf, decname, 0);
}
param = parse_get(args, "password", &len);
if (len) {
memcpy(buf, param, len);
buf[len] = '\0';
- percent_decode(buf, decpw);
+ percent_decode(buf, decpw, 0);
struct crypt_data cdata;
cdata.initialized = 0;
@@ -1023,7 +1053,7 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
if (len) {
memcpy(buf, param, len);
buf[len] = '\0';
- percent_decode(buf, decname);
+ percent_decode(buf, decname, 0);
}
if (!decname[0])
@@ -1052,7 +1082,7 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
if (len) {
memcpy(buf, param, len);
buf[len] = '\0';
- percent_decode(buf, decname);
+ percent_decode(buf, decname, 0);
}
if (!decname[0])
@@ -1097,7 +1127,7 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in) {
if (len) {
memcpy(buf, param, len);
buf[len] = '\0';
- percent_decode(buf, decname);
+ percent_decode(buf, decname, 0);
} else {
wserr("client param required\n");
goto nope;
@@ -1320,6 +1350,8 @@ ws_ctx_t *do_handshake(int sock) {
} else {
// Client tried an empty password, just fail them
response[0] = '\0';
+ authbuf[0] = 'a';
+ authbuf[1] = '\0';
}
}
diff --git a/common/rfb/InputHandler.h b/common/rfb/InputHandler.h
index 806625f..e16a810 100644
--- a/common/rfb/InputHandler.h
+++ b/common/rfb/InputHandler.h
@@ -38,7 +38,9 @@ namespace rfb {
virtual void pointerEvent(const Point& __unused_attr pos,
int __unused_attr buttonMask,
const bool __unused_attr skipClick,
- const bool __unused_attr skipRelease) { }
+ const bool __unused_attr skipRelease,
+ int scrollX,
+ int scrollY) { }
virtual void clientCutText(const char* __unused_attr str,
int __unused_attr len) { }
};
diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx
index bd1ea45..5567a96 100644
--- a/common/rfb/SConnection.cxx
+++ b/common/rfb/SConnection.cxx
@@ -284,74 +284,26 @@ void SConnection::setEncodings(int nEncodings, const rdr::S32* encodings)
}
SMsgHandler::setEncodings(nEncodings, encodings);
-
- if (cp.supportsExtendedClipboard) {
- rdr::U32 sizes[] = { 0 };
- writer()->writeClipboardCaps(rfb::clipboardUTF8 |
- rfb::clipboardRequest |
- rfb::clipboardPeek |
- rfb::clipboardNotify |
- rfb::clipboardProvide,
- sizes);
- }
}
-void SConnection::clientCutText(const char* str, int len)
+void SConnection::clearBinaryClipboard()
{
- hasLocalClipboard = false;
-
- strFree(clientClipboard);
- clientClipboard = NULL;
-
- clientClipboard = latin1ToUTF8(str);
-
- handleClipboardAnnounce(true);
-}
-
-void SConnection::handleClipboardRequest(rdr::U32 flags)
-{
- if (!(flags & rfb::clipboardUTF8))
- return;
- if (!hasLocalClipboard)
- return;
- handleClipboardRequest();
+ binaryClipboard.clear();
}
-void SConnection::handleClipboardPeek(rdr::U32 flags)
+void SConnection::addBinaryClipboard(const char mime[], const rdr::U8 *data,
+ const rdr::U32 len)
{
- if (!hasLocalClipboard)
- return;
- if (cp.clipboardFlags() & rfb::clipboardNotify)
- writer()->writeClipboardNotify(rfb::clipboardUTF8);
-}
+ binaryClipboard_t bin;
+ strncpy(bin.mime, mime, sizeof(bin.mime));
+ bin.mime[sizeof(bin.mime) - 1] = '\0';
-void SConnection::handleClipboardNotify(rdr::U32 flags)
-{
- strFree(clientClipboard);
- clientClipboard = NULL;
+ bin.data.resize(len);
+ memcpy(&bin.data[0], data, len);
- if (flags & rfb::clipboardUTF8) {
- handleClipboardAnnounce(true);
- hasLocalClipboard = false;
- } else {
- handleClipboardAnnounce(false);
- }
+ binaryClipboard.push_back(bin);
}
-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, strlen(clientClipboard));
-}
void SConnection::supportsQEMUKeyEvent()
{
@@ -445,56 +397,13 @@ void SConnection::enableContinuousUpdates(bool enable,
{
}
-void SConnection::handleClipboardRequest()
-{
-}
-
void SConnection::handleClipboardAnnounce(bool available)
{
}
-void SConnection::handleClipboardData(const char* data, int len)
-{
-}
-
-void SConnection::requestClipboard()
-{
- if (clientClipboard != NULL) {
- handleClipboardData(clientClipboard, strlen(clientClipboard));
- return;
- }
-
- if (cp.supportsExtendedClipboard &&
- (cp.clipboardFlags() & rfb::clipboardRequest))
- writer()->writeClipboardRequest(rfb::clipboardUTF8);
-}
-
void SConnection::announceClipboard(bool available)
{
hasLocalClipboard = available;
-
- if (cp.supportsExtendedClipboard &&
- (cp.clipboardFlags() & rfb::clipboardNotify))
- writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
- else {
- if (available)
- handleClipboardRequest();
- }
-}
-
-void SConnection::sendClipboardData(const char* data, int len)
-{
- if (cp.supportsExtendedClipboard &&
- (cp.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, strlen(latin1.buf));
- }
}
void SConnection::writeFakeColourMap(void)
diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h
index 811ba04..8b5b3de 100644
--- a/common/rfb/SConnection.h
+++ b/common/rfb/SConnection.h
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
namespace rfb {
@@ -73,14 +74,9 @@ namespace rfb {
virtual void setEncodings(int nEncodings, const rdr::S32* encodings);
- virtual void clientCutText(const char* str, int len);
-
- 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 clearBinaryClipboard();
+ virtual void addBinaryClipboard(const char mime[], const rdr::U8 *data,
+ const rdr::U32 len);
virtual void supportsQEMUKeyEvent();
@@ -127,25 +123,11 @@ namespace rfb {
virtual void enableContinuousUpdates(bool enable,
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, int len);
-
-
virtual void add_changed_all() {}
// setAccessRights() allows a security package to limit the access rights
@@ -166,22 +148,11 @@ namespace rfb {
// 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, int len);
-
-
// authenticated() returns true if the client has authenticated
// successfully.
bool authenticated() { return (state_ == RFBSTATE_INITIALISATION ||
@@ -221,12 +192,19 @@ namespace rfb {
rdr::S32 getPreferredEncoding() { return preferredEncoding; }
+ struct binaryClipboard_t {
+ char mime[32];
+ std::vector data;
+ };
+
protected:
void setState(stateEnum s) { state_ = s; }
void setReader(SMsgReader *r) { reader_ = r; }
void setWriter(SMsgWriter *w) { writer_ = w; }
+ std::vector binaryClipboard;
+
private:
void writeFakeColourMap(void);
diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h
index ec833c3..5696cfd 100644
--- a/common/rfb/SDesktop.h
+++ b/common/rfb/SDesktop.h
@@ -78,23 +78,13 @@ namespace rfb {
// the relevant RFB protocol messages from clients.
// 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, int len __unused_attr) {}
+ virtual void handleClipboardAnnounceBinary(const unsigned __unused_attr num,
+ const char __unused_attr mimes[][32]) {}
protected:
virtual ~SDesktop() {}
diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx
index 29c33ea..07499bc 100644
--- a/common/rfb/SMsgHandler.cxx
+++ b/common/rfb/SMsgHandler.cxx
@@ -64,26 +64,16 @@ void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings)
supportsQEMUKeyEvent();
}
-void SMsgHandler::handleClipboardCaps(rdr::U32 flags, const rdr::U32* lengths)
+void SMsgHandler::handleClipboardAnnounceBinary(const unsigned, const char mimes[][32])
{
- cp.setClipboardCaps(flags, lengths);
}
-void SMsgHandler::handleClipboardRequest(rdr::U32 flags)
+void SMsgHandler::clearBinaryClipboard()
{
}
-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::addBinaryClipboard(const char mime[], const rdr::U8 *data,
+ const rdr::U32 len)
{
}
diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h
index d2fe4af..d9d852a 100644
--- a/common/rfb/SMsgHandler.h
+++ b/common/rfb/SMsgHandler.h
@@ -54,14 +54,10 @@ namespace rfb {
virtual void enableContinuousUpdates(bool enable,
int x, int y, int w, int h) = 0;
- virtual void handleClipboardCaps(rdr::U32 flags,
- const rdr::U32* lengths);
- virtual void handleClipboardRequest(rdr::U32 flags);
- virtual void handleClipboardPeek(rdr::U32 flags);
- virtual void handleClipboardNotify(rdr::U32 flags);
- virtual void handleClipboardProvide(rdr::U32 flags,
- const size_t* lengths,
- const rdr::U8* const* data);
+ virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
+ virtual void clearBinaryClipboard();
+ virtual void addBinaryClipboard(const char mime[], const rdr::U8 *data,
+ const rdr::U32 len);
virtual void sendStats(const bool toClient = true) = 0;
virtual void handleFrameStats(rdr::U32 all, rdr::U32 render) = 0;
diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx
index de5e1b3..3719756 100644
--- a/common/rfb/SMsgReader.cxx
+++ b/common/rfb/SMsgReader.cxx
@@ -35,8 +35,6 @@ using namespace rfb;
static LogWriter vlog("SMsgReader");
-static IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
-
SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_)
: handler(handler_), is(is_)
{
@@ -83,6 +81,9 @@ void SMsgReader::readMsg()
case msgTypeFrameStats:
readFrameStats();
break;
+ case msgTypeBinaryClipboard:
+ readBinaryClipboard();
+ break;
case msgTypeKeyEvent:
readKeyEvent();
break;
@@ -223,7 +224,9 @@ void SMsgReader::readPointerEvent()
int mask = is->readU8();
int x = is->readU16();
int y = is->readU16();
- handler->pointerEvent(Point(x, y), mask, false, false);
+ int scrollX = is->readS16();
+ int scrollY = is->readS16();
+ handler->pointerEvent(Point(x, y), mask, false, false, scrollX, scrollY);
}
@@ -238,109 +241,54 @@ void SMsgReader::readClientCutText()
readExtendedClipboard(slen);
return;
}
- if (len > (size_t)maxCutText) {
- is->skip(len);
- vlog.error("Cut text too long (%d bytes) - ignoring", len);
- return;
- }
- CharArray ca(len+1);
- ca.buf[len] = 0;
- is->readBytes(ca.buf, len);
- handler->clientCutText(ca.buf, len);
+ is->skip(len);
+ vlog.error("Client sent old cuttext msg, ignoring");
}
-void SMsgReader::readExtendedClipboard(rdr::S32 len)
+void SMsgReader::readBinaryClipboard()
{
- 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;
+ const rdr::U8 num = is->readU8();
+ rdr::U8 i, valid = 0;
+ char tmpmimes[num][32];
+
+ handler->clearBinaryClipboard();
+ for (i = 0; i < num; i++) {
+ const rdr::U8 mimelen = is->readU8();
+ if (mimelen > 32 - 1) {
+ vlog.error("Mime too long (%u)", mimelen);
+ }
- if (action & clipboardCaps) {
- int i;
- size_t num;
- rdr::U32 lengths[16];
+ char mime[mimelen + 1];
+ mime[mimelen] = '\0';
+ is->readBytes(mime, mimelen);
- num = 0;
- for (i = 0;i < 16;i++) {
- if (flags & (1 << i))
- num++;
- }
+ strncpy(tmpmimes[valid], mime, 32);
+ tmpmimes[valid][31] = '\0';
- if (len < (rdr::S32)(4 + 4*num))
- throw Exception("Invalid extended clipboard message");
+ const rdr::U32 len = is->readU32();
+ CharArray ca(len);
+ is->readBytes(ca.buf, len);
- num = 0;
- for (i = 0;i < 16;i++) {
- if (flags & (1 << i))
- lengths[num++] = is->readU32();
+ if (rfb::Server::DLP_ClipAcceptMax && len > (unsigned) rfb::Server::DLP_ClipAcceptMax) {
+ vlog.info("DLP: refused to receive binary clipboard, too large");
+ continue;
}
- 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++;
- }
+ vlog.debug("Received binary clipboard, type %s, %u bytes", mime, len);
- zis.flushUnderlying();
- zis.setUnderlying(NULL, 0);
+ handler->addBinaryClipboard(mime, (rdr::U8 *) ca.buf, len);
+ valid++;
+ }
- handler->handleClipboardProvide(flags, lengths, buffers);
+ handler->handleClipboardAnnounceBinary(valid, tmpmimes);
+}
- 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::readExtendedClipboard(rdr::S32 len)
+{
+ if (len < 4)
+ throw Exception("Invalid extended clipboard message");
+ vlog.error("Client sent old cuttext msg, ignoring");
+ is->skip(len);
}
void SMsgReader::readRequestStats()
diff --git a/common/rfb/SMsgReader.h b/common/rfb/SMsgReader.h
index a9b09cc..8a1eb34 100644
--- a/common/rfb/SMsgReader.h
+++ b/common/rfb/SMsgReader.h
@@ -58,6 +58,7 @@ namespace rfb {
void readExtendedClipboard(rdr::S32 len);
void readRequestStats();
void readFrameStats();
+ void readBinaryClipboard();
void readQEMUMessage();
void readQEMUKeyEvent();
diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
index a7c12f4..a0a9df0 100644
--- a/common/rfb/SMsgWriter.cxx
+++ b/common/rfb/SMsgWriter.cxx
@@ -85,118 +85,21 @@ void SMsgWriter::writeBell()
endMsg();
}
-void SMsgWriter::writeServerCutText(const char* str, int len)
+void SMsgWriter::writeBinaryClipboard(const std::vector &b)
{
- startMsg(msgTypeServerCutText);
- os->pad(3);
- os->writeU32(len);
- os->writeBytes(str, len);
- endMsg();
-}
-
-void SMsgWriter::writeClipboardCaps(rdr::U32 caps,
- const rdr::U32* lengths)
-{
- size_t i, count;
-
- if (!cp->supportsExtendedClipboard)
- 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 (!cp->supportsExtendedClipboard)
- throw Exception("Client does not support extended clipboard");
- if (!(cp->clipboardFlags() & clipboardRequest))
- throw Exception("Client does not support clipboard \"request\" action");
-
- startMsg(msgTypeServerCutText);
- os->pad(3);
- os->writeS32(-4);
- os->writeU32(flags | clipboardRequest);
- endMsg();
-}
+ startMsg(msgTypeBinaryClipboard);
-void SMsgWriter::writeClipboardPeek(rdr::U32 flags)
-{
- if (!cp->supportsExtendedClipboard)
- throw Exception("Client does not support extended clipboard");
- if (!(cp->clipboardFlags() & clipboardPeek))
- throw Exception("Client does not support clipboard \"peek\" action");
+ os->writeU8(b.size());
+ rdr::U8 i;
+ for (i = 0; i < b.size(); i++) {
+ const rdr::U8 mimelen = strlen(b[i].mime);
+ os->writeU8(mimelen);
+ os->writeBytes(b[i].mime, mimelen);
- startMsg(msgTypeServerCutText);
- os->pad(3);
- os->writeS32(-4);
- os->writeU32(flags | clipboardPeek);
- endMsg();
-}
-
-void SMsgWriter::writeClipboardNotify(rdr::U32 flags)
-{
- if (!cp->supportsExtendedClipboard)
- throw Exception("Client does not support extended clipboard");
- if (!(cp->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 (!cp->supportsExtendedClipboard)
- throw Exception("Client does not support extended clipboard");
- if (!(cp->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++;
+ os->writeU32(b[i].data.size());
+ os->writeBytes(&b[i].data[0], b[i].data.size());
}
- zos.flush();
-
- startMsg(msgTypeServerCutText);
- os->pad(3);
- os->writeS32(-(4 + mos.length()));
- os->writeU32(flags | clipboardProvide);
- os->writeBytes(mos.data(), mos.length());
endMsg();
}
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
index 0313bcc..c72012e 100644
--- a/common/rfb/SMsgWriter.h
+++ b/common/rfb/SMsgWriter.h
@@ -26,6 +26,8 @@
#include
#include
#include
+#include
+#include
namespace rdr { class OutStream; }
@@ -54,14 +56,8 @@ namespace rfb {
// writeBell() and writeServerCutText() do the obvious thing.
void writeBell();
- void writeServerCutText(const char* str, int len);
-
- 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);
+
+ void writeBinaryClipboard(const std::vector &b);
void writeStats(const char* str, int len);
diff --git a/common/rfb/ServerCore.cxx b/common/rfb/ServerCore.cxx
index 28ce777..1d568c1 100644
--- a/common/rfb/ServerCore.cxx
+++ b/common/rfb/ServerCore.cxx
@@ -149,15 +149,15 @@ rfb::IntParameter rfb::Server::webpVideoQuality
rfb::IntParameter rfb::Server::DLP_ClipSendMax
("DLP_ClipSendMax",
"Limit clipboard bytes to send to clients in one transaction",
- 10000, 0, INT_MAX);
+ 0, 0, INT_MAX);
rfb::IntParameter rfb::Server::DLP_ClipAcceptMax
("DLP_ClipAcceptMax",
"Limit clipboard bytes to receive from clients in one transaction",
- 10000, 0, INT_MAX);
+ 0, 0, INT_MAX);
rfb::IntParameter rfb::Server::DLP_ClipDelay
("DLP_ClipDelay",
"This many milliseconds must pass between clipboard actions",
- 1000, 0, INT_MAX);
+ 0, 0, INT_MAX);
rfb::IntParameter rfb::Server::DLP_KeyRateLimit
("DLP_KeyRateLimit",
"Reject keyboard presses over this many per second",
@@ -171,6 +171,10 @@ rfb::StringParameter rfb::Server::DLP_Region
("DLP_Region",
"Black out anything outside this region",
"");
+rfb::StringParameter rfb::Server::DLP_Clip_Types
+("DLP_ClipTypes",
+ "Allowed binary clipboard mimetypes",
+ "text/html,image/png");
rfb::BoolParameter rfb::Server::DLP_RegionAllowClick
("DLP_RegionAllowClick",
diff --git a/common/rfb/ServerCore.h b/common/rfb/ServerCore.h
index 766eda0..70075bf 100644
--- a/common/rfb/ServerCore.h
+++ b/common/rfb/ServerCore.h
@@ -50,6 +50,7 @@ namespace rfb {
static IntParameter DLP_KeyRateLimit;
static StringParameter DLP_ClipLog;
static StringParameter DLP_Region;
+ static StringParameter DLP_Clip_Types;
static BoolParameter DLP_RegionAllowClick;
static BoolParameter DLP_RegionAllowRelease;
static IntParameter jpegVideoQuality;
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index bd24229..fa85a70 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -57,7 +57,8 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
inProcessMessages(false),
pendingSyncFence(false), syncFence(false), fenceFlags(0),
fenceDataLen(0), fenceData(NULL), congestionTimer(this),
- losslessTimer(this), kbdLogTimer(this), server(server_), updates(false),
+ losslessTimer(this), kbdLogTimer(this), binclipTimer(this),
+ server(server_), updates(false),
updateRenderedCursor(false), removeRenderedCursor(false),
continuousUpdates(false), encodeManager(this, &server_->encCache),
needsPermCheck(false), pointerEventTime(0),
@@ -413,18 +414,6 @@ static void keylog(unsigned keysym, const char *client) {
flushKeylog(client);
}
-void VNCSConnectionST::requestClipboardOrClose()
-{
- try {
- if (!(accessRights & AccessCutText)) return;
- if (!rfb::Server::acceptCutText) return;
- if (state() != RFBSTATE_NORMAL) return;
- requestClipboard();
- } catch(rdr::Exception& e) {
- close(e.str());
- }
-}
-
void VNCSConnectionST::announceClipboardOrClose(bool available)
{
try {
@@ -437,29 +426,51 @@ void VNCSConnectionST::announceClipboardOrClose(bool available)
}
}
-void VNCSConnectionST::sendClipboardDataOrClose(const char* data)
+void VNCSConnectionST::clearBinaryClipboardData()
+{
+ clearBinaryClipboard();
+}
+
+void VNCSConnectionST::sendBinaryClipboardDataOrClose(const char* mime,
+ const unsigned char *data,
+ const unsigned len)
{
try {
if (!(accessRights & AccessCutText)) return;
if (!rfb::Server::sendCutText) return;
- if (msSince(&lastClipboardOp) < (unsigned) rfb::Server::DLP_ClipDelay) {
- vlog.info("DLP: client %s: refused to send clipboard, too soon",
+ if (rfb::Server::DLP_ClipSendMax && len > (unsigned) rfb::Server::DLP_ClipSendMax) {
+ vlog.info("DLP: client %s: refused to send binary clipboard, too large",
sock->getPeerAddress());
return;
}
- int len = strlen(data);
- const int origlen = len;
- if (rfb::Server::DLP_ClipSendMax && len > rfb::Server::DLP_ClipSendMax)
- len = rfb::Server::DLP_ClipSendMax;
- cliplog(data, len, origlen, "sent", sock->getPeerAddress());
+
+ cliplog((const char *) data, len, len, "sent", sock->getPeerAddress());
if (state() != RFBSTATE_NORMAL) return;
- sendClipboardData(data, len);
- gettimeofday(&lastClipboardOp, NULL);
+
+ addBinaryClipboard(mime, data, len);
+ binclipTimer.start(100);
} catch(rdr::Exception& e) {
close(e.str());
}
}
+void VNCSConnectionST::getBinaryClipboardData(const char* mime, const unsigned char **data,
+ unsigned *len)
+{
+ unsigned i;
+ for (i = 0; i < binaryClipboard.size(); i++) {
+ if (!strcmp(binaryClipboard[i].mime, mime)) {
+ *data = &binaryClipboard[i].data[0];
+ *len = binaryClipboard[i].data.size();
+ return;
+ }
+ }
+
+ vlog.error("Binary clipboard data for mime %s not found", mime);
+ *data = (const unsigned char *) "";
+ *len = 1;
+}
+
void VNCSConnectionST::setDesktopNameOrClose(const char *name)
{
try {
@@ -692,7 +703,7 @@ void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
setCursor();
}
-void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask, const bool skipClick, const bool skipRelease)
+void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask, const bool skipClick, const bool skipRelease, int scrollX, int scrollY)
{
pointerEventTime = lastEventTime = time(0);
server->lastUserInputTime = lastEventTime;
@@ -720,7 +731,7 @@ void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask, const bool
}
}
- server->desktop->pointerEvent(pointerEventPos, buttonMask, skipclick, skiprelease);
+ server->desktop->pointerEvent(pointerEventPos, buttonMask, skipclick, skiprelease, scrollX, scrollY);
}
}
@@ -1014,12 +1025,6 @@ void VNCSConnectionST::enableContinuousUpdates(bool enable,
}
}
-void VNCSConnectionST::handleClipboardRequest()
-{
- if (!(accessRights & AccessCutText)) return;
- server->handleClipboardRequest(this);
-}
-
void VNCSConnectionST::handleClipboardAnnounce(bool available)
{
if (!(accessRights & AccessCutText)) return;
@@ -1027,25 +1032,13 @@ void VNCSConnectionST::handleClipboardAnnounce(bool available)
server->handleClipboardAnnounce(this, available);
}
-void VNCSConnectionST::handleClipboardData(const char* data, int len)
+void VNCSConnectionST::handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32])
{
if (!(accessRights & AccessCutText)) return;
if (!rfb::Server::acceptCutText) return;
- if (msSince(&lastClipboardOp) < (unsigned) rfb::Server::DLP_ClipDelay) {
- vlog.info("DLP: client %s: refused to receive clipboard, too soon",
- sock->getPeerAddress());
- return;
- }
- const int origlen = len;
- if (rfb::Server::DLP_ClipAcceptMax && len > rfb::Server::DLP_ClipAcceptMax)
- len = rfb::Server::DLP_ClipAcceptMax;
- cliplog(data, len, origlen, "received", sock->getPeerAddress());
-
- gettimeofday(&lastClipboardOp, NULL);
- server->handleClipboardData(this, data, len);
+ server->handleClipboardAnnounceBinary(this, num, mimes);
}
-
// supportsLocalCursor() is called whenever the status of
// cp.supportsLocalCursor has changed. If the client does now support local
// cursor, we make sure that the old server-side rendered cursor is cleaned up
@@ -1089,6 +1082,8 @@ bool VNCSConnectionST::handleTimeout(Timer* t)
writeFramebufferUpdate();
else if (t == &kbdLogTimer)
flushKeylog(sock->getPeerAddress());
+ else if (t == &binclipTimer)
+ writeBinaryClipboard();
} catch (rdr::Exception& e) {
close(e.str());
}
@@ -1446,6 +1441,18 @@ void VNCSConnectionST::writeDataUpdate()
requested.clear();
}
+void VNCSConnectionST::writeBinaryClipboard()
+{
+ if (msSince(&lastClipboardOp) < (unsigned) rfb::Server::DLP_ClipDelay) {
+ vlog.info("DLP: client %s: refused to send binary clipboard, too soon",
+ sock->getPeerAddress());
+ return;
+ }
+
+ writer()->writeBinaryClipboard(binaryClipboard);
+
+ gettimeofday(&lastClipboardOp, NULL);
+}
void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
{
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 86c99c6..63ce49c 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -77,9 +77,12 @@ namespace rfb {
void bellOrClose();
void setDesktopNameOrClose(const char *name);
void setLEDStateOrClose(unsigned int state);
- void requestClipboardOrClose();
void announceClipboardOrClose(bool available);
- void sendClipboardDataOrClose(const char* data);
+ void clearBinaryClipboardData();
+ void sendBinaryClipboardDataOrClose(const char* mime, const unsigned char *data,
+ const unsigned len);
+ void getBinaryClipboardData(const char* mime, const unsigned char **data,
+ unsigned *len);
// checkIdleTimeout() returns the number of milliseconds left until the
// idle timeout expires. If it has expired, the connection is closed and
@@ -204,7 +207,7 @@ namespace rfb {
virtual void queryConnection(const char* userName);
virtual void clientInit(bool shared);
virtual void setPixelFormat(const PixelFormat& pf);
- virtual void pointerEvent(const Point& pos, int buttonMask, const bool skipClick, const bool skipRelease);
+ virtual void pointerEvent(const Point& pos, int buttonMask, const bool skipClick, const bool skipRelease, int scrollX, int scrollY);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
virtual void setDesktopSize(int fb_width, int fb_height,
@@ -212,9 +215,8 @@ namespace rfb {
virtual void fence(rdr::U32 flags, unsigned len, const char data[]);
virtual void enableContinuousUpdates(bool enable,
int x, int y, int w, int h);
- virtual void handleClipboardRequest();
virtual void handleClipboardAnnounce(bool available);
- virtual void handleClipboardData(const char* data, int len);
+ virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
virtual void supportsLocalCursor();
virtual void supportsFence();
virtual void supportsContinuousUpdates();
@@ -260,6 +262,8 @@ namespace rfb {
void writeNoDataUpdate();
void writeDataUpdate();
+ void writeBinaryClipboard();
+
void screenLayoutChange(rdr::U16 reason);
void setCursor();
void setCursorPos();
@@ -282,6 +286,7 @@ namespace rfb {
Timer congestionTimer;
Timer losslessTimer;
Timer kbdLogTimer;
+ Timer binclipTimer;
VNCServerST* server;
SimpleUpdateTracker updates;
diff --git a/common/rfb/VNCServer.h b/common/rfb/VNCServer.h
index 54e3504..33b0533 100644
--- a/common/rfb/VNCServer.h
+++ b/common/rfb/VNCServer.h
@@ -52,22 +52,11 @@ namespace rfb {
// getPixelBuffer() returns a pointer to the PixelBuffer object.
virtual PixelBuffer* getPixelBuffer() const = 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.
virtual void bell() = 0;
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 3e87892..7807feb 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -518,14 +518,6 @@ void VNCServerST::setScreenLayout(const ScreenSet& layout)
}
}
-void VNCServerST::requestClipboard()
-{
- if (clipboardClient == NULL)
- return;
-
- clipboardClient->requestClipboard();
-}
-
void VNCServerST::announceClipboard(bool available)
{
std::list::iterator ci, ci_next;
@@ -541,20 +533,31 @@ void VNCServerST::announceClipboard(bool available)
}
}
-void VNCServerST::sendClipboardData(const char* data)
+void VNCServerST::sendBinaryClipboardData(const char* mime, const unsigned char *data,
+ const unsigned len)
{
std::list::iterator ci, ci_next;
+ for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
+ ci_next = ci; ci_next++;
+ (*ci)->sendBinaryClipboardDataOrClose(mime, data, len);
+ }
+}
- if (strchr(data, '\r') != NULL)
- throw Exception("Invalid carriage return in clipboard data");
+void VNCServerST::getBinaryClipboardData(const char* mime, const unsigned char **data,
+ unsigned *len)
+{
+ if (!clipboardClient)
+ return;
+ clipboardClient->getBinaryClipboardData(mime, data, len);
+}
- for (ci = clipboardRequestors.begin();
- ci != clipboardRequestors.end(); ci = ci_next) {
+void VNCServerST::clearBinaryClipboardData()
+{
+ std::list::iterator ci, ci_next;
+ for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
ci_next = ci; ci_next++;
- (*ci)->sendClipboardDataOrClose(data);
+ (*ci)->clearBinaryClipboardData();
}
-
- clipboardRequestors.clear();
}
void VNCServerST::bell()
@@ -1198,13 +1201,6 @@ bool VNCServerST::getComparerState()
return false;
}
-void VNCServerST::handleClipboardRequest(VNCSConnectionST* client)
-{
- clipboardRequestors.push_back(client);
- if (clipboardRequestors.size() == 1)
- desktop->handleClipboardRequest();
-}
-
void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client,
bool available)
{
@@ -1218,11 +1214,10 @@ void VNCServerST::handleClipboardAnnounce(VNCSConnectionST* client,
desktop->handleClipboardAnnounce(available);
}
-void VNCServerST::handleClipboardData(VNCSConnectionST* client,
- const char* data, int len)
+void VNCServerST::handleClipboardAnnounceBinary(VNCSConnectionST* client,
+ const unsigned num,
+ const char mimes[][32])
{
- if (client != clipboardClient)
- return;
- desktop->handleClipboardData(data, len);
+ clipboardClient = client;
+ desktop->handleClipboardAnnounceBinary(num, mimes);
}
-
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index 26c9ef6..0eff2d1 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -96,9 +96,12 @@ namespace rfb {
virtual void setPixelBuffer(PixelBuffer* pb);
virtual void setScreenLayout(const ScreenSet& layout);
virtual PixelBuffer* getPixelBuffer() const { if (DLPRegion.enabled && blackedpb) return blackedpb; else return pb; }
- virtual void requestClipboard();
virtual void announceClipboard(bool available);
- virtual void sendClipboardData(const char* data);
+ virtual void clearBinaryClipboardData();
+ virtual void sendBinaryClipboardData(const char* mime, const unsigned char *data,
+ const unsigned len);
+ virtual void getBinaryClipboardData(const char *mime, const unsigned char **ptr,
+ unsigned *len);
virtual void add_changed(const Region ®ion);
virtual void add_copied(const Region &dest, const Point &delta);
virtual void setCursor(int width, int height, const Point& hotspot,
@@ -191,9 +194,9 @@ namespace rfb {
void setAPIMessager(network::GetAPIMessager *msgr) { apimessager = msgr; }
- void handleClipboardRequest(VNCSConnectionST* client);
void handleClipboardAnnounce(VNCSConnectionST* client, bool available);
- void handleClipboardData(VNCSConnectionST* client, const char* data, int len);
+ void handleClipboardAnnounceBinary(VNCSConnectionST* client, const unsigned num,
+ const char mimes[][32]);
protected:
diff --git a/common/rfb/msgTypes.h b/common/rfb/msgTypes.h
index 5070c3f..ea8e007 100644
--- a/common/rfb/msgTypes.h
+++ b/common/rfb/msgTypes.h
@@ -31,6 +31,7 @@ namespace rfb {
// kasm
const int msgTypeStats = 178;
const int msgTypeRequestFrameStats = 179;
+ const int msgTypeBinaryClipboard = 180;
const int msgTypeServerFence = 248;
@@ -49,6 +50,7 @@ namespace rfb {
// kasm
const int msgTypeRequestStats = 178;
const int msgTypeFrameStats = 179;
+ //const int msgTypeBinaryClipboard = 180;
const int msgTypeClientFence = 248;
diff --git a/common/rfb/scale_sse2.cxx b/common/rfb/scale_sse2.cxx
index e4c717b..d4110a6 100644
--- a/common/rfb/scale_sse2.cxx
+++ b/common/rfb/scale_sse2.cxx
@@ -69,7 +69,7 @@ void SSE2_halve(const uint8_t *oldpx,
uint8_t * const dst = newpx + newstride * (y / 2) * 4;
- for (x = 0; x < srcw; x += 4) {
+ for (x = 0; x < srcw - 3; x += 4) {
__m128i lo, hi, a, b, c, d;
lo = _mm_loadu_si128((__m128i *) &row0[x * 4]);
hi = _mm_loadu_si128((__m128i *) &row1[x * 4]);
@@ -141,7 +141,7 @@ void SSE2_scale(const uint8_t *oldpx,
const __m128i vertmul = _mm_set1_epi16(top);
const __m128i vertmul2 = _mm_set1_epi16(bot);
- for (x = 0; x < tgtw; x += 2) {
+ for (x = 0; x < tgtw - 1; x += 2) {
const float nx[2] = {
x * invdiff,
(x + 1) * invdiff,
diff --git a/unix/xserver/hw/vnc/Input.c b/unix/xserver/hw/vnc/Input.c
index f8ac3fd..e8f9170 100644
--- a/unix/xserver/hw/vnc/Input.c
+++ b/unix/xserver/hw/vnc/Input.c
@@ -234,6 +234,14 @@ void vncPointerMove(int x, int y)
cursorPosY = y;
}
+void vncScroll(int x, int y) {
+ ValuatorMask mask;
+ valuator_mask_zero(&mask);
+ valuator_mask_set(&mask, 2, x);
+ valuator_mask_set(&mask, 3, y);
+ QueuePointerEvents(vncPointerDev, MotionNotify, 0, POINTER_RELATIVE, &mask);
+}
+
void vncGetPointerPos(int *x, int *y)
{
if (vncPointerDev != NULL) {
@@ -261,7 +269,7 @@ static int vncPointerProc(DeviceIntPtr pDevice, int onoff)
* is not a bug.
*/
Atom btn_labels[BUTTONS];
- Atom axes_labels[2];
+ Atom axes_labels[4];
switch (onoff) {
case DEVICE_INIT:
@@ -278,11 +286,29 @@ static int vncPointerProc(DeviceIntPtr pDevice, int onoff)
axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
+ axes_labels[2] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL);
+ axes_labels[3] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL);
+
InitPointerDeviceStruct(pDev, map, BUTTONS, btn_labels,
(PtrCtrlProcPtr)NoopDDA,
GetMotionHistorySize(),
- 2, axes_labels);
+ 4, axes_labels);
+
+ InitValuatorAxisStruct(pDevice, 2, axes_labels[2], NO_AXIS_LIMITS, NO_AXIS_LIMITS, 0, 0, 0, Relative);
+ InitValuatorAxisStruct(pDevice, 3, axes_labels[3], NO_AXIS_LIMITS, NO_AXIS_LIMITS, 0, 0, 0, Relative);
+
+ char* envScrollFactorH = getenv("SCROLL_FACTOR_H");
+ char* envScrollFactorV = getenv("SCROLL_FACTOR_V");
+
+ float scrollFactorH = envScrollFactorH ? atof(envScrollFactorH) : 50.0;
+ float scrollFactorV = envScrollFactorV ? atof(envScrollFactorV) : 50.0;
+
+ LOG_INFO("Mouse horizonatl scroll factor: %f", scrollFactorH);
+ LOG_INFO("Mouse vertical scroll factor: %f", scrollFactorV);
+
+ SetScrollValuator(pDevice, 2, SCROLL_TYPE_HORIZONTAL, scrollFactorH, SCROLL_FLAG_NONE);
+ SetScrollValuator(pDevice, 3, SCROLL_TYPE_VERTICAL, scrollFactorV, SCROLL_FLAG_PREFERRED);
break;
case DEVICE_ON:
pDev->on = TRUE;
diff --git a/unix/xserver/hw/vnc/Input.h b/unix/xserver/hw/vnc/Input.h
index 76680c0..ddc4e06 100644
--- a/unix/xserver/hw/vnc/Input.h
+++ b/unix/xserver/hw/vnc/Input.h
@@ -35,6 +35,7 @@ void vncInitInputDevice(void);
void vncPointerButtonAction(int buttonMask, const unsigned char skipclick,
const unsigned char skiprelease);
void vncPointerMove(int x, int y);
+void vncScroll(int x, int y);
void vncGetPointerPos(int *x, int *y);
void vncKeyboardEvent(KeySym keysym, unsigned xtcode, int down);
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index 1e9d663..26a9bfd 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -176,30 +176,43 @@ XserverDesktop::queryConnection(network::Socket* sock,
return rfb::VNCServerST::PENDING;
}
-void XserverDesktop::requestClipboard()
+void XserverDesktop::announceClipboard(bool available)
{
try {
- server->requestClipboard();
+ server->announceClipboard(available);
} catch (rdr::Exception& e) {
- vlog.error("XserverDesktop::requestClipboard: %s",e.str());
+ vlog.error("XserverDesktop::announceClipboard: %s",e.str());
}
}
-void XserverDesktop::announceClipboard(bool available)
+void XserverDesktop::clearBinaryClipboardData()
{
try {
- server->announceClipboard(available);
+ server->clearBinaryClipboardData();
} catch (rdr::Exception& e) {
- vlog.error("XserverDesktop::announceClipboard: %s",e.str());
+ vlog.error("XserverDesktop::clearBinaryClipboardData: %s",e.str());
}
}
-void XserverDesktop::sendClipboardData(const char* data)
+void XserverDesktop::sendBinaryClipboardData(const char* mime,
+ const unsigned char *data,
+ const unsigned len)
{
try {
- server->sendClipboardData(data);
+ server->sendBinaryClipboardData(mime, data, len);
} catch (rdr::Exception& e) {
- vlog.error("XserverDesktop::sendClipboardData: %s",e.str());
+ vlog.error("XserverDesktop::sendBinaryClipboardData: %s",e.str());
+ }
+}
+
+void XserverDesktop::getBinaryClipboardData(const char* mime,
+ const unsigned char **data,
+ unsigned *len)
+{
+ try {
+ server->getBinaryClipboardData(mime, data, len);
+ } catch (rdr::Exception& e) {
+ vlog.error("XserverDesktop::getBinaryClipboardData: %s",e.str());
}
}
@@ -446,11 +459,14 @@ void XserverDesktop::approveConnection(uint32_t opaqueId, bool accept,
void XserverDesktop::pointerEvent(const Point& pos, int buttonMask,
- const bool skipClick, const bool skipRelease)
+ const bool skipClick, const bool skipRelease, int scrollX, int scrollY)
{
- vncPointerMove(pos.x + vncGetScreenX(screenIndex),
- pos.y + vncGetScreenY(screenIndex));
- vncPointerButtonAction(buttonMask, skipClick, skipRelease);
+ if (scrollX == 0 && scrollY == 0) {
+ vncPointerMove(pos.x + vncGetScreenX(screenIndex), pos.y + vncGetScreenY(screenIndex));
+ vncPointerButtonAction(buttonMask, skipClick, skipRelease);
+ } else {
+ vncScroll(scrollX, scrollY);
+ }
}
unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
@@ -469,19 +485,14 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
return ret;
}
-void XserverDesktop::handleClipboardRequest()
-{
- vncHandleClipboardRequest();
-}
-
void XserverDesktop::handleClipboardAnnounce(bool available)
{
vncHandleClipboardAnnounce(available);
}
-void XserverDesktop::handleClipboardData(const char* data_, int len)
+void XserverDesktop::handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32])
{
- vncHandleClipboardData(data_, len);
+ vncHandleClipboardAnnounceBinary(num, mimes);
}
void XserverDesktop::grabRegion(const rfb::Region& region)
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index 014a48e..fb9b365 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -62,7 +62,11 @@ public:
void refreshScreenLayout();
void requestClipboard();
void announceClipboard(bool available);
- void sendClipboardData(const char* data);
+ void clearBinaryClipboardData();
+ void sendBinaryClipboardData(const char* mime, const unsigned char *data,
+ const unsigned len);
+ void getBinaryClipboardData(const char *mime, const unsigned char **ptr,
+ unsigned *len);
void bell();
void setLEDState(unsigned int state);
void setDesktopName(const char* name);
@@ -90,13 +94,12 @@ public:
// rfb::SDesktop callbacks
virtual void pointerEvent(const rfb::Point& pos, int buttonMask,
- const bool skipClick, const bool skipRelease);
+ const bool skipClick, const bool skipRelease, int scrollX = 0, int scrollY = 0);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
virtual unsigned int setScreenLayout(int fb_width, int fb_height,
const rfb::ScreenSet& layout);
- virtual void handleClipboardRequest();
virtual void handleClipboardAnnounce(bool available);
- virtual void handleClipboardData(const char* data, int len);
+ virtual void handleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
// rfb::PixelBuffer callbacks
virtual void grabRegion(const rfb::Region& r);
diff --git a/unix/xserver/hw/vnc/Xvnc.man b/unix/xserver/hw/vnc/Xvnc.man
index f3a6ac6..a031b3e 100644
--- a/unix/xserver/hw/vnc/Xvnc.man
+++ b/unix/xserver/hw/vnc/Xvnc.man
@@ -295,17 +295,22 @@ Allow click releases inside the blacked-out region.
.
.TP
.B \-DLP_ClipSendMax \fIbytes\fP
-Limit clipboard bytes to send to clients in one transaction. Default 10,000.
+Limit clipboard bytes to send to clients in one transaction. Default 0.
0 disables the limit, use \fBSendCutText\fP to disable clipboard sending entirely.
.
.TP
.B \-DLP_ClipAcceptMax \fIbytes\fP
-Limit clipboard bytes to receive from clients in one transaction. Default 10,000.
+Limit clipboard bytes to receive from clients in one transaction. Default 0.
0 disables the limit, use \fBAcceptCutText\fP to disable clipboard receiving entirely.
.
.TP
.B \-DLP_ClipDelay \fIms\fP
-This many milliseconds must pass between clipboard actions. Default 1000.
+This many milliseconds must pass between clipboard actions. Default 0, 0 disables the limit.
+.
+.TP
+.B \-DLP_ClipTypes \fIa,b\fP
+Allowed binary clipboard mimetypes, separated by commas. Default
+chromium/x-web-custom-data,text/html,image/png
.
.TP
.B \-DLP_KeyRateLimit \fIkeys-per-second\fP
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index 6b60c0a..66252b9 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -18,10 +18,12 @@
*/
#include
+#include
#include
#include
#include
+#include
#include
#include
@@ -64,6 +66,8 @@ int vncFbstride[MAXSCREENS];
int vncInetdSock = -1;
+static std::vector dlp_mimetypes;
+
struct CaseInsensitiveCompare {
bool operator() (const std::string &a, const std::string &b) const {
return strcasecmp(a.c_str(), b.c_str()) < 0;
@@ -147,6 +151,38 @@ static void parseOverrideList(const char *text, ParamSet &out)
}
}
+static void parseClipTypes()
+{
+ char *str = strdup(Server::DLP_Clip_Types);
+ char * const origstr = str;
+
+ while (1) {
+ char *cur = strsep(&str, ",");
+ if (!cur)
+ break;
+ if (!cur[0])
+ continue;
+
+ // Hardcoded filters
+ if (!strcmp(cur, "TEXT") ||
+ !strcmp(cur, "STRING") ||
+ strstr(cur, "text/plain") ||
+ !strcmp(cur, "UTF8_STRING"))
+ continue;
+
+ struct dlp_mimetype_t m;
+ strncpy(m.mime, cur, sizeof(m.mime));
+ m.mime[sizeof(m.mime) - 1] = '\0';
+
+ dlp_mimetypes.push_back(m);
+
+ vlog.debug("Adding DLP binary mime type %s", m.mime);
+ }
+ vlog.debug("Total %u binary mime types", dlp_mimetypes.size());
+
+ free(origstr);
+}
+
void vncExtensionInit(void)
{
if (vncExtGeneration == vncGetServerGeneration()) {
@@ -163,6 +199,8 @@ void vncExtensionInit(void)
vncAddExtension();
+ if (!initialised)
+ parseClipTypes();
vncSelectionInit();
vlog.info("VNC extension running!");
@@ -315,22 +353,30 @@ void vncUpdateDesktopName(void)
desktop[scr]->setDesktopName(desktopName);
}
-void vncRequestClipboard(void)
+void vncAnnounceClipboard(int available)
+{
+ for (int scr = 0; scr < vncGetScreenCount(); scr++)
+ desktop[scr]->announceClipboard(available);
+}
+
+void vncSendBinaryClipboardData(const char* mime, const unsigned char *data,
+ const unsigned len)
{
for (int scr = 0; scr < vncGetScreenCount(); scr++)
- desktop[scr]->requestClipboard();
+ desktop[scr]->sendBinaryClipboardData(mime, data, len);
}
-void vncAnnounceClipboard(int available)
+void vncGetBinaryClipboardData(const char *mime, const unsigned char **ptr,
+ unsigned *len)
{
for (int scr = 0; scr < vncGetScreenCount(); scr++)
- desktop[scr]->announceClipboard(available);
+ desktop[scr]->getBinaryClipboardData(mime, ptr, len);
}
-void vncSendClipboardData(const char* data)
+void vncClearBinaryClipboardData()
{
for (int scr = 0; scr < vncGetScreenCount(); scr++)
- desktop[scr]->sendClipboardData(data);
+ desktop[scr]->clearBinaryClipboardData();
}
int vncConnectClient(const char *addr)
@@ -486,3 +532,13 @@ int vncOverrideParam(const char *nameAndValue)
return rfb::Configuration::setParam(nameAndValue);
}
+
+unsigned dlp_num_mimetypes()
+{
+ return dlp_mimetypes.size();
+}
+
+const char *dlp_get_mimetype(const unsigned i)
+{
+ return dlp_mimetypes[i].mime;
+}
diff --git a/unix/xserver/hw/vnc/vncExtInit.h b/unix/xserver/hw/vnc/vncExtInit.h
index 943537d..0b4abfd 100644
--- a/unix/xserver/hw/vnc/vncExtInit.h
+++ b/unix/xserver/hw/vnc/vncExtInit.h
@@ -45,6 +45,13 @@ int vncNotifyQueryConnect(void);
extern void* vncFbptr[];
extern int vncFbstride[];
+struct dlp_mimetype_t {
+ char mime[32];
+};
+
+unsigned dlp_num_mimetypes();
+const char *dlp_get_mimetype(const unsigned i);
+
extern int vncInetdSock;
void vncExtensionInit(void);
@@ -60,9 +67,12 @@ int vncGetSendPrimary(void);
void vncUpdateDesktopName(void);
-void vncRequestClipboard(void);
void vncAnnounceClipboard(int available);
-void vncSendClipboardData(const char* data);
+void vncClearBinaryClipboardData();
+void vncSendBinaryClipboardData(const char* mime, const unsigned char *data,
+ const unsigned len);
+void vncGetBinaryClipboardData(const char *mime, const unsigned char **ptr,
+ unsigned *len);
int vncConnectClient(const char *addr);
diff --git a/unix/xserver/hw/vnc/vncSelection.c b/unix/xserver/hw/vnc/vncSelection.c
index 21a2a61..bdadd70 100644
--- a/unix/xserver/hw/vnc/vncSelection.c
+++ b/unix/xserver/hw/vnc/vncSelection.c
@@ -43,6 +43,14 @@
static Atom xaPRIMARY, xaCLIPBOARD;
static Atom xaTARGETS, xaTIMESTAMP, xaSTRING, xaTEXT, xaUTF8_STRING;
+static Atom xaINCR;
+static Atom *xaBinclips;
+static unsigned xaHtmlIndex, xaPngIndex;
+static Bool htmlPngPresent;
+
+static unsigned *mimeIndexesFromClient;
+static unsigned numMimesFromClient;
+static Bool textFromClient;
static WindowPtr pWindow;
static Window wid;
@@ -66,8 +74,7 @@ static int vncCreateSelectionWindow(void);
static int vncOwnSelection(Atom selection);
static int vncConvertSelection(ClientPtr client, Atom selection,
Atom target, Atom property,
- Window requestor, CARD32 time,
- const char* data, int len);
+ Window requestor, CARD32 time);
static int vncProcConvertSelection(ClientPtr client);
static void vncSelectionRequest(Atom selection, Atom target);
static int vncProcSendEvent(ClientPtr client);
@@ -90,6 +97,32 @@ void vncSelectionInit(void)
xaTEXT = MakeAtom("TEXT", 4, TRUE);
xaUTF8_STRING = MakeAtom("UTF8_STRING", 11, TRUE);
+ xaINCR = MakeAtom("INCR", 4, TRUE);
+
+ unsigned i;
+ mimeIndexesFromClient = calloc(dlp_num_mimetypes(), sizeof(unsigned));
+ numMimesFromClient = 0;
+ textFromClient = FALSE;
+ xaBinclips = calloc(dlp_num_mimetypes(), sizeof(Atom));
+ htmlPngPresent = FALSE;
+ Bool htmlfound = FALSE, pngfound = FALSE;
+ for (i = 0; i < dlp_num_mimetypes(); i++) {
+ const char *cur = dlp_get_mimetype(i);
+ xaBinclips[i] = MakeAtom(cur, strlen(cur), TRUE);
+
+ if (!strcmp(cur, "text/html")) {
+ xaHtmlIndex = i;
+ htmlfound = TRUE;
+ }
+ if (!strcmp(cur, "image/png")) {
+ xaPngIndex = i;
+ pngfound = TRUE;
+ }
+ }
+
+ if (htmlfound && pngfound)
+ htmlPngPresent = TRUE;
+
/* There are no hooks for when these are internal windows, so
* override the relevant handlers. */
origProcConvertSelection = ProcVector[X_ConvertSelection];
@@ -103,7 +136,7 @@ void vncSelectionInit(void)
FatalError("Add VNC ClientStateCallback failed\n");
}
-void vncHandleClipboardRequest(void)
+static void vncHandleClipboardRequest(void)
{
if (activeSelection == None) {
LOG_DEBUG("Got request for local clipboard although no clipboard is active");
@@ -161,24 +194,55 @@ void vncHandleClipboardAnnounce(int available)
}
}
-void vncHandleClipboardData(const char* data, int len)
+void vncHandleClipboardAnnounceBinary(const unsigned num, const char mimes[][32])
{
- struct VncDataTarget* next;
+ if (num) {
+ int rc;
- LOG_DEBUG("Got remote clipboard data, sending to X11 clients");
+ LOG_DEBUG("Remote binary clipboard announced, grabbing local ownership");
+
+ if (vncGetSetPrimary()) {
+ rc = vncOwnSelection(xaPRIMARY);
+ if (rc != Success)
+ LOG_ERROR("Could not set PRIMARY selection");
+ }
+
+ rc = vncOwnSelection(xaCLIPBOARD);
+ if (rc != Success)
+ LOG_ERROR("Could not set CLIPBOARD selection");
+
+ unsigned i, valid = 0;
+ for (i = 0; i < num; i++) {
+ unsigned j;
+ for (j = 0; j < dlp_num_mimetypes(); j++) {
+ if (!strcmp(dlp_get_mimetype(j), mimes[i])) {
+ mimeIndexesFromClient[valid] = j;
+ valid++;
+ break;
+ }
+ }
+
+ if (!strcmp(mimes[i], "text/plain"))
+ textFromClient = TRUE;
+ }
+ numMimesFromClient = valid;
+ LOG_DEBUG("Client sent %u mimes, %u were valid", num, valid);
+ } else {
+ struct VncDataTarget* next;
+ numMimesFromClient = 0;
+ textFromClient = FALSE;
+
+ if (pWindow == NULL)
+ return;
+
+ LOG_DEBUG("Remote binary clipboard lost, removing local ownership");
+
+ DeleteWindowFromAnySelections(pWindow);
+
+ /* Abort any pending transfer */
+ while (vncDataTargetHead != NULL) {
+ xEvent event;
- while (vncDataTargetHead != NULL) {
- int rc;
- xEvent event;
-
- rc = vncConvertSelection(vncDataTargetHead->client,
- vncDataTargetHead->selection,
- vncDataTargetHead->target,
- vncDataTargetHead->property,
- vncDataTargetHead->requestor,
- vncDataTargetHead->time,
- data, len);
- if (rc != Success) {
event.u.u.type = SelectionNotify;
event.u.selectionNotify.time = vncDataTargetHead->time;
event.u.selectionNotify.requestor = vncDataTargetHead->requestor;
@@ -186,11 +250,11 @@ void vncHandleClipboardData(const char* data, int len)
event.u.selectionNotify.target = vncDataTargetHead->target;
event.u.selectionNotify.property = None;
WriteEventsToClient(vncDataTargetHead->client, 1, &event);
- }
- next = vncDataTargetHead->next;
- free(vncDataTargetHead);
- vncDataTargetHead = next;
+ next = vncDataTargetHead->next;
+ free(vncDataTargetHead);
+ vncDataTargetHead = next;
+ }
}
}
@@ -277,10 +341,22 @@ static int vncOwnSelection(Atom selection)
return Success;
}
+static Bool clientHasBinaryAtom(const Atom target, unsigned *which)
+{
+ unsigned i;
+ for (i = 0; i < numMimesFromClient; i++) {
+ if (xaBinclips[mimeIndexesFromClient[i]] == target) {
+ *which = mimeIndexesFromClient[i];
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
static int vncConvertSelection(ClientPtr client, Atom selection,
Atom target, Atom property,
- Window requestor, CARD32 time,
- const char* data, int len)
+ Window requestor, CARD32 time)
{
Selection *pSel;
WindowPtr pWin;
@@ -290,13 +366,8 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
xEvent event;
- 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));
- }
+ LOG_DEBUG("Selection request for %s (type %s)",
+ NameForAtom(selection), NameForAtom(target));
rc = dixLookupSelection(&pSel, selection, client, DixGetAttrAccess);
if (rc != Success)
@@ -315,14 +386,23 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
realProperty = target;
/* FIXME: MULTIPLE target */
+ unsigned binatomidx;
if (target == xaTARGETS) {
- Atom targets[] = { xaTARGETS, xaTIMESTAMP,
- xaSTRING, xaTEXT, xaUTF8_STRING };
+ Atom targets[5 + numMimesFromClient];
+ targets[0] = xaTARGETS;
+ targets[1] = xaTIMESTAMP;
+ targets[2] = xaSTRING;
+ targets[3] = xaTEXT;
+ targets[4] = xaUTF8_STRING;
+
+ unsigned i;
+ for (i = 0; i < numMimesFromClient; i++)
+ targets[5 + i] = xaBinclips[mimeIndexesFromClient[i]];
rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
XA_ATOM, 32, PropModeReplace,
- sizeof(targets)/sizeof(targets[0]),
+ 5 + numMimesFromClient,
targets, TRUE);
if (rc != Success)
return rc;
@@ -333,59 +413,47 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
TRUE);
if (rc != Success)
return rc;
- } 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)
+ } else if (clientHasBinaryAtom(target, &binatomidx)) {
+ const unsigned char *data;
+ unsigned len;
+ vncGetBinaryClipboardData(dlp_get_mimetype(binatomidx), &data, &len);
+ rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
+ xaBinclips[binatomidx], 8, PropModeReplace,
+ len, (unsigned char *) data, TRUE);
+ if (rc != Success)
+ return rc;
+ } else if (textFromClient) {
+ const unsigned char *data;
+ unsigned len;
+ vncGetBinaryClipboardData("text/plain", &data, &len);
+
+ if ((target == xaSTRING) || (target == xaTEXT)) {
+ char* latin1;
+ latin1 = vncUTF8ToLatin1(data, (size_t)-1);
+ if (latin1 == 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;
+ rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
+ XA_STRING, 8, PropModeReplace,
+ len, latin1, TRUE);
- LOG_DEBUG("Requesting clipboard data from client");
+ vncStrFree(latin1);
- vncRequestClipboard();
-
- return Success;
+ if (rc != Success)
+ return rc;
+ } else if (target == xaUTF8_STRING) {
+ rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
+ xaUTF8_STRING, 8, PropModeReplace,
+ len, (char *) data, TRUE);
+ if (rc != Success)
+ return rc;
} 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,
- len, latin1, TRUE);
-
- vncStrFree(latin1);
-
- if (rc != Success)
- return rc;
- } else if (target == xaUTF8_STRING) {
- rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
- xaUTF8_STRING, 8, PropModeReplace,
- len, data, TRUE);
- if (rc != Success)
- return rc;
- } else {
- return BadMatch;
- }
+ return BadMatch;
}
+ } else {
+ LOG_ERROR("Text clipboard paste requested, but client sent no text");
+
+ return BadMatch;
}
event.u.u.type = SelectionNotify;
@@ -424,7 +492,7 @@ static int vncProcConvertSelection(ClientPtr client)
pSel->window == wid) {
rc = vncConvertSelection(client, stuff->selection,
stuff->target, stuff->property,
- stuff->requestor, stuff->time, NULL, 0);
+ stuff->requestor, stuff->time);
if (rc != Success) {
xEvent event;
@@ -483,6 +551,21 @@ static Bool vncHasAtom(Atom atom, const Atom list[], size_t size)
return FALSE;
}
+static Bool vncHasBinaryClipboardAtom(const Atom list[], size_t size)
+{
+ size_t i, b;
+ const unsigned num = dlp_num_mimetypes();
+
+ for (i = 0;i < size;i++) {
+ for (b = 0; b < num; b++) {
+ if (list[i] == xaBinclips[b])
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
static void vncHandleSelection(Atom selection, Atom target,
Atom property, Atom requestor,
TimeStamp time)
@@ -502,6 +585,9 @@ static void vncHandleSelection(Atom selection, Atom target,
if (target != property)
return;
+ if (prop->type == xaINCR)
+ LOG_INFO("Incremental clipboard transfer denied, too large");
+
if (target == xaTARGETS) {
if (prop->format != 32)
return;
@@ -510,16 +596,36 @@ static void vncHandleSelection(Atom selection, Atom target,
if (probing) {
if (vncHasAtom(xaSTRING, (const Atom*)prop->data, prop->size) ||
- vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size)) {
+ vncHasAtom(xaUTF8_STRING, (const Atom*)prop->data, prop->size) ||
+ vncHasBinaryClipboardAtom((const Atom*)prop->data, prop->size)) {
LOG_DEBUG("Compatible format found, notifying clients");
+ vncClearBinaryClipboardData();
activeSelection = selection;
vncAnnounceClipboard(TRUE);
+ vncHandleClipboardRequest();
}
} 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);
+
+ unsigned i;
+
+ Bool skiphtml = FALSE;
+ if (htmlPngPresent &&
+ vncHasAtom(xaBinclips[xaHtmlIndex], (const Atom*)prop->data, prop->size) &&
+ vncHasAtom(xaBinclips[xaPngIndex], (const Atom*)prop->data, prop->size))
+ skiphtml = TRUE;
+
+ for (i = 0; i < dlp_num_mimetypes(); i++) {
+ if (skiphtml && i == xaHtmlIndex)
+ continue;
+ if (vncHasAtom(xaBinclips[i], (const Atom*)prop->data, prop->size)) {
+ vncSelectionRequest(selection, xaBinclips[i]);
+ //break;
+ }
+ }
}
} else if (target == xaSTRING) {
char* filtered;
@@ -539,10 +645,10 @@ static void vncHandleSelection(Atom selection, Atom target,
if (utf8 == NULL)
return;
- LOG_DEBUG("Sending clipboard to clients (%d bytes)",
+ LOG_DEBUG("Sending text part of binary clipboard to clients (%d bytes)",
(int)strlen(utf8));
- vncSendClipboardData(utf8);
+ vncSendBinaryClipboardData("text/plain", utf8, strlen(utf8));
vncStrFree(utf8);
} else if (target == xaUTF8_STRING) {
@@ -557,12 +663,31 @@ static void vncHandleSelection(Atom selection, Atom target,
if (filtered == NULL)
return;
- LOG_DEBUG("Sending clipboard to clients (%d bytes)",
+ LOG_DEBUG("Sending text part of binary clipboard to clients (%d bytes)",
(int)strlen(filtered));
- vncSendClipboardData(filtered);
+ vncSendBinaryClipboardData("text/plain", filtered, strlen(filtered));
vncStrFree(filtered);
+ } else {
+ unsigned i;
+
+ if (prop->format != 8)
+ return;
+
+ for (i = 0; i < dlp_num_mimetypes(); i++) {
+ if (target == xaBinclips[i]) {
+ if (prop->type != xaBinclips[i])
+ return;
+
+ LOG_DEBUG("Sending binary clipboard to clients (%d bytes)",
+ prop->size);
+
+ vncSendBinaryClipboardData(dlp_get_mimetype(i), prop->data, prop->size);
+
+ break;
+ }
+ }
}
}
diff --git a/unix/xserver/hw/vnc/vncSelection.h b/unix/xserver/hw/vnc/vncSelection.h
index 337f9bf..68266bf 100644
--- a/unix/xserver/hw/vnc/vncSelection.h
+++ b/unix/xserver/hw/vnc/vncSelection.h
@@ -24,9 +24,8 @@ extern "C" {
void vncSelectionInit(void);
-void vncHandleClipboardRequest(void);
void vncHandleClipboardAnnounce(int available);
-void vncHandleClipboardData(const char* data, int len);
+void vncHandleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]);
#ifdef __cplusplus
}