@@ -230,6 +230,7 @@ void guac_terminal_reset(guac_terminal* term) {
230230    term -> application_cursor_keys  =  false;
231231    term -> automatic_carriage_return  =  false;
232232    term -> insert_mode  =  false;
233+     term -> bracketed_paste_mode  =  false;
233234
234235    /* Reset tabs */ 
235236    term -> tab_interval  =  8 ;
@@ -1500,6 +1501,87 @@ int guac_terminal_send_string(guac_terminal* term, const char* data) {
15001501
15011502}
15021503
1504+ int  guac_terminal_send_clipboard (guac_terminal  * term ) {
1505+     char  * filtered  =  guac_mem_alloc (term -> clipboard -> length  +  12 );
1506+     uint8_t  * src_ptr  =  (uint8_t  * )term -> clipboard -> buffer ;
1507+     uint8_t  * src_end  =  (uint8_t  * )(term -> clipboard -> buffer  +  term -> clipboard -> length );
1508+     uint8_t  * dst_ptr  =  (uint8_t  * )filtered ;
1509+     int  filtered_len  =  0 ;
1510+ 
1511+     /* Send the paste start sequence */ 
1512+     if  (term -> bracketed_paste_mode ) {
1513+         memcpy (dst_ptr , "\x1B[200~" , 6 );
1514+         dst_ptr  +=  6 ;
1515+         filtered_len  +=  6 ;
1516+     }
1517+ 
1518+     while  (src_ptr  <  src_end ) {
1519+ 
1520+         /* Exclude Unicode CO and C1 control characters except tab, line feed 
1521+          * and carriage return. */ 
1522+         bool  is_control  =  (((* src_ptr  >= 0x00 ) &&  (* src_ptr  <  0x20 )) || 
1523+                 ((* src_ptr  >= 0x80 ) &&  (* src_ptr  <  0xa0 ))) && 
1524+                 (* src_ptr  !=  0x09 ) &&  (* src_ptr  !=  0x0a ) &&  (* src_ptr  !=  0x0d );
1525+ 
1526+         /* Allow UTF-8 codepoints */ 
1527+         if  ((* src_ptr  &  0xe0 ) ==  0xc0 ) {
1528+ 
1529+             /* UTF-8 2-byte codepoint */ 
1530+             if  ((src_ptr  +  1  <  src_end ) &&  ((src_ptr [1 ] &  0xc0 ) ==  0x80 )) {
1531+                 dst_ptr [0 ] =  src_ptr [0 ];
1532+                 dst_ptr [1 ] =  src_ptr [1 ];
1533+                 dst_ptr  +=  2 ;
1534+                 filtered_len  +=  2 ;
1535+                 src_ptr ++ ;
1536+             }
1537+         }
1538+         else  if  ((* src_ptr  &  0xf0 ) ==  0xe0 ) {
1539+ 
1540+             /* UTF-8 3-byte codepoint */ 
1541+             if  ((src_ptr  +  2  <  src_end ) &&  ((src_ptr [1 ] &  0xc0 ) ==  0x80 ) && 
1542+                     ((src_ptr [2 ] &  0xc0 ) ==  0x80 )) {
1543+                 dst_ptr [0 ] =  src_ptr [0 ];
1544+                 dst_ptr [1 ] =  src_ptr [1 ];
1545+                 dst_ptr [2 ] =  src_ptr [2 ];
1546+                 dst_ptr  +=  3 ;
1547+                 filtered_len  +=  3 ;
1548+                 src_ptr  +=  2 ;
1549+             }
1550+         }
1551+         else  if  ((* src_ptr  &  0xf8 ) ==  0xf0 ) {
1552+ 
1553+             /* UTF-8 4-byte codepoint */ 
1554+             if  ((src_ptr  +  3  <  src_end ) &&  ((src_ptr [1 ] &  0xc0 ) ==  0x80 ) && 
1555+                     ((src_ptr [2 ] &  0xc0 ) ==  0x80 ) &&  ((src_ptr [3 ] &  0xc0 ) ==  0x80 )) {
1556+                 dst_ptr [0 ] =  src_ptr [0 ];
1557+                 dst_ptr [1 ] =  src_ptr [1 ];
1558+                 dst_ptr [2 ] =  src_ptr [2 ];
1559+                 dst_ptr [3 ] =  src_ptr [3 ];
1560+                 dst_ptr  +=  4 ;
1561+                 filtered_len  +=  4 ;
1562+                 src_ptr  +=  3 ;
1563+             }
1564+         }
1565+         else  if  (!is_control ) {
1566+             * dst_ptr  =  * src_ptr ;
1567+             dst_ptr ++ ;
1568+             filtered_len ++ ;
1569+         }
1570+         src_ptr ++ ;
1571+     }
1572+ 
1573+     /* Send the paste stop sequence */ 
1574+     if  (term -> bracketed_paste_mode ) {
1575+         memcpy (dst_ptr , "\x1B[201~" , 6 );
1576+         dst_ptr  +=  6 ;
1577+         filtered_len  +=  6 ;
1578+     }
1579+ 
1580+     int  result  =  guac_terminal_send_data (term , filtered , filtered_len );
1581+     guac_mem_free (filtered );
1582+     return  result ;
1583+ }
1584+ 
15031585static  int  __guac_terminal_send_key (guac_terminal *  term , int  keysym , int  pressed ) {
15041586
15051587    /* Ignore user input if terminal is not started */ 
@@ -1529,7 +1611,7 @@ static int __guac_terminal_send_key(guac_terminal* term, int keysym, int pressed
15291611
15301612        /* Ctrl+Shift+V shortcut for paste */ 
15311613        if  (keysym  ==  'V'  &&  term -> mod_ctrl )
1532-             return  guac_terminal_send_data (term ,  term -> clipboard -> buffer ,  term -> clipboard -> length );
1614+             return  guac_terminal_send_clipboard (term );
15331615
15341616        /* Shift+PgUp / Shift+PgDown shortcuts for scrolling */ 
15351617        if  (term -> mod_shift ) {
@@ -1722,7 +1804,7 @@ static int __guac_terminal_send_mouse(guac_terminal* term, guac_user* user,
17221804
17231805    /* Paste contents of clipboard on right or middle mouse button up */ 
17241806    if  ((released_mask  &  GUAC_CLIENT_MOUSE_RIGHT ) ||  (released_mask  &  GUAC_CLIENT_MOUSE_MIDDLE ))
1725-         return  guac_terminal_send_data (term ,  term -> clipboard -> buffer ,  term -> clipboard -> length );
1807+         return  guac_terminal_send_clipboard (term );
17261808
17271809    /* If left mouse button was just released, stop selection */ 
17281810    if  (released_mask  &  GUAC_CLIENT_MOUSE_LEFT )
0 commit comments