]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Add media-type localizations for printer-specific media types (Issue #5168)
authorMichael R Sweet <michaelrsweet@gmail.com>
Fri, 10 Nov 2017 20:33:47 +0000 (15:33 -0500)
committerMichael R Sweet <michaelrsweet@gmail.com>
Fri, 10 Nov 2017 20:33:47 +0000 (15:33 -0500)
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.

CHANGES.md
cups/dest-localization.c
cups/language-private.h
cups/language.c
cups/ppd-cache.c
cups/ppd-private.h
locale/checkpo.c

index 8e3d2a96a04e5c907347b9d7171418217ceed97a..3ad6777eec1fe36485cad833dee3ec7e80f68d1f 100644 (file)
@@ -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)
index a35540b7286b047665fa16c75ce8d638cd59397f..1eef3ea7a8798a11206fb6e8ca68593ab5beab80 100644 (file)
@@ -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);
-}
index bd5daf0d1bb5b3058cd9cb27f414091e3345db1b..ca6a9cb4e5c672c186bce634cbbe590fe45bd205 100644 (file)
@@ -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[]);
index aefba5551876a461db6a5723c53cd6dc96101040..1f2a125be8b923c0742a1ab5ecc1fe32f6f8dee5 100644 (file)
@@ -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...
  */
index da1414796cc5d38bb0d2a404a87a5059806885b9..9d9cf7602cd05e6403a9375e3f3113bb6b0ba081 100644 (file)
@@ -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: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, _cupsLangString(lang, media_types[j][1]), ppdname);
       else
-        cupsFilePrintf(fp, "*MediaType %s/%s: \"<</MediaType(%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: \"<</MediaType(%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.
  */
index e14b952c4ea3bd4818b19be28ebd99276effd9a6..e7c0d6e5f8d578a95296e399709d4eea5d0d5c3e 100644 (file)
@@ -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. */
 };
 
index f46f4cef0f9bb3a01d9cdbcb75d13241dd3b88e1..75d9255dad06113826c002d1fb7f39d997e8fd3f 100644 (file)
@@ -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.
  */