2 * Destination localization support for CUPS.
4 * Copyright 2012-2017 by Apple Inc.
6 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
10 * Include necessary headers...
13 #include "cups-private.h"
14 #include "debug-internal.h"
21 static void cups_create_localizations(http_t
*http
, cups_dinfo_t
*dinfo
);
25 * 'cupsLocalizeDestMedia()' - Get the localized string for a destination media
28 * The returned string is stored in the destination information and will become
29 * invalid if the destination information is deleted.
31 * @since CUPS 2.0/macOS 10.10@
34 const char * /* O - Localized string */
35 cupsLocalizeDestMedia(
36 http_t
*http
, /* I - Connection to destination */
37 cups_dest_t
*dest
, /* I - Destination */
38 cups_dinfo_t
*dinfo
, /* I - Destination information */
39 unsigned flags
, /* I - Media flags */
40 cups_size_t
*size
) /* I - Media size */
42 cups_lang_t
*lang
; /* Standard localizations */
43 _cups_message_t key
, /* Search key */
44 *match
; /* Matching entry */
45 pwg_media_t
*pwg
; /* PWG media information */
46 cups_array_t
*db
; /* Media database */
47 _cups_media_db_t
*mdb
; /* Media database entry */
48 char lstr
[1024], /* Localized size name */
49 temp
[256]; /* Temporary string */
50 const char *lsize
, /* Localized media size */
51 *lsource
, /* Localized media source */
52 *ltype
; /* Localized media type */
55 DEBUG_printf(("cupsLocalizeDestMedia(http=%p, dest=%p, dinfo=%p, flags=%x, size=%p(\"%s\"))", (void *)http
, (void *)dest
, (void *)dinfo
, flags
, (void *)size
, size
? size
->media
: "(null)"));
58 * Range check input...
61 if (!http
|| !dest
|| !dinfo
|| !size
)
63 DEBUG_puts("1cupsLocalizeDestMedia: Returning NULL.");
64 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
69 * Find the matching media database entry...
72 if (flags
& CUPS_MEDIA_FLAGS_READY
)
77 DEBUG_printf(("1cupsLocalizeDestMedia: size->media=\"%s\"", size
->media
));
79 for (mdb
= (_cups_media_db_t
*)cupsArrayFirst(db
); mdb
; mdb
= (_cups_media_db_t
*)cupsArrayNext(db
))
81 if (mdb
->key
&& !strcmp(mdb
->key
, size
->media
))
83 else if (mdb
->size_name
&& !strcmp(mdb
->size_name
, size
->media
))
89 for (mdb
= (_cups_media_db_t
*)cupsArrayFirst(db
); mdb
; mdb
= (_cups_media_db_t
*)cupsArrayNext(db
))
91 if (mdb
->width
== size
->width
&& mdb
->length
== size
->length
&& mdb
->bottom
== size
->bottom
&& mdb
->left
== size
->left
&& mdb
->right
== size
->right
&& mdb
->top
== size
->top
)
97 * See if the localization is cached...
100 lang
= cupsLangDefault();
102 if (!dinfo
->localizations
)
103 cups_create_localizations(http
, dinfo
);
105 snprintf(temp
, sizeof(temp
), "media.%s", size
->media
);
108 if ((match
= (_cups_message_t
*)cupsArrayFind(dinfo
->localizations
, &key
)) != NULL
)
115 * Not a media name, try a media-key name...
118 snprintf(temp
, sizeof(temp
), "media-key.%s", size
->media
);
119 if ((match
= (_cups_message_t
*)cupsArrayFind(dinfo
->localizations
, &key
)) != NULL
)
125 if (!lsize
&& (pwg
= pwgMediaForSize(size
->width
, size
->length
)) != NULL
&& pwg
->ppd
)
128 * Get a standard localization...
131 snprintf(temp
, sizeof(temp
), "media.%s", pwg
->pwg
);
132 if ((lsize
= _cupsLangString(lang
, temp
)) == temp
)
139 * Make a dimensional localization...
142 if ((size
->width
% 635) == 0 && (size
->length
% 635) == 0)
145 * Use inches since the size is a multiple of 1/4 inch.
148 snprintf(temp
, sizeof(temp
), _cupsLangString(lang
, _("%g x %g \"")), size
->width
/ 2540.0, size
->length
/ 2540.0);
153 * Use millimeters since the size is not a multiple of 1/4 inch.
156 snprintf(temp
, sizeof(temp
), _cupsLangString(lang
, _("%d x %d mm")), (size
->width
+ 50) / 100, (size
->length
+ 50) / 100);
164 DEBUG_printf(("1cupsLocalizeDestMedia: MATCH mdb%p [key=\"%s\" size_name=\"%s\" source=\"%s\" type=\"%s\" width=%d length=%d B%d L%d R%d T%d]", (void *)mdb
, mdb
->key
, mdb
->size_name
, mdb
->source
, mdb
->type
, mdb
->width
, mdb
->length
, mdb
->bottom
, mdb
->left
, mdb
->right
, mdb
->top
));
166 if ((lsource
= cupsLocalizeDestValue(http
, dest
, dinfo
, "media-source", mdb
->source
)) == mdb
->source
&& mdb
->source
)
167 lsource
= _cupsLangString(lang
, _("Other Tray"));
168 if ((ltype
= cupsLocalizeDestValue(http
, dest
, dinfo
, "media-type", mdb
->type
)) == mdb
->type
&& mdb
->type
)
169 ltype
= _cupsLangString(lang
, _("Other Media"));
177 if (!lsource
&& !ltype
)
179 if (!size
->bottom
&& !size
->left
&& !size
->right
&& !size
->top
)
180 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (Borderless)")), lsize
);
182 strlcpy(lstr
, lsize
, sizeof(lstr
));
186 if (!size
->bottom
&& !size
->left
&& !size
->right
&& !size
->top
)
187 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (Borderless, %s)")), lsize
, ltype
);
189 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (%s)")), lsize
, ltype
);
193 if (!size
->bottom
&& !size
->left
&& !size
->right
&& !size
->top
)
194 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (Borderless, %s)")), lsize
, lsource
);
196 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (%s)")), lsize
, lsource
);
200 if (!size
->bottom
&& !size
->left
&& !size
->right
&& !size
->top
)
201 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (Borderless, %s, %s)")), lsize
, ltype
, lsource
);
203 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (%s, %s)")), lsize
, ltype
, lsource
);
206 if ((match
= (_cups_message_t
*)calloc(1, sizeof(_cups_message_t
))) == NULL
)
209 match
->msg
= strdup(size
->media
);
210 match
->str
= strdup(lstr
);
212 cupsArrayAdd(dinfo
->localizations
, match
);
214 DEBUG_printf(("1cupsLocalizeDestMedia: Returning \"%s\".", match
->str
));
221 * 'cupsLocalizeDestOption()' - Get the localized string for a destination
224 * The returned string is stored in the destination information and will become
225 * invalid if the destination information is deleted.
227 * @since CUPS 1.6/macOS 10.8@
230 const char * /* O - Localized string */
231 cupsLocalizeDestOption(
232 http_t
*http
, /* I - Connection to destination */
233 cups_dest_t
*dest
, /* I - Destination */
234 cups_dinfo_t
*dinfo
, /* I - Destination information */
235 const char *option
) /* I - Option to localize */
237 _cups_message_t key
, /* Search key */
238 *match
; /* Matching entry */
239 const char *localized
; /* Localized string */
242 DEBUG_printf(("cupsLocalizeDestOption(http=%p, dest=%p, dinfo=%p, option=\"%s\")", (void *)http
, (void *)dest
, (void *)dinfo
, option
));
244 if (!http
|| !dest
|| !dinfo
)
247 if (!dinfo
->localizations
)
248 cups_create_localizations(http
, dinfo
);
250 key
.msg
= (char *)option
;
251 if ((match
= (_cups_message_t
*)cupsArrayFind(dinfo
->localizations
, &key
)) != NULL
)
253 else if ((localized
= _cupsLangString(cupsLangDefault(), option
)) != NULL
)
261 * 'cupsLocalizeDestValue()' - Get the localized string for a destination
264 * The returned string is stored in the destination information and will become
265 * invalid if the destination information is deleted.
267 * @since CUPS 1.6/macOS 10.8@
270 const char * /* O - Localized string */
271 cupsLocalizeDestValue(
272 http_t
*http
, /* I - Connection to destination */
273 cups_dest_t
*dest
, /* I - Destination */
274 cups_dinfo_t
*dinfo
, /* I - Destination information */
275 const char *option
, /* I - Option to localize */
276 const char *value
) /* I - Value to localize */
278 _cups_message_t key
, /* Search key */
279 *match
; /* Matching entry */
280 char pair
[256]; /* option.value pair */
281 const char *localized
; /* Localized string */
284 DEBUG_printf(("cupsLocalizeDestValue(http=%p, dest=%p, dinfo=%p, option=\"%s\", value=\"%s\")", (void *)http
, (void *)dest
, (void *)dinfo
, option
, value
));
286 if (!http
|| !dest
|| !dinfo
)
289 if (!strcmp(option
, "media"))
291 pwg_media_t
*media
= pwgMediaForPWG(value
);
294 strlcpy(size
.media
, value
, sizeof(size
.media
));
295 size
.width
= media
? media
->width
: 0;
296 size
.length
= media
? media
->length
: 0;
302 return (cupsLocalizeDestMedia(http
, dest
, dinfo
, CUPS_MEDIA_FLAGS_DEFAULT
, &size
));
305 if (!dinfo
->localizations
)
306 cups_create_localizations(http
, dinfo
);
308 snprintf(pair
, sizeof(pair
), "%s.%s", option
, value
);
310 if ((match
= (_cups_message_t
*)cupsArrayFind(dinfo
->localizations
, &key
)) != NULL
)
312 else if ((localized
= _cupsLangString(cupsLangDefault(), pair
)) != NULL
&& strcmp(localized
, pair
))
320 * 'cups_create_localizations()' - Create the localizations array for a
325 cups_create_localizations(
326 http_t
*http
, /* I - Connection to destination */
327 cups_dinfo_t
*dinfo
) /* I - Destination informations */
329 http_t
*http2
; /* Connection for strings file */
330 http_status_t status
; /* Request status */
331 ipp_attribute_t
*attr
; /* "printer-strings-uri" attribute */
332 char scheme
[32], /* URI scheme */
333 userpass
[256], /* Username/password info */
334 hostname
[256], /* Hostname */
335 resource
[1024], /* Resource */
337 /* Hostname of connection */
338 tempfile
[1024]; /* Temporary filename */
339 int port
; /* Port number */
340 http_encryption_t encryption
; /* Encryption to use */
341 cups_file_t
*temp
; /* Temporary file */
345 * See if there are any localizations...
348 if ((attr
= ippFindAttribute(dinfo
->attrs
, "printer-strings-uri",
349 IPP_TAG_URI
)) == NULL
)
352 * Nope, create an empty message catalog...
355 dinfo
->localizations
= _cupsMessageNew(NULL
);
356 DEBUG_puts("4cups_create_localizations: No printer-strings-uri (uri) value.");
361 * Pull apart the URI and determine whether we need to try a different
365 if (httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[0].string
.text
,
366 scheme
, sizeof(scheme
), userpass
, sizeof(userpass
),
367 hostname
, sizeof(hostname
), &port
, resource
,
368 sizeof(resource
)) < HTTP_URI_STATUS_OK
)
370 dinfo
->localizations
= _cupsMessageNew(NULL
);
371 DEBUG_printf(("4cups_create_localizations: Bad printer-strings-uri value \"%s\".", attr
->values
[0].string
.text
));
375 httpGetHostname(http
, http_hostname
, sizeof(http_hostname
));
377 if (!_cups_strcasecmp(http_hostname
, hostname
) &&
378 port
== httpAddrPort(http
->hostaddr
))
381 * Use the same connection...
389 * Connect to the alternate host...
392 if (!strcmp(scheme
, "https"))
393 encryption
= HTTP_ENCRYPTION_ALWAYS
;
395 encryption
= HTTP_ENCRYPTION_IF_REQUESTED
;
397 if ((http2
= httpConnect2(hostname
, port
, NULL
, AF_UNSPEC
, encryption
, 1,
398 30000, NULL
)) == NULL
)
400 DEBUG_printf(("4cups_create_localizations: Unable to connect to "
401 "%s:%d: %s", hostname
, port
, cupsLastErrorString()));
407 * Get a temporary file...
410 if ((temp
= cupsTempFile2(tempfile
, sizeof(tempfile
))) == NULL
)
412 DEBUG_printf(("4cups_create_localizations: Unable to create temporary "
413 "file: %s", cupsLastErrorString()));
419 status
= cupsGetFd(http2
, resource
, cupsFileNumber(temp
));
422 DEBUG_printf(("4cups_create_localizations: GET %s = %s", resource
, httpStatus(status
)));
424 if (status
== HTTP_STATUS_OK
)
427 * Got the file, read it...
430 dinfo
->localizations
= _cupsMessageLoad(tempfile
, _CUPS_MESSAGE_STRINGS
);
433 DEBUG_printf(("4cups_create_localizations: %d messages loaded.",
434 cupsArrayCount(dinfo
->localizations
)));