From 507707efe0a434afad9e80164628c902357485b7 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Sun, 13 Mar 2022 07:39:37 -0400 Subject: [PATCH] Implement papplClientGetLoc and use if from papplClientHTML* (Issue #58) Still need to implement positional parameter support and handle R-to-L languages. --- pappl/client-loc.c | 72 ++++++++++++++++++++++++++++++++++++++++-- pappl/client-private.h | 1 + pappl/client-webif.c | 20 ++++++++---- pappl/client.c | 3 +- 4 files changed, 87 insertions(+), 9 deletions(-) diff --git a/pappl/client-loc.c b/pappl/client-loc.c index 74515bce..170587dd 100644 --- a/pappl/client-loc.c +++ b/pappl/client-loc.c @@ -19,6 +19,74 @@ pappl_loc_t * // O - Localization data to use papplClientGetLoc( pappl_client_t *client) // I - Client { - (void)client; - return (NULL); + // Range check input... + if (!client) + return (NULL); + + if (!client->loc) + { + const char *language; // Language name + char temp[7], // Temporary language string + *ptr; // Pointer into temp string + + // Look up language + if ((language = ippGetString(ippFindAttribute(client->request, "attributes-natural-language", IPP_TAG_LANGUAGE), 0, NULL)) != NULL) + { + // Use IPP language specification... + if ((client->loc = papplSystemFindLoc(client->system, language)) == NULL && language[2]) + { + // Try the generic localization... + papplCopyString(temp, language, sizeof(temp)); + temp[2] = '\0'; + client->loc = papplSystemFindLoc(client->system, temp); + } + } + else if ((language = httpGetField(client->http, HTTP_FIELD_ACCEPT_LANGUAGE)) != NULL) + { + // Parse language string... + while (*language) + { + // Grab the next language code. The format (from RFC 7231) is: + // + // lang-code[;q=#][,...,land-code[;q=#]] + for (ptr = temp; *language && *language != ';' && *language != ','; language ++) + { + if (ptr < (temp + sizeof(temp) - 1)) + *ptr++ = *language; + } + *ptr = '\0'; + + if (*language == ';') + { + // Skip "quality" parameter... + while (*language && *language != ',') + language ++; + } + + if (*language == ',') + { + // Skip comma and whitespace... + language ++; + while (*language && isspace(*language & 255)) + language ++; + } + + // Look up the language... + if ((client->loc = papplSystemFindLoc(client->system, temp)) != NULL) + break; + + // If the lookup failed and this is a regional language request, try + // the generic localization for that language... + if (temp[2]) + { + // Truncate after the 2-digit language code... + temp[2] = '\0'; + if ((client->loc = papplSystemFindLoc(client->system, temp)) != NULL) + break; + } + } + } + } + + return (client->loc); } diff --git a/pappl/client-private.h b/pappl/client-private.h index 97c41a3e..ef9c1c3a 100644 --- a/pappl/client-private.h +++ b/pappl/client-private.h @@ -41,6 +41,7 @@ struct _pappl_client_s // Client data pappl_printer_t *printer; // Printer, if any pappl_scanner_t *scanner; // Scanner, if any pappl_job_t *job; // Job, if any + pappl_loc_t *loc; // Localization, if any int num_files; // Number of temporary files char *files[10]; // Temporary files }; diff --git a/pappl/client-webif.c b/pappl/client-webif.c index 791f3018..d2e0bc17 100644 --- a/pappl/client-webif.c +++ b/pappl/client-webif.c @@ -685,7 +685,7 @@ papplClientHTMLHeader( " %s%s%s\n" " \n" " \n" - " \n", title ? title : "", title ? " - " : "", name); + " \n", title ? papplLocGetString(papplClientGetLoc(client), title) : "", title ? " - " : "", name); if (refresh > 0) papplClientHTMLPrintf(client, "\n", refresh); papplClientHTMLPuts(client, @@ -1094,8 +1094,9 @@ papplClientHTMLPrintf( // Loop through the format string, formatting as needed... + // TODO: Support positional parameters, e.g. "%2$s" to access the second string argument va_start(ap, format); - start = format; + start = format = papplLocGetString(papplClientGetLoc(client), format); while (*format) { @@ -1295,6 +1296,7 @@ _papplClientHTMLPutLinks( size_t i, // Looping var count; // Number of links _pappl_link_t *l; // Current link + pappl_loc_t *loc; // Localization const char *webscheme = (httpAddrLocalhost(httpGetAddress(client->http)) || !papplSystemGetTLSOnly(client->system)) ? "http" : "https"; // URL scheme for links @@ -1303,6 +1305,7 @@ _papplClientHTMLPutLinks( // // Note: We use a loop and not cupsArrayGetFirst/Last because other threads may // be enumerating the same array of links. + loc = papplClientGetLoc(client); for (i = 0, count = cupsArrayGetCount(links); i < count; i ++) { @@ -1314,12 +1317,12 @@ _papplClientHTMLPutLinks( if (strcmp(client->uri, l->path_or_url)) { if (l->path_or_url[0] != '/' || !(l->options & PAPPL_LOPTIONS_HTTPS_REQUIRED) || (!client->system->auth_service && !client->system->auth_cb && !client->system->password_hash[0])) - papplClientHTMLPrintf(client, " %s\n", l->path_or_url, l->label); + papplClientHTMLPrintf(client, " %s\n", l->path_or_url, papplLocGetString(loc, l->label)); else - papplClientHTMLPrintf(client, " %s\n", webscheme, client->host_field, client->host_port, l->path_or_url, l->label); + papplClientHTMLPrintf(client, " %s\n", webscheme, client->host_field, client->host_port, l->path_or_url, papplLocGetString(loc, l->label)); } else - papplClientHTMLPrintf(client, " %s\n", l->label); + papplClientHTMLPrintf(client, " %s\n", papplLocGetString(loc, l->label)); } } @@ -1337,7 +1340,12 @@ papplClientHTMLPuts( const char *s) // I - String { if (client && s && *s) - httpWrite2(client->http, s, strlen(s)); + { + s = papplLocGetString(papplClientGetLoc(client), s); + + if (*s) + httpWrite2(client->http, s, strlen(s)); + } } diff --git a/pappl/client.c b/pappl/client.c index 077209f0..df5767dd 100644 --- a/pappl/client.c +++ b/pappl/client.c @@ -1,7 +1,7 @@ // // Client processing code for the Printer Application Framework // -// Copyright © 2019-2021 by Michael R Sweet. +// Copyright © 2019-2022 by Michael R Sweet. // Copyright © 2010-2019 by Apple Inc. // // Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -213,6 +213,7 @@ _papplClientProcessHTTP( ippDelete(client->request); ippDelete(client->response); + client->loc = NULL; client->request = NULL; client->response = NULL; client->operation = HTTP_STATE_WAITING;