]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Initial work on loading all desired languages from IPP printer.
authorMichael R Sweet <msweet@msweet.org>
Tue, 9 Apr 2024 22:18:32 +0000 (18:18 -0400)
committerMichael R Sweet <msweet@msweet.org>
Tue, 9 Apr 2024 22:18:32 +0000 (18:18 -0400)
cups/ppd-cache.c
cups/ppd-private.h

index 34b11304e866b5be966bb24e78e8d28c172294b0..ae88076cfb78bbfed78b027f6b86fcef50f385ad 100644 (file)
  */
 
 static int     cups_connect(http_t **http, const char *url, char *resource, size_t ressize);
-static int     cups_get_url(http_t **http, const char *url, char *name, size_t namesize);
+static cups_array_t *cups_get_languages(void);
+static cups_lang_t *cups_get_strings(http_t **http, const char *printer_uri, const char *language);
+static int     cups_get_url(http_t **http, const char *url, const char *suffix, char *name, size_t namesize);
 static const char *ppd_inputslot_for_keyword(_ppd_cache_t *pc, const char *keyword);
+static void    ppd_put_strings(cups_file_t *fp, cups_lang_t *langs, const char *ppd_option, const char *ppd_choice, const char *pwg_msgid);
 static void    pwg_add_finishing(cups_array_t *finishings, ipp_finishings_t template, const char *name, const char *value);
 static void    pwg_add_message(cups_array_t *a, const char *msg, const char *str);
 static int     pwg_compare_finishings(_pwg_finishings_t *a, _pwg_finishings_t *b, void *data);
@@ -3131,28 +3134,17 @@ _ppdCacheWriteFile(
  *                         of an IPP printer.
  */
 
-char *                                 /* O - PPD filename or @code NULL@ on error */
+char *                                 /* O - PPD filename or `NULL` on error */
 _ppdCreateFromIPP(char   *buffer,      /* I - Filename buffer */
                   size_t bufsize,      /* I - Size of filename buffer */
                  ipp_t  *supported)    /* I - Get-Printer-Attributes response */
 {
-  return (_ppdCreateFromIPP2(buffer, bufsize, supported, cupsLangDefault()));
-}
-
-
-/*
- * '_ppdCreateFromIPP2()' - Create a PPD file describing the capabilities
- *                          of an IPP printer.
- */
-
-
-char *
-_ppdCreateFromIPP2(
-    char        *buffer,               /* I - Filename buffer */
-    size_t      bufsize,               /* I - Size of filename buffer */
-    ipp_t       *supported,            /* I - Get-Printer-Attributes response */
-    cups_lang_t *lang)                 /* I - Language */
-{
+  const char           *printer_uri;   /* Printer URI */
+  http_t               *http = NULL;   /* HTTP connection */
+  cups_array_t         *languages;     /* List of languages */
+  cups_lang_t          *lang,          /* Current language information */
+                       *langs = NULL;  /* Language (strings) files */
+  const char           *prefix;        /* Prefix string */
   cups_file_t          *fp;            /* PPD file */
   cups_array_t         *sizes;         /* Media sizes supported by printer */
   cups_size_t          *size;          /* Current media size */
@@ -3187,10 +3179,8 @@ _ppdCreateFromIPP2(
                                         /* Array of resolution indices */
   int                  have_qdraft = 0,/* Have draft quality? */
                        have_qhigh = 0; /* Have high quality? */
-  char                 msgid[256];     /* Message identifier (attr.value) */
-  const char           *keyword,       /* Keyword value */
-                       *msgstr;        /* Localized string */
-  cups_array_t         *strings = NULL;/* Printer strings file */
+  char                 msgid[256];     /* PWG message identifier (attr.value) */
+  const char           *keyword;       /* Keyword value */
   struct lconv         *loc = localeconv();
                                        /* Locale data */
   cups_array_t         *fin_options = NULL;
@@ -3216,16 +3206,28 @@ _ppdCreateFromIPP2(
     return (NULL);
   }
 
+  if ((printer_uri = ippGetString(ippFindAttribute(supported, "printer-uri-supported", IPP_TAG_URI), 0, NULL)) == NULL)
+  {
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No printer-uri-supported attribute."), 1);
+    return (NULL);
+  }
+
  /*
   * Open a temporary file for the PPD...
   */
 
-  if ((fp = cupsTempFile2(buffer, (int)bufsize)) == NULL)
+  if ((fp = cupsCreateTempFile("ippeve", ".ppd", buffer, bufsize)) == NULL)
   {
     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
     return (NULL);
   }
 
+ /*
+  * Figure out the languages to load/generate...
+  */
+
+  languages = cups_get_languages();
+
  /*
   * Standard stuff for PPD file...
   */
@@ -3261,7 +3263,7 @@ _ppdCreateFromIPP2(
   cupsFilePrintf(fp, "*NickName: \"%s - IPP Everywhere\"\n", model);
   cupsFilePrintf(fp, "*ShortNickName: \"%s - IPP Everywhere\"\n", model);
 
-  if ((attr = ippFindAttribute(supported, "color-supported", IPP_TAG_BOOLEAN)) != NULL && ippGetBoolean(attr, 0))
+  if (ippGetBoolean(ippFindAttribute(supported, "color-supported", IPP_TAG_BOOLEAN), 0))
     cupsFilePuts(fp, "*ColorDevice: True\n");
   else
     cupsFilePuts(fp, "*ColorDevice: False\n");
@@ -3271,81 +3273,47 @@ _ppdCreateFromIPP2(
   cupsFilePrintf(fp, "*APAirPrint: True\n");
 #endif // __APPLE__
   cupsFilePuts(fp, "*cupsSNMPSupplies: False\n");
-  cupsFilePrintf(fp, "*cupsLanguages: \"%s", lang->language);
-  if ((lang_supp = ippFindAttribute(supported, "printer-strings-languages-supported", IPP_TAG_LANGUAGE)) != NULL)
-  {
-    for (i = 0, count = ippGetCount(lang_supp); i < count; i ++)
-    {
-      keyword = ippGetString(lang_supp, i, NULL);
 
-      if (strcmp(keyword, lang->language))
-        cupsFilePrintf(fp, " %s", keyword);
-    }
-  }
-  cupsFilePuts(fp, "\"\n");
-
-  if ((attr = ippFindAttribute(supported, "printer-more-info", IPP_TAG_URI)) != NULL)
-    cupsFilePrintf(fp, "*APSupplies: \"%s\"\n", ippGetString(attr, 0, NULL));
-
-  if ((attr = ippFindAttribute(supported, "printer-charge-info-uri", IPP_TAG_URI)) != NULL)
-    cupsFilePrintf(fp, "*cupsChargeInfoURI: \"%s\"\n", ippGetString(attr, 0, NULL));
-
-  if ((attr = ippFindAttribute(supported, "printer-strings-uri", IPP_TAG_URI)) != NULL)
+  if ((lang_supp = ippFindAttribute(supported, "printer-strings-languages-supported", IPP_TAG_LANGUAGE)) != NULL)
   {
-    http_t     *http = NULL;           /* Connection to printer */
-    char       stringsfile[1024];      /* Temporary strings file */
+   /*
+    * List supported languages...
+    */
 
-    if (cups_get_url(&http, ippGetString(attr, 0, NULL), stringsfile, sizeof(stringsfile)))
+    for (i = 0, count = ippGetCount(lang_supp), prefix = "*cupsLanguages: \""; i < count; i ++)
     {
-      const char       *printer_uri = ippGetString(ippFindAttribute(supported, "printer-uri-supported", IPP_TAG_URI), 0, NULL);
-                                       // Printer URI
-      char             resource[256];  // Resource path
-      ipp_t            *request,       // Get-Printer-Attributes request
-                       *response;      // Response to request
-
-     /*
-      * Load strings and save the URL for clients using the destination API
-      * instead of this PPD file...
-      */
-
-      cupsFilePrintf(fp, "*cupsStringsURI: \"%s\"\n", ippGetString(attr, 0, NULL));
-
-      strings = _cupsMessageLoad(stringsfile, _CUPS_MESSAGE_STRINGS | _CUPS_MESSAGE_UNQUOTE);
-
-      unlink(stringsfile);
+      keyword = ippGetString(lang_supp, i, NULL);
 
-      if (lang_supp && printer_uri && cups_connect(&http, printer_uri, resource, sizeof(resource)))
+      if (cupsArrayFind(languages, (void *)keyword) && (lang = cups_get_strings(&http, printer_uri, keyword)) != NULL)
       {
        /*
-       * Loop through all of the languages and save their URIs...
-       */
+        * Add language...
+        */
 
-       for (i = 0, count = ippGetCount(lang_supp); i < count; i ++)
-       {
-         keyword = ippGetString(lang_supp, i, NULL);
+        lang->next = langs;
+        langs      = lang;
 
-         request = ippNew();
-         ippSetOperation(request, IPP_OP_GET_PRINTER_ATTRIBUTES);
-         ippSetRequestId(request, i + 1);
-         ippAddString(request, IPP_TAG_OPERATION, IPP_CONST_TAG(IPP_TAG_CHARSET), "attributes-charset", NULL, "utf-8");
-         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, keyword);
-         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer_uri);
-         ippAddString(request, IPP_TAG_OPERATION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "requested-attributes", NULL, "printer-strings-uri");
-
-         response = cupsDoRequest(http, request, resource);
-
-         if ((attr = ippFindAttribute(response, "printer-strings-uri", IPP_TAG_URI)) != NULL)
-           cupsFilePrintf(fp, "*cupsStringsURI %s: \"%s\"\n", keyword, ippGetString(attr, 0, NULL));
-
-         ippDelete(response);
-       }
+        cupsFilePrintf(fp, "%s%s", prefix, keyword);
+        prefix = ",";
       }
     }
 
-    if (http)
-      httpClose(http);
+    if (!strcmp(prefix, ","))
+      cupsFilePuts(fp, "\"\n");
+  }
+
+  if (http)
+  {
+    httpClose(http);
+    http = NULL;
   }
 
+  if ((attr = ippFindAttribute(supported, "printer-more-info", IPP_TAG_URI)) != NULL)
+    cupsFilePrintf(fp, "*APSupplies: \"%s\"\n", ippGetString(attr, 0, NULL));
+
+  if ((attr = ippFindAttribute(supported, "printer-charge-info-uri", IPP_TAG_URI)) != NULL)
+    cupsFilePrintf(fp, "*cupsChargeInfoURI: \"%s\"\n", ippGetString(attr, 0, NULL));
+
  /*
   * Accounting...
   */
@@ -3361,38 +3329,36 @@ _ppdCreateFromIPP2(
 
   if ((attr = ippFindAttribute(supported, "printer-mandatory-job-attributes", IPP_TAG_KEYWORD)) != NULL)
   {
-    char       prefix = '\"';          // Prefix for string
-
-    cupsFilePuts(fp, "*cupsMandatory: \"");
-    for (i = 0, count = ippGetCount(attr); i < count; i ++)
+    for (i = 0, count = ippGetCount(attr), prefix = "*cupsMandatory: \""; i < count; i ++)
     {
       keyword = ippGetString(attr, i, NULL);
 
       if (strcmp(keyword, "attributes-charset") && strcmp(keyword, "attributes-natural-language") && strcmp(keyword, "printer-uri"))
       {
-        cupsFilePrintf(fp, "%c%s", prefix, keyword);
-        prefix = ',';
+        cupsFilePrintf(fp, "%s%s", prefix, keyword);
+        prefix = ",";
       }
     }
-    cupsFilePuts(fp, "\"\n");
+
+    if (!strcmp(prefix, ","))
+      cupsFilePuts(fp, "\"\n");
   }
 
   if ((attr = ippFindAttribute(supported, "printer-requested-job-attributes", IPP_TAG_KEYWORD)) != NULL)
   {
-    char       prefix = '\"';          // Prefix for string
-
-    cupsFilePuts(fp, "*cupsRequested: \"");
-    for (i = 0, count = ippGetCount(attr); i < count; i ++)
+    for (i = 0, count = ippGetCount(attr), prefix = "*cupsRequested: \""; i < count; i ++)
     {
       keyword = ippGetString(attr, i, NULL);
 
       if (strcmp(keyword, "attributes-charset") && strcmp(keyword, "attributes-natural-language") && strcmp(keyword, "printer-uri"))
       {
-        cupsFilePrintf(fp, "%c%s", prefix, keyword);
-        prefix = ',';
+        cupsFilePrintf(fp, "%s%s", prefix, keyword);
+        prefix = ",";
       }
     }
-    cupsFilePuts(fp, "\"\n");
+
+    if (!strcmp(prefix, ","))
+      cupsFilePuts(fp, "\"\n");
   }
 
  /*
@@ -3926,18 +3892,16 @@ _ppdCreateFromIPP2(
        cupsFilePrintf(fp, "*DefaultInputSlot: %s\n", ppdname);
 
       for (j = 0; j < (int)(sizeof(sources) / sizeof(sources[0])); j ++)
+      {
         if (!strcmp(sources[j], keyword))
        {
          snprintf(msgid, sizeof(msgid), "media-source.%s", keyword);
 
-         if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
-           if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
-             msgstr = keyword;
-
          cupsFilePrintf(fp, "*InputSlot %s: \"<</MediaPosition %d>>setpagedevice\"\n", ppdname, j);
-         cupsFilePrintf(fp, "*%s.InputSlot %s/%s: \"\"\n", lang->language, ppdname, msgstr);
+         ppd_put_strings(fp, langs, "InputSlot", ppdname, msgid);
          break;
        }
+      }
     }
     cupsFilePuts(fp, "*CloseUI: *InputSlot\n");
   }
@@ -3963,12 +3927,9 @@ _ppdCreateFromIPP2(
       pwg_ppdize_name(keyword, ppdname, sizeof(ppdname));
 
       snprintf(msgid, sizeof(msgid), "media-type.%s", keyword);
-      if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
-       if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
-         msgstr = keyword;
 
-      cupsFilePrintf(fp, "*MediaType %s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, ppdname);
-      cupsFilePrintf(fp, "*%s.MediaType %s/%s: \"\"\n", lang->language, ppdname, msgstr);
+      cupsFilePrintf(fp, "*MediaType %s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, keyword);
+      ppd_put_strings(fp, langs, "MediaType", ppdname, msgid);
     }
     cupsFilePuts(fp, "*CloseUI: *MediaType\n");
   }
@@ -4015,26 +3976,25 @@ _ppdCreateFromIPP2(
 
       cupsFilePrintf(fp, "*DefaultResolution: %ddpi\n", lowdpi);
 
-      cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality: PickOne\n"
-                        "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
-                        "*%s.Translation cupsPrintQuality/%s: \"\"\n"
-                        "*DefaultcupsPrintQuality: Normal\n", lang->language, _cupsLangString(lang, _("Print Quality")));
+      cupsFilePuts(fp, "*OpenUI *cupsPrintQuality: PickOne\n"
+                      "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
+                      "*DefaultcupsPrintQuality: Normal\n");
       if ((lowdpi & 1) == 0)
       {
-       cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality Draft/%s: \"\"\n", lowdpi, lowdpi / 2, lang->language, _cupsLangString(lang, _("Draft")));
+       cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n", lowdpi, lowdpi / 2);
        have_qdraft = 1;
       }
       else if (ippContainsInteger(quality, IPP_QUALITY_DRAFT))
       {
-       cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality Draft/%s: \"\"\n", lowdpi, lowdpi, lang->language, _cupsLangString(lang, _("Draft")));
+       cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n*", lowdpi, lowdpi);
        have_qdraft = 1;
       }
 
-      cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality Normal/%s: \"\"\n", lowdpi, lowdpi, lang->language, _cupsLangString(lang, _("Normal")));
+      cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<</HWResolution[%d %d]>>setpagedevice\"\n", lowdpi, lowdpi);
 
       if (hidpi > lowdpi || ippContainsInteger(quality, IPP_QUALITY_HIGH))
       {
-       cupsFilePrintf(fp, "*cupsPrintQuality High: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality High/%s: \"\"\n", hidpi, hidpi, lang->language, _cupsLangString(lang, _("High")));
+       cupsFilePrintf(fp, "*cupsPrintQuality High: \"<</HWResolution[%d %d]>>setpagedevice\"\n", hidpi, hidpi);
        have_qhigh = 1;
       }
 
@@ -4087,34 +4047,32 @@ _ppdCreateFromIPP2(
     pwg_ppdize_resolution(attr, resolutions[count / 2], &xres, &yres, ppdname, sizeof(ppdname));
     cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname);
 
-    cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality: PickOne\n"
-                      "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
-                      "*%s.Translation cupsPrintQuality/%s: \"\"\n"
-                      "*DefaultcupsPrintQuality: Normal\n", lang->language, _cupsLangString(lang, _("Print Quality")));
+    cupsFilePuts(fp, "*OpenUI *cupsPrintQuality: PickOne\n"
+                    "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
+                    "*DefaultcupsPrintQuality: Normal\n");
     if (count > 2 || ippContainsInteger(quality, IPP_QUALITY_DRAFT))
     {
       pwg_ppdize_resolution(attr, resolutions[0], &xres, &yres, NULL, 0);
       cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres);
-      cupsFilePrintf(fp, "*%s.cupsPrintQuality Draft/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Draft")));
       have_qdraft = 1;
     }
 
     pwg_ppdize_resolution(attr, resolutions[count / 2], &xres, &yres, NULL, 0);
     cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres);
-    cupsFilePrintf(fp, "*%s.cupsPrintQuality Normal/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Normal")));
 
     if (count > 1 || ippContainsInteger(quality, IPP_QUALITY_HIGH))
     {
       pwg_ppdize_resolution(attr, resolutions[count - 1], &xres, &yres, NULL, 0);
       cupsFilePrintf(fp, "*cupsPrintQuality High: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres);
-      cupsFilePrintf(fp, "*%s.cupsPrintQuality High/%s: \"\"\n", lang->language, _cupsLangString(lang, _("High")));
       have_qhigh = 1;
     }
 
     cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n");
   }
   else if (is_apple || is_pwg)
+  {
     goto bad_ppd;
+  }
   else
   {
     if ((attr = ippFindAttribute(supported, "printer-resolution-default", IPP_TAG_RESOLUTION)) != NULL)
@@ -4129,21 +4087,20 @@ _ppdCreateFromIPP2(
 
     cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname);
 
-    cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality: PickOne\n"
-                       "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
-                       "*%s.Translation cupsPrintQuality/%s: \"\"\n"
-                       "*DefaultcupsPrintQuality: Normal\n", lang->language, _cupsLangString(lang, _("Print Quality")));
+    cupsFilePuts(fp, "*OpenUI *cupsPrintQuality: PickOne\n"
+                     "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
+                     "*DefaultcupsPrintQuality: Normal\n");
     if (ippContainsInteger(quality, IPP_QUALITY_DRAFT))
     {
-      cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality Draft/%s: \"\"\n", xres, yres, lang->language, _cupsLangString(lang, _("Draft")));
+      cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n*", xres, yres);
       have_qdraft = 1;
     }
 
-    cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality Normal/%s: \"\"\n", xres, yres, lang->language, _cupsLangString(lang, _("Normal")));
+    cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres);
 
     if (ippContainsInteger(quality, IPP_QUALITY_HIGH))
     {
-      cupsFilePrintf(fp, "*cupsPrintQuality High: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality High/%s: \"\"\n", xres, yres, lang->language, _cupsLangString(lang, _("High")));
+      cupsFilePrintf(fp, "*cupsPrintQuality High: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres);
       have_qhigh = 1;
     }
     cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n");
@@ -4183,8 +4140,8 @@ _ppdCreateFromIPP2(
     {
       keyword = ippGetString(attr, i, NULL);
 
-#define PRINTF_COLORMODEL if (!wrote_color) { cupsFilePrintf(fp, "*OpenUI *ColorModel: PickOne\n*OrderDependency: 10 AnySetup *ColorModel\n*%s.Translation ColorModel/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Color Mode"))); wrote_color = 1; }
-#define PRINTF_COLOROPTION(name,text,cspace,bpp) { cupsFilePrintf(fp, "*ColorModel %s: \"<</cupsColorSpace %d/cupsBitsPerColor %d/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", name, cspace, bpp); cupsFilePrintf(fp, "*%s.ColorModel %s/%s: \"\"\n", lang->language, name, _cupsLangString(lang, text)); }
+#define PRINTF_COLORMODEL if (!wrote_color) { cupsFilePuts(fp, "*OpenUI *ColorModel: PickOne\n*OrderDependency: 10 AnySetup *ColorModel\n"); wrote_color = 1; }
+#define PRINTF_COLOROPTION(name,text,cspace,bpp) cupsFilePrintf(fp, "*ColorModel %s/%s: \"<</cupsColorSpace %d/cupsBitsPerColor %d/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", name, text, cspace, bpp);
 
       if (!strcasecmp(keyword, "black_1") || !strcmp(keyword, "bi-level") || !strcmp(keyword, "process-bi-level"))
       {
@@ -4340,17 +4297,13 @@ _ppdCreateFromIPP2(
 
   if ((attr = ippFindAttribute(supported, "sides-supported", IPP_TAG_KEYWORD)) != NULL && ippContainsString(attr, "two-sided-long-edge"))
   {
-    cupsFilePrintf(fp, "*OpenUI *Duplex: PickOne\n"
-                      "*OrderDependency: 10 AnySetup *Duplex\n"
-                      "*%s.Translation Duplex/%s: \"\"\n"
-                      "*DefaultDuplex: None\n"
-                      "*Duplex None: \"<</Duplex false>>setpagedevice\"\n"
-                      "*%s.Duplex None/%s: \"\"\n"
-                      "*Duplex DuplexNoTumble: \"<</Duplex true/Tumble false>>setpagedevice\"\n"
-                      "*%s.Duplex DuplexNoTumble/%s: \"\"\n"
-                      "*Duplex DuplexTumble: \"<</Duplex true/Tumble true>>setpagedevice\"\n"
-                      "*%s.Duplex DuplexTumble/%s: \"\"\n"
-                      "*CloseUI: *Duplex\n", lang->language, _cupsLangString(lang, _("2-Sided Printing")), lang->language, _cupsLangString(lang, _("Off (1-Sided)")), lang->language, _cupsLangString(lang, _("Long-Edge (Portrait)")), lang->language, _cupsLangString(lang, _("Short-Edge (Landscape)")));
+    cupsFilePuts(fp, "*OpenUI *Duplex: PickOne\n"
+                    "*OrderDependency: 10 AnySetup *Duplex\n"
+                    "*DefaultDuplex: None\n"
+                    "*Duplex None: \"<</Duplex false>>setpagedevice\"\n"
+                    "*Duplex DuplexNoTumble: \"<</Duplex true/Tumble false>>setpagedevice\"\n"
+                    "*Duplex DuplexTumble: \"<</Duplex true/Tumble true>>setpagedevice\"\n"
+                    "*CloseUI: *Duplex\n");
 
     if ((attr = ippFindAttribute(supported, "urf-supported", IPP_TAG_KEYWORD)) != NULL)
     {
@@ -4429,12 +4382,9 @@ _ppdCreateFromIPP2(
       pwg_ppdize_name(keyword, ppdname, sizeof(ppdname));
 
       snprintf(msgid, sizeof(msgid), "output-bin.%s", keyword);
-      if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
-       if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
-         msgstr = keyword;
 
       cupsFilePrintf(fp, "*OutputBin %s: \"\"\n", ppdname);
-      cupsFilePrintf(fp, "*%s.OutputBin %s/%s: \"\"\n", lang->language, ppdname, msgstr);
+      ppd_put_strings(fp, langs, "OutputBin", ppdname, msgid);
 
       if ((tray_ptr = ippGetOctetString(trays, i, &tray_len)) != NULL)
       {
@@ -4534,10 +4484,10 @@ _ppdCreateFromIPP2(
 
       cupsFilePuts(fp, "*OpenUI *StapleLocation: PickOne\n");
       cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *StapleLocation\n");
-      cupsFilePrintf(fp, "*%s.Translation StapleLocation/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Staple")));
+      ppd_put_strings(fp, langs, "Translation", "StapleLocation", "finishings.4");
       cupsFilePuts(fp, "*DefaultStapleLocation: None\n");
       cupsFilePuts(fp, "*StapleLocation None: \"\"\n");
-      cupsFilePrintf(fp, "*%s.StapleLocation None/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None")));
+      ppd_put_strings(fp, langs, "StapleLocation", "None", "finishings.3");
 
       for (; i < count; i ++)
       {
@@ -4553,9 +4503,6 @@ _ppdCreateFromIPP2(
         cupsArrayAdd(names, (char *)keyword);
 
        snprintf(msgid, sizeof(msgid), "finishings.%d", value);
-       if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
-         if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
-           msgstr = keyword;
 
         if (value >= IPP_FINISHINGS_NONE && value <= IPP_FINISHINGS_LAMINATE)
           ppd_keyword = base_keywords[value - IPP_FINISHINGS_NONE];
@@ -4570,7 +4517,7 @@ _ppdCreateFromIPP2(
           continue;
 
        cupsFilePrintf(fp, "*StapleLocation %s: \"\"\n", ppd_keyword);
-       cupsFilePrintf(fp, "*%s.StapleLocation %s/%s: \"\"\n", lang->language, ppd_keyword, msgstr);
+       ppd_put_strings(fp, langs, "StapleLocation", ppd_keyword, msgid);
        cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*StapleLocation %s\"\n", value, keyword, ppd_keyword);
       }
 
@@ -4612,10 +4559,10 @@ _ppdCreateFromIPP2(
 
       cupsFilePuts(fp, "*OpenUI *FoldType: PickOne\n");
       cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *FoldType\n");
-      cupsFilePrintf(fp, "*%s.Translation FoldType/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Fold")));
+      ppd_put_strings(fp, langs, "Translation", "FoldType", "finishings.10");
       cupsFilePuts(fp, "*DefaultFoldType: None\n");
       cupsFilePuts(fp, "*FoldType None: \"\"\n");
-      cupsFilePrintf(fp, "*%s.FoldType None/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None")));
+      ppd_put_strings(fp, langs, "FoldType", "None", "finishings.3");
 
       for (; i < count; i ++)
       {
@@ -4633,9 +4580,6 @@ _ppdCreateFromIPP2(
         cupsArrayAdd(names, (char *)keyword);
 
        snprintf(msgid, sizeof(msgid), "finishings.%d", value);
-       if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
-         if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
-           msgstr = keyword;
 
         if (value >= IPP_FINISHINGS_NONE && value <= IPP_FINISHINGS_LAMINATE)
           ppd_keyword = base_keywords[value - IPP_FINISHINGS_NONE];
@@ -4650,7 +4594,7 @@ _ppdCreateFromIPP2(
           continue;
 
        cupsFilePrintf(fp, "*FoldType %s: \"\"\n", ppd_keyword);
-       cupsFilePrintf(fp, "*%s.FoldType %s/%s: \"\"\n", lang->language, ppd_keyword, msgstr);
+       ppd_put_strings(fp, langs, "FoldType", ppd_keyword, msgid);
        cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*FoldType %s\"\n", value, keyword, ppd_keyword);
       }
 
@@ -4700,10 +4644,10 @@ _ppdCreateFromIPP2(
 
       cupsFilePuts(fp, "*OpenUI *PunchMedia: PickOne\n");
       cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *PunchMedia\n");
-      cupsFilePrintf(fp, "*%s.Translation PunchMedia/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Punch")));
+      ppd_put_strings(fp, langs, "Translation", "PunchMedia", "finishings.5");
       cupsFilePuts(fp, "*DefaultPunchMedia: None\n");
       cupsFilePuts(fp, "*PunchMedia None: \"\"\n");
-      cupsFilePrintf(fp, "*%s.PunchMedia None/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None")));
+      ppd_put_strings(fp, langs, "PunchMedia", "None", "finishings.3");
 
       for (i = 0; i < count; i ++)
       {
@@ -4721,9 +4665,6 @@ _ppdCreateFromIPP2(
         cupsArrayAdd(names, (char *)keyword);
 
        snprintf(msgid, sizeof(msgid), "finishings.%d", value);
-       if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
-         if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
-           msgstr = keyword;
 
         if (value >= IPP_FINISHINGS_NONE && value <= IPP_FINISHINGS_LAMINATE)
           ppd_keyword = base_keywords[value - IPP_FINISHINGS_NONE];
@@ -4738,7 +4679,7 @@ _ppdCreateFromIPP2(
           continue;
 
        cupsFilePrintf(fp, "*PunchMedia %s: \"\"\n", ppd_keyword);
-       cupsFilePrintf(fp, "*%s.PunchMedia %s/%s: \"\"\n", lang->language, ppd_keyword, msgstr);
+       ppd_put_strings(fp, langs, "PunchMedia", ppd_keyword, msgid);
        cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*PunchMedia %s\"\n", value, keyword, ppd_keyword);
       }
 
@@ -4755,7 +4696,7 @@ _ppdCreateFromIPP2(
 
       cupsFilePuts(fp, "*OpenUI *Booklet: Boolean\n");
       cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *Booklet\n");
-      cupsFilePrintf(fp, "*%s.Translation Booklet/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Booklet")));
+      ppd_put_strings(fp, langs, "Translation", "StapleLocation", "finishings.13");
       cupsFilePuts(fp, "*DefaultBooklet: False\n");
       cupsFilePuts(fp, "*Booklet False: \"\"\n");
       cupsFilePuts(fp, "*Booklet True: \"\"\n");
@@ -4790,10 +4731,10 @@ _ppdCreateFromIPP2(
 
       cupsFilePuts(fp, "*OpenUI *CutMedia: PickOne\n");
       cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *CutMedia\n");
-      cupsFilePrintf(fp, "*%s.Translation CutMedia/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Cut")));
+      ppd_put_strings(fp, langs, "Translation", "CutMedia", "finishings.11");
       cupsFilePuts(fp, "*DefaultCutMedia: None\n");
       cupsFilePuts(fp, "*CutMedia None: \"\"\n");
-      cupsFilePrintf(fp, "*%s.CutMedia None/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None")));
+      ppd_put_strings(fp, langs, "CutMedia", "None", "finishings.3");
 
       for (i = 0; i < count; i ++)
       {
@@ -4809,9 +4750,6 @@ _ppdCreateFromIPP2(
         cupsArrayAdd(names, (char *)keyword);
 
        snprintf(msgid, sizeof(msgid), "finishings.%d", value);
-       if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
-         if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
-           msgstr = keyword;
 
         if (value == IPP_FINISHINGS_TRIM)
           ppd_keyword = "Auto";
@@ -4819,7 +4757,7 @@ _ppdCreateFromIPP2(
          ppd_keyword = trim_keywords[value - IPP_FINISHINGS_TRIM_AFTER_PAGES];
 
        cupsFilePrintf(fp, "*CutMedia %s: \"\"\n", ppd_keyword);
-       cupsFilePrintf(fp, "*%s.CutMedia %s/%s: \"\"\n", lang->language, ppd_keyword, msgstr);
+       ppd_put_strings(fp, langs, "CutMedia", ppd_keyword, msgid);
        cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*CutMedia %s\"\n", value, keyword, ppd_keyword);
       }
 
@@ -4837,10 +4775,10 @@ _ppdCreateFromIPP2(
 
     cupsFilePuts(fp, "*OpenUI *cupsFinishingTemplate: PickOne\n");
     cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *cupsFinishingTemplate\n");
-    cupsFilePrintf(fp, "*%s.Translation cupsFinishingTemplate/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Finishing Preset")));
+    ppd_put_strings(fp, langs, "Translation", "cupsFinishingTemplate", "finishing-template");
     cupsFilePuts(fp, "*DefaultcupsFinishingTemplate: none\n");
     cupsFilePuts(fp, "*cupsFinishingTemplate none: \"\"\n");
-    cupsFilePrintf(fp, "*%s.cupsFinishingTemplate none/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None")));
+    ppd_put_strings(fp, langs, "cupsFinishingTemplate", "none", "finishings.3");
 
     templates = cupsArrayNew((cups_array_func_t)_cupsArrayStrcmp, NULL);
     count     = ippGetCount(attr);
@@ -4859,9 +4797,6 @@ _ppdCreateFromIPP2(
       cupsArrayAdd(templates, (void *)keyword);
 
       snprintf(msgid, sizeof(msgid), "finishing-template.%s", keyword);
-      if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr))
-       if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid)
-         msgstr = keyword;
 
       cupsFilePrintf(fp, "*cupsFinishingTemplate %s: \"\n", keyword);
       for (finishing_attr = ippFirstAttribute(finishing_col); finishing_attr; finishing_attr = ippNextAttribute(finishing_col))
@@ -4876,7 +4811,7 @@ _ppdCreateFromIPP2(
        }
       }
       cupsFilePuts(fp, "\"\n");
-      cupsFilePrintf(fp, "*%s.cupsFinishingTemplate %s/%s: \"\"\n", lang->language, keyword, msgstr);
+      ppd_put_strings(fp, langs, "cupsFinishingTemplate", keyword, msgid);
       cupsFilePuts(fp, "*End\n");
     }
 
@@ -4891,7 +4826,7 @@ _ppdCreateFromIPP2(
         cupsFilePrintf(fp, " %s", fin_option);
       cupsFilePuts(fp, "\"\n");
 
-      cupsFilePuts(fp, "*cupsUIResolver finishing-template: \"*cupsFinishingTemplate None");
+      cupsFilePuts(fp, "*cupsUIResolver finishing-template: \"*cupsFinishingTemplate none");
       for (fin_option = (const char *)cupsArrayFirst(fin_options); fin_option; fin_option = (const char *)cupsArrayNext(fin_options))
         cupsFilePrintf(fp, " %s None", fin_option);
       cupsFilePuts(fp, "\"\n");
@@ -4912,9 +4847,8 @@ _ppdCreateFromIPP2(
     {
       ipp_t    *preset = ippGetCollection(attr, i);
                                        /* Preset collection */
-      const char *preset_name = ippGetString(ippFindAttribute(preset, "preset-name", IPP_TAG_ZERO), 0, NULL),
+      const char *preset_name = ippGetString(ippFindAttribute(preset, "preset-name", IPP_TAG_ZERO), 0, NULL);
                                        /* Preset name */
-               *localized_name;        /* Localized preset name */
       ipp_attribute_t *member;         /* Member attribute in preset */
       const char *member_name;         /* Member attribute name */
       char             member_value[256];      /* Member attribute value */
@@ -5041,8 +4975,8 @@ _ppdCreateFromIPP2(
 
       cupsFilePuts(fp, "\"\n*End\n");
 
-      if ((localized_name = _cupsMessageLookup(strings, preset_name)) != preset_name)
-        cupsFilePrintf(fp, "*%s.APPrinterPreset %s/%s: \"\"\n", lang->language, preset_name, localized_name);
+//      if ((localized_name = _cupsMessageLookup(strings, preset_name)) != preset_name)
+//        cupsFilePrintf(fp, "*%s.APPrinterPreset %s/%s: \"\"\n", lang->language, preset_name, localized_name);
     }
   }
 
@@ -5062,7 +4996,15 @@ _ppdCreateFromIPP2(
 
   cupsFileClose(fp);
 
-  _cupsMessageFree(strings);
+  for (lang = langs; lang;)
+  {
+    cups_lang_t *next = lang->next;
+
+    cupsArrayDelete(lang->strings);
+    free(lang);
+
+    lang = next;
+  }
 
   return (buffer);
 
@@ -5073,11 +5015,20 @@ _ppdCreateFromIPP2(
   bad_ppd:
 
   cupsFileClose(fp);
+
+  for (lang = langs; lang;)
+  {
+    cups_lang_t *next = lang->next;
+
+    cupsArrayDelete(lang->strings);
+    free(lang);
+
+    lang = next;
+  }
+
   unlink(buffer);
   *buffer = '\0';
 
-  _cupsMessageFree(strings);
-
   _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Printer does not support required IPP attributes or document formats."), 1);
 
   return (NULL);
@@ -5277,6 +5228,134 @@ cups_connect(http_t     **http,         /* IO - Current HTTP connection */
 }
 
 
+/*
+ * 'cups_get_languages()' - Get the languages to load for PPDs.
+ */
+
+static cups_array_t *                  /* O - Array of languages */
+cups_get_languages(void)
+{
+  cups_array_t *languages = NULL;      /* Array of languages */
+  cups_file_t  *fp;                    /* CUPS_SERVERROOT/cups-files.conf file */
+  char         filename[1024];         /* Filename */
+  _cups_globals_t *cg = _cupsGlobals();        /* Global data */
+
+
+  snprintf(filename, sizeof(filename), "%s/cups-files.conf", cg->cups_serverroot);
+
+  if ((fp = cupsFileOpen(filename, "r")) != NULL)
+  {
+   /*
+    * Read the cups-files.conf file, looking for a Languages directive...
+    */
+
+    char       line[1024],             /* Line from file */
+               *value;                 /* Value from line */
+    int                linenum = 0;            /* Current line number */
+
+    while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+    {
+      if (!_cups_strcasecmp(line, "Languages") && value)
+      {
+        languages = cupsArrayNewStrings(value, ' ');
+        break;
+      }
+    }
+
+    cupsFileClose(fp);
+  }
+
+  if (!languages)
+  {
+   /*
+    * No Languages directive in CUPS_SERVERROOT/cups-files.conf, so use the
+    * current locale...
+    */
+
+    cups_lang_t        *deflang;               /* Default language */
+
+    languages = cupsArrayNewStrings(NULL, ' ');
+    deflang   = cupsLangDefault();
+
+    cupsArrayAdd(languages, deflang->language);
+  }
+
+  return (languages);
+}
+
+
+/*
+ * 'cups_get_strings()' - Get the strings for the specified language.
+ */
+
+static cups_lang_t *                   /* O  - Language data */
+cups_get_strings(
+    http_t     **http,                 /* IO - Current HTTP connection */
+    const char *printer_uri,           /* I  - Printer URI */
+    const char *language)              /* I  - Language name */
+{
+  cups_lang_t  *lang = NULL;           /* Language data */
+  char         resource[256];          /* Resource path for printer */
+  ipp_t                *request,               /* IPP request */
+               *response = NULL;       /* IPP response */
+  const char   *strings_uri;           /* "printer-strings-uri" value */
+  char         strings_file[1024] = "";/* Strings filename */
+
+
+ /*
+  * Connect to the printer...
+  */
+
+  if (!cups_connect(http, printer_uri, resource, sizeof(resource)))
+    goto done;
+
+ /*
+  * Get the URL for the corresponding language strings...
+  */
+
+  request = ippNew();
+  ippSetOperation(request, IPP_OP_GET_PRINTER_ATTRIBUTES);
+  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", /*language*/NULL, "utf-8");
+  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", /*language*/NULL, language);
+  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", /*language*/NULL, printer_uri);
+
+  response = cupsDoRequest(*http, request, resource);
+
+  if ((strings_uri = ippGetString(ippFindAttribute(response, "printer-strings-uri", IPP_TAG_URI), 0, NULL)) != NULL)
+  {
+   /*
+    * Download the strings file...
+    */
+
+    if (!cups_get_url(http, strings_uri, ".strings", strings_file, sizeof(strings_file)))
+      goto done;
+
+   /*
+    * Allocate memory...
+    */
+
+    if ((lang = (cups_lang_t *)calloc(1, sizeof(cups_lang_t))) == NULL)
+      goto done;
+
+   /*
+    * Load the strings...
+    */
+
+    cupsCopyString(lang->language, language, sizeof(lang->language));
+    lang->strings = _cupsMessageLoad(strings_file, _CUPS_MESSAGE_STRINGS);
+  }
+
+  done:
+
+  ippDelete(response);
+
+  if (strings_file[0])
+    unlink(strings_file);
+
+  return (lang);
+}
+
+
 /*
  * 'cups_get_url()' - Get a copy of the file at the given URL.
  */
@@ -5284,6 +5363,7 @@ cups_connect(http_t     **http,           /* IO - Current HTTP connection */
 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 */
+             const char *suffix,       /* I  - Filename suffix */
              char       *name,         /* I  - Temporary filename */
              size_t     namesize)      /* I  - Size of temporary filename buffer */
 {
@@ -5295,7 +5375,7 @@ cups_get_url(http_t     **http,           /* IO - Current HTTP connection */
   if (!cups_connect(http, url, resource, sizeof(resource)))
     return (0);
 
-  if ((fd = cupsTempFd(name, (int)namesize)) < 0)
+  if ((fd = cupsCreateTempFd("ippeve", suffix, name, namesize)) < 0)
     return (0);
 
   status = cupsGetFd(*http, resource, fd);
@@ -5313,6 +5393,29 @@ cups_get_url(http_t     **http,          /* IO - Current HTTP connection */
 }
 
 
+/*
+ * 'ppd_put_strings()' - Write localization attributes to a PPD file.
+ */
+
+static void
+ppd_put_strings(cups_file_t *fp,       /* I - PPD file */
+                cups_lang_t *langs,    /* I - Languages */
+                const char  *ppd_option,/* I - PPD option */
+                const char  *ppd_choice,/* I - PPD choice */
+                const char  *pwg_msgid)        /* I - PWG message ID */
+{
+  cups_lang_t  *lang;                  /* Current language */
+  const char   *text;                  /* Localized text */
+
+
+  for (lang = langs; lang; lang = lang->next)
+  {
+    if ((text = _cupsLangString(lang, pwg_msgid)) != pwg_msgid)
+      cupsFilePrintf(fp, "*%s.%s %s/%s: \"\"\n", lang->language, ppd_option, ppd_choice, text);
+  }
+}
+
+
 /*
  * 'pwg_add_finishing()' - Add a finishings value.
  */
index fc65d37334eceb19a2b47d89fbab254514d0257b..f264406ccede9a98f09de9fc2367189fa2ba2974 100644 (file)
 
 #ifndef _CUPS_PPD_PRIVATE_H_
 #  define _CUPS_PPD_PRIVATE_H_
-
-/*
- * Include necessary headers...
- */
-
 #  include <cups/cups.h>
 #  include <cups/ppd.h>
 #  include "pwg-private.h"
-
-
-/*
- * C++ magic...
- */
-
 #  ifdef __cplusplus
 extern "C" {
 #  endif /* __cplusplus */
@@ -147,7 +136,8 @@ 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 */
-  cups_array_t *strings;               /* Localization strings */
+  cups_lang_t  *langs;                 /* Localization languages/strings */
+  cups_array_t *strings;               /* TODO: REMOVE ME */
   cups_array_t *support_files;         /* Support files - ICC profiles, etc. */
 };
 
@@ -160,65 +150,36 @@ extern int                _cupsConvertOptions(ipp_t *request, ppd_file_t *ppd, _ppd_cache_t *p
 extern int             _cupsRasterExecPS(cups_page_header2_t *h, int *preferred_bits, const char *code) _CUPS_NONNULL(3) _CUPS_PRIVATE;
 extern int             _cupsRasterInterpretPPD(cups_page_header2_t *h, ppd_file_t *ppd, int num_options, cups_option_t *options, cups_interpret_cb_t func) _CUPS_PRIVATE;
 
-extern _ppd_cache_t    *_ppdCacheCreateWithFile(const char *filename,
-                                                ipp_t **attrs) _CUPS_PRIVATE;
+extern _ppd_cache_t    *_ppdCacheCreateWithFile(const char *filename, ipp_t **attrs) _CUPS_PRIVATE;
 extern _ppd_cache_t    *_ppdCacheCreateWithPPD(ppd_file_t *ppd) _CUPS_PRIVATE;
 extern void            _ppdCacheDestroy(_ppd_cache_t *pc) _CUPS_PRIVATE;
-extern const char      *_ppdCacheGetBin(_ppd_cache_t *pc,
-                                        const char *output_bin) _CUPS_PRIVATE;
-extern int             _ppdCacheGetFinishingOptions(_ppd_cache_t *pc,
-                                                    ipp_t *job,
-                                                    ipp_finishings_t value,
-                                                    int num_options,
-                                                    cups_option_t **options) _CUPS_PRIVATE;
+extern const char      *_ppdCacheGetBin(_ppd_cache_t *pc, const char *output_bin) _CUPS_PRIVATE;
+extern int             _ppdCacheGetFinishingOptions(_ppd_cache_t *pc, ipp_t *job, ipp_finishings_t value, int num_options, cups_option_t **options) _CUPS_PRIVATE;
 extern int             _ppdCacheGetFinishingValues(ppd_file_t *ppd, _ppd_cache_t *pc, int max_values, int *values) _CUPS_PRIVATE;
-extern const char      *_ppdCacheGetInputSlot(_ppd_cache_t *pc, ipp_t *job,
-                                              const char *keyword) _CUPS_PRIVATE;
-extern const char      *_ppdCacheGetMediaType(_ppd_cache_t *pc, ipp_t *job,
-                                              const char *keyword) _CUPS_PRIVATE;
-extern const char      *_ppdCacheGetOutputBin(_ppd_cache_t *pc,
-                                              const char *keyword) _CUPS_PRIVATE;
-extern const char      *_ppdCacheGetPageSize(_ppd_cache_t *pc, ipp_t *job,
-                                             const char *keyword, int *exact) _CUPS_PRIVATE;
-extern pwg_size_t      *_ppdCacheGetSize(_ppd_cache_t *pc,
-                                         const char *page_size) _CUPS_PRIVATE;
-extern const char      *_ppdCacheGetSource(_ppd_cache_t *pc,
-                                           const char *input_slot) _CUPS_PRIVATE;
-extern const char      *_ppdCacheGetType(_ppd_cache_t *pc,
-                                         const char *media_type) _CUPS_PRIVATE;
-extern int             _ppdCacheWriteFile(_ppd_cache_t *pc,
-                                          const char *filename, ipp_t *attrs) _CUPS_PRIVATE;
+extern const char      *_ppdCacheGetInputSlot(_ppd_cache_t *pc, ipp_t *job, const char *keyword) _CUPS_PRIVATE;
+extern const char      *_ppdCacheGetMediaType(_ppd_cache_t *pc, ipp_t *job, const char *keyword) _CUPS_PRIVATE;
+extern const char      *_ppdCacheGetOutputBin(_ppd_cache_t *pc, const char *keyword) _CUPS_PRIVATE;
+extern const char      *_ppdCacheGetPageSize(_ppd_cache_t *pc, ipp_t *job, const char *keyword, int *exact) _CUPS_PRIVATE;
+extern pwg_size_t      *_ppdCacheGetSize(_ppd_cache_t *pc, const char *page_size) _CUPS_PRIVATE;
+extern const char      *_ppdCacheGetSource(_ppd_cache_t *pc, const char *input_slot) _CUPS_PRIVATE;
+extern const char      *_ppdCacheGetType(_ppd_cache_t *pc, const char *media_type) _CUPS_PRIVATE;
+extern int             _ppdCacheWriteFile(_ppd_cache_t *pc, const char *filename, ipp_t *attrs) _CUPS_PRIVATE;
 extern char            *_ppdCreateFromIPP(char *buffer, size_t bufsize, ipp_t *response) _CUPS_PRIVATE;
-extern char            *_ppdCreateFromIPP2(char *buffer, size_t bufsize, ipp_t *response, cups_lang_t *lang) _CUPS_PRIVATE;
 extern void            _ppdFreeLanguages(cups_array_t *languages) _CUPS_PRIVATE;
 extern cups_encoding_t _ppdGetEncoding(const char *name) _CUPS_PRIVATE;
 extern cups_array_t    *_ppdGetLanguages(ppd_file_t *ppd) _CUPS_PRIVATE;
 extern _ppd_globals_t  *_ppdGlobals(void) _CUPS_PRIVATE;
 extern unsigned                _ppdHashName(const char *name) _CUPS_PRIVATE;
-extern ppd_attr_t      *_ppdLocalizedAttr(ppd_file_t *ppd, const char *keyword,
-                                          const char *spec, const char *ll_CC) _CUPS_PRIVATE;
-extern char            *_ppdNormalizeMakeAndModel(const char *make_and_model,
-                                                  char *buffer,
-                                                  size_t bufsize) _CUPS_PRIVATE;
-extern ppd_file_t      *_ppdOpen(cups_file_t *fp,
-                                 _ppd_localization_t localization) _CUPS_PRIVATE;
-extern ppd_file_t      *_ppdOpenFile(const char *filename,
-                                     _ppd_localization_t localization) _CUPS_PRIVATE;
-extern int             _ppdParseOptions(const char *s, int num_options,
-                                        cups_option_t **options,
-                                        _ppd_parse_t which) _CUPS_PRIVATE;
-extern const char      *_pwgInputSlotForSource(const char *media_source,
-                                               char *name, size_t namesize) _CUPS_PRIVATE;
-extern const char      *_pwgMediaTypeForType(const char *media_type,
-                                             char *name, size_t namesize) _CUPS_PRIVATE;
-extern const char      *_pwgPageSizeForMedia(pwg_media_t *media,
-                                             char *name, size_t namesize) _CUPS_PRIVATE;
+extern ppd_attr_t      *_ppdLocalizedAttr(ppd_file_t *ppd, const char *keyword, const char *spec, const char *ll_CC) _CUPS_PRIVATE;
+extern char            *_ppdNormalizeMakeAndModel(const char *make_and_model, char *buffer, size_t bufsize) _CUPS_PRIVATE;
+extern ppd_file_t      *_ppdOpen(cups_file_t *fp, _ppd_localization_t localization) _CUPS_PRIVATE;
+extern ppd_file_t      *_ppdOpenFile(const char *filename, _ppd_localization_t localization) _CUPS_PRIVATE;
+extern int             _ppdParseOptions(const char *s, int num_options, cups_option_t **options, _ppd_parse_t which) _CUPS_PRIVATE;
+extern const char      *_pwgInputSlotForSource(const char *media_source, char *name, size_t namesize) _CUPS_PRIVATE;
+extern const char      *_pwgMediaTypeForType(const char *media_type, char *name, size_t namesize) _CUPS_PRIVATE;
+extern const char      *_pwgPageSizeForMedia(pwg_media_t *media, char *name, size_t namesize) _CUPS_PRIVATE;
 
 
-/*
- * C++ magic...
- */
-
 #  ifdef __cplusplus
 }
 #  endif /* __cplusplus */