1 /* -*- c-basic-offset: 8 -*- 2 rdesktop: A Remote Desktop Protocol client. 3 Protocol services - Clipboard functions 4 Copyright (C) Erik Forsberg <forsberg@cendio.se> 2003 5 Copyright (C) Matthew Chapman 2003 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License along 18 with this program; if not, write to the Free Software Foundation, Inc., 19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 */ 21 22 #include "rdesktop.h" 23 24 #define CLIPRDR_CONNECT 1 25 #define CLIPRDR_FORMAT_ANNOUNCE 2 26 #define CLIPRDR_FORMAT_ACK 3 27 #define CLIPRDR_DATA_REQUEST 4 28 #define CLIPRDR_DATA_RESPONSE 5 29 30 #define CLIPRDR_REQUEST 0 31 #define CLIPRDR_RESPONSE 1 32 #define CLIPRDR_ERROR 2 33 34 static void 35 cliprdr_send_packet(RDPCLIENT * This, uint16 type, uint16 status, uint8 * data, uint32 length) 36 { 37 STREAM s; 38 39 DEBUG_CLIPBOARD(("CLIPRDR send: type=%d, status=%d, length=%d\n", type, status, length)); 40 41 s = channel_init(This, This->cliprdr.channel, length + 12); 42 out_uint16_le(s, type); 43 out_uint16_le(s, status); 44 out_uint32_le(s, length); 45 out_uint8p(s, data, length); 46 out_uint32(s, 0); /* pad? */ 47 s_mark_end(s); 48 channel_send(This, s, This->cliprdr.channel); 49 } 50 51 /* Helper which announces our readiness to supply clipboard data 52 in a single format (such as CF_TEXT) to the RDP side. 53 To announce more than one format at a time, use 54 cliprdr_send_native_format_announce. 55 */ 56 void 57 cliprdr_send_simple_native_format_announce(RDPCLIENT * This, uint32 format) 58 { 59 uint8 buffer[36]; 60 61 DEBUG_CLIPBOARD(("cliprdr_send_simple_native_format_announce\n")); 62 63 buf_out_uint32(buffer, format); 64 memset(buffer + 4, 0, sizeof(buffer) - 4); /* description */ 65 cliprdr_send_native_format_announce(This, buffer, sizeof(buffer)); 66 } 67 68 /* Announces our readiness to supply clipboard data in multiple 69 formats, each denoted by a 36-byte format descriptor of 70 [ uint32 format + 32-byte description ]. 71 */ 72 void 73 cliprdr_send_native_format_announce(RDPCLIENT * This, uint8 * formats_data, uint32 formats_data_length) 74 { 75 DEBUG_CLIPBOARD(("cliprdr_send_native_format_announce\n")); 76 77 cliprdr_send_packet(This, CLIPRDR_FORMAT_ANNOUNCE, CLIPRDR_REQUEST, formats_data, 78 formats_data_length); 79 80 if (formats_data != This->cliprdr.last_formats) 81 { 82 if (This->cliprdr.last_formats) 83 xfree(This->cliprdr.last_formats); 84 85 This->cliprdr.last_formats = xmalloc(formats_data_length); 86 memcpy(This->cliprdr.last_formats, formats_data, formats_data_length); 87 This->cliprdr.last_formats_length = formats_data_length; 88 } 89 } 90 91 void 92 cliprdr_send_data_request(RDPCLIENT * This, uint32 format) 93 { 94 uint8 buffer[4]; 95 96 DEBUG_CLIPBOARD(("cliprdr_send_data_request\n")); 97 buf_out_uint32(buffer, format); 98 cliprdr_send_packet(This, CLIPRDR_DATA_REQUEST, CLIPRDR_REQUEST, buffer, sizeof(buffer)); 99 } 100 101 void 102 cliprdr_send_data(RDPCLIENT * This, uint8 * data, uint32 length) 103 { 104 DEBUG_CLIPBOARD(("cliprdr_send_data\n")); 105 cliprdr_send_packet(This, CLIPRDR_DATA_RESPONSE, CLIPRDR_RESPONSE, data, length); 106 } 107 108 static void 109 cliprdr_process(RDPCLIENT * This, STREAM s) 110 { 111 uint16 type, status; 112 uint32 length, format; 113 uint8 *data; 114 115 in_uint16_le(s, type); 116 in_uint16_le(s, status); 117 in_uint32_le(s, length); 118 data = s->p; 119 120 DEBUG_CLIPBOARD(("CLIPRDR recv: type=%d, status=%d, length=%d\n", type, status, length)); 121 122 if (status == CLIPRDR_ERROR) 123 { 124 switch (type) 125 { 126 case CLIPRDR_FORMAT_ACK: 127 /* FIXME: We seem to get this when we send an announce while the server is 128 still processing a paste. Try sending another announce. */ 129 cliprdr_send_native_format_announce(This, This->cliprdr.last_formats, 130 This->cliprdr.last_formats_length); 131 break; 132 case CLIPRDR_DATA_RESPONSE: 133 ui_clip_request_failed(This); 134 break; 135 default: 136 DEBUG_CLIPBOARD(("CLIPRDR error (type=%d)\n", type)); 137 } 138 139 return; 140 } 141 142 switch (type) 143 { 144 case CLIPRDR_CONNECT: 145 ui_clip_sync(This); 146 break; 147 case CLIPRDR_FORMAT_ANNOUNCE: 148 ui_clip_format_announce(This, data, length); 149 cliprdr_send_packet(This, CLIPRDR_FORMAT_ACK, CLIPRDR_RESPONSE, NULL, 0); 150 return; 151 case CLIPRDR_FORMAT_ACK: 152 break; 153 case CLIPRDR_DATA_REQUEST: 154 in_uint32_le(s, format); 155 ui_clip_request_data(This, format); 156 break; 157 case CLIPRDR_DATA_RESPONSE: 158 ui_clip_handle_data(This, data, length); 159 break; 160 case 7: /* TODO: W2K3 SP1 sends this on connect with a value of 1 */ 161 break; 162 default: 163 unimpl("CLIPRDR packet type %d\n", type); 164 } 165 } 166 167 void 168 cliprdr_set_mode(RDPCLIENT * This, const char *optarg) 169 { 170 ui_clip_set_mode(This, optarg); 171 } 172 173 BOOL 174 cliprdr_init(RDPCLIENT * This) 175 { 176 This->cliprdr.channel = 177 channel_register(This, "cliprdr", 178 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | 179 CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL, 180 cliprdr_process); 181 return (This->cliprdr.channel != NULL); 182 } 183