@@ -1446,6 +1446,12 @@ SetFormatAndEncodings(rfbClient* client)
14461446 if (se -> nEncodings < MAX_ENCODINGS )
14471447 encs [se -> nEncodings ++ ] = rfbClientSwap32IfLE (rfbEncodingQemuExtendedKeyEvent );
14481448
1449+ #ifdef LIBVNCSERVER_HAVE_LIBZ
1450+ /* extendedclipboard */
1451+ if (se -> nEncodings < MAX_ENCODINGS )
1452+ encs [se -> nEncodings ++ ] = rfbClientSwap32IfLE (rfbEncodingExtendedClipboard );
1453+ #endif
1454+
14491455 /* client extensions */
14501456 for (e = rfbClientExtensions ; e ; e = e -> next )
14511457 if (e -> encodings ) {
@@ -1769,6 +1775,78 @@ SendExtendedKeyEvent(rfbClient* client, uint32_t keysym, uint32_t keycode, rfbBo
17691775}
17701776
17711777
1778+ #ifdef LIBVNCSERVER_HAVE_LIBZ
1779+ /*
1780+ * sendExtClientCutTextNotify
1781+ * it is needed when client send utf8 clipboard data
1782+ * please refer to
1783+ * https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#extended-clipboard-pseudo-encoding
1784+ * to supprot utf-8 clipboard we need at least support notify and text
1785+ */
1786+
1787+ static rfbBool
1788+ sendExtClientCutTextNotify (rfbClient * client )
1789+ {
1790+ rfbClientCutTextMsg cct = {0 , };
1791+ const uint32_t be_flags = rfbClientSwap32IfLE (rfbExtendedClipboard_Notify
1792+ | rfbExtendedClipboard_Text ); /*text and notify*/
1793+ cct .type = rfbClientCutText ;
1794+ cct .length = rfbClientSwap32IfLE (- ((uint32_t )sizeof (be_flags )));/*flag*/
1795+ rfbBool ret = WriteToRFBServer (client , (char * )& cct , sz_rfbClientCutTextMsg )
1796+ && WriteToRFBServer (client , (char * )& be_flags , sizeof (be_flags ));
1797+ return ret ;
1798+ }
1799+
1800+
1801+ /*
1802+ * sendExtClientCutTextProvide
1803+ * it need send notify first to grab clipboard (server will check that)
1804+ */
1805+
1806+ static rfbBool
1807+ sendExtClientCutTextProvide (rfbClient * client , char * data , int len )
1808+ {
1809+ rfbClientCutTextMsg cct = {0 , };
1810+ const uint32_t be_flags = rfbClientSwap32IfLE (rfbExtendedClipboard_Provide
1811+ | rfbExtendedClipboard_Text ); /*text and provide*/
1812+ const uint32_t be_size = rfbClientSwap32IfLE (len );
1813+ const size_t sz_to_compressed = sizeof (be_size ) + len ; /*size, data*/
1814+ size_t csz = compressBound (sz_to_compressed + 1 ); /*tricky, some server need extar byte to flush data*/
1815+
1816+ unsigned char * buf = malloc (sz_to_compressed + 1 ); /*tricky, some server need extra byte to flush data*/
1817+ if (!buf ) {
1818+ rfbClientLog ("sendExtClientCutTextProvide. alloc buf failed\n" );
1819+ return FALSE;
1820+ }
1821+ memcpy (buf , & be_size , sizeof (be_size ));
1822+ memcpy (buf + sizeof (be_size ), data , len );
1823+ buf [sz_to_compressed ] = 0 ;
1824+
1825+ unsigned char * cbuf = malloc (sizeof (be_flags ) + csz ); /*flag, compressed*/
1826+ if (!cbuf ) {
1827+ rfbClientLog ("sendExtClientCutTextProvide. alloc cbuf failed\n" );
1828+ free (buf );
1829+ return FALSE;
1830+ }
1831+ memcpy (cbuf , & be_flags , sizeof (be_flags ));
1832+ if (compress (cbuf + sizeof (be_flags ), & csz , buf , sz_to_compressed + 1 ) != Z_OK ) {
1833+ rfbClientLog ("sendExtClientCutTextProvide: compress cbuf failed\n" );
1834+ free (buf );
1835+ free (cbuf );
1836+ return FALSE;
1837+ }
1838+
1839+ cct .type = rfbClientCutText ;
1840+ cct .length = rfbClientSwap32IfLE (- (sizeof (be_flags ) + csz ));/*flag, compressed*/
1841+ rfbBool ret = sendExtClientCutTextNotify (client )
1842+ && WriteToRFBServer (client , (char * )& cct , sz_rfbClientCutTextMsg )
1843+ && WriteToRFBServer (client , (char * )cbuf , sizeof (be_flags ) + csz );
1844+ free (buf );
1845+ free (cbuf );
1846+ return ret ;
1847+ }
1848+ #endif
1849+
17721850/*
17731851 * SendClientCutText.
17741852 */
@@ -1787,6 +1865,111 @@ SendClientCutText(rfbClient* client, char *str, int len)
17871865 WriteToRFBServer (client , str , len ));
17881866}
17891867
1868+ rfbBool
1869+ SendClientCutTextUTF8 (rfbClient * client , char * str , int len )
1870+ {
1871+ #ifdef LIBVNCSERVER_HAVE_LIBZ
1872+ return client -> extendedClipboardServerCapabilities && sendExtClientCutTextProvide (client , str , len );
1873+ #else
1874+ return FALSE;
1875+ #endif
1876+ }
1877+
1878+
1879+ #ifdef LIBVNCSERVER_HAVE_LIBZ
1880+ /*
1881+ * process server clipboard extend text
1882+ */
1883+
1884+ static rfbBool
1885+ rfbClientProcessExtServerCutText (rfbClient * client , char * data , int len )
1886+ {
1887+ uint32_t flags ;
1888+ if (len < sizeof (flags )) {
1889+ rfbClientLog ("rfbClientProcessExtServerCutText. len < 4\n" );
1890+ return FALSE;
1891+ }
1892+ memcpy (& flags , data , sizeof (flags ));
1893+ data += sizeof (flags );
1894+ len -= sizeof (flags );
1895+ flags = rfbClientSwap32IfLE (flags );
1896+
1897+ /*
1898+ * only process (text | provide). Ignore all others
1899+ * modify here if need more types(rtf,html,dib,files)
1900+ */
1901+ if (!(flags & rfbExtendedClipboard_Text )) {
1902+ rfbClientLog ("rfbClientProcessExtServerCutText. not text type. ignore\n" );
1903+ return TRUE;
1904+ }
1905+ if (!(flags & rfbExtendedClipboard_Provide )) {
1906+ rfbClientLog ("rfbClientProcessExtServerCutText. not provide type. ignore\n" );
1907+ return TRUE;
1908+ }
1909+ if (flags & rfbExtendedClipboard_Caps ) {
1910+ rfbClientLog ("rfbClientProcessExtServerCutText. default cap.\n" );
1911+ client -> extendedClipboardServerCapabilities |= rfbExtendedClipboard_Text ; /* for now, only text */
1912+ return TRUE;
1913+ }
1914+
1915+ z_stream stream ;
1916+ stream .zalloc = NULL ;
1917+ stream .zfree = NULL ;
1918+ stream .opaque = NULL ;
1919+ stream .avail_in = 0 ;
1920+ stream .next_in = NULL ;
1921+ if (inflateInit (& stream ) != Z_OK ) {
1922+ rfbClientLog ("rfbClientProcessExtServerCutText. inflateInit failed\n" );
1923+ return FALSE;
1924+ }
1925+ stream .avail_in = len ;
1926+ stream .next_in = (unsigned char * )data ;
1927+
1928+ uint32_t size ;
1929+ stream .avail_out = sizeof (size );
1930+ stream .next_out = (unsigned char * )& size ;
1931+ if (inflate (& stream , Z_SYNC_FLUSH ) != Z_OK ) {
1932+ rfbClientLog ("rfbClientProcessExtServerCutText. inflate size failed\n" );
1933+ inflateEnd (& stream );
1934+ return FALSE;
1935+ }
1936+ size = rfbClientSwap32IfLE (size );
1937+ if (size > (1 << 20 )) {
1938+ rfbClientLog ("rfbClientProcessExtServerCutText. size too large\n" );
1939+ inflateEnd (& stream );
1940+ return FALSE;
1941+ }
1942+
1943+ unsigned char * buf = malloc (size );
1944+ if (!buf ) {
1945+ rfbClientLog ("rfbClientProcessExtServerCutText. alloc buf failed\n" );
1946+ inflateEnd (& stream );
1947+ return FALSE;
1948+ }
1949+ stream .avail_out = size ;
1950+ stream .next_out = buf ;
1951+ uLong out_before = stream .total_out ;
1952+ int err = inflate (& stream , Z_SYNC_FLUSH );
1953+ if (err != Z_OK && err != Z_STREAM_END ) {
1954+ rfbClientLog ("rfbClientProcessExtServerCutText. inflate buf failed\n" );
1955+ free (buf );
1956+ inflateEnd (& stream );
1957+ return FALSE;
1958+ }
1959+ if ((stream .total_out - out_before ) != size ) {
1960+ rfbClientLog ("rfbClientProcessExtServerCutText. inflate size error\n" );
1961+ free (buf );
1962+ inflateEnd (& stream );
1963+ return FALSE;
1964+ }
1965+ if (client -> GotXCutTextUTF8 )
1966+ client -> GotXCutTextUTF8 (client , buf , size );
1967+ free (buf );
1968+
1969+ inflateEnd (& stream );
1970+ return TRUE;
1971+ }
1972+ #endif
17901973
17911974
17921975/*
@@ -2332,12 +2515,20 @@ HandleRFBServerMessage(rfbClient* client)
23322515 case rfbServerCutText :
23332516 {
23342517 char * buffer ;
2518+ #ifdef LIBVNCSERVER_HAVE_LIBZ
2519+ int32_t ilen ; /* also as a flag, if ilen < 0, it is ext clipboard text */
2520+ #endif
23352521
23362522 if (!ReadFromRFBServer (client , ((char * )& msg ) + 1 ,
23372523 sz_rfbServerCutTextMsg - 1 ))
23382524 return FALSE;
23392525
2526+ #ifdef LIBVNCSERVER_HAVE_LIBZ
2527+ ilen = rfbClientSwap32IfLE (msg .sct .length );
2528+ msg .sct .length = ilen < 0 ? - ilen : ilen ;
2529+ #else
23402530 msg .sct .length = rfbClientSwap32IfLE (msg .sct .length );
2531+ #endif
23412532
23422533 if (msg .sct .length > 1 <<20 ) {
23432534 rfbClientErr ("Ignoring too big cut text length sent by server: %u B > 1 MB\n" , (unsigned int )msg .sct .length );
@@ -2353,8 +2544,18 @@ HandleRFBServerMessage(rfbClient* client)
23532544
23542545 buffer [msg .sct .length ] = 0 ;
23552546
2547+ #ifdef LIBVNCSERVER_HAVE_LIBZ
2548+ if (ilen < 0 && client -> GotXCutTextUTF8 ) {
2549+ if (!rfbClientProcessExtServerCutText (client , buffer , - ilen )) {
2550+ free (buffer );
2551+ return FALSE;
2552+ }
2553+ } else if (client -> GotXCutText )
2554+ client -> GotXCutText (client , buffer , msg .sct .length );
2555+ #else
23562556 if (client -> GotXCutText )
23572557 client -> GotXCutText (client , buffer , msg .sct .length );
2558+ #endif
23582559
23592560 free (buffer );
23602561
0 commit comments