]> source.dussan.org Git - tigervnc.git/commitdiff
Handle unsolicited clipboard transfers
authorPierre Ossman <ossman@cendio.se>
Mon, 4 Jan 2021 12:04:26 +0000 (13:04 +0100)
committerPierre Ossman <ossman@cendio.se>
Mon, 4 Jan 2021 12:04:26 +0000 (13:04 +0100)
The extended clipboard protocol has the ability for the peer to request
things to be sent automatically, without a request message. Make sure we
honor such settings.

common/rfb/CConnection.cxx
common/rfb/CConnection.h
common/rfb/ClientParams.cxx
common/rfb/ClientParams.h
common/rfb/SConnection.cxx
common/rfb/SConnection.h
common/rfb/ServerParams.cxx
common/rfb/ServerParams.h

index bdde32538271381e7b2fb80a6422f535a7dffb09..538d90a821985ba75bde0fe2a6d45ed82cadc7a6 100644 (file)
@@ -578,13 +578,25 @@ void CConnection::requestClipboard()
 void CConnection::announceClipboard(bool available)
 {
   hasLocalClipboard = available;
+  unsolicitedClipboardAttempt = false;
+
+  // Attempt an unsolicited transfer?
+  if (available &&
+      (server.clipboardSize(rfb::clipboardUTF8) > 0) &&
+      (server.clipboardFlags() & rfb::clipboardProvide)) {
+    vlog.debug("Attempting unsolicited clipboard transfer...");
+    unsolicitedClipboardAttempt = true;
+    handleClipboardRequest();
+    return;
+  }
 
-  if (server.clipboardFlags() & rfb::clipboardNotify)
+  if (server.clipboardFlags() & rfb::clipboardNotify) {
     writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
-  else {
-    if (available)
-      handleClipboardRequest();
+    return;
   }
+
+  if (available)
+    handleClipboardRequest();
 }
 
 void CConnection::sendClipboardData(const char* data)
@@ -593,6 +605,17 @@ void CConnection::sendClipboardData(const char* data)
     CharArray filtered(convertCRLF(data));
     size_t sizes[1] = { strlen(filtered.buf) + 1 };
     const rdr::U8* data[1] = { (const rdr::U8*)filtered.buf };
+
+    if (unsolicitedClipboardAttempt) {
+      unsolicitedClipboardAttempt = false;
+      if (sizes[0] > server.clipboardSize(rfb::clipboardUTF8)) {
+        vlog.debug("Clipboard was too large for unsolicited clipboard transfer");
+        if (server.clipboardFlags() & rfb::clipboardNotify)
+          writer()->writeClipboardNotify(rfb::clipboardUTF8);
+        return;
+      }
+    }
+
     writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data);
   } else {
     CharArray latin1(utf8ToLatin1(data));
index f01d5d362101d3f2470c5e8a931f00d1131fb021..ca76f53036d309993a48494466c5578c5c255901 100644 (file)
@@ -287,6 +287,7 @@ namespace rfb {
 
     char* serverClipboard;
     bool hasLocalClipboard;
+    bool unsolicitedClipboardAttempt;
   };
 }
 #endif
index 987abe32e4392f30496ad60076a73933f6b68821..6f075a2461673392a2e364160fc7913fc20d3be3 100644 (file)
@@ -143,6 +143,18 @@ void ClientParams::setLEDState(unsigned int state)
   ledState_ = state;
 }
 
+rdr::U32 ClientParams::clipboardSize(unsigned int format) const
+{
+  int i;
+
+  for (i = 0;i < 16;i++) {
+    if (((unsigned)1 << i) == format)
+      return clipSizes[i];
+  }
+
+  throw Exception("Invalid clipboard format 0x%x", format);
+}
+
 void ClientParams::setClipboardCaps(rdr::U32 flags, const rdr::U32* lengths)
 {
   int i, num;
index aab3d644a77ea780f49af4177da0093d817e6abd..3894ef2dd58e70a36f88f4806d5595e0634efe15 100644 (file)
@@ -85,6 +85,7 @@ namespace rfb {
     void setLEDState(unsigned int state);
 
     rdr::U32 clipboardFlags() const { return clipFlags; }
+    rdr::U32 clipboardSize(unsigned int format) const;
     void setClipboardCaps(rdr::U32 flags, const rdr::U32* lengths);
 
     // Wrappers to check for functionality rather than specific
index 4869199a088328ebd8d649f452ea95401000405c..1b5f513e10764cb63c1e597d19fe350ddfe04223 100644 (file)
@@ -54,7 +54,8 @@ SConnection::SConnection()
     is(0), os(0), reader_(0), writer_(0),
     ssecurity(0), state_(RFBSTATE_UNINITIALISED),
     preferredEncoding(encodingRaw),
-    clientClipboard(NULL), hasLocalClipboard(false)
+    clientClipboard(NULL), hasLocalClipboard(false),
+    unsolicitedClipboardAttempt(false)
 {
   defaultMajorVersion = 3;
   defaultMinorVersion = 8;
@@ -503,14 +504,27 @@ void SConnection::requestClipboard()
 void SConnection::announceClipboard(bool available)
 {
   hasLocalClipboard = available;
+  unsolicitedClipboardAttempt = false;
 
-  if (client.supportsEncoding(pseudoEncodingExtendedClipboard) &&
-      (client.clipboardFlags() & rfb::clipboardNotify))
-    writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
-  else {
-    if (available)
+  if (client.supportsEncoding(pseudoEncodingExtendedClipboard)) {
+    // Attempt an unsolicited transfer?
+    if (available &&
+        (client.clipboardSize(rfb::clipboardUTF8) > 0) &&
+        (client.clipboardFlags() & rfb::clipboardProvide)) {
+      vlog.debug("Attempting unsolicited clipboard transfer...");
+      unsolicitedClipboardAttempt = true;
       handleClipboardRequest();
+      return;
+    }
+
+    if (client.clipboardFlags() & rfb::clipboardNotify) {
+      writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
+      return;
+    }
   }
+
+  if (available)
+    handleClipboardRequest();
 }
 
 void SConnection::sendClipboardData(const char* data)
@@ -520,6 +534,17 @@ void SConnection::sendClipboardData(const char* data)
     CharArray filtered(convertCRLF(data));
     size_t sizes[1] = { strlen(filtered.buf) + 1 };
     const rdr::U8* data[1] = { (const rdr::U8*)filtered.buf };
+
+    if (unsolicitedClipboardAttempt) {
+      unsolicitedClipboardAttempt = false;
+      if (sizes[0] > client.clipboardSize(rfb::clipboardUTF8)) {
+        vlog.debug("Clipboard was too large for unsolicited clipboard transfer");
+        if (client.clipboardFlags() & rfb::clipboardNotify)
+          writer()->writeClipboardNotify(rfb::clipboardUTF8);
+        return;
+      }
+    }
+
     writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data);
   } else {
     CharArray latin1(utf8ToLatin1(data));
index db3ab08c8fbf227d04e223d42c4f0510e7ffbf30..1119c7c9494b1e01219cc7febb78833af525b4d2 100644 (file)
@@ -255,6 +255,7 @@ namespace rfb {
 
     char* clientClipboard;
     bool hasLocalClipboard;
+    bool unsolicitedClipboardAttempt;
   };
 }
 #endif
index a2e3aa8354235c010720f3e519817b5a02efd3f9..a9a96b6e74488af09c1be7e80e4080c17cd23fd6 100644 (file)
@@ -87,6 +87,18 @@ void ServerParams::setLEDState(unsigned int state)
   ledState_ = state;
 }
 
+rdr::U32 ServerParams::clipboardSize(unsigned int format) const
+{
+  int i;
+
+  for (i = 0;i < 16;i++) {
+    if (((unsigned)1 << i) == format)
+      return clipSizes[i];
+  }
+
+  throw Exception("Invalid clipboard format 0x%x", format);
+}
+
 void ServerParams::setClipboardCaps(rdr::U32 flags, const rdr::U32* lengths)
 {
   int i, num;
index c84f6252ffa8050cde59e37f4a02c8a7d5532c79..ce0c722f17ee0ead444747f1a5b2028e61c85036 100644 (file)
@@ -70,6 +70,7 @@ namespace rfb {
     void setLEDState(unsigned int state);
 
     rdr::U32 clipboardFlags() const { return clipFlags; }
+    rdr::U32 clipboardSize(unsigned int format) const;
     void setClipboardCaps(rdr::U32 flags, const rdr::U32* lengths);
 
     bool supportsQEMUKeyEvent;