diff --git a/common/network/GetAPI.h b/common/network/GetAPI.h index f02c75e..5b6c7ed 100644 --- a/common/network/GetAPI.h +++ b/common/network/GetAPI.h @@ -66,6 +66,7 @@ namespace network { void netResetFrameStatsCall(); uint8_t netServerFrameStatsReady(); void netUdpUpgrade(void *client, uint32_t ip); + void netClearClipboard(); enum USER_ACTION { NONE, @@ -73,7 +74,8 @@ namespace network { WANT_FRAME_STATS_ALL, WANT_FRAME_STATS_OWNER, WANT_FRAME_STATS_SPECIFIC, - UDP_UPGRADE + UDP_UPGRADE, + CLEAR_CLIPBOARD, }; uint8_t netRequestFrameStats(USER_ACTION what, const char *client); diff --git a/common/network/GetAPIMessager.cxx b/common/network/GetAPIMessager.cxx index 0fb2ee0..17e53cd 100644 --- a/common/network/GetAPIMessager.cxx +++ b/common/network/GetAPIMessager.cxx @@ -806,3 +806,16 @@ void GetAPIMessager::netUdpUpgrade(void *client, uint32_t ip) { pthread_mutex_unlock(&userMutex); } + +void GetAPIMessager::netClearClipboard() { + action_data act; + act.action = CLEAR_CLIPBOARD; + + // Send it in + if (pthread_mutex_lock(&userMutex)) + return; + + actionQueue.push_back(act); + + pthread_mutex_unlock(&userMutex); +} diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx index faa80f1..db13ec7 100644 --- a/common/network/TcpSocket.cxx +++ b/common/network/TcpSocket.cxx @@ -545,6 +545,12 @@ static uint8_t serverFrameStatsReadyCb(void *messager) return msgr->netServerFrameStatsReady(); } +static void clearClipboardCb(void *messager) +{ + GetAPIMessager *msgr = (GetAPIMessager *) messager; + msgr->netClearClipboard(); +} + #if OPENSSL_VERSION_NUMBER < 0x1010000f static pthread_mutex_t *sslmutex; @@ -693,6 +699,8 @@ WebsocketListener::WebsocketListener(const struct sockaddr *listenaddr, settings.getClientFrameStatsNumCb = getClientFrameStatsNumCb; settings.serverFrameStatsReadyCb = serverFrameStatsReadyCb; + settings.clearClipboardCb = clearClipboardCb; + openssl_threads(); pthread_t tid; diff --git a/common/network/websocket.c b/common/network/websocket.c index 52c5183..816eb2e 100644 --- a/common/network/websocket.c +++ b/common/network/websocket.c @@ -1596,6 +1596,22 @@ static uint8_t ownerapi(ws_ctx_t *ws_ctx, const char *in, const char * const use ws_send(ws_ctx, buf, strlen(buf)); weblog(200, wsthread_handler_id, 0, origip, ip, user, 1, origpath, strlen(buf)); + ret = 1; + } else entry("/api/clear_clipboard") { + settings.clearClipboardCb(settings.messager); + write(wakeuppipe[1], "", 1); + + sprintf(buf, "HTTP/1.1 200 OK\r\n" + "Server: KasmVNC/4.0\r\n" + "Connection: close\r\n" + "Content-type: text/plain\r\n" + "Content-length: 6\r\n" + "%s" + "\r\n" + "200 OK", extra_headers ? extra_headers : ""); + ws_send(ws_ctx, buf, strlen(buf)); + weblog(200, wsthread_handler_id, 0, origip, ip, user, 1, origpath, strlen(buf)); + ret = 1; } diff --git a/common/network/websocket.h b/common/network/websocket.h index 00d72e2..b5fc674 100644 --- a/common/network/websocket.h +++ b/common/network/websocket.h @@ -105,6 +105,8 @@ typedef struct { void (*getUsersCb)(void *messager, const char **buf); uint8_t (*getClientFrameStatsNumCb)(void *messager); uint8_t (*serverFrameStatsReadyCb)(void *messager); + + void (*clearClipboardCb)(void *messager); } settings_t; #ifdef __cplusplus diff --git a/common/rfb/SDesktop.h b/common/rfb/SDesktop.h index 5696cfd..7afc14c 100644 --- a/common/rfb/SDesktop.h +++ b/common/rfb/SDesktop.h @@ -86,6 +86,8 @@ namespace rfb { virtual void handleClipboardAnnounceBinary(const unsigned __unused_attr num, const char __unused_attr mimes[][32]) {} + virtual void clearLocalClipboards() {} + protected: virtual ~SDesktop() {} }; diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index 419e543..7abd972 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -832,9 +832,8 @@ static void upgradeClientToUdp(const network::GetAPIMessager::action_data &act, } } -static void checkAPIMessages(network::GetAPIMessager *apimessager, - rdr::U8 &trackingFrameStats, char trackingClient[], - std::list &clients) +void VNCServerST::checkAPIMessages(network::GetAPIMessager *apimessager, + rdr::U8 &trackingFrameStats, char trackingClient[]) { if (pthread_mutex_lock(&apimessager->userMutex)) return; @@ -866,6 +865,15 @@ static void checkAPIMessages(network::GetAPIMessager *apimessager, case network::GetAPIMessager::UDP_UPGRADE: upgradeClientToUdp(act, clients); break; + case network::GetAPIMessager::CLEAR_CLIPBOARD: + clearBinaryClipboardData(); + clipboardClient = NULL; + desktop->handleClipboardAnnounceBinary(0, NULL); + + sendBinaryClipboardData("text/plain", NULL, 0); + + desktop->clearLocalClipboards(); + break; } } @@ -1031,7 +1039,7 @@ void VNCServerST::writeUpdate() shottime = msSince(&shotstart); trackingFrameStats = 0; - checkAPIMessages(apimessager, trackingFrameStats, trackingClient, clients); + checkAPIMessages(apimessager, trackingFrameStats, trackingClient); } const rdr::U8 origtrackingFrameStats = trackingFrameStats; diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index e36412a..bdd43b0 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -284,6 +284,9 @@ namespace rfb { void translateDLPRegion(rdr::U16 &x1, rdr::U16 &y1, rdr::U16 &x2, rdr::U16 &y2) const; rdr::U32 clipboardId; + + void checkAPIMessages(network::GetAPIMessager *apimessager, + rdr::U8 &trackingFrameStats, char trackingClient[]); }; }; diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc index a3aa73a..605e228 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.cc +++ b/unix/xserver/hw/vnc/XserverDesktop.cc @@ -182,6 +182,11 @@ XserverDesktop::queryConnection(network::Socket* sock, return rfb::VNCServerST::PENDING; } +void XserverDesktop::clearLocalClipboards() +{ + vncClearLocalClipboards(); +} + void XserverDesktop::announceClipboard(bool available) { try { diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h index 32a204b..de9baa7 100644 --- a/unix/xserver/hw/vnc/XserverDesktop.h +++ b/unix/xserver/hw/vnc/XserverDesktop.h @@ -61,6 +61,7 @@ public: void setFramebuffer(int w, int h, void* fbptr, int stride); void refreshScreenLayout(); void requestClipboard(); + void clearLocalClipboards(); void announceClipboard(bool available); void clearBinaryClipboardData(); void sendBinaryClipboardData(const char* mime, const unsigned char *data, diff --git a/unix/xserver/hw/vnc/vncSelection.c b/unix/xserver/hw/vnc/vncSelection.c index c4a90bf..103535f 100644 --- a/unix/xserver/hw/vnc/vncSelection.c +++ b/unix/xserver/hw/vnc/vncSelection.c @@ -763,3 +763,42 @@ static void vncClientStateCallback(CallbackListPtr * l, } } } + +static void vncClearLocalClipboard(Atom selection) +{ + SelectionInfoRec info; + Selection *pSel; + int rc; + + rc = dixLookupSelection(&pSel, selection, serverClient, DixSetAttrAccess); + if (rc != Success) + return; + + if (pSel->client && (pSel->client != serverClient)) { + xEvent event = { + .u.selectionClear.time = currentTime.milliseconds, + .u.selectionClear.window = pSel->window, + .u.selectionClear.atom = pSel->selection + }; + event.u.u.type = SelectionClear; + WriteEventsToClient(pSel->client, 1, &event); + } + + pSel->lastTimeChanged = currentTime; + pSel->window = None; + pSel->pWin = NULL; + pSel->client = NullClient; + + LOG_DEBUG("Cleared %s selection", NameForAtom(selection)); + + info.selection = pSel; + info.client = serverClient; + info.kind = SelectionSetOwner; + CallCallbacks(&SelectionCallback, &info); +} + +void vncClearLocalClipboards() +{ + vncClearLocalClipboard(xaPRIMARY); + vncClearLocalClipboard(xaCLIPBOARD); +} diff --git a/unix/xserver/hw/vnc/vncSelection.h b/unix/xserver/hw/vnc/vncSelection.h index 68266bf..f929c18 100644 --- a/unix/xserver/hw/vnc/vncSelection.h +++ b/unix/xserver/hw/vnc/vncSelection.h @@ -26,6 +26,7 @@ void vncSelectionInit(void); void vncHandleClipboardAnnounce(int available); void vncHandleClipboardAnnounceBinary(const unsigned num, const char mimes[][32]); +void vncClearLocalClipboards(); #ifdef __cplusplus }