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