38b38bbe5c2263ad17b044f4c7d3816988c16d52
[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 return 0;
184 }
185
186 *data = (uint8 *) xmalloc(st.st_size);
187 length = read(fd, *data, st.st_size);
188 close(fd);
189 xfree(path);
190 return length;
191 }
192
193 static void
194 printercache_save_blob(char *printer_name, uint8 * data, uint32 length)
195 {
196 char *home, *path;
197 int fd;
198
199 if (printer_name == NULL)
200 return;
201
202 home = getenv("HOME");
203 if (home == NULL)
204 return;
205
206 if (!printercache_mkdir(home, printer_name))
207 return;
208
209 path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer_name) +
210 sizeof("/AutoPrinterCacheData") + 1);
211 sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer_name);
212
213 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
214 if (fd == -1)
215 {
216 perror(path);
217 xfree(path);
218 return;
219 }
220
221 if (write(fd, data, length) != length)
222 {
223 perror(path);
224 unlink(path);
225 }
226
227 close(fd);
228 xfree(path);
229 }
230
231 void
232 printercache_process(RDPCLIENT * This, STREAM s)
233 {
234 uint32 type, printer_length, driver_length, printer_unicode_length, blob_length;
235 char device_name[9], printer[256], driver[256];
236
237 in_uint32_le(s, type);
238 switch (type)
239 {
240 case 4: /* rename item */
241 in_uint8(s, printer_length);
242 in_uint8s(s, 0x3); /* padding */
243 in_uint8(s, driver_length);
244 in_uint8s(s, 0x3); /* padding */
245
246 /* NOTE - 'driver' doesn't contain driver, it contains the new printer name */
247
248 rdp_in_unistr(This, s, printer, printer_length);
249 rdp_in_unistr(This, s, driver, driver_length);
250
251 printercache_rename_blob(printer, driver);
252 break;
253
254 case 3: /* delete item */
255 in_uint8(s, printer_unicode_length);
256 in_uint8s(s, 0x3); /* padding */
257 printer_length = rdp_in_unistr(This, s, printer, printer_unicode_length);
258 printercache_unlink_blob(printer);
259 break;
260
261 case 2: /* save printer data */
262 in_uint32_le(s, printer_unicode_length);
263 in_uint32_le(s, blob_length);
264
265 if (printer_unicode_length < 2 * 255)
266 {
267 rdp_in_unistr(This, s, printer, printer_unicode_length);
268 printercache_save_blob(printer, s->p, blob_length);
269 }
270 break;
271
272 case 1: /* save device data */
273 in_uint8a(s, device_name, 5); /* get LPTx/COMx name */
274
275 /* need to fetch this data so that we can get the length of the packet to store. */
276 in_uint8s(s, 0x2); /* ??? */
277 in_uint8s(s, 0x2) /* pad?? */
278 in_uint32_be(s, driver_length);
279 in_uint32_be(s, printer_length);
280 in_uint8s(s, 0x7) /* pad?? */
281 /* next is driver in unicode */
282 /* next is printer in unicode */
283 /* TODO: figure out how to use this information when reconnecting */
284 /* actually - all we need to store is the driver and printer */
285 /* and figure out what the first word is. */
286 /* rewind stream so that we can save this blob */
287 /* length is driver_length + printer_length + 19 */
288 /* rewind stream */
289 s->p = s->p - 19;
290
291 printercache_save_blob(device_name, s->p,
292 driver_length + printer_length + 19);
293 break;
294 default:
295
296 unimpl("RDPDR Printer Cache Packet Type: %d\n", type);
297 break;
298 }
299 }