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