Martin Ettl <ettl DOT martin AT gmx DOT de>: Fix various resource and memory leaks
[reactos.git] / reactos / base / applications / tsclient / rdesktop / cliprdr.c
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 }