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"
20 static void cups_create_localizations(http_t
*http
, cups_dinfo_t
*dinfo
);
24 * 'cupsLocalizeDestMedia()' - Get the localized string for a destination media
27 * The returned string is stored in the destination information and will become
28 * invalid if the destination information is deleted.
30 * @since CUPS 2.0/macOS 10.10@
33 const char * /* O - Localized string */
34 cupsLocalizeDestMedia(
35 http_t
*http
, /* I - Connection to destination */
36 cups_dest_t
*dest
, /* I - Destination */
37 cups_dinfo_t
*dinfo
, /* I - Destination information */
38 unsigned flags
, /* I - Media flags */
39 cups_size_t
*size
) /* I - Media size */
41 cups_lang_t
*lang
; /* Standard localizations */
42 _cups_message_t key
, /* Search key */
43 *match
; /* Matching entry */
44 pwg_media_t
*pwg
; /* PWG media information */
45 cups_array_t
*db
; /* Media database */
46 _cups_media_db_t
*mdb
; /* Media database entry */
47 char lstr
[1024], /* Localized size name */
48 temp
[256]; /* Temporary string */
49 const char *lsize
, /* Localized media size */
50 *lsource
, /* Localized media source */
51 *ltype
; /* Localized media type */
54 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)"));
57 * Range check input...
60 if (!http
|| !dest
|| !dinfo
|| !size
)
62 DEBUG_puts("1cupsLocalizeDestMedia: Returning NULL.");
63 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
68 * Find the matching media database entry...
71 if (flags
& CUPS_MEDIA_FLAGS_READY
)
76 DEBUG_printf(("1cupsLocalizeDestMedia: size->media=\"%s\"", size
->media
));
78 for (mdb
= (_cups_media_db_t
*)cupsArrayFirst(db
); mdb
; mdb
= (_cups_media_db_t
*)cupsArrayNext(db
))
80 if (mdb
->key
&& !strcmp(mdb
->key
, size
->media
))
82 else if (mdb
->size_name
&& !strcmp(mdb
->size_name
, size
->media
))
88 for (mdb
= (_cups_media_db_t
*)cupsArrayFirst(db
); mdb
; mdb
= (_cups_media_db_t
*)cupsArrayNext(db
))
90 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
)
96 * See if the localization is cached...
99 lang
= cupsLangDefault();
101 if (!dinfo
->localizations
)
102 cups_create_localizations(http
, dinfo
);
104 snprintf(temp
, sizeof(temp
), "media.%s", size
->media
);
107 if ((match
= (_cups_message_t
*)cupsArrayFind(dinfo
->localizations
, &key
)) != NULL
)
114 * Not a media name, try a media-key name...
117 snprintf(temp
, sizeof(temp
), "media-key.%s", size
->media
);
118 if ((match
= (_cups_message_t
*)cupsArrayFind(dinfo
->localizations
, &key
)) != NULL
)
124 if (!lsize
&& (pwg
= pwgMediaForSize(size
->width
, size
->length
)) != NULL
&& pwg
->ppd
)
127 * Get a standard localization...
130 snprintf(temp
, sizeof(temp
), "media.%s", pwg
->pwg
);
131 if ((lsize
= _cupsLangString(lang
, temp
)) == temp
)
138 * Make a dimensional localization...
141 if ((size
->width
% 635) == 0 && (size
->length
% 635) == 0)
144 * Use inches since the size is a multiple of 1/4 inch.
147 snprintf(temp
, sizeof(temp
), _cupsLangString(lang
, _("%g x %g \"")), size
->width
/ 2540.0, size
->length
/ 2540.0);
152 * Use millimeters since the size is not a multiple of 1/4 inch.
155 snprintf(temp
, sizeof(temp
), _cupsLangString(lang
, _("%d x %d mm")), (size
->width
+ 50) / 100, (size
->length
+ 50) / 100);
163 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
));
165 if ((lsource
= cupsLocalizeDestValue(http
, dest
, dinfo
, "media-source", mdb
->source
)) == mdb
->source
&& mdb
->source
)
166 lsource
= _cupsLangString(lang
, _("Other Tray"));
167 if ((ltype
= cupsLocalizeDestValue(http
, dest
, dinfo
, "media-type", mdb
->type
)) == mdb
->type
&& mdb
->type
)
168 ltype
= _cupsLangString(lang
, _("Other Media"));
176 if (!lsource
&& !ltype
)
178 if (!size
->bottom
&& !size
->left
&& !size
->right
&& !size
->top
)
179 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (Borderless)")), lsize
);
181 strlcpy(lstr
, lsize
, sizeof(lstr
));
185 if (!size
->bottom
&& !size
->left
&& !size
->right
&& !size
->top
)
186 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (Borderless, %s)")), lsize
, ltype
);
188 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (%s)")), lsize
, ltype
);
192 if (!size
->bottom
&& !size
->left
&& !size
->right
&& !size
->top
)
193 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (Borderless, %s)")), lsize
, lsource
);
195 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (%s)")), lsize
, lsource
);
199 if (!size
->bottom
&& !size
->left
&& !size
->right
&& !size
->top
)
200 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (Borderless, %s, %s)")), lsize
, ltype
, lsource
);
202 snprintf(lstr
, sizeof(lstr
), _cupsLangString(lang
, _("%s (%s, %s)")), lsize
, ltype
, lsource
);
205 if ((match
= (_cups_message_t
*)calloc(1, sizeof(_cups_message_t
))) == NULL
)
208 match
->msg
= strdup(size
->media
);
209 match
->str
= strdup(lstr
);
211 cupsArrayAdd(dinfo
->localizations
, match
);
213 DEBUG_printf(("1cupsLocalizeDestMedia: Returning \"%s\".", match
->str
));
220 * 'cupsLocalizeDestOption()' - Get the localized string for a destination
223 * The returned string is stored in the destination information and will become
224 * invalid if the destination information is deleted.
226 * @since CUPS 1.6/macOS 10.8@
229 const char * /* O - Localized string */
230 cupsLocalizeDestOption(
231 http_t
*http
, /* I - Connection to destination */
232 cups_dest_t
*dest
, /* I - Destination */
233 cups_dinfo_t
*dinfo
, /* I - Destination information */
234 const char *option
) /* I - Option to localize */
236 _cups_message_t key
, /* Search key */
237 *match
; /* Matching entry */
238 const char *localized
; /* Localized string */
241 DEBUG_printf(("cupsLocalizeDestOption(http=%p, dest=%p, dinfo=%p, option=\"%s\")", (void *)http
, (void *)dest
, (void *)dinfo
, option
));
243 if (!http
|| !dest
|| !dinfo
)
246 if (!dinfo
->localizations
)
247 cups_create_localizations(http
, dinfo
);
249 key
.msg
= (char *)option
;
250 if ((match
= (_cups_message_t
*)cupsArrayFind(dinfo
->localizations
, &key
)) != NULL
)
252 else if ((localized
= _cupsLangString(cupsLangDefault(), option
)) != NULL
)
260 * 'cupsLocalizeDestValue()' - Get the localized string for a destination
263 * The returned string is stored in the destination information and will become
264 * invalid if the destination information is deleted.
266 * @since CUPS 1.6/macOS 10.8@
269 const char * /* O - Localized string */
270 cupsLocalizeDestValue(
271 http_t
*http
, /* I - Connection to destination */
272 cups_dest_t
*dest
, /* I - Destination */
273 cups_dinfo_t
*dinfo
, /* I - Destination information */
274 const char *option
, /* I - Option to localize */
275 const char *value
) /* I - Value to localize */
277 _cups_message_t key
, /* Search key */
278 *match
; /* Matching entry */
279 char pair
[256]; /* option.value pair */
280 const char *localized
; /* Localized string */
283 DEBUG_printf(("cupsLocalizeDestValue(http=%p, dest=%p, dinfo=%p, option=\"%s\", value=\"%s\")", (void *)http
, (void *)dest
, (void *)dinfo
, option
, value
));
285 if (!http
|| !dest
|| !dinfo
)
288 if (!strcmp(option
, "media"))
290 pwg_media_t
*media
= pwgMediaForPWG(value
);
293 strlcpy(size
.media
, value
, sizeof(size
.media
));
294 size
.width
= media
? media
->width
: 0;
295 size
.length
= media
? media
->length
: 0;
301 return (cupsLocalizeDestMedia(http
, dest
, dinfo
, CUPS_MEDIA_FLAGS_DEFAULT
, &size
));
304 if (!dinfo
->localizations
)
305 cups_create_localizations(http
, dinfo
);
307 snprintf(pair
, sizeof(pair
), "%s.%s", option
, value
);
309 if ((match
= (_cups_message_t
*)cupsArrayFind(dinfo
->localizations
, &key
)) != NULL
)
311 else if ((localized
= _cupsLangString(cupsLangDefault(), pair
)) != NULL
&& strcmp(localized
, pair
))
319 * 'cups_create_localizations()' - Create the localizations array for a
324 cups_create_localizations(
325 http_t
*http
, /* I - Connection to destination */
326 cups_dinfo_t
*dinfo
) /* I - Destination informations */
328 http_t
*http2
; /* Connection for strings file */
329 http_status_t status
; /* Request status */
330 ipp_attribute_t
*attr
; /* "printer-strings-uri" attribute */
331 char scheme
[32], /* URI scheme */
332 userpass
[256], /* Username/password info */
333 hostname
[256], /* Hostname */
334 resource
[1024], /* Resource */
336 /* Hostname of connection */
337 tempfile
[1024]; /* Temporary filename */
338 int port
; /* Port number */
339 http_encryption_t encryption
; /* Encryption to use */
340 cups_file_t
*temp
; /* Temporary file */
344 * See if there are any localizations...
347 if ((attr
= ippFindAttribute(dinfo
->attrs
, "printer-strings-uri",
348 IPP_TAG_URI
)) == NULL
)
351 * Nope, create an empty message catalog...
354 dinfo
->localizations
= _cupsMessageNew(NULL
);
355 DEBUG_puts("4cups_create_localizations: No printer-strings-uri (uri) value.");
360 * Pull apart the URI and determine whether we need to try a different
364 if (httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[0].string
.text
,
365 scheme
, sizeof(scheme
), userpass
, sizeof(userpass
),
366 hostname
, sizeof(hostname
), &port
, resource
,
367 sizeof(resource
)) < HTTP_URI_STATUS_OK
)
369 dinfo
->localizations
= _cupsMessageNew(NULL
);
370 DEBUG_printf(("4cups_create_localizations: Bad printer-strings-uri value \"%s\".", attr
->values
[0].string
.text
));
374 httpGetHostname(http
, http_hostname
, sizeof(http_hostname
));
376 if (!_cups_strcasecmp(http_hostname
, hostname
) &&
377 port
== httpAddrPort(http
->hostaddr
))
380 * Use the same connection...
388 * Connect to the alternate host...
391 if (!strcmp(scheme
, "https"))
392 encryption
= HTTP_ENCRYPTION_ALWAYS
;
394 encryption
= HTTP_ENCRYPTION_IF_REQUESTED
;
396 if ((http2
= httpConnect2(hostname
, port
, NULL
, AF_UNSPEC
, encryption
, 1,
397 30000, NULL
)) == NULL
)
399 DEBUG_printf(("4cups_create_localizations: Unable to connect to "
400 "%s:%d: %s", hostname
, port
, cupsLastErrorString()));
406 * Get a temporary file...
409 if ((temp
= cupsTempFile2(tempfile
, sizeof(tempfile
))) == NULL
)
411 DEBUG_printf(("4cups_create_localizations: Unable to create temporary "
412 "file: %s", cupsLastErrorString()));
418 status
= cupsGetFd(http2
, resource
, cupsFileNumber(temp
));
421 DEBUG_printf(("4cups_create_localizations: GET %s = %s", resource
, httpStatus(status
)));
423 if (status
== HTTP_STATUS_OK
)
426 * Got the file, read it...
429 dinfo
->localizations
= _cupsMessageLoad(tempfile
, _CUPS_MESSAGE_STRINGS
);
432 DEBUG_printf(("4cups_create_localizations: %d messages loaded.",
433 cupsArrayCount(dinfo
->localizations
)));