From: Michael R Sweet Date: Fri, 10 Nov 2017 20:33:47 +0000 (-0500) Subject: Add media-type localizations for printer-specific media types (Issue #5168) X-Git-Tag: v2.3b1~53 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=89550f3f3373604d656a422896600446c33e1f2e;p=thirdparty%2Fcups.git Add media-type localizations for printer-specific media types (Issue #5168) cups/dest-localization.c: Move .strings file loader to language.c. cups/language-private.h: Add load options for _cupsMessageLoad. cups/language.c: Move .strings file loader to this file. cups/ppd-cache.c: Save printer-strings-uri value and load the strings file for m edia-type cups/ppd-private.h: Bump cache version and add strings_uri. locale/checkpo.c: Use _cupsMessageLoad for .strings files. --- diff --git a/CHANGES.md b/CHANGES.md index 8e3d2a96a0..3ad6777eec 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -37,3 +37,5 @@ Changes in CUPS v2.3b1 - Added label markup to checkbox and radio button controls in the web interface templates (Issue #5161) - Fixed group validation on OpenBSD (Issue #5166) +- IPP Everywhere PPDs now include localizations of printer-specific media types, + when available (Issue #5168) diff --git a/cups/dest-localization.c b/cups/dest-localization.c index a35540b728..1eef3ea7a8 100644 --- a/cups/dest-localization.c +++ b/cups/dest-localization.c @@ -1,7 +1,7 @@ /* * Destination localization support for CUPS. * - * Copyright 2012-2014 by Apple Inc. + * Copyright 2012-2017 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ @@ -18,9 +18,6 @@ */ static void cups_create_localizations(http_t *http, cups_dinfo_t *dinfo); -static int cups_read_strings(cups_file_t *fp, char *buffer, size_t bufsize, - char **id, char **str); -static char *cups_scan_strings(char *buffer); /* @@ -74,7 +71,7 @@ cupsLocalizeDestMedia( if (!dinfo->localizations) cups_create_localizations(http, dinfo); - key.id = size->media; + key.msg = size->media; if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, &key)) != NULL) { DEBUG_printf(("1cupsLocalizeDestMedia: Returning \"%s\".", match->str)); @@ -192,7 +189,7 @@ cupsLocalizeDestMedia( if ((match = (_cups_message_t *)calloc(1, sizeof(_cups_message_t))) == NULL) return (NULL); - match->id = strdup(size->media); + match->msg = strdup(size->media); match->str = strdup(name); cupsArrayAdd(dinfo->localizations, match); @@ -233,9 +230,8 @@ cupsLocalizeDestOption( if (!dinfo->localizations) cups_create_localizations(http, dinfo); - key.id = (char *)option; - if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, - &key)) != NULL) + key.msg = (char *)option; + if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, &key)) != NULL) return (match->str); else if ((localized = _cupsLangString(cupsLangDefault(), option)) != NULL) return (localized); @@ -293,9 +289,8 @@ cupsLocalizeDestValue( cups_create_localizations(http, dinfo); snprintf(pair, sizeof(pair), "%s.%s", option, value); - key.id = pair; - if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, - &key)) != NULL) + key.msg = pair; + if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, &key)) != NULL) return (match->str); else if ((localized = _cupsLangString(cupsLangDefault(), pair)) != NULL && strcmp(localized, pair)) return (localized); @@ -329,12 +324,6 @@ cups_create_localizations( cups_file_t *temp; /* Temporary file */ - /* - * Create an empty message catalog... - */ - - dinfo->localizations = _cupsMessageNew(NULL); - /* * See if there are any localizations... */ @@ -343,12 +332,12 @@ cups_create_localizations( IPP_TAG_URI)) == NULL) { /* - * Nope... + * Nope, create an empty message catalog... */ - DEBUG_puts("4cups_create_localizations: No printer-strings-uri (uri) " - "value."); - return; /* Nope */ + dinfo->localizations = _cupsMessageNew(NULL); + DEBUG_puts("4cups_create_localizations: No printer-strings-uri (uri) value."); + return; } /* @@ -361,8 +350,8 @@ cups_create_localizations( hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) { - DEBUG_printf(("4cups_create_localizations: Bad printer-strings-uri value " - "\"%s\".", attr->values[0].string.text)); + dinfo->localizations = _cupsMessageNew(NULL); + DEBUG_printf(("4cups_create_localizations: Bad printer-strings-uri value \"%s\".", attr->values[0].string.text)); return; } @@ -411,9 +400,9 @@ cups_create_localizations( } status = cupsGetFd(http2, resource, cupsFileNumber(temp)); + cupsFileClose(temp); - DEBUG_printf(("4cups_create_localizations: GET %s = %s", resource, - httpStatus(status))); + DEBUG_printf(("4cups_create_localizations: GET %s = %s", resource, httpStatus(status))); if (status == HTTP_STATUS_OK) { @@ -421,35 +410,7 @@ cups_create_localizations( * Got the file, read it... */ - char buffer[8192], /* Message buffer */ - *id, /* ID string */ - *str; /* Translated message */ - _cups_message_t *m; /* Current message */ - - lseek(cupsFileNumber(temp), 0, SEEK_SET); - - while (cups_read_strings(temp, buffer, sizeof(buffer), &id, &str)) - { - if ((m = malloc(sizeof(_cups_message_t))) == NULL) - break; - - m->id = strdup(id); - m->str = strdup(str); - - if (m->id && m->str) - cupsArrayAdd(dinfo->localizations, m); - else - { - if (m->id) - free(m->id); - - if (m->str) - free(m->str); - - free(m); - break; - } - } + dinfo->localizations = _cupsMessageLoad(tempfile, _CUPS_MESSAGE_STRINGS); } DEBUG_printf(("4cups_create_localizations: %d messages loaded.", @@ -460,102 +421,8 @@ cups_create_localizations( */ unlink(tempfile); - cupsFileClose(temp); if (http2 != http) httpClose(http2); } - -/* - * 'cups_read_strings()' - Read a pair of strings from a .strings file. - */ - -static int /* O - 1 on success, 0 on failure */ -cups_read_strings(cups_file_t *strings, /* I - .strings file */ - char *buffer, /* I - Line buffer */ - size_t bufsize, /* I - Size of line buffer */ - char **id, /* O - Pointer to ID string */ - char **str) /* O - Pointer to translation string */ -{ - char *bufptr; /* Pointer into buffer */ - - - while (cupsFileGets(strings, buffer, bufsize)) - { - if (buffer[0] != '\"') - continue; - - *id = buffer + 1; - bufptr = cups_scan_strings(buffer); - - if (*bufptr != '\"') - continue; - - *bufptr++ = '\0'; - - while (*bufptr && *bufptr != '\"') - bufptr ++; - - if (!*bufptr) - continue; - - *str = bufptr + 1; - bufptr = cups_scan_strings(bufptr); - - if (*bufptr != '\"') - continue; - - *bufptr = '\0'; - - return (1); - } - - return (0); -} - - -/* - * 'cups_scan_strings()' - Scan a quoted string. - */ - -static char * /* O - End of string */ -cups_scan_strings(char *buffer) /* I - Start of string */ -{ - char *bufptr; /* Pointer into string */ - - - for (bufptr = buffer + 1; *bufptr && *bufptr != '\"'; bufptr ++) - { - if (*bufptr == '\\') - { - if (bufptr[1] >= '0' && bufptr[1] <= '3' && - bufptr[2] >= '0' && bufptr[2] <= '7' && - bufptr[3] >= '0' && bufptr[3] <= '7') - { - /* - * Decode \nnn octal escape... - */ - - *bufptr = (char)(((((bufptr[1] - '0') << 3) | (bufptr[2] - '0')) << 3) | (bufptr[3] - '0')); - _cups_strcpy(bufptr + 1, bufptr + 4); - } - else - { - /* - * Decode \C escape... - */ - - _cups_strcpy(bufptr, bufptr + 1); - if (*bufptr == 'n') - *bufptr = '\n'; - else if (*bufptr == 'r') - *bufptr = '\r'; - else if (*bufptr == 't') - *bufptr = '\t'; - } - } - } - - return (bufptr); -} diff --git a/cups/language-private.h b/cups/language-private.h index bd5daf0d1b..ca6a9cb4e5 100644 --- a/cups/language-private.h +++ b/cups/language-private.h @@ -32,13 +32,21 @@ extern "C" { # define _(x) x +/* + * Constants... + */ + +# define _CUPS_MESSAGE_UNQUOTE 1 /* Unescape \foo in strings? */ +# define _CUPS_MESSAGE_STRINGS 2 /* Message file is in Apple .strings format */ + + /* * Types... */ typedef struct _cups_message_s /**** Message catalog entry ****/ { - char *id, /* Original string */ + char *msg, /* Original string */ *str; /* Localized string */ } _cups_message_t; @@ -64,7 +72,7 @@ extern int _cupsLangPuts(FILE *fp, const char *message); extern const char *_cupsLangString(cups_lang_t *lang, const char *message); extern void _cupsMessageFree(cups_array_t *a); -extern cups_array_t *_cupsMessageLoad(const char *filename, int unquote); +extern cups_array_t *_cupsMessageLoad(const char *filename, int flags); extern const char *_cupsMessageLookup(cups_array_t *a, const char *m); extern cups_array_t *_cupsMessageNew(void *context); extern void _cupsSetLocale(char *argv[]); diff --git a/cups/language.c b/cups/language.c index aefba55518..1f2a125be8 100644 --- a/cups/language.c +++ b/cups/language.c @@ -140,16 +140,14 @@ static const char *appleLangDefault(void); # define CF_RETURNS_RETAINED # endif /* __has_feature(attribute_cf_returns_retained) */ # endif /* !CF_RETURNED_RETAINED */ -static cups_array_t *appleMessageLoad(const char *locale) - CF_RETURNS_RETAINED; +static cups_array_t *appleMessageLoad(const char *locale) CF_RETURNS_RETAINED; # endif /* CUPS_BUNDLEDIR */ #endif /* __APPLE__ */ -static cups_lang_t *cups_cache_lookup(const char *name, - cups_encoding_t encoding); -static int cups_message_compare(_cups_message_t *m1, - _cups_message_t *m2); +static cups_lang_t *cups_cache_lookup(const char *name, cups_encoding_t encoding); +static int cups_message_compare(_cups_message_t *m1, _cups_message_t *m2); static void cups_message_free(_cups_message_t *m); static void cups_message_load(cups_lang_t *lang); +static int cups_read_strings(cups_file_t *fp, int flags, cups_array_t *a); static void cups_unquote(char *d, const char *s); @@ -906,12 +904,12 @@ _cupsMessageFree(cups_array_t *a) /* I - Message array */ /* - * '_cupsMessageLoad()' - Load a .po file into a messages array. + * '_cupsMessageLoad()' - Load a .po or .strings file into a messages array. */ cups_array_t * /* O - New message array */ _cupsMessageLoad(const char *filename, /* I - Message catalog to load */ - int unquote) /* I - Unescape \foo in strings? */ + int flags) /* I - Load flags */ { cups_file_t *fp; /* Message file */ cups_array_t *a; /* Message array */ @@ -946,187 +944,189 @@ _cupsMessageLoad(const char *filename, /* I - Message catalog to load */ return (a); } - /* - * Read messages from the catalog file until EOF... - * - * The format is the GNU gettext .po format, which is fairly simple: - * - * msgid "some text" - * msgstr "localized text" - * - * The ID and localized text can span multiple lines using the form: - * - * msgid "" - * "some long text" - * msgstr "" - * "localized text spanning " - * "multiple lines" - */ - - m = NULL; - - while (cupsFileGets(fp, s, sizeof(s)) != NULL) + if (flags & _CUPS_MESSAGE_STRINGS) + { + while (cups_read_strings(fp, flags, a)); + } + else { /* - * Skip blank and comment lines... - */ - - if (s[0] == '#' || !s[0]) - continue; - - /* - * Strip the trailing quote... + * Read messages from the catalog file until EOF... + * + * The format is the GNU gettext .po format, which is fairly simple: + * + * msgid "some text" + * msgstr "localized text" + * + * The ID and localized text can span multiple lines using the form: + * + * msgid "" + * "some long text" + * msgstr "" + * "localized text spanning " + * "multiple lines" */ - if ((ptr = strrchr(s, '\"')) == NULL) - continue; - - *ptr = '\0'; - - /* - * Find start of value... - */ + m = NULL; - if ((ptr = strchr(s, '\"')) == NULL) - continue; + while (cupsFileGets(fp, s, sizeof(s)) != NULL) + { + /* + * Skip blank and comment lines... + */ - ptr ++; + if (s[0] == '#' || !s[0]) + continue; - /* - * Unquote the text... - */ + /* + * Strip the trailing quote... + */ - if (unquote) - cups_unquote(ptr, ptr); + if ((ptr = strrchr(s, '\"')) == NULL) + continue; - /* - * Create or add to a message... - */ + *ptr = '\0'; - if (!strncmp(s, "msgid", 5)) - { /* - * Add previous message as needed... + * Find start of value... */ - if (m) - { - if (m->str && m->str[0]) - { - cupsArrayAdd(a, m); - } - else - { - /* - * Translation is empty, don't add it... (STR #4033) - */ - - free(m->id); - if (m->str) - free(m->str); - free(m); - } - } + if ((ptr = strchr(s, '\"')) == NULL) + continue; + + ptr ++; /* - * Create a new message with the given msgid string... + * Unquote the text... */ - if ((m = (_cups_message_t *)calloc(1, sizeof(_cups_message_t))) == NULL) - { - cupsFileClose(fp); - return (a); - } + if (flags & _CUPS_MESSAGE_UNQUOTE) + cups_unquote(ptr, ptr); - if ((m->id = strdup(ptr)) == NULL) - { - free(m); - cupsFileClose(fp); - return (a); - } - } - else if (s[0] == '\"' && m) - { /* - * Append to current string... + * Create or add to a message... */ - length = strlen(m->str ? m->str : m->id); - ptrlen = strlen(ptr); - - if ((temp = realloc(m->str ? m->str : m->id, length + ptrlen + 1)) == NULL) + if (!strncmp(s, "msgid", 5)) { - if (m->str) - free(m->str); - free(m->id); - free(m); + /* + * Add previous message as needed... + */ - cupsFileClose(fp); - return (a); - } + if (m) + { + if (m->str && m->str[0]) + { + cupsArrayAdd(a, m); + } + else + { + /* + * Translation is empty, don't add it... (STR #4033) + */ + + free(m->msg); + if (m->str) + free(m->str); + free(m); + } + } - if (m->str) - { /* - * Copy the new portion to the end of the msgstr string - safe - * to use memcpy because the buffer is allocated to the correct - * size... + * Create a new message with the given msgid string... */ - m->str = temp; + if ((m = (_cups_message_t *)calloc(1, sizeof(_cups_message_t))) == NULL) + break; - memcpy(m->str + length, ptr, ptrlen + 1); + if ((m->msg = strdup(ptr)) == NULL) + { + free(m); + m = NULL; + break; + } } - else + else if (s[0] == '\"' && m) { /* - * Copy the new portion to the end of the msgid string - safe - * to use memcpy because the buffer is allocated to the correct - * size... + * Append to current string... */ - m->id = temp; + length = strlen(m->str ? m->str : m->msg); + ptrlen = strlen(ptr); - memcpy(m->id + length, ptr, ptrlen + 1); - } - } - else if (!strncmp(s, "msgstr", 6) && m) - { - /* - * Set the string... - */ + if ((temp = realloc(m->str ? m->str : m->msg, length + ptrlen + 1)) == NULL) + { + if (m->str) + free(m->str); + free(m->msg); + free(m); + m = NULL; + break; + } - if ((m->str = strdup(ptr)) == NULL) + if (m->str) + { + /* + * Copy the new portion to the end of the msgstr string - safe + * to use memcpy because the buffer is allocated to the correct + * size... + */ + + m->str = temp; + + memcpy(m->str + length, ptr, ptrlen + 1); + } + else + { + /* + * Copy the new portion to the end of the msgid string - safe + * to use memcpy because the buffer is allocated to the correct + * size... + */ + + m->msg = temp; + + memcpy(m->msg + length, ptr, ptrlen + 1); + } + } + else if (!strncmp(s, "msgstr", 6) && m) { - free(m->id); - free(m); + /* + * Set the string... + */ - cupsFileClose(fp); - return (a); + if ((m->str = strdup(ptr)) == NULL) + { + free(m->msg); + free(m); + m = NULL; + break; + } } } - } - /* - * Add the last message string to the array as needed... - */ + /* + * Add the last message string to the array as needed... + */ - if (m) - { - if (m->str && m->str[0]) + if (m) { - cupsArrayAdd(a, m); - } - else - { - /* - * Translation is empty, don't add it... (STR #4033) - */ + if (m->str && m->str[0]) + { + cupsArrayAdd(a, m); + } + else + { + /* + * Translation is empty, don't add it... (STR #4033) + */ - free(m->id); - if (m->str) - free(m->str); - free(m); + free(m->msg); + if (m->str) + free(m->str); + free(m); + } } } @@ -1136,8 +1136,7 @@ _cupsMessageLoad(const char *filename, /* I - Message catalog to load */ cupsFileClose(fp); - DEBUG_printf(("5_cupsMessageLoad: Returning %d messages...", - cupsArrayCount(a))); + DEBUG_printf(("5_cupsMessageLoad: Returning %d messages...", cupsArrayCount(a))); return (a); } @@ -1162,8 +1161,8 @@ _cupsMessageLookup(cups_array_t *a, /* I - Message array */ * then return the message that was passed to us... */ - key.id = (char *)m; - match = (_cups_message_t *)cupsArrayFind(a, &key); + key.msg = (char *)m; + match = (_cups_message_t *)cupsArrayFind(a, &key); #if defined(__APPLE__) && defined(CUPS_BUNDLEDIR) if (!match && cupsArrayUserData(a)) @@ -1176,12 +1175,11 @@ _cupsMessageLookup(cups_array_t *a, /* I - Message array */ CFStringRef cfm, /* Message as a CF string */ cfstr; /* Localized text as a CF string */ - dict = (CFDictionaryRef)cupsArrayUserData(a); - cfm = CFStringCreateWithCString(kCFAllocatorDefault, m, - kCFStringEncodingUTF8); - match = calloc(1, sizeof(_cups_message_t)); - match->id = strdup(m); - cfstr = cfm ? CFDictionaryGetValue(dict, cfm) : NULL; + dict = (CFDictionaryRef)cupsArrayUserData(a); + cfm = CFStringCreateWithCString(kCFAllocatorDefault, m, kCFStringEncodingUTF8); + match = calloc(1, sizeof(_cups_message_t)); + match->msg = strdup(m); + cfstr = cfm ? CFDictionaryGetValue(dict, cfm) : NULL; if (cfstr) { @@ -1190,8 +1188,7 @@ _cupsMessageLookup(cups_array_t *a, /* I - Message array */ CFStringGetCString(cfstr, buffer, sizeof(buffer), kCFStringEncodingUTF8); match->str = strdup(buffer); - DEBUG_printf(("1_cupsMessageLookup: Found \"%s\" as \"%s\"...", - m, buffer)); + DEBUG_printf(("1_cupsMessageLookup: Found \"%s\" as \"%s\"...", m, buffer)); } else { @@ -1601,7 +1598,7 @@ cups_message_compare( _cups_message_t *m1, /* I - First message */ _cups_message_t *m2) /* I - Second message */ { - return (strcmp(m1->id, m2->id)); + return (strcmp(m1->msg, m2->msg)); } @@ -1612,8 +1609,8 @@ cups_message_compare( static void cups_message_free(_cups_message_t *m) /* I - Message */ { - if (m->id) - free(m->id); + if (m->msg) + free(m->msg); if (m->str) free(m->str); @@ -1667,11 +1664,128 @@ cups_message_load(cups_lang_t *lang) /* I - Language */ * Read the strings from the file... */ - lang->strings = _cupsMessageLoad(filename, 1); + lang->strings = _cupsMessageLoad(filename, _CUPS_MESSAGE_UNQUOTE); #endif /* __APPLE__ && CUPS_BUNDLEDIR */ } +/* + * 'cups_read_strings()' - Read a pair of strings from a .strings file. + */ + +static int /* O - 1 on success, 0 on failure */ +cups_read_strings(cups_file_t *fp, /* I - .strings file */ + int flags, /* I - CUPS_MESSAGE_xxx flags */ + cups_array_t *a) /* I - Message catalog array */ +{ + char buffer[8192], /* Line buffer */ + *bufptr, /* Pointer into buffer */ + *msg, /* Pointer to start of message */ + *str; /* Pointer to start of translation string */ + _cups_message_t *m; /* New message */ + + + while (cupsFileGets(fp, buffer, sizeof(buffer))) + { + /* + * Skip any line (comments, blanks, etc.) that isn't: + * + * "message" = "translation"; + */ + + for (bufptr = buffer; *bufptr && isspace(*bufptr & 255); bufptr ++); + + if (*bufptr != '\"') + continue; + + /* + * Find the end of the message... + */ + + bufptr ++; + for (msg = bufptr; *bufptr && *bufptr != '\"'; bufptr ++) + if (*bufptr == '\\' && bufptr[1]) + bufptr ++; + + if (!*bufptr) + continue; + + *bufptr++ = '\0'; + + if (flags & _CUPS_MESSAGE_UNQUOTE) + cups_unquote(msg, msg); + + /* + * Find the start of the translation... + */ + + while (*bufptr && isspace(*bufptr & 255)) + bufptr ++; + + if (*bufptr != '=') + continue; + + bufptr ++; + while (*bufptr && isspace(*bufptr & 255)) + bufptr ++; + + if (*bufptr != '\"') + continue; + + /* + * Find the end of the translation... + */ + + bufptr ++; + for (str = bufptr; *bufptr && *bufptr != '\"'; bufptr ++) + if (*bufptr == '\\' && bufptr[1]) + bufptr ++; + + if (!*bufptr) + continue; + + *bufptr++ = '\0'; + + if (flags & _CUPS_MESSAGE_UNQUOTE) + cups_unquote(str, str); + + /* + * If we get this far we have a valid pair of strings, add them... + */ + + if ((m = malloc(sizeof(_cups_message_t))) == NULL) + break; + + m->msg = strdup(msg); + m->str = strdup(str); + + if (m->msg && m->str) + { + cupsArrayAdd(a, m); + } + else + { + if (m->msg) + free(m->msg); + + if (m->str) + free(m->str); + + free(m); + break; + } + + return (1); + } + + /* + * No more strings... + */ + + return (0); +} + + /* * 'cups_unquote()' - Unquote characters in strings... */ diff --git a/cups/ppd-cache.c b/cups/ppd-cache.c index da1414796c..9d9cf7602c 100644 --- a/cups/ppd-cache.c +++ b/cups/ppd-cache.c @@ -26,6 +26,7 @@ * Local functions... */ +static int cups_get_url(http_t **http, const char *url, char *name, size_t namesize); static void pwg_add_finishing(cups_array_t *finishings, ipp_finishings_t template, const char *name, const char *value); static int pwg_compare_finishings(_pwg_finishings_t *a, _pwg_finishings_t *b); @@ -879,6 +880,8 @@ _ppdCacheCreateWithFile( else pc->mandatory = _cupsArrayNewStrings(value, ' '); } + else if (!_cups_strcasecmp(line, "StringsURI")) + pc->strings_uri = _cupsStrAlloc(value); else if (!_cups_strcasecmp(line, "SupportFile")) { if (!pc->support_files) @@ -1826,6 +1829,13 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ if ((ppd_attr = ppdFindAttr(ppd, "cupsMandatory", NULL)) != NULL) pc->mandatory = _cupsArrayNewStrings(ppd_attr->value, ' '); + /* + * Strings (remote) file... + */ + + if ((ppd_attr = ppdFindAttr(ppd, "cupsStringsURI", NULL)) != NULL) + pc->strings_uri = _cupsStrAlloc(ppd_attr->value); + /* * Support files... */ @@ -2893,6 +2903,13 @@ _ppdCacheWriteFile( value = (char *)cupsArrayNext(pc->mandatory)) cupsFilePutConf(fp, "Mandatory", value); + /* + * (Remote) strings file... + */ + + if (pc->strings_uri) + cupsFilePutConf(fp, "StringsURI", pc->strings_uri); + /* * Support files... */ @@ -2965,6 +2982,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ /* Array of resolution indices */ cups_lang_t *lang = cupsLangDefault(); /* Localization info */ + cups_array_t *strings = NULL;/* Printer strings file */ struct lconv *loc = localeconv(); /* Locale data */ static const char * const finishings[][2] = @@ -3109,7 +3127,31 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePrintf(fp, "*cupsVersion: %d.%d\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR); cupsFilePuts(fp, "*cupsSNMPSupplies: False\n"); - cupsFilePuts(fp, "*cupsLanguages: \"en\"\n"); + cupsFilePrintf(fp, "*cupsLanguages: \"%s\"\n", lang->language); + + if ((attr = ippFindAttribute(response, "printer-more-info", IPP_TAG_URI)) != NULL) + cupsFilePrintf(fp, "*APSupplies: \"%s\"\n", ippGetString(attr, 0, NULL)); + + if ((attr = ippFindAttribute(response, "printer-charge-info-uri", IPP_TAG_URI)) != NULL) + cupsFilePrintf(fp, "*cupsChargeInfoURI: \"%s\"\n", ippGetString(attr, 0, NULL)); + + if ((attr = ippFindAttribute(response, "printer-strings-uri", IPP_TAG_URI)) != NULL) + { + http_t *http = NULL; /* Connection to printer */ + char stringsfile[1024]; /* Temporary strings file */ + + if (cups_get_url(&http, ippGetString(attr, 0, NULL), stringsfile, sizeof(stringsfile))) + { + cupsFilePrintf(fp, "*cupsStringsURI: \"%s\"\n", ippGetString(attr, 0, NULL)); + + strings = _cupsMessageLoad(stringsfile, _CUPS_MESSAGE_STRINGS | _CUPS_MESSAGE_UNQUOTE); + + unlink(stringsfile); + } + + if (http) + httpClose(http); + } /* * Filters... @@ -3586,7 +3628,16 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if (j < (int)(sizeof(media_types) / sizeof(media_types[0]))) cupsFilePrintf(fp, "*MediaType %s/%s: \"<>setpagedevice\"\n", ppdname, _cupsLangString(lang, media_types[j][1]), ppdname); else - cupsFilePrintf(fp, "*MediaType %s/%s: \"<>setpagedevice\"\n", ppdname, keyword, ppdname); + { + char msg[256]; /* Message key */ + const char *str; /* Localized string */ + + snprintf(msg, sizeof(msg), "media-type.%s", keyword); + if ((str = _cupsMessageLookup(strings, msg)) == msg) + str = keyword; + + cupsFilePrintf(fp, "*MediaType %s/%s: \"<>setpagedevice\"\n", ppdname, str, ppdname); + } } cupsFilePuts(fp, "*CloseUI: *MediaType\n"); } @@ -4295,6 +4346,62 @@ _pwgPageSizeForMedia( } +/* + * 'cups_get_url()' - Get a copy of the file at the given URL. + */ + +static int /* O - 1 on success, 0 on failure */ +cups_get_url(http_t **http, /* IO - Current HTTP connection */ + const char *url, /* I - URL to get */ + char *name, /* I - Temporary filename */ + size_t namesize) /* I - Size of temporary filename buffer */ +{ + char scheme[32], /* URL scheme */ + userpass[256], /* URL username:password */ + host[256], /* URL host */ + curhost[256], /* Current host */ + resource[256]; /* URL resource */ + int port; /* URL port */ + http_encryption_t encryption; /* Type of encryption to use */ + http_status_t status; /* Status of GET request */ + int fd; /* Temporary file */ + + + if (httpSeparateURI(HTTP_URI_CODING_ALL, url, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) + return (0); + + if (port == 443 || !strcmp(scheme, "https")) + encryption = HTTP_ENCRYPTION_ALWAYS; + else + encryption = HTTP_ENCRYPTION_IF_REQUESTED; + + if (!*http || strcasecmp(host, httpGetHostname(*http, curhost, sizeof(curhost))) || httpAddrPort(httpGetAddress(*http)) != port) + { + httpClose(*http); + *http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 5000, NULL); + } + + if (!*http) + return (0); + + if ((fd = cupsTempFd(name, (int)namesize)) < 0) + return (0); + + status = cupsGetFd(*http, resource, fd); + + close(fd); + + if (status != HTTP_STATUS_OK) + { + unlink(name); + *name = '\0'; + return (0); + } + + return (1); +} + + /* * 'pwg_add_finishing()' - Add a finishings value. */ diff --git a/cups/ppd-private.h b/cups/ppd-private.h index e14b952c4e..e7c0d6e5f8 100644 --- a/cups/ppd-private.h +++ b/cups/ppd-private.h @@ -4,16 +4,10 @@ * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * - * Licensed under Apache License v2.0. See the file "LICENSE" for more information. + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. * * PostScript is a trademark of Adobe Systems, Inc. - * - * This code and any derivative of it may be used and distributed - * freely under the terms of the GNU General Public License when - * used with GNU Ghostscript or its derivatives. Use of the code - * (or any derivative of it) with software other than GNU - * GhostScript (or its derivatives) is governed by the CUPS license - * agreement. */ #ifndef _CUPS_PPD_PRIVATE_H_ @@ -41,7 +35,7 @@ extern "C" { * Constants... */ -# define _PPD_CACHE_VERSION 8 /* Version number in cache file */ +# define _PPD_CACHE_VERSION 9 /* Version number in cache file */ /* @@ -151,6 +145,7 @@ struct _ppd_cache_s /**** PPD cache and PWG conversion data ****/ char *password; /* cupsJobPassword value */ cups_array_t *mandatory; /* cupsMandatory value */ char *charge_info_uri; /* cupsChargeInfoURI value */ + char *strings_uri; /* cupsStringsURI value */ cups_array_t *support_files; /* Support files - ICC profiles, etc. */ }; diff --git a/locale/checkpo.c b/locale/checkpo.c index f46f4cef0f..75d9255dad 100644 --- a/locale/checkpo.c +++ b/locale/checkpo.c @@ -25,9 +25,6 @@ static char *abbreviate(const char *s, char *buf, int bufsize); static cups_array_t *collect_formats(const char *id); -static cups_array_t *cups_load_strings(const char *filename); -static int cups_read_strings(cups_file_t *fp, char *buffer, size_t bufsize, char **id, char **str); -static char *cups_scan_strings(char *buffer); static void free_formats(cups_array_t *fmts); @@ -71,9 +68,9 @@ main(int argc, /* I - Number of command-line args */ */ if (strstr(argv[i], ".strings")) - po = cups_load_strings(argv[i]); + po = _cupsMessageLoad(argv[i], _CUPS_MESSAGE_STRINGS | _CUPS_MESSAGE_UNQUOTE); else - po = _cupsMessageLoad(argv[i], 1); + po = _cupsMessageLoad(argv[i], _CUPS_MESSAGE_UNQUOTE); if (!po) { @@ -102,11 +99,11 @@ main(int argc, /* I - Number of command-line args */ * Make sure filter message prefixes are not translated... */ - if (!strncmp(msg->id, "ALERT:", 6) || !strncmp(msg->id, "CRIT:", 5) || - !strncmp(msg->id, "DEBUG:", 6) || !strncmp(msg->id, "DEBUG2:", 7) || - !strncmp(msg->id, "EMERG:", 6) || !strncmp(msg->id, "ERROR:", 6) || - !strncmp(msg->id, "INFO:", 5) || !strncmp(msg->id, "NOTICE:", 7) || - !strncmp(msg->id, "WARNING:", 8)) + if (!strncmp(msg->msg, "ALERT:", 6) || !strncmp(msg->msg, "CRIT:", 5) || + !strncmp(msg->msg, "DEBUG:", 6) || !strncmp(msg->msg, "DEBUG2:", 7) || + !strncmp(msg->msg, "EMERG:", 6) || !strncmp(msg->msg, "ERROR:", 6) || + !strncmp(msg->msg, "INFO:", 5) || !strncmp(msg->msg, "NOTICE:", 7) || + !strncmp(msg->msg, "WARNING:", 8)) { if (pass) { @@ -115,11 +112,11 @@ main(int argc, /* I - Number of command-line args */ } printf(" Bad prefix on filter message \"%s\"\n", - abbreviate(msg->id, idbuf, sizeof(idbuf))); + abbreviate(msg->msg, idbuf, sizeof(idbuf))); } - idfmt = msg->id + strlen(msg->id) - 1; - if (idfmt >= msg->id && *idfmt == '\n') + idfmt = msg->msg + strlen(msg->msg) - 1; + if (idfmt >= msg->msg && *idfmt == '\n') { if (pass) { @@ -128,14 +125,14 @@ main(int argc, /* I - Number of command-line args */ } printf(" Trailing newline in message \"%s\"\n", - abbreviate(msg->id, idbuf, sizeof(idbuf))); + abbreviate(msg->msg, idbuf, sizeof(idbuf))); } - for (; idfmt >= msg->id; idfmt --) + for (; idfmt >= msg->msg; idfmt --) if (!isspace(*idfmt & 255)) break; - if (idfmt >= msg->id && *idfmt == '!') + if (idfmt >= msg->msg && *idfmt == '!') { if (pass) { @@ -144,10 +141,10 @@ main(int argc, /* I - Number of command-line args */ } printf(" Exclamation in message \"%s\"\n", - abbreviate(msg->id, idbuf, sizeof(idbuf))); + abbreviate(msg->msg, idbuf, sizeof(idbuf))); } - if ((idfmt - 2) >= msg->id && !strncmp(idfmt - 2, "...", 3)) + if ((idfmt - 2) >= msg->msg && !strncmp(idfmt - 2, "...", 3)) { if (pass) { @@ -156,7 +153,7 @@ main(int argc, /* I - Number of command-line args */ } printf(" Ellipsis in message \"%s\"\n", - abbreviate(msg->id, idbuf, sizeof(idbuf))); + abbreviate(msg->msg, idbuf, sizeof(idbuf))); } @@ -165,9 +162,9 @@ main(int argc, /* I - Number of command-line args */ untranslated ++; continue; } - else if (strchr(msg->id, '%')) + else if (strchr(msg->msg, '%')) { - idfmts = collect_formats(msg->id); + idfmts = collect_formats(msg->msg); strfmts = collect_formats(msg->str); fmtidx = 0; @@ -211,7 +208,7 @@ main(int argc, /* I - Number of command-line args */ printf(" Bad translation string \"%s\"\n for \"%s\"\n", abbreviate(msg->str, strbuf, sizeof(strbuf)), - abbreviate(msg->id, idbuf, sizeof(idbuf))); + abbreviate(msg->msg, idbuf, sizeof(idbuf))); fputs(" Translation formats:", stdout); for (strfmt = (char *)cupsArrayFirst(strfmts); strfmt; @@ -248,7 +245,7 @@ main(int argc, /* I - Number of command-line args */ printf(" Bad escape \\%c in filter message \"%s\"\n" " for \"%s\"\n", strfmt[1], abbreviate(msg->str, strbuf, sizeof(strbuf)), - abbreviate(msg->id, idbuf, sizeof(idbuf))); + abbreviate(msg->msg, idbuf, sizeof(idbuf))); break; } } @@ -386,152 +383,6 @@ collect_formats(const char *id) /* I - msgid string */ } -/* - * 'cups_load_strings()' - Load a .strings file into a _cups_msg_t array. - */ - -static cups_array_t * /* O - CUPS array of _cups_msg_t values */ -cups_load_strings(const char *filename) /* I - File to load */ -{ - cups_file_t *fp; /* .strings file */ - cups_array_t *po; /* Localization array */ - _cups_message_t *m; /* Localization message */ - char buffer[8192], /* Message buffer */ - *id, /* ID string */ - *str; /* Translated message */ - - - if ((fp = cupsFileOpen(filename, "r")) == NULL) - return (NULL); - - po = _cupsMessageNew(NULL); - - while (cups_read_strings(fp, buffer, sizeof(buffer), &id, &str)) - { - if ((m = malloc(sizeof(_cups_message_t))) == NULL) - break; - - m->id = strdup(id); - m->str = strdup(str); - - if (m->id && m->str) - cupsArrayAdd(po, m); - else - { - if (m->id) - free(m->id); - - if (m->str) - free(m->str); - - free(m); - - cupsArrayDelete(po); - po = NULL; - break; - } - } - - cupsFileClose(fp); - - return (po); -} - - -/* - * 'cups_read_strings()' - Read a pair of strings from a .strings file. - */ - -static int /* O - 1 on success, 0 on failure */ -cups_read_strings(cups_file_t *strings, /* I - .strings file */ - char *buffer, /* I - Line buffer */ - size_t bufsize, /* I - Size of line buffer */ - char **id, /* O - Pointer to ID string */ - char **str) /* O - Pointer to translation string */ -{ - char *bufptr; /* Pointer into buffer */ - - - while (cupsFileGets(strings, buffer, bufsize)) - { - if (buffer[0] != '\"') - continue; - - *id = buffer + 1; - bufptr = cups_scan_strings(buffer); - - if (*bufptr != '\"') - continue; - - *bufptr++ = '\0'; - - while (*bufptr && *bufptr != '\"') - bufptr ++; - - if (!*bufptr) - continue; - - *str = bufptr + 1; - bufptr = cups_scan_strings(bufptr); - - if (*bufptr != '\"') - continue; - - *bufptr = '\0'; - - return (1); - } - - return (0); -} - - -/* - * 'cups_scan_strings()' - Scan a quoted string. - */ - -static char * /* O - End of string */ -cups_scan_strings(char *buffer) /* I - Start of string */ -{ - char *bufptr; /* Pointer into string */ - - - for (bufptr = buffer + 1; *bufptr && *bufptr != '\"'; bufptr ++) - { - if (*bufptr == '\\') - { - if (bufptr[1] >= '0' && bufptr[1] <= '3' && - bufptr[2] >= '0' && bufptr[2] <= '7' && - bufptr[3] >= '0' && bufptr[3] <= '7') - { - /* - * Decode \nnn octal escape... - */ - - *bufptr = (char)(((((bufptr[1] - '0') << 3) | (bufptr[2] - '0')) << 3) | (bufptr[3] - '0')); - _cups_strcpy(bufptr + 1, bufptr + 4); - } - else - { - /* - * Decode \C escape... - */ - - _cups_strcpy(bufptr, bufptr + 1); - if (*bufptr == 'n') - *bufptr = '\n'; - else if (*bufptr == 'r') - *bufptr = '\r'; - else if (*bufptr == 't') - *bufptr = '\t'; - } - } - } - - return (bufptr); -} - - /* * 'free_formats()' - Free all of the format strings. */