]>
Commit | Line | Data |
---|---|---|
dcb445bc MS |
1 | /* |
2 | * "$Id$" | |
3 | * | |
4 | * Destination localization support for CUPS. | |
5 | * | |
6 | * Copyright 2012 by Apple Inc. | |
7 | * | |
8 | * These coded instructions, statements, and computer programs are the | |
9 | * property of Apple Inc. and are protected by Federal copyright | |
10 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
11 | * which should have been included with this file. If this file is | |
12 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
13 | * | |
14 | * This file is subject to the Apple OS-Developed Software exception. | |
15 | * | |
16 | * Contents: | |
17 | * | |
a29fd7dd MS |
18 | * cupsLocalizeDestOption() - Get the localized string for a destination |
19 | * option. | |
20 | * cupsLocalizeDestValue() - Get the localized string for a destination | |
21 | * option+value pair. | |
22 | * cups_create_localizations() - Create the localizations array for a | |
23 | * destination. | |
24 | * cups_read_strings() - Read a pair of strings from a .strings file. | |
25 | * cups_scan_strings() - Scan a quoted string. | |
dcb445bc MS |
26 | */ |
27 | ||
28 | /* | |
29 | * Include necessary headers... | |
30 | */ | |
31 | ||
32 | #include "cups-private.h" | |
33 | ||
34 | ||
a29fd7dd MS |
35 | /* |
36 | * Local functions... | |
37 | */ | |
38 | ||
39 | static void cups_create_localizations(http_t *http, cups_dinfo_t *dinfo); | |
40 | static int cups_read_strings(cups_file_t *fp, char *buffer, size_t bufsize, | |
41 | char **id, char **str); | |
42 | static char *cups_scan_strings(char *buffer); | |
43 | ||
44 | ||
dcb445bc MS |
45 | /* |
46 | * 'cupsLocalizeDestOption()' - Get the localized string for a destination | |
47 | * option. | |
48 | * | |
a29fd7dd MS |
49 | * The returned string is stored in the destination information and will become |
50 | * invalid if the destination information is deleted. | |
dcb445bc | 51 | * |
f3c17241 | 52 | * @since CUPS 1.6/OS X 10.8@ |
dcb445bc MS |
53 | */ |
54 | ||
55 | const char * /* O - Localized string */ | |
56 | cupsLocalizeDestOption( | |
57 | http_t *http, /* I - Connection to destination */ | |
58 | cups_dest_t *dest, /* I - Destination */ | |
59 | cups_dinfo_t *dinfo, /* I - Destination information */ | |
60 | const char *option) /* I - Option to localize */ | |
61 | { | |
a29fd7dd MS |
62 | _cups_message_t key, /* Search key */ |
63 | *match; /* Matching entry */ | |
64 | ||
65 | ||
66 | if (!http || !dest || !dinfo) | |
67 | return (option); | |
68 | ||
69 | if (!dinfo->localizations) | |
70 | cups_create_localizations(http, dinfo); | |
71 | ||
72 | if (cupsArrayCount(dinfo->localizations) == 0) | |
73 | return (option); | |
74 | ||
75 | key.id = (char *)option; | |
76 | if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, | |
77 | &key)) != NULL) | |
78 | return (match->str); | |
79 | else | |
80 | return (option); | |
dcb445bc MS |
81 | } |
82 | ||
83 | ||
84 | /* | |
85 | * 'cupsLocalizeDestValue()' - Get the localized string for a destination | |
86 | * option+value pair. | |
87 | * | |
a29fd7dd MS |
88 | * The returned string is stored in the destination information and will become |
89 | * invalid if the destination information is deleted. | |
dcb445bc | 90 | * |
f3c17241 | 91 | * @since CUPS 1.6/OS X 10.8@ |
dcb445bc MS |
92 | */ |
93 | ||
94 | const char * /* O - Localized string */ | |
95 | cupsLocalizeDestValue( | |
96 | http_t *http, /* I - Connection to destination */ | |
97 | cups_dest_t *dest, /* I - Destination */ | |
98 | cups_dinfo_t *dinfo, /* I - Destination information */ | |
99 | const char *option, /* I - Option to localize */ | |
100 | const char *value) /* I - Value to localize */ | |
101 | { | |
a29fd7dd MS |
102 | _cups_message_t key, /* Search key */ |
103 | *match; /* Matching entry */ | |
104 | char pair[256]; /* option.value pair */ | |
105 | ||
106 | ||
107 | if (!http || !dest || !dinfo) | |
108 | return (value); | |
109 | ||
110 | if (!dinfo->localizations) | |
111 | cups_create_localizations(http, dinfo); | |
112 | ||
113 | if (cupsArrayCount(dinfo->localizations) == 0) | |
114 | return (value); | |
115 | ||
116 | snprintf(pair, sizeof(pair), "%s.%s", option, value); | |
117 | key.id = pair; | |
118 | if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, | |
119 | &key)) != NULL) | |
120 | return (match->str); | |
121 | else | |
122 | return (value); | |
123 | } | |
124 | ||
125 | ||
126 | /* | |
127 | * 'cups_create_localizations()' - Create the localizations array for a | |
128 | * destination. | |
129 | */ | |
130 | ||
131 | static void | |
132 | cups_create_localizations( | |
133 | http_t *http, /* I - Connection to destination */ | |
134 | cups_dinfo_t *dinfo) /* I - Destination informations */ | |
135 | { | |
136 | http_t *http2; /* Connection for strings file */ | |
137 | http_status_t status; /* Request status */ | |
138 | ipp_attribute_t *attr; /* "printer-strings-uri" attribute */ | |
139 | char scheme[32], /* URI scheme */ | |
140 | userpass[256], /* Username/password info */ | |
141 | hostname[256], /* Hostname */ | |
142 | resource[1024], /* Resource */ | |
143 | http_hostname[256], | |
144 | /* Hostname of connection */ | |
145 | tempfile[1024]; /* Temporary filename */ | |
146 | int port; /* Port number */ | |
147 | http_encryption_t encryption; /* Encryption to use */ | |
148 | cups_file_t *temp; /* Temporary file */ | |
149 | ||
150 | ||
151 | /* | |
152 | * Create an empty message catalog... | |
153 | */ | |
154 | ||
155 | dinfo->localizations = _cupsMessageNew(NULL); | |
156 | ||
157 | /* | |
158 | * See if there are any localizations... | |
159 | */ | |
160 | ||
161 | if ((attr = ippFindAttribute(dinfo->attrs, "printer-strings-uri", | |
162 | IPP_TAG_URI)) == NULL) | |
163 | { | |
164 | /* | |
165 | * Nope... | |
166 | */ | |
167 | ||
168 | DEBUG_puts("4cups_create_localizations: No printer-strings-uri (uri) " | |
169 | "value."); | |
170 | return; /* Nope */ | |
171 | } | |
172 | ||
173 | /* | |
174 | * Pull apart the URI and determine whether we need to try a different | |
175 | * server... | |
176 | */ | |
177 | ||
178 | if (httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, | |
179 | scheme, sizeof(scheme), userpass, sizeof(userpass), | |
180 | hostname, sizeof(hostname), &port, resource, | |
181 | sizeof(resource)) < HTTP_URI_OK) | |
182 | { | |
183 | DEBUG_printf(("4cups_create_localizations: Bad printer-strings-uri value " | |
184 | "\"%s\".", attr->values[0].string.text)); | |
185 | return; | |
186 | } | |
187 | ||
188 | httpGetHostname(http, http_hostname, sizeof(http_hostname)); | |
189 | ||
190 | if (!_cups_strcasecmp(http_hostname, hostname) && | |
a469f8a5 | 191 | port == httpAddrPort(http->hostaddr)) |
a29fd7dd MS |
192 | { |
193 | /* | |
194 | * Use the same connection... | |
195 | */ | |
196 | ||
197 | http2 = http; | |
198 | } | |
199 | else | |
200 | { | |
201 | /* | |
202 | * Connect to the alternate host... | |
203 | */ | |
204 | ||
205 | if (!strcmp(scheme, "https")) | |
206 | encryption = HTTP_ENCRYPT_ALWAYS; | |
207 | else | |
208 | encryption = HTTP_ENCRYPT_IF_REQUESTED; | |
209 | ||
210 | if ((http2 = httpConnectEncrypt(hostname, port, encryption)) == NULL) | |
211 | { | |
212 | DEBUG_printf(("4cups_create_localizations: Unable to connect to " | |
213 | "%s:%d: %s", hostname, port, cupsLastErrorString())); | |
214 | return; | |
215 | } | |
216 | } | |
217 | ||
218 | /* | |
219 | * Get a temporary file... | |
220 | */ | |
221 | ||
222 | if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL) | |
223 | { | |
224 | DEBUG_printf(("4cups_create_localizations: Unable to create temporary " | |
225 | "file: %s", cupsLastErrorString())); | |
226 | if (http2 != http) | |
227 | httpClose(http2); | |
228 | return; | |
229 | } | |
230 | ||
231 | status = cupsGetFd(http2, resource, cupsFileNumber(temp)); | |
232 | ||
233 | DEBUG_printf(("4cups_create_localizations: GET %s = %s", resource, | |
234 | httpStatus(status))); | |
235 | ||
236 | if (status == HTTP_OK) | |
237 | { | |
238 | /* | |
239 | * Got the file, read it... | |
240 | */ | |
241 | ||
242 | char buffer[8192], /* Message buffer */ | |
243 | *id, /* ID string */ | |
244 | *str; /* Translated message */ | |
245 | _cups_message_t *m; /* Current message */ | |
246 | ||
247 | lseek(cupsFileNumber(temp), 0, SEEK_SET); | |
248 | ||
249 | while (cups_read_strings(temp, buffer, sizeof(buffer), &id, &str)) | |
250 | { | |
251 | if ((m = malloc(sizeof(_cups_message_t))) == NULL) | |
252 | break; | |
253 | ||
254 | m->id = strdup(id); | |
255 | m->str = strdup(str); | |
256 | ||
257 | if (m->id && m->str) | |
258 | cupsArrayAdd(dinfo->localizations, m); | |
259 | else | |
260 | { | |
261 | if (m->id) | |
262 | free(m->id); | |
263 | ||
264 | if (m->str) | |
265 | free(m->str); | |
266 | ||
267 | free(m); | |
268 | break; | |
269 | } | |
270 | } | |
271 | } | |
272 | ||
273 | DEBUG_printf(("4cups_create_localizations: %d messages loaded.", | |
274 | cupsArrayCount(dinfo->localizations))); | |
275 | ||
276 | /* | |
277 | * Cleanup... | |
278 | */ | |
279 | ||
280 | unlink(tempfile); | |
281 | cupsFileClose(temp); | |
282 | ||
283 | if (http2 != http) | |
284 | httpClose(http2); | |
285 | } | |
286 | ||
287 | ||
288 | /* | |
289 | * 'cups_read_strings()' - Read a pair of strings from a .strings file. | |
290 | */ | |
291 | ||
292 | static int /* O - 1 on success, 0 on failure */ | |
293 | cups_read_strings(cups_file_t *strings, /* I - .strings file */ | |
294 | char *buffer, /* I - Line buffer */ | |
295 | size_t bufsize, /* I - Size of line buffer */ | |
296 | char **id, /* O - Pointer to ID string */ | |
297 | char **str) /* O - Pointer to translation string */ | |
298 | { | |
299 | char *bufptr; /* Pointer into buffer */ | |
300 | ||
301 | ||
302 | while (cupsFileGets(strings, buffer, bufsize)) | |
303 | { | |
304 | if (buffer[0] != '\"') | |
305 | continue; | |
306 | ||
307 | *id = buffer + 1; | |
308 | bufptr = cups_scan_strings(buffer); | |
309 | ||
310 | if (*bufptr != '\"') | |
311 | continue; | |
312 | ||
313 | *bufptr++ = '\0'; | |
314 | ||
315 | while (*bufptr && *bufptr != '\"') | |
316 | bufptr ++; | |
317 | ||
318 | if (!*bufptr) | |
319 | continue; | |
320 | ||
321 | *str = bufptr + 1; | |
322 | bufptr = cups_scan_strings(bufptr); | |
323 | ||
324 | if (*bufptr != '\"') | |
325 | continue; | |
326 | ||
327 | *bufptr = '\0'; | |
328 | ||
329 | return (1); | |
330 | } | |
331 | ||
332 | return (0); | |
333 | } | |
334 | ||
335 | ||
336 | /* | |
337 | * 'cups_scan_strings()' - Scan a quoted string. | |
338 | */ | |
339 | ||
340 | static char * /* O - End of string */ | |
341 | cups_scan_strings(char *buffer) /* I - Start of string */ | |
342 | { | |
343 | char *bufptr; /* Pointer into string */ | |
344 | ||
345 | ||
346 | for (bufptr = buffer + 1; *bufptr && *bufptr != '\"'; bufptr ++) | |
347 | { | |
348 | if (*bufptr == '\\') | |
349 | { | |
350 | if (bufptr[1] >= '0' && bufptr[1] <= '3' && | |
351 | bufptr[2] >= '0' && bufptr[2] <= '7' && | |
352 | bufptr[3] >= '0' && bufptr[3] <= '7') | |
353 | { | |
354 | /* | |
355 | * Decode \nnn octal escape... | |
356 | */ | |
357 | ||
358 | *bufptr = ((((bufptr[1] - '0') << 3) | (bufptr[2] - '0')) << 3) | | |
359 | (bufptr[3] - '0'); | |
360 | _cups_strcpy(bufptr + 1, bufptr + 4); | |
361 | } | |
362 | else | |
363 | { | |
364 | /* | |
365 | * Decode \C escape... | |
366 | */ | |
367 | ||
368 | _cups_strcpy(bufptr, bufptr + 1); | |
369 | if (*bufptr == 'n') | |
370 | *bufptr = '\n'; | |
371 | else if (*bufptr == 'r') | |
372 | *bufptr = '\r'; | |
373 | else if (*bufptr == 't') | |
374 | *bufptr = '\t'; | |
375 | } | |
376 | } | |
377 | } | |
378 | ||
379 | return (bufptr); | |
dcb445bc MS |
380 | } |
381 | ||
382 | ||
a29fd7dd | 383 | |
dcb445bc MS |
384 | /* |
385 | * End of "$Id$". | |
386 | */ |