/*
- * "$Id: cups-driverd.c 6377 2007-03-21 07:17:11Z mike $"
+ * "$Id: cups-driverd.c 6508 2007-05-03 20:07:14Z mike $"
*
* PPD/driver support for the Common UNIX Printing System (CUPS).
*
* cat_ppd() - Copy a PPD file to stdout.
* compare_names() - Compare PPD filenames for sorting.
* compare_ppds() - Compare PPD file make and model names for sorting.
+ * free_array() - Free an array of strings.
* list_ppds() - List PPD files.
* load_ppds() - Load PPD files recursively.
* load_drivers() - Load driver-generated PPD files.
extern cups_encoding_t _ppdGetEncoding(const char *name);
+/*
+ * Constants...
+ */
+
+#define PPD_SYNC 0x50504433 /* Sync word for ppds.dat (PPD3) */
+#define PPD_MAX_LANG 32 /* Maximum languages */
+#define PPD_MAX_PROD 8 /* Maximum products */
+#define PPD_MAX_VERS 8 /* Maximum versions */
+
+
/*
* PPD information structures...
*/
{
time_t mtime; /* Modification time */
size_t size; /* Size in bytes */
- char name[512 - sizeof(time_t) - sizeof(size_t)],
- /* PPD name */
- natural_language[6], /* LanguageVersion */
- product[122], /* Product */
+ char name[512], /* PPD name */
+ languages[PPD_MAX_LANG][6],
+ /* LanguageVersion/cupsLanguages */
+ products[PPD_MAX_PROD][128],
+ /* Product strings */
+ psversions[PPD_MAX_VERS][32],
+ /* PSVersion strings */
make[128], /* Manufacturer */
make_and_model[128], /* NickName/ModelName */
device_id[128]; /* IEEE 1284 Device ID */
-} ppd_rec_t;
+} ppd_rec_t;
typedef struct /**** In-memory record ****/
{
* Local functions...
*/
-static ppd_info_t *add_ppd(const char *name, const char *natural_language,
+static ppd_info_t *add_ppd(const char *name, const char *language,
const char *make, const char *make_and_model,
const char *device_id, const char *product,
- time_t mtime, size_t size);
-static int cat_ppd(const char *name);
+ const char *psversion, time_t mtime,
+ size_t size);
+static int cat_ppd(const char *name, int request_id);
static int compare_names(const ppd_info_t *p0,
const ppd_info_t *p1);
static int compare_ppds(const ppd_info_t *p0,
const ppd_info_t *p1);
+static void free_array(cups_array_t *a);
static int list_ppds(int request_id, int limit, const char *opt);
static int load_drivers(void);
-static int load_ppds(const char *d, const char *p);
+static int load_ppds(const char *d, const char *p, int descend);
/*
*/
if (argc == 3 && !strcmp(argv[1], "cat"))
- return (cat_ppd(argv[2]));
+ return (cat_ppd(argv[2], 0));
+ else if (argc == 4 && !strcmp(argv[1], "get"))
+ return (cat_ppd(argv[3], atoi(argv[2])));
else if (argc == 5 && !strcmp(argv[1], "list"))
return (list_ppds(atoi(argv[2]), atoi(argv[3]), argv[4]));
else
{
fputs("Usage: cups-driverd cat ppd-name\n", stderr);
+ fputs("Usage: cups-driverd get request_id ppd-name\n", stderr);
fputs("Usage: cups-driverd list request_id limit options\n", stderr);
return (1);
}
static ppd_info_t * /* O - PPD */
add_ppd(const char *name, /* I - PPD name */
- const char *natural_language, /* I - Language(s) */
+ const char *language, /* I - LanguageVersion */
const char *make, /* I - Manufacturer */
const char *make_and_model, /* I - NickName/ModelName */
const char *device_id, /* I - 1284DeviceID */
const char *product, /* I - Product */
+ const char *psversion, /* I - PSVersion */
time_t mtime, /* I - Modification time */
size_t size) /* I - File size */
{
if (ppd == NULL)
{
- fprintf(stderr, "ERROR: [cups-driverd] Ran out of memory for %d PPD files!\n",
+ fprintf(stderr,
+ "ERROR: [cups-driverd] Ran out of memory for %d PPD files!\n",
AllocPPDs);
return (NULL);
}
ppd->record.size = size;
strlcpy(ppd->record.name, name, sizeof(ppd->record.name));
- strlcpy(ppd->record.natural_language, natural_language,
- sizeof(ppd->record.natural_language));
- strlcpy(ppd->record.product, product, sizeof(ppd->record.product));
+ strlcpy(ppd->record.languages[0], language,
+ sizeof(ppd->record.languages[0]));
+ strlcpy(ppd->record.products[0], product, sizeof(ppd->record.products[0]));
+ strlcpy(ppd->record.psversions[0], psversion,
+ sizeof(ppd->record.psversions[0]));
strlcpy(ppd->record.make, make, sizeof(ppd->record.make));
strlcpy(ppd->record.make_and_model, make_and_model,
sizeof(ppd->record.make_and_model));
* Foomatic drivers...
*/
- if ((recommended = strstr(ppd->record.make_and_model, " (recommended)")) != NULL)
+ if ((recommended = strstr(ppd->record.make_and_model,
+ " (recommended)")) != NULL)
*recommended = '\0';
/*
*/
static int /* O - Exit code */
-cat_ppd(const char *name) /* I - PPD name */
+cat_ppd(const char *name, /* I - PPD name */
+ int request_id) /* I - Request ID for response? */
{
char scheme[256], /* Scheme from PPD name */
*sptr; /* Pointer into scheme */
char line[1024]; /* Line/filename */
+ char message[2048]; /* status-message */
/*
else
scheme[0] = '\0';
+ puts("Content-Type: application/ipp\n");
+
if (scheme[0])
{
/*
fprintf(stderr, "ERROR: [cups-driverd] Unable to access \"%s\" - %s\n",
line, strerror(errno));
+
+ if (request_id > 0)
+ {
+ snprintf(message, sizeof(message), "Unable to access \"%s\" - %s",
+ line, strerror(errno));
+
+ cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message);
+ cupsdSendIPPTrailer();
+ }
+
return (1);
}
* Yes, let it cat the PPD file...
*/
+ if (request_id)
+ {
+ cupsdSendIPPHeader(IPP_OK, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPTrailer();
+ }
+
if (execl(line, scheme, "cat", name, (char *)NULL))
{
/*
*/
fprintf(stderr, "ERROR: [cups-driverd] Bad PPD name \"%s\"!\n", name);
+
+ if (request_id)
+ {
+ snprintf(message, sizeof(message), "Bad PPD name \"%s\"!", name);
+
+ cupsdSendIPPHeader(IPP_OK, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message);
+ cupsdSendIPPTrailer();
+ }
+
return (1);
}
* Try opening the file...
*/
- if ((datadir = getenv("CUPS_DATADIR")) == NULL)
- datadir = CUPS_DATADIR;
+#ifdef __APPLE__
+ if (!strncmp(name, "System/Library/Printers/PPDs/Contents/Resources/", 48) ||
+ !strncmp(name, "Library/Printers/PPDs/Contents/Resources/", 41))
+ {
+ /*
+ * Map ppd-name to Mac OS X standard locations...
+ */
+
+ snprintf(line, sizeof(line), "/%s", name);
+ }
+ else
+
+#elif defined(__linux)
+ if (!strncmp(name, "lsb/usr/", 8))
+ {
+ /*
+ * Map ppd-name to LSB standard /usr/share/ppd location...
+ */
+
+ snprintf(line, sizeof(line), "/usr/share/ppd/%s", name + 8);
+ }
+ else if (!strncmp(name, "lsb/opt/", 8))
+ {
+ /*
+ * Map ppd-name to LSB standard /opt/share/ppd location...
+ */
+
+ snprintf(line, sizeof(line), "/opt/share/ppd/%s", name + 8);
+ }
+ else if (!strncmp(name, "lsb/local/", 10))
+ {
+ /*
+ * Map ppd-name to LSB standard /usr/local/share/ppd location...
+ */
+
+ snprintf(line, sizeof(line), "/usr/local/share/ppd/%s", name + 10);
+ }
+ else
+
+#endif /* __APPLE__ */
+ {
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ snprintf(line, sizeof(line), "%s/model/%s", datadir, name);
+ }
- snprintf(line, sizeof(line), "%s/model/%s", datadir, name);
if ((fp = cupsFileOpen(line, "r")) == NULL)
{
fprintf(stderr, "ERROR: [cups-driverd] Unable to open \"%s\" - %s\n",
line, strerror(errno));
+
+ if (request_id)
+ {
+ snprintf(message, sizeof(message), "Unable to open \"%s\" - %s",
+ line, strerror(errno));
+
+ cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message);
+ cupsdSendIPPTrailer();
+ }
+
return (1);
}
+ if (request_id)
+ {
+ cupsdSendIPPHeader(IPP_OK, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+ "en-US");
+ cupsdSendIPPTrailer();
+ }
+
/*
* Now copy the file to stdout...
*/
p1->record.make_and_model)) != 0)
return (diff);
else
- return (strcasecmp(p0->record.natural_language,
- p1->record.natural_language));
+ return (strcasecmp(p0->record.languages[0],
+ p1->record.languages[0]));
+}
+
+
+/*
+ * 'free_array()' - Free an array of strings.
+ */
+
+static void
+free_array(cups_array_t *a) /* I - Array to free */
+{
+ char *ptr; /* Pointer to string */
+
+
+ for (ptr = (char *)cupsArrayFirst(a);
+ ptr;
+ ptr = (char *)cupsArrayNext(a))
+ free(ptr);
+
+ cupsArrayDelete(a);
}
int limit, /* I - Limit */
const char *opt) /* I - Option argument */
{
- int i; /* Looping var */
+ int i, j; /* Looping vars */
int count; /* Number of PPDs to send */
ppd_info_t *ppd; /* Current PPD file */
cups_file_t *fp; /* ppds.dat file */
int num_options; /* Number of options */
cups_option_t *options; /* Options */
const char *requested, /* requested-attributes option */
- *make; /* ppd-make option */
- int send_natural_language, /* Send ppd-natural-language attribute? */
- send_make, /* Send ppd-make attribute? */
- send_make_and_model, /* Send ppd-make-and-model attribute? */
- send_name, /* Send ppd-name attribute? */
- send_device_id, /* Send ppd-device-id attribute? */
- send_product; /* Send ppd-product attribute? */
-
-
- fprintf(stderr, "DEBUG2: [cups-driverd] list_ppds(request_id=%d, limit=%d, opt=\"%s\"\n",
- request_id, limit, opt);
+ *device_id, /* ppd-device-id option */
+ *language, /* ppd-natural-language option */
+ *make, /* ppd-make option */
+ *make_and_model, /* ppd-make-and-model option */
+ *product, /* ppd-product option */
+ *psversion; /* ppd-psversion option */
+ int mam_len, /* Length of ppd-make-and-model */
+ device_id_len, /* Length of ppd-device-id */
+ send_natural_language, /* Send ppd-natural-language? */
+ send_make, /* Send ppd-make? */
+ send_make_and_model, /* Send ppd-make-and-model? */
+ send_name, /* Send ppd-name? */
+ send_device_id, /* Send ppd-device-id? */
+ send_product, /* Send ppd-product? */
+ send_psversion, /* Send ppd-psversion? */
+ sent_header; /* Sent the IPP header? */
+
+
+ fprintf(stderr,
+ "DEBUG2: [cups-driverd] list_ppds(request_id=%d, limit=%d, "
+ "opt=\"%s\"\n", request_id, limit, opt);
/*
* See if we a PPD database file...
cups_cachedir = CUPS_CACHEDIR;
snprintf(filename, sizeof(filename), "%s/ppds.dat", cups_cachedir);
- if (!stat(filename, &fileinfo) &&
- (fileinfo.st_size % sizeof(ppd_rec_t)) == 0 &&
- (NumPPDs = fileinfo.st_size / sizeof(ppd_rec_t)) > 0)
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
{
/*
- * We have a ppds.dat file, so read it!
+ * See if we have the right sync word...
*/
- AllocPPDs = NumPPDs;
+ unsigned ppdsync; /* Sync word */
- if ((PPDs = malloc(sizeof(ppd_info_t) * NumPPDs)) == NULL)
+ if (cupsFileRead(fp, (char *)&ppdsync, sizeof(ppdsync))
+ == sizeof(ppdsync) &&
+ ppdsync == PPD_SYNC &&
+ !stat(filename, &fileinfo) &&
+ ((fileinfo.st_size - sizeof(ppdsync)) % sizeof(ppd_rec_t)) == 0 &&
+ (NumPPDs = (fileinfo.st_size - sizeof(ppdsync)) /
+ sizeof(ppd_rec_t)) > 0)
{
- fprintf(stderr,
- "ERROR: [cups-driverd] Unable to allocate memory for %d "
- "PPD files!\n", NumPPDs);
- NumPPDs = 0;
- AllocPPDs = 0;
- }
- else if ((fp = cupsFileOpen(filename, "r")) != NULL)
- {
- for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
+ /*
+ * We have a ppds.dat file, so read it!
+ */
+
+ if ((PPDs = malloc(sizeof(ppd_info_t) * NumPPDs)) == NULL)
+ fprintf(stderr,
+ "ERROR: [cups-driverd] Unable to allocate memory for %d "
+ "PPD files!\n", NumPPDs);
+ else
{
- cupsFileRead(fp, (char *)&(ppd->record), sizeof(ppd_rec_t));
- ppd->found = 0;
- }
+ AllocPPDs = NumPPDs;
- cupsFileClose(fp);
+ for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
+ {
+ cupsFileRead(fp, (char *)&(ppd->record), sizeof(ppd_rec_t));
+ ppd->found = 0;
+ }
- fprintf(stderr, "INFO: [cups-driverd] Read \"%s\", %d PPDs...\n",
- filename, NumPPDs);
- }
- else
- {
- fprintf(stderr, "ERROR: [cups-driverd] Unable to read \"%s\" - %s\n", filename,
- strerror(errno));
- NumPPDs = 0;
+ fprintf(stderr, "INFO: [cups-driverd] Read \"%s\", %d PPDs...\n",
+ filename, NumPPDs);
+ }
}
- }
+ cupsFileClose(fp);
+ }
+
/*
* Load all PPDs in the specified directory and below...
*/
cups_datadir = CUPS_DATADIR;
snprintf(model, sizeof(model), "%s/model", cups_datadir);
- load_ppds(model, "");
+ load_ppds(model, "", 1);
+
+#ifdef __APPLE__
+ /*
+ * Load PPDs from standard Mac OS X locations...
+ */
+
+ load_ppds("/Library/Printers/PPDs/Contents/Resources",
+ "Library/Printers/PPDs/Contents/Resources", 0);
+ load_ppds("/Library/Printers/PPDs/Contents/Resources/en.lproj",
+ "Library/Printers/PPDs/Contents/Resources/en.lproj", 0);
+ load_ppds("/System/Library/Printers/PPDs/Contents/Resources",
+ "System/Library/Printers/PPDs/Contents/Resources", 0);
+ load_ppds("/System/Library/Printers/PPDs/Contents/Resources/en.lproj",
+ "System/Library/Printers/PPDs/Contents/Resources/en.lproj", 0);
+
+#elif defined(__linux)
+ /*
+ * Load PPDs from LSB-defined locations...
+ */
+
+ load_ppds("/usr/local/share/ppds", "lsb/local", 1);
+ load_ppds("/usr/share/ppds", "lsb/usr", 1);
+ load_ppds("/opt/share/ppds", "lsb/opt", 1);
+#endif /* __APPLE__ */
/*
* Cull PPD files that are no longer present...
{
if ((fp = cupsFileOpen(filename, "w")) != NULL)
{
+ unsigned ppdsync = PPD_SYNC; /* Sync word */
+
+
+ cupsFileWrite(fp, (char *)&ppdsync, sizeof(ppdsync));
+
for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
cupsFileWrite(fp, (char *)&(ppd->record), sizeof(ppd_rec_t));
* Add the raw driver...
*/
- add_ppd("raw", "en", "Raw", "Raw Queue", "", "", 0, 0);
+ add_ppd("raw", "en", "Raw", "Raw Queue", "", "", "", 0, 0);
/*
* Sort the PPDs by make and model...
* Send IPP attributes...
*/
- num_options = cupsParseOptions(opt, 0, &options);
- requested = cupsGetOption("requested-attributes", num_options, options);
- make = cupsGetOption("ppd-make", num_options, options);
+ num_options = cupsParseOptions(opt, 0, &options);
+ requested = cupsGetOption("requested-attributes", num_options, options);
+ device_id = cupsGetOption("ppd-device-id", num_options, options);
+ language = cupsGetOption("ppd-natural-language", num_options, options);
+ make = cupsGetOption("ppd-make", num_options, options);
+ make_and_model = cupsGetOption("ppd-make-and-model", num_options, options);
+ product = cupsGetOption("ppd-product", num_options, options);
+ psversion = cupsGetOption("ppd-psversion", num_options, options);
+
+ if (make_and_model)
+ mam_len = strlen(make_and_model);
+ else
+ mam_len = 0;
- fprintf(stderr, "DEBUG: [cups-driverd] requested=\"%s\"\n",
- requested ? requested : "(nil)");
+ if (device_id)
+ device_id_len = strlen(device_id);
+ else
+ device_id_len = 0;
+
+ if (requested)
+ fprintf(stderr, "DEBUG: [cups-driverd] requested-attributes=\"%s\"\n",
+ requested);
+ if (device_id)
+ fprintf(stderr, "DEBUG: [cups-driverd] ppd-device-id=\"%s\"\n",
+ device_id);
+ if (language)
+ fprintf(stderr, "DEBUG: [cups-driverd] ppd-natural-language=\"%s\"\n",
+ language);
+ if (make)
+ fprintf(stderr, "DEBUG: [cups-driverd] ppd-make=\"%s\"\n",
+ make);
+ if (make_and_model)
+ fprintf(stderr, "DEBUG: [cups-driverd] ppd-make-and-model=\"%s\"\n",
+ make_and_model);
+ if (product)
+ fprintf(stderr, "DEBUG: [cups-driverd] ppd-product=\"%s\"\n",
+ product);
+ if (psversion)
+ fprintf(stderr, "DEBUG: [cups-driverd] ppd-psversion=\"%s\"\n",
+ psversion);
if (!requested || strstr(requested, "all"))
{
send_natural_language = 1;
send_device_id = 1;
send_product = 1;
+ send_psversion = 1;
}
else
{
send_natural_language = strstr(requested, "ppd-natural-language") != NULL;
send_device_id = strstr(requested, "ppd-device-id") != NULL;
send_product = strstr(requested, "ppd-product") != NULL;
+ send_psversion = strstr(requested, "ppd-psversion") != NULL;
}
puts("Content-Type: application/ipp\n");
- cupsdSendIPPHeader(IPP_OK, request_id);
- cupsdSendIPPGroup(IPP_TAG_OPERATION);
- cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
- cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");
+ sent_header = 0;
if (limit <= 0 || limit > NumPPDs)
count = NumPPDs;
count = limit;
for (i = NumPPDs, ppd = PPDs; count > 0 && i > 0; i --, ppd ++)
- if (!make || !strcasecmp(ppd->record.make, make))
+ {
+ /*
+ * Filter PPDs based on make, model, or device ID...
+ */
+
+ if (device_id && strncasecmp(ppd->record.device_id, device_id,
+ device_id_len))
+ continue; /* TODO: implement smart compare */
+
+ if (language)
{
- /*
- * Send this PPD...
- */
+ for (j = 0; j < PPD_MAX_LANG; j ++)
+ if (!ppd->record.languages[j][0] ||
+ !strcasecmp(ppd->record.languages[j], language))
+ break;
+
+ if (j >= PPD_MAX_LANG || !ppd->record.languages[j][0])
+ continue;
+ }
+
+ if (make && strcasecmp(ppd->record.make, make))
+ continue;
+
+ if (make_and_model && strncasecmp(ppd->record.make_and_model,
+ make_and_model, mam_len))
+ continue;
+
+ if (product)
+ {
+ for (j = 0; j < PPD_MAX_PROD; j ++)
+ if (!ppd->record.products[j][0] ||
+ !strcasecmp(ppd->record.products[j], product))
+ break;
- fprintf(stderr, "DEBUG: [cups-driverd] Sending %s (%s)...\n",
- ppd->record.name, ppd->record.make_and_model);
+ if (j >= PPD_MAX_PROD || !ppd->record.products[j][0])
+ continue;
+ }
- count --;
+ if (psversion)
+ {
+ for (j = 0; j < PPD_MAX_VERS; j ++)
+ if (!ppd->record.psversions[j][0] ||
+ !strcasecmp(ppd->record.psversions[j], psversion))
+ break;
- cupsdSendIPPGroup(IPP_TAG_PRINTER);
+ if (j >= PPD_MAX_VERS || !ppd->record.psversions[j][0])
+ continue;
+ }
- if (send_name)
- cupsdSendIPPString(IPP_TAG_NAME, "ppd-name", ppd->record.name);
+ /*
+ * Send this PPD...
+ */
- if (send_natural_language)
- cupsdSendIPPString(IPP_TAG_LANGUAGE, "ppd-natural-language",
- ppd->record.natural_language);
+ if (!sent_header)
+ {
+ sent_header = 1;
- if (send_make)
- cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make", ppd->record.make);
+ cupsdSendIPPHeader(IPP_OK, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");
+ }
- if (send_make_and_model)
- cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make-and-model",
- ppd->record.make_and_model);
+ fprintf(stderr, "DEBUG: [cups-driverd] Sending %s (%s)...\n",
+ ppd->record.name, ppd->record.make_and_model);
- if (send_device_id)
- cupsdSendIPPString(IPP_TAG_TEXT, "ppd-device-id",
- ppd->record.device_id);
+ count --;
- if (send_product)
- cupsdSendIPPString(IPP_TAG_TEXT, "ppd-product",
- ppd->record.product);
+ cupsdSendIPPGroup(IPP_TAG_PRINTER);
- /*
- * If we have only requested the ppd-make attribute, then skip
- * the remaining PPDs with this make...
- */
+ if (send_name)
+ cupsdSendIPPString(IPP_TAG_NAME, "ppd-name", ppd->record.name);
- if (requested && !strcmp(requested, "ppd-make"))
- {
- const char *this_make; /* This ppd-make */
+ if (send_natural_language)
+ {
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "ppd-natural-language",
+ ppd->record.languages[0]);
+ for (j = 1; j < PPD_MAX_LANG && ppd->record.languages[j][0]; j ++)
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "", ppd->record.languages[j]);
+ }
- for (this_make = ppd->record.make, i --, ppd ++; i > 0; i --, ppd ++)
- if (strcasecmp(this_make, ppd->record.make))
- break;
+ if (send_make)
+ cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make", ppd->record.make);
- i ++;
- ppd --;
- }
+ if (send_make_and_model)
+ cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make-and-model",
+ ppd->record.make_and_model);
+
+ if (send_device_id)
+ cupsdSendIPPString(IPP_TAG_TEXT, "ppd-device-id",
+ ppd->record.device_id);
+
+ if (send_product)
+ {
+ cupsdSendIPPString(IPP_TAG_TEXT, "ppd-product",
+ ppd->record.products[0]);
+
+ for (j = 1; j < PPD_MAX_PROD && ppd->record.products[j][0]; j ++)
+ cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.products[j]);
+ }
+
+ if (send_psversion)
+ {
+ cupsdSendIPPString(IPP_TAG_TEXT, "ppd-psversion",
+ ppd->record.psversions[0]);
+
+ for (j = 1; j < PPD_MAX_VERS && ppd->record.psversions[j][0]; j ++)
+ cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.psversions[j]);
+ }
+
+ /*
+ * If we have only requested the ppd-make attribute, then skip
+ * the remaining PPDs with this make...
+ */
+
+ if (requested && !strcmp(requested, "ppd-make"))
+ {
+ const char *this_make; /* This ppd-make */
+
+
+ for (this_make = ppd->record.make, i --, ppd ++; i > 0; i --, ppd ++)
+ if (strcasecmp(this_make, ppd->record.make))
+ break;
+
+ i ++;
+ ppd --;
}
+ }
+
+ if (!sent_header)
+ {
+ cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+ cupsdSendIPPGroup(IPP_TAG_OPERATION);
+ cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+ cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");
+ }
cupsdSendIPPTrailer();
static int /* O - 1 on success, 0 on failure */
load_ppds(const char *d, /* I - Actual directory */
- const char *p) /* I - Virtual path in name */
+ const char *p, /* I - Virtual path in name */
+ int descend) /* I - Descend into directories? */
{
int i; /* Looping var */
cups_file_t *fp; /* Pointer to file */
model_name[256], /* ModelName */
nick_name[256], /* NickName */
device_id[256], /* 1284DeviceID */
- product[256]; /* Product */
- cups_array_t *products; /* Array of product strings */
+ product[256], /* Product */
+ psversion[256]; /* PSVersion */
+ cups_array_t *products, /* Product array */
+ *psversions, /* PSVersion array */
+ *cups_languages; /* cupsLanguages array */
ppd_info_t *ppd, /* New PPD file */
key; /* Search key */
int new_ppd; /* Is this a new PPD? */
*language; /* Language code */
} languages[] =
{
- { "chinese", "cn" },
+ { "chinese", "zh" },
{ "danish", "da" },
{ "dutch", "nl" },
{ "english", "en" },
if ((dir = cupsDirOpen(d)) == NULL)
{
- fprintf(stderr, "ERROR: [cups-driverd] Unable to open PPD directory \"%s\": %s\n",
+ fprintf(stderr,
+ "ERROR: [cups-driverd] Unable to open PPD directory \"%s\": %s\n",
d, strerror(errno));
return (0);
}
* Do subdirectory...
*/
- if (!load_ppds(filename, name))
- {
- cupsDirClose(dir);
- return (1);
- }
+ if (descend)
+ if (!load_ppds(filename, name, 1))
+ {
+ cupsDirClose(dir);
+ return (1);
+ }
continue;
}
* Now read until we get the NickName field...
*/
- products = cupsArrayNew(NULL, NULL);
+ cups_languages = cupsArrayNew(NULL, NULL);
+ products = cupsArrayNew(NULL, NULL);
+ psversions = cupsArrayNew(NULL, NULL);
model_name[0] = '\0';
nick_name[0] = '\0';
sscanf(line, "%*[^\"]\"(%255[^)]", product);
cupsArrayAdd(products, strdup(product));
}
+ else if (!strncasecmp(line, "*PSVersion:", 11))
+ {
+ sscanf(line, "%*[^\"]\"%255[^\"]", psversion);
+ cupsArrayAdd(psversions, strdup(psversion));
+ }
+ else if (!strncasecmp(line, "*cupsLanguages:", 15))
+ {
+ char *start; /* Start of language */
+
+
+ for (start = line + 15; *start && isspace(*start & 255); start ++);
+
+ if (*start++ == '\"')
+ {
+ while (*start)
+ {
+ for (ptr = start + 1;
+ *ptr && *ptr != '\"' && !isspace(*ptr & 255);
+ ptr ++);
+
+ if (*ptr)
+ {
+ *ptr++ = '\0';
+
+ while (isspace(*ptr & 255))
+ *ptr++ = '\0';
+ }
+
+ cupsArrayAdd(cups_languages, strdup(start));
+ start = ptr;
+ }
+ }
+ }
else if (!strncmp(line, "*OpenUI", 7))
{
/*
* before the first OpenUI...
*/
- if ((model_name[0] || nick_name[0]) && cupsArrayCount(products) > 0)
+ if ((model_name[0] || nick_name[0]) && cupsArrayCount(products) > 0 &&
+ cupsArrayCount(psversions) > 0)
break;
}
}
while (isspace(make_model[0] & 255))
_cups_strcpy(make_model, make_model + 1);
- if (!make_model[0] || cupsArrayCount(products) == 0)
+ if (!make_model[0] || cupsArrayCount(products) == 0 ||
+ cupsArrayCount(psversions) == 0)
{
/*
* We don't have all the info needed, so skip this file...
if (cupsArrayCount(products) == 0)
fprintf(stderr, "WARNING: Missing Product in %s!\n", filename);
- for (ptr = (char *)cupsArrayFirst(products);
- ptr;
- ptr = (char *)cupsArrayNext(products))
- free(ptr);
+ if (cupsArrayCount(psversions) == 0)
+ fprintf(stderr, "WARNING: Missing PSVersion in %s!\n", filename);
- cupsArrayDelete(products);
+ free_array(products);
+ free_array(psversions);
+ free_array(cups_languages);
continue;
}
fprintf(stderr, "DEBUG: [cups-driverd] Adding ppd \"%s\"...\n", name);
- /* TODO: Support multiple Products... */
- if (!add_ppd(name, lang_version, manufacturer, make_model, device_id,
- (char *)cupsArrayFirst(products),
- dent->fileinfo.st_mtime, dent->fileinfo.st_size))
+ ppd = add_ppd(name, lang_version, manufacturer, make_model, device_id,
+ (char *)cupsArrayFirst(products),
+ (char *)cupsArrayFirst(psversions),
+ dent->fileinfo.st_mtime, dent->fileinfo.st_size);
+
+ if (!ppd)
{
cupsDirClose(dir);
return (0);
strlcpy(ppd->record.make, manufacturer, sizeof(ppd->record.make));
strlcpy(ppd->record.make_and_model, make_model,
sizeof(ppd->record.make_and_model));
- strlcpy(ppd->record.natural_language, lang_version,
- sizeof(ppd->record.natural_language));
- strlcpy(ppd->record.product, (char *)cupsArrayFirst(products),
- sizeof(ppd->record.product));
+ strlcpy(ppd->record.languages[0], lang_version,
+ sizeof(ppd->record.languages[0]));
+ strlcpy(ppd->record.products[0], (char *)cupsArrayFirst(products),
+ sizeof(ppd->record.products[0]));
+ strlcpy(ppd->record.psversions[0], (char *)cupsArrayFirst(psversions),
+ sizeof(ppd->record.psversions[0]));
strlcpy(ppd->record.device_id, device_id, sizeof(ppd->record.device_id));
}
/*
- * Free products...
+ * Add remaining products, versions, and languages...
*/
- for (ptr = (char *)cupsArrayFirst(products);
- ptr;
- ptr = (char *)cupsArrayNext(products))
- free(ptr);
+ for (i = 1;
+ i < PPD_MAX_PROD && (ptr = (char *)cupsArrayNext(products)) != NULL;
+ i ++)
+ strlcpy(ppd->record.products[i], ptr,
+ sizeof(ppd->record.products[0]));
+
+ for (i = 1;
+ i < PPD_MAX_VERS && (ptr = (char *)cupsArrayNext(psversions)) != NULL;
+ i ++)
+ strlcpy(ppd->record.psversions[i], ptr,
+ sizeof(ppd->record.psversions[0]));
- cupsArrayDelete(products);
+ for (i = 1, ptr = (char *)cupsArrayFirst(cups_languages);
+ i < PPD_MAX_LANG && ptr;
+ i ++, ptr = (char *)cupsArrayNext(cups_languages))
+ strlcpy(ppd->record.languages[i], ptr,
+ sizeof(ppd->record.languages[0]));
+
+ /*
+ * Free products, versions, and languages...
+ */
+
+ free_array(cups_languages);
+ free_array(products);
+ free_array(psversions);
ChangedPPD = 1;
}
static int /* O - 1 on success, 0 on failure */
load_drivers(void)
{
- const char *server_bin; /* CUPS_SERVERBIN environment variable */
+ int i; /* Looping var */
+ char *start, /* Start of value */
+ *ptr; /* Pointer into string */
+ const char *server_bin; /* CUPS_SERVERBIN env variable */
char drivers[1024]; /* Location of driver programs */
FILE *fp; /* Pipe to driver program */
cups_dir_t *dir; /* Directory pointer */
char filename[1024], /* Name of driver */
line[2048], /* Line from driver */
name[512], /* ppd-name */
- natural_language[128], /* ppd-natural-language */
make[128], /* ppd-make */
- make_and_model[256], /* ppd-make-and-model */
- device_id[256], /* ppd-device-id */
- product[256]; /* ppd-product */
+ make_and_model[128], /* ppd-make-and-model */
+ device_id[128], /* ppd-device-id */
+ languages[128], /* ppd-natural-language */
+ product[128], /* ppd-product */
+ psversion[128]; /* ppd-psversion */
+ ppd_info_t *ppd; /* Newly added PPD */
/*
* Each line is of the form:
*
* "ppd-name" ppd-natural-language "ppd-make" "ppd-make-and-model" \
- * "ppd-device-id" "ppd-product"
+ * "ppd-device-id" "ppd-product" "ppd-psversion"
*/
device_id[0] = '\0';
product[0] = '\0';
+ psversion[0] = '\0';
if (sscanf(line, "\"%511[^\"]\"%127s%*[ \t]\"%127[^\"]\""
- "%*[ \t]\"%256[^\"]\"%*[ \t]\"%256[^\"]\""
- "%*[ \t]\"%256[^\"]\"",
- name, natural_language, make, make_and_model,
- device_id, product) < 4)
+ "%*[ \t]\"%127[^\"]\"%*[ \t]\"%127[^\"]\""
+ "%*[ \t]\"%127[^\"]\"%*[ \t]\"%127[^\"]\"",
+ name, languages, make, make_and_model,
+ device_id, product, psversion) < 4)
{
/*
* Bad format; strip trailing newline and write an error message.
* Add the device to the array of available devices...
*/
- if (!add_ppd(name, natural_language, make, make_and_model, device_id,
- product, 0, 0))
+ if ((start = strchr(languages, ',')) != NULL)
+ *start++ = '\0';
+
+ ppd = add_ppd(name, languages, make, make_and_model, device_id,
+ product, psversion, 0, 0);
+
+ if (!ppd)
{
cupsDirClose(dir);
return (0);
}
+ if (start && *start)
+ {
+ for (i = 1; i < PPD_MAX_LANG && *start; i ++)
+ {
+ if ((ptr = strchr(start, ',')) != NULL)
+ *ptr++ = '\0';
+ else
+ ptr = start + strlen(start);
+
+ strlcpy(ppd->record.languages[i], start,
+ sizeof(ppd->record.languages[0]));
+
+ start = ptr;
+ }
+ }
+
fprintf(stderr, "DEBUG: [cups-driverd] Added dynamic PPD \"%s\"...\n",
name);
}
/*
- * End of "$Id: cups-driverd.c 6377 2007-03-21 07:17:11Z mike $".
+ * End of "$Id: cups-driverd.c 6508 2007-05-03 20:07:14Z mike $".
*/