we are interested in.
Add support for Languages directive in cups-files.conf.
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,
void *data);
+static _cups_message_t *cups_message_copy(_cups_message_t *m, void *data);
static void cups_message_free(_cups_message_t *m, void *data);
static void cups_message_load(cups_lang_t *lang);
static void cups_message_puts(cups_file_t *fp, const char *s);
int flags) /* I - Load flags */
{
cups_file_t *fp; /* Message file */
- _cups_message_t *m; /* Current message */
+ _cups_message_t m; /* Current message */
char s[4096], /* String buffer */
- *ptr, /* Pointer into buffer */
- *temp; /* New string */
- size_t length, /* Length of combined strings */
- ptrlen; /* Length of string */
+ msg_id[4096], /* Message ID buffer */
+ msg_str[4096], /* Message string buffer */
+ *ptr; /* Pointer into buffer */
DEBUG_printf("4_cupsMessageLoad(a=%p, filename=\"%s\", flags=%d)", (void *)a, filename, flags);
* "multiple lines"
*/
- m = NULL;
+ m.msg = NULL;
+ m.str = NULL;
while (cupsFileGets(fp, s, sizeof(s)) != NULL)
{
* Add previous message as needed...
*/
- if (m)
- {
- if (m->str && (m->str[0] || (flags & _CUPS_MESSAGE_EMPTY)))
- {
- 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 && (m.str[0] || (flags & _CUPS_MESSAGE_EMPTY)))
+ cupsArrayAdd(a, &m);
/*
* Create a new message with the given msgid string...
*/
- if ((m = (_cups_message_t *)calloc(1, sizeof(_cups_message_t))) == NULL)
- break;
-
- if ((m->msg = strdup(ptr)) == NULL)
- {
- free(m);
- m = NULL;
- break;
- }
+ cupsCopyString(msg_id, ptr, sizeof(msg_id));
+ m.msg = msg_id;
+ m.str = NULL;
}
- else if (s[0] == '\"' && m)
+ else if (s[0] == '\"' && (m.msg || m.str))
{
/*
* Append to current string...
*/
- length = strlen(m->str ? m->str : m->msg);
- ptrlen = strlen(ptr);
-
- 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)
- {
- /*
- * 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);
- }
+ if (m.str)
+ cupsConcatString(msg_str, ptr, sizeof(msg_str));
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);
- }
+ cupsConcatString(msg_id, ptr, sizeof(msg_id));
}
- else if (!strncmp(s, "msgstr", 6) && m)
+ else if (!strncmp(s, "msgstr", 6) && m.msg)
{
/*
* Set the string...
*/
- if ((m->str = strdup(ptr)) == NULL)
- {
- free(m->msg);
- free(m);
- m = NULL;
- break;
- }
+ cupsCopyString(msg_str, ptr, sizeof(msg_str));
+ m.str = msg_str;
}
}
* Add the last message string to the array as needed...
*/
- if (m)
- {
- if (m->str && (m->str[0] || (flags & _CUPS_MESSAGE_EMPTY)))
- {
- if (cupsArrayFind(a, m))
- cups_message_free(m, NULL);
- else
- cupsArrayAdd(a, m);
- }
- else
- {
- /*
- * Translation is empty, don't add it... (STR #4033)
- */
-
- cups_message_free(m, NULL);
- }
- }
+ if (m.msg && m.str && (m.str[0] || (flags & _CUPS_MESSAGE_EMPTY)))
+ cupsArrayAdd(a, &m);
}
/*
cups_array_t * /* O - Array */
_cupsMessageNew(void *context) /* I - User data */
{
- return (cupsArrayNew3((cups_array_func_t)cups_message_compare, context,
- (cups_ahash_func_t)NULL, 0,
- (cups_acopy_func_t)NULL,
- (cups_afree_func_t)cups_message_free));
+ return (cupsArrayNew3((cups_array_cb_t)cups_message_compare, context,
+ (cups_ahash_cb_t)NULL, 0,
+ (cups_acopy_cb_t)cups_message_copy,
+ (cups_afree_cb_t)cups_message_free));
}
}
+//
+// 'cups_message_copy()' - Copy a message.
+//
+
+static _cups_message_t * // O - New message
+cups_message_copy(_cups_message_t *m, // I - Message
+ void *data)// I - Callback data (unused)
+{
+ _cups_message_t *newm; // New message
+
+
+ (void)data;
+
+ if ((newm = (_cups_message_t *)malloc(sizeof(_cups_message_t))) != NULL)
+ {
+ newm->msg = strdup(m->msg);
+ newm->str = strdup(m->str);
+
+ if (!newm->msg || !newm->str)
+ {
+ free(newm->msg);
+ free(newm->str);
+ free(newm);
+
+ newm = NULL;
+ }
+ }
+
+ return (newm);
+}
+
/*
* 'cups_message_free()' - Free a message.
*/
static void
cups_message_free(_cups_message_t *m, /* I - Message */
- void *data)/* Unused */
+ void *data)/* I - Callback data (unused) */
{
(void)data;
*bufptr, /* Pointer into buffer */
*msg, /* Pointer to start of message */
*str; /* Pointer to start of translation string */
- _cups_message_t *m; /* New message */
+ _cups_message_t m; /* New message */
while (cupsFileGets(fp, buffer, sizeof(buffer)))
* 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);
+ m.msg = msg;
+ m.str = str;
- if (m->msg && m->str)
- {
- if (cupsArrayFind(a, m))
- cups_message_free(m, NULL);
- else
- cupsArrayAdd(a, m);
- }
- else
- {
- cups_message_free(m, NULL);
- break;
- }
+ if (!cupsArrayFind(a, &m))
+ cupsArrayAdd(a, &m);
return (1);
}
*/
static int cups_connect(http_t **http, const char *url, char *resource, size_t ressize);
-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_get_string(cups_lang_t *base, cups_lang_t *printer, const char *msgid, char *buffer, size_t bufsize);
+static void ppd_get_strings(ppd_file_t *ppd, cups_lang_t *langs, const char *option, ppd_choice_t *choice, const char *pwg_msgid);
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);
*/
snprintf(msg_id, sizeof(msg_id), "media-source.%s", pwg_name);
- msg.msg = msg_id;
-
- for (lang = langs; lang; lang = lang->next)
- {
- // See if the string is already localized...
- if (cupsArrayFind(lang->strings, &msg))
- continue; // Yes
-
- // Otherwise add the text...
- if (!strcmp(lang->language, "en"))
- {
- // English
- msg.str = choice->text;
- }
- else
- {
- // Other languauge...
- snprintf(ppd_name, sizeof(ppd_name), "%s.InputSlot", lang->language);
- if ((ppd_attr = ppdFindAttr(ppd, ppd_name, choice->choice)) != NULL)
- msg.str = ppd_attr->text;
- else
- continue;
- }
-
- cupsArrayAdd(lang->strings, &msg);
- }
+ ppd_get_strings(ppd, langs, "InputSlot", choice, msg_id);
}
}
}
}
-
/*
* Add localized text for PWG keyword to message catalog...
*/
snprintf(msg_id, sizeof(msg_id), "media-type.%s", map->pwg);
- msg.msg = msg_id;
-
- for (lang = langs; lang; lang = lang->next)
- {
- // See if the string is already localized...
- if (cupsArrayFind(lang->strings, &msg))
- continue; // Yes
-
- // Otherwise add the text...
- if (!strcmp(lang->language, "en"))
- {
- // English
- msg.str = choice->text;
- }
- else
- {
- // Other languauge...
- snprintf(ppd_name, sizeof(ppd_name), "%s.MediaType", lang->language);
- if ((ppd_attr = ppdFindAttr(ppd, ppd_name, choice->choice)) != NULL)
- msg.str = ppd_attr->text;
- else
- continue;
- }
-
- cupsArrayAdd(lang->strings, &msg);
- }
+ ppd_get_strings(ppd, langs, "MediaType", choice, msg_id);
}
}
*/
snprintf(msg_id, sizeof(msg_id), "output-bin.%s", pwg_name);
- msg.msg = msg_id;
-
- for (lang = langs; lang; lang = lang->next)
- {
- // See if the string is already localized...
- if (cupsArrayFind(lang->strings, &msg))
- continue; // Yes
-
- // Otherwise add the text...
- if (!strcmp(lang->language, "en"))
- {
- // English
- msg.str = choice->text;
- }
- else
- {
- // Other languauge...
- snprintf(ppd_name, sizeof(ppd_name), "%s.OutputBin", lang->language);
- if ((ppd_attr = ppdFindAttr(ppd, ppd_name, choice->choice)) != NULL)
- msg.str = ppd_attr->text;
- else
- continue;
- }
-
- cupsArrayAdd(lang->strings, &msg);
- }
+ ppd_get_strings(ppd, langs, "OutputBin", choice, msg_id);
}
}
}
-/*
- * '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.
*/
}
+//
+// 'ppd_get_strings()' - Get the strings for a given option and choice.
+//
+
+static void
+ppd_get_strings(
+ ppd_file_t *ppd, // I - PPD file
+ cups_lang_t *langs, // I - Languages
+ const char *option, // I - PPD option keyword
+ ppd_choice_t *choice, // I - PPD choice
+ const char *pwg_msgid) // I - PWG message ID
+{
+ cups_lang_t *lang; // Current language
+ char ppd_name[PPD_MAX_NAME]; // PPD main keyword
+ ppd_attr_t *ppd_attr; // PPD attribute
+ _cups_message_t msg; // Message
+
+
+ msg.msg = (char *)pwg_msgid;
+
+ for (lang = langs; lang; lang = lang->next)
+ {
+ // See if the string is already localized...
+ if (cupsArrayFind(lang->strings, &msg))
+ continue; // Yes
+
+ // Otherwise add the text...
+ if (!strcmp(lang->language, "en"))
+ {
+ // English
+ msg.str = choice->text;
+ }
+ else
+ {
+ // Other languauge...
+ snprintf(ppd_name, sizeof(ppd_name), "%s.%s", lang->language, option);
+ if ((ppd_attr = ppdFindAttr(ppd, ppd_name, choice->choice)) != NULL)
+ msg.str = ppd_attr->text;
+ else
+ continue;
+ }
+
+ cupsArrayAdd(lang->strings, &msg);
+ }
+}
+
+
/*
* 'ppd_put_strings()' - Write localization attributes to a PPD file.
*/
return (1);
}
- if ((pc = _ppdCacheCreateWithPPD(ppd)) == NULL)
+ if ((pc = _ppdCacheCreateWithPPD(NULL, ppd)) == NULL)
{
fprintf(stderr, "Unable to create PPD cache from \"%s\".\n", ppdfile);
return (1);
attr->text, attr->value ? attr->value : "");
puts("\nPPD Cache:");
- if ((pc = _ppdCacheCreateWithPPD(ppd)) == NULL)
+ if ((pc = _ppdCacheCreateWithPPD(NULL, ppd)) == NULL)
printf(" Unable to create: %s\n", cupsGetErrorString());
else
{
else
puts("PASS");
- fputs("_ppdCacheCreateWithPPD(ppd): ", stdout);
- if ((pc = _ppdCacheCreateWithPPD(ppd)) == NULL)
+ fputs("_ppdCacheCreateWithPPD(NULL, ppd): ", stdout);
+ if ((pc = _ppdCacheCreateWithPPD(NULL, ppd)) == NULL)
{
puts("FAIL");
status ++;
* information.
*/
-/*
- * Include necessary headers...
- */
-
#define _CUPS_NO_DEPRECATED
#define _HTTP_NO_PRIVATE
#include "cupsd.h"
struct stat *filestats);
static int compare_clients(cupsd_client_t *a, cupsd_client_t *b, void *data);
static int cupsd_start_tls(cupsd_client_t *con, http_encryption_t e);
-static char *get_file(cupsd_client_t *con, struct stat *filestats,
- char *filename, size_t len);
+static char *get_file(cupsd_client_t *con, struct stat *filestats, char *filename, size_t len);
static http_status_t install_cupsd_conf(cupsd_client_t *con);
-static int is_cgi(cupsd_client_t *con, const char *filename,
- struct stat *filestats, mime_type_t *type);
+static int is_cgi(cupsd_client_t *con, const char *filename, struct stat *filestats, mime_type_t *type);
static int is_path_absolute(const char *path);
-static int pipe_command(cupsd_client_t *con, int infile, int *outfile,
- char *command, char *options, int root);
+static int pipe_command(cupsd_client_t *con, int infile, int *outfile, char *command, char *options, int root);
static int valid_host(cupsd_client_t *con);
-static int write_file(cupsd_client_t *con, http_status_t code,
- char *filename, char *type,
- struct stat *filestats);
+static int write_file(cupsd_client_t *con, http_status_t code, char *filename, char *type, struct stat *filestats);
static void write_pipe(cupsd_client_t *con);
return (NULL);
}
else if (!strncmp(con->uri, "/rss/", 5) && !strchr(con->uri + 5, '/'))
+ {
snprintf(filename, len, "%s/rss/%s", CacheDir, con->uri + 5);
+ }
else if (!strncmp(con->uri, "/strings/", 9) && !strcmp(con->uri + strlen(con->uri) - 8, ".strings"))
{
- cupsCopyString(dest, con->uri + 9, sizeof(dest));
- dest[strlen(dest) - 8] = '\0';
-
- if ((p = cupsdFindDest(dest)) == NULL)
- {
- cupsCopyString(filename, "/", len);
- cupsdLogClient(con, CUPSD_LOG_INFO, "No destination \"%s\" found.", dest);
- return (NULL);
- }
-
- if (!p->strings)
- {
- cupsCopyString(filename, "/", len);
- cupsdLogClient(con, CUPSD_LOG_INFO, "No strings files for \"%s\".", dest);
- return (NULL);
- }
-
- cupsCopyString(filename, p->strings, len);
-
+ snprintf(filename, len, "%s/strings/%s", ServerRoot, con->uri + 9);
perm_check = 0;
}
else if (con->language)
* Local functions...
*/
+static void add_language(const char *language);
static http_addrlist_t *get_address(const char *value, int defport);
static int get_addr_and_mask(const char *value, unsigned *ip,
unsigned *mask);
else
cupsdSetString(&DefaultLanguage, language->language);
+ if (Languages)
+ {
+ // Free old languages...
+ cups_lang_t *lang, // Current language
+ *next; // Next language
+
+ for (lang = Languages; lang; lang = next)
+ {
+ next = lang->next;
+
+ cupsArrayDelete(lang->strings);
+ free(lang);
+ }
+
+ Languages = NULL;
+ }
+
cupsdClearString(&DefaultPaperSize);
cupsArrayDelete(ReadyPaperSizes);
ReadyPaperSizes = NULL;
cupsdSetStringf(&DefaultLocale, "%s.UTF-8", DefaultLanguage);
+ /*
+ * Make sure we have languages loaded...
+ */
+
+ if (!Languages)
+ add_language(DefaultLanguage);
+
+ add_language("en");
+
/*
* Update all relative filenames to include the full path from ServerRoot...
*/
}
+//
+// 'cupsdWriteStrings()' - Write out strings files.
+//
+
+void
+cupsdWriteStrings(void)
+{
+ cups_lang_t *lang; // New language
+ char strings_file[1024]; // Strings file
+
+
+ // Save each language...
+ for (lang = Languages; lang; lang = lang->next)
+ {
+ snprintf(strings_file, sizeof(strings_file), "%s/strings/%s.strings", ServerRoot, lang->language);
+ _cupsMessageSave(strings_file, _CUPS_MESSAGE_STRINGS, lang->strings);
+ }
+}
+
+
+//
+// 'add_language()' - Add a language to the Languages array.
+//
+
+static void
+add_language(const char *language) // I - Language code
+{
+ cups_lang_t *lang; // New language
+ char strings_file[1024]; // Strings file
+
+
+ // See if the language was already added...
+ for (lang = Languages; lang; lang = lang->next)
+ {
+ if (!strcmp(lang->language, language))
+ return;
+ }
+
+ // Not already added, so create a new entry and load any existing strings...
+ lang = (cups_lang_t *)calloc(1, sizeof(cups_lang_t));
+ cupsCopyString(lang->language, language, sizeof(lang->language));
+
+ snprintf(strings_file, sizeof(strings_file), "%s/strings/%s.strings", ServerRoot, language);
+ lang->strings = _cupsMessageLoad(NULL, strings_file, _CUPS_MESSAGE_STRINGS);
+
+ // Add the language to the list - English (en) is always first, then the rest
+ // follow...
+ if (Languages && !strcmp(Languages->language, "en"))
+ {
+ // Insert this language after the first one...
+ lang->next = Languages->next;
+ Languages->next = lang;
+ }
+ else
+ {
+ // Insert this at the front of the list...
+ lang->next = Languages;
+ Languages = lang;
+ }
+}
+
+
/*
* 'get_address()' - Get an address + port number from a line.
*/
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
{
if (!_cups_strcasecmp(line, "FatalErrors"))
+ {
FatalErrors = parse_fatal_errors(value);
+ }
else if (!_cups_strcasecmp(line, "Group") && value)
{
/*
}
}
else if (!_cups_strcasecmp(line, "LogFileGroup") && value)
+ {
+ /*
+ * List of languages to support...
+ */
+ cups_array_t *languages; // Array of language codes
+ const char *language; // Current language
+
+ languages = cupsArrayNewStrings(value, ' ');
+
+ for (language = (const char *)cupsArrayGetFirst(languages); language; language = (const char *)cupsArrayGetNext(languages))
+ add_language(language);
+
+ cupsArrayDelete(languages);
+ }
+ else if (!_cups_strcasecmp(line, "LogFileGroup") && value)
{
/*
* Group ID to log as...
extern int cupsdLogRequest(cupsd_client_t *con, http_status_t code);
extern int cupsdReadConfiguration(void);
extern int cupsdWriteErrorLog(int level, const char *message);
+extern void cupsdWriteStrings(void);
if (!ra || cupsArrayFind(ra, "printer-state-reasons"))
add_printer_state_reasons(con, printer);
+ if (!ra || cupsArrayFind(ra, "printer-strings-languages-supported"))
+ {
+ cups_lang_t *lang; // Current language
+ ipp_attribute_t *attr = NULL; // Attribute
+
+ for (lang = Languages; lang; lang = lang->next)
+ {
+ if (attr)
+ ippSetString(con->response, &attr, ippGetCount(attr), lang->language);
+ else
+ attr = ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, "printer-strings-languages-supported", NULL, lang->language);
+ }
+ }
+
if (!ra || cupsArrayFind(ra, "printer-strings-uri"))
{
- httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, "/strings/%s.strings", printer->name);
+ cups_lang_t *lang; // Current language
+
+ for (lang = Languages; lang; lang = lang->next)
+ {
+ if (!strcmp(lang->language, con->language->language))
+ break;
+ }
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, "/strings/%s.strings", lang ? lang->language : "en");
ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-strings-uri", NULL, uri);
cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-strings-uri=\"%s\"", uri);
}
if (!p->pc)
cupsdLogMessage(CUPSD_LOG_WARN, "Unable to create cache of \"%s\": %s", ppd_name, cupsGetErrorString());
+ cupsdWriteStrings();
+
ppdMarkDefaults(ppd);
if (ppd->color_device)
*prefilter; /* Pre-filter type */
- pc = _ppdCacheCreateWithPPD(ppd);
+ pc = _ppdCacheCreateWithPPD(NULL, ppd);
if (!pc)
return;