Martin Ettl <ettl DOT martin AT gmx DOT de>: Fix various resource and memory leaks
[reactos.git] / reactos / base / applications / tsclient / rdesktop / printercache.c
1 /* -*- c-basic-offset: 8 -*-
2 * rdesktop: A Remote Desktop Protocol client.
3 * Entrypoint and utility functions
4 * Copyright (C) Matthew Chapman 1999-2005
5 * Copyright (C) Jeroen Meijer 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 /* According to the W2K RDP Printer Redirection WhitePaper, a data
23 * blob is sent to the client after the configuration of the printer
24 * is changed at the server.
25 *
26 * This data blob is saved to the registry. The client returns this
27 * data blob in a new session with the printer announce data.
28 * The data is not interpreted by the client.
29 */
30
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include "rdesktop.h"
38
39 static BOOL
40 printercache_mkdir(char *base, char *printer)
41 {
42 char *path;
43
44 path = (char *) xmalloc(strlen(base) + sizeof("/.rdesktop/rdpdr/") + strlen(printer) + 1);
45
46 sprintf(path, "%s/.rdesktop", base);
47 if ((mkdir(path, 0700) == -1) && errno != EEXIST)
48 {
49 perror(path);
50 xfree(path);
51 return False;
52 }
53
54 strcat(path, "/rdpdr");
55 if ((mkdir(path, 0700) == -1) && errno != EEXIST)
56 {
57 perror(path);
58 xfree(path);
59 return False;
60 }
61
62 strcat(path, "/");
63 strcat(path, printer);
64 if ((mkdir(path, 0700) == -1) && errno != EEXIST)
65 {
66 perror(path);
67 xfree(path);
68 return False;
69 }
70
71 xfree(path);
72 return True;
73 }
74
75 static BOOL
76 printercache_unlink_blob(char *printer)
77 {
78 char *path;
79 char *home;
80
81 if (printer == NULL)
82 return False;
83
84 home = getenv("HOME");
85 if (home == NULL)
86 return False;
87
88 path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer) +
89 sizeof("/AutoPrinterCacheData") + 1);
90
91 sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer);
92
93 if (unlink(path) < 0)
94 {
95 xfree(path);
96 return False;
97 }
98
99 sprintf(path, "%s/.rdesktop/rdpdr/%s", home, printer);
100
101 if (rmdir(path) < 0)
102 {
103 xfree(path);
104 return False;
105 }
106
107 xfree(path);
108 return True;
109 }
110
111
112 static BOOL
113 printercache_rename_blob(char *printer, char *new_printer)
114 {
115 char *printer_path;
116 char *new_printer_path;
117 int printer_maxlen;
118
119 char *home;
120
121 if (printer == NULL)
122 return False;
123
124 home = getenv("HOME");
125 if (home == NULL)
126 return False;
127
128 printer_maxlen =
129 (strlen(printer) >
130 strlen(new_printer) ? strlen(printer) : strlen(new_printer)) + strlen(home) +
131 sizeof("/.rdesktop/rdpdr/") + 1;
132
133 printer_path = (char *) xmalloc(printer_maxlen);
134 new_printer_path = (char *) xmalloc(printer_maxlen);
135
136 sprintf(printer_path, "%s/.rdesktop/rdpdr/%s", home, printer);
137 sprintf(new_printer_path, "%s/.rdesktop/rdpdr/%s", home, new_printer);
138
139 printf("%s,%s\n", printer_path, new_printer_path);
140 if (rename(printer_path, new_printer_path) < 0)
141 {
142 xfree(printer_path);
143 xfree(new_printer_path);
144 return False;
145 }
146
147 xfree(printer_path);
148 xfree(new_printer_path);
149 return True;
150 }
151
152
153 int
154 printercache_load_blob(char *printer_name, uint8 ** data)
155 {
156 char *home, *path;
157 struct stat st;
158 int fd, length;
159
160 if (printer_name == NULL)
161 return 0;
162
163 *data = NULL;
164
165 home = getenv("HOME");
166 if (home == NULL)
167 return 0;
168
169 path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer_name) +
170 sizeof("/AutoPrinterCacheData") + 1);
171 sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer_name);
172
173 fd = open(path, O_RDONLY);
174 if (fd == -1)
175 {
176 xfree(path);
177 return 0;
178 }
179
180 if (fstat(fd, &st))
181 {
182 xfree(path);
183 close(fd);
184 return 0;
185 }
186
187 *data = (uint8 *) xmalloc(st.st_size);
188 length = read(fd, *data, st.st_size);
189 close(fd);
190 xfree(path);
191 return length;
192 }
193
194 static void
195 printercache_save_blob(char *printer_name, uint8 * data, uint32 length)
196 {
197 char *home, *path;
198 int fd;
199
200 if (printer_name == NULL)
201 return;
202
203 home = getenv("HOME");
204 if (home == NULL)
205 return;
206
207 if (!printercache_mkdir(home, printer_name))
208 return;
209
210 path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer_name) +
211 sizeof("/AutoPrinterCacheData") + 1);
212 sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer_name);
213
214 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
215 if (fd == -1)
216 {
217 perror(path);
218 xfree(path);
219 return;
220 }
221
222 if (write(fd, data, length) != length)
223 {
224 perror(path);
225 unlink(path);
226 }
227
228 close(fd);
229 xfree(path);
230 }
231
232 void
233 printercache_process(RDPCLIENT * This, STREAM s)
234 {
235 uint32 type, printer_length, driver_length, printer_unicode_length, blob_length;
236 char device_name[9], printer[256], driver[256];
237
238 in_uint32_le(s, type);
239 switch (type)
240 {
241 case 4: /* rename item */
242 in_uint8(s, printer_length);
243 in_uint8s(s, 0x3); /* padding */
244 in_uint8(s, driver_length);
245 in_uint8s(s, 0x3); /* padding */
246
247 /* NOTE - 'driver' doesn't contain driver, it contains the new printer name */
248
249 rdp_in_unistr(This, s, printer, printer_length);
250 rdp_in_unistr(This, s, driver, driver_length);
251
252 printercache_rename_blob(printer, driver);
253 break;
254
255 case 3: /* delete item */
256 in_uint8(s, printer_unicode_length);
257 in_uint8s(s, 0x3); /* padding */
258 printer_length = rdp_in_unistr(This, s, printer, printer_unicode_length);
259 printercache_unlink_blob(printer);
260 break;
261
262 case 2: /* save printer data */
263 in_uint32_le(s, printer_unicode_length);
264 in_uint32_le(s, blob_length);
265
266 if (printer_unicode_length < 2 * 255)
267 {
268 rdp_in_unistr(This, s, printer, printer_unicode_length);
269 printercache_save_blob(printer, s->p, blob_length);
270 }
271 break;
272
273 case 1: /* save device data */
274 in_uint8a(s, device_name, 5); /* get LPTx/COMx name */
275
276 /* need to fetch this data so that we can get the length of the packet to store. */
277 in_uint8s(s, 0x2); /* ??? */
278 in_uint8s(s, 0x2) /* pad?? */
279 in_uint32_be(s, driver_length);
280 in_uint32_be(s, printer_length);
281 in_uint8s(s, 0x7) /* pad?? */
282 /* next is driver in unicode */
283 /* next is printer in unicode */
284 /* TODO: figure out how to use this information when reconnecting */
285 /* actually - all we need to store is the driver and printer */
286 /* and figure out what the first word is. */
287 /* rewind stream so that we can save this blob */
288 /* length is driver_length + printer_length + 19 */
289 /* rewind stream */
290 s->p = s->p - 19;
291
292 printercache_save_blob(device_name, s->p,
293 driver_length + printer_length + 19);
294 break;
295 default:
296
297 unimpl("RDPDR Printer Cache Packet Type: %d\n", type);
298 break;
299 }
300 }