]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/cups-driverd.c
Finish up cups-driverd and fix some bugs.
[thirdparty/cups.git] / scheduler / cups-driverd.c
CommitLineData
08379093 1/*
2 * "$Id$"
3 *
4 * PPD/driver support for the Common UNIX Printing System (CUPS).
5 *
f2bc527f 6 * This program handles listing and installing both static PPD files
7 * in CUPS_DATADIR/model and dynamically generated PPD files using
8 * the driver helper programs in CUPS_SERVERBIN/driver.
9 *
08379093 10 * Copyright 1997-2005 by Easy Software Products.
11 *
12 * These coded instructions, statements, and computer programs are the
13 * property of Easy Software Products and are protected by Federal
14 * copyright law. Distribution and use rights are outlined in the file
15 * "LICENSE.txt" which should have been included with this file. If this
16 * file is missing or damaged please contact Easy Software Products
17 * at:
18 *
19 * Attn: CUPS Licensing Information
20 * Easy Software Products
21 * 44141 Airport View Drive, Suite 204
22 * Hollywood, Maryland 20636 USA
23 *
24 * Voice: (301) 373-9600
25 * EMail: cups-info@cups.org
26 * WWW: http://www.cups.org
27 *
28 * Contents:
29 *
08379093 30 */
31
32/*
33 * Include necessary headers...
34 */
35
36#include "util.h"
37#include <cups/dir.h>
38
39
40/*
41 * PPD information structures...
42 */
43
59d67ae4 44typedef struct /**** PPD record ****/
08379093 45{
46 time_t mtime; /* Modification time */
47 size_t size; /* Size in bytes */
48 char name[512 - sizeof(time_t) - sizeof(size_t)],
49 /* PPD name */
50 natural_language[128], /* Natural language(s) */
51 make[128], /* Manufacturer */
52 make_and_model[256]; /* Make and model */
53} ppd_rec_t;
54
59d67ae4 55typedef struct /**** In-memory record ****/
08379093 56{
57 int found; /* 1 if PPD is found */
59d67ae4 58 ppd_rec_t record; /* PPDs.dat record */
08379093 59} ppd_info_t;
60
61
62/*
59d67ae4 63 * Globals...
08379093 64 */
65
59d67ae4 66int NumPPDs, /* Number of PPD files */
67 SortedPPDs, /* Number of sorted PPD files */
68 AllocPPDs; /* Number of allocated entries */
69ppd_info_t *PPDs; /* PPD file info */
70int ChangedPPD; /* Did we change the PPD database? */
08379093 71
72
73/*
74 * Local functions...
75 */
76
59d67ae4 77ppd_info_t *add_ppd(const char *name, const char *natural_language,
78 const char *make, const char *make_and_model,
79 time_t mtime, size_t size);
80int cat_ppd(const char *name);
81int compare_names(const ppd_info_t *p0, const ppd_info_t *p1);
82int compare_ppds(const ppd_info_t *p0, const ppd_info_t *p1);
f2bc527f 83int list_ppds(int request_id, int limit, const char *opt);
59d67ae4 84int load_drivers(void);
85int load_ppds(const char *d, const char *p);
08379093 86
87
88/*
89 * 'main()' - Scan for drivers and return an IPP response.
90 *
91 * Usage:
92 *
93 * cups-driverd request_id limit options
94 */
95
96int /* O - Exit code */
97main(int argc, /* I - Number of command-line args */
98 char *argv[]) /* I - Command-line arguments */
99{
100 /*
101 * Check the command-line...
102 */
103
104 if (argc < 3 ||
105 (!strcmp(argv[1], "cat") && argc != 3) ||
106 (!strcmp(argv[1], "list") && argc != 5))
107 {
108 fputs("Usage: cups-driverd cat ppd-name\n", stderr);
109 fputs("Usage: cups-driverd list request_id limit options\n", stderr);
110 return (1);
111 }
112
113 /*
114 * Install or list PPDs...
115 */
116
f2bc527f 117 if (!strcmp(argv[1], "cat"))
118 return (cat_ppd(argv[2]));
08379093 119 else
120 return (list_ppds(atoi(argv[2]), atoi(argv[3]), argv[4]));
121}
122
123
124/*
125 * 'add_ppd()' - Add a PPD file.
126 */
127
59d67ae4 128ppd_info_t * /* O - PPD */
08379093 129add_ppd(const char *name, /* I - PPD name */
130 const char *natural_language, /* I - Language(s) */
131 const char *make, /* I - Manufacturer */
132 const char *make_and_model, /* I - NickName */
133 time_t mtime, /* I - Modification time */
134 size_t size) /* I - File size */
135{
59d67ae4 136 ppd_info_t *ppd; /* PPD */
137
138
139 /*
140 * Add a new PPD file...
141 */
142
143 if (NumPPDs >= AllocPPDs)
144 {
145 /*
146 * Allocate (more) memory for the PPD files...
147 */
148
149 AllocPPDs += 128;
150
151 if (!PPDs)
152 ppd = malloc(sizeof(ppd_info_t) * AllocPPDs);
153 else
154 ppd = realloc(PPDs, sizeof(ppd_info_t) * AllocPPDs);
155
156 if (ppd == NULL)
157 {
f2bc527f 158 fprintf(stderr, "ERROR: [cups-driverd] Ran out of memory for %d PPD files!\n",
59d67ae4 159 AllocPPDs);
160 return (NULL);
161 }
162
163 PPDs = ppd;
164 }
165
166 ppd = PPDs + NumPPDs;
167 NumPPDs ++;
168
169 /*
170 * Zero-out the PPD data and copy the values over...
171 */
172
173 memset(ppd, 0, sizeof(ppd_info_t));
174
175 ppd->found = 1;
176 ppd->record.mtime = mtime;
177 ppd->record.size = size;
178
179 strlcpy(ppd->record.name, name, sizeof(ppd->record.name));
f2bc527f 180 strlcpy(ppd->record.natural_language, natural_language,
181 sizeof(ppd->record.natural_language));
59d67ae4 182 strlcpy(ppd->record.make, make, sizeof(ppd->record.make));
183 strlcpy(ppd->record.make_and_model, make_and_model,
184 sizeof(ppd->record.make_and_model));
59d67ae4 185
186 /*
187 * Return the new PPD pointer...
188 */
189
190 return (ppd);
08379093 191}
192
193
194/*
195 * 'cat_ppd()' - Copy a PPD file to stdout.
196 */
197
59d67ae4 198int /* O - Exit code */
08379093 199cat_ppd(const char *name) /* I - PPD name */
200{
201 return (0);
202}
203
204
205/*
206 * 'compare_names()' - Compare PPD filenames for sorting.
207 */
208
59d67ae4 209int /* O - Result of comparison */
08379093 210compare_names(const ppd_info_t *p0, /* I - First PPD file */
211 const ppd_info_t *p1) /* I - Second PPD file */
212{
213 return (strcasecmp(p0->record.name, p1->record.name));
214}
215
216
217/*
218 * 'compare_ppds()' - Compare PPD file make and model names for sorting.
219 */
220
59d67ae4 221int /* O - Result of comparison */
08379093 222compare_ppds(const ppd_info_t *p0, /* I - First PPD file */
223 const ppd_info_t *p1) /* I - Second PPD file */
224{
225 int diff; /* Difference between strings */
226
227 /*
228 * First compare manufacturers...
229 */
230
231 if ((diff = strcasecmp(p0->record.make, p1->record.make)) != 0)
232 return (diff);
233 else if ((diff = cupsdCompareNames(p0->record.make_and_model,
234 p1->record.make_and_model)) != 0)
235 return (diff);
236 else
237 return (strcasecmp(p0->record.natural_language,
238 p1->record.natural_language));
239}
240
241
242/*
243 * 'list_ppds()' - List PPD files.
244 */
245
59d67ae4 246int /* O - Exit code */
08379093 247list_ppds(int request_id, /* I - Request ID */
248 int limit, /* I - Limit */
f2bc527f 249 const char *opt) /* I - Option argument */
08379093 250{
f2bc527f 251 int i; /* Looping var */
252 int count; /* Number of PPDs to send */
253 ppd_info_t *ppd; /* Current PPD file */
254 cups_file_t *fp; /* ppds.dat file */
255 struct stat fileinfo; /* ppds.dat information */
256 char filename[1024], /* ppds.dat filename */
257 model[1024]; /* Model directory */
258 const char *cups_cachedir; /* CUPS_CACHEDIR environment variable */
259 const char *cups_datadir; /* CUPS_DATADIR environment variable */
08379093 260 int num_options; /* Number of options */
261 cups_option_t *options; /* Options */
f2bc527f 262 const char *requested, /* requested-attributes option */
263 *make; /* ppd-make option */
08379093 264 int send_natural_language, /* Send ppd-natural-language attribute? */
265 send_make, /* Send ppd-make attribute? */
266 send_make_and_model, /* Send ppd-make-and-model attribute? */
267 send_name; /* Send ppd-name attribute? */
08379093 268
269
270 /*
271 * See if we a PPD database file...
272 */
273
59d67ae4 274 NumPPDs = 0;
275 AllocPPDs = 0;
f2bc527f 276 PPDs = (ppd_info_t *)NULL;
59d67ae4 277 ChangedPPD = 0;
08379093 278
f2bc527f 279 if ((cups_cachedir = getenv("CUPS_CACHEDIR")) == NULL)
280 cups_cachedir = CUPS_CACHEDIR;
281
282 snprintf(filename, sizeof(filename), "%s/ppds.dat", cups_cachedir);
08379093 283 if (!stat(filename, &fileinfo) &&
f2bc527f 284 (fileinfo.st_size % sizeof(ppd_rec_t)) == 0 &&
59d67ae4 285 (NumPPDs = fileinfo.st_size / sizeof(ppd_rec_t)) > 0)
08379093 286 {
287 /*
f2bc527f 288 * We have a ppds.dat file, so read it!
08379093 289 */
290
59d67ae4 291 AllocPPDs = NumPPDs;
08379093 292
59d67ae4 293 if ((PPDs = malloc(sizeof(ppd_info_t) * NumPPDs)) == NULL)
08379093 294 {
f2bc527f 295 fprintf(stderr, "ERROR: [cups-driverd] Unable to allocate memory for %d PPD files!\n",
296 NumPPDs);
59d67ae4 297 NumPPDs = 0;
298 AllocPPDs = 0;
08379093 299 }
f2bc527f 300 else if ((fp = cupsFileOpen(filename, "r")) != NULL)
08379093 301 {
59d67ae4 302 for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
08379093 303 {
304 cupsFileRead(fp, (char *)&(ppd->record), sizeof(ppd_rec_t));
305 ppd->found = 0;
306 }
307
308 cupsFileClose(fp);
309
f2bc527f 310 fprintf(stderr, "INFO: [cups-driverd] Read \"%s\", %d PPDs...\n",
311 filename, NumPPDs);
08379093 312 }
313 else
314 {
f2bc527f 315 fprintf(stderr, "ERROR: [cups-driverd] Unable to read \"%s\" - %s\n", filename,
316 strerror(errno));
59d67ae4 317 NumPPDs = 0;
08379093 318 }
319 }
320
321 /*
322 * Load all PPDs in the specified directory and below...
323 */
324
59d67ae4 325 SortedPPDs = NumPPDs;
08379093 326
f2bc527f 327 if ((cups_datadir = getenv("CUPS_DATADIR")) == NULL)
328 cups_datadir = CUPS_DATADIR;
329
330 snprintf(model, sizeof(model), "%s/model", cups_datadir);
331 load_ppds(model, "");
08379093 332
333 /*
334 * Cull PPD files that are no longer present...
335 */
336
59d67ae4 337 for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
08379093 338 if (!ppd->found)
339 {
340 /*
341 * Remove this PPD file from the list...
342 */
343
344 if (i > 1)
345 memmove(ppd, ppd + 1, (i - 1) * sizeof(ppd_info_t));
346
59d67ae4 347 NumPPDs --;
08379093 348 ppd --;
349 }
350
351 /*
f2bc527f 352 * Sort the PPDs by name...
08379093 353 */
354
59d67ae4 355 if (NumPPDs > 1)
356 qsort(PPDs, NumPPDs, sizeof(ppd_info_t),
f2bc527f 357 (int (*)(const void *, const void *))compare_names);
08379093 358
359 /*
f2bc527f 360 * Write the new ppds.dat file...
08379093 361 */
362
59d67ae4 363 if (ChangedPPD)
08379093 364 {
f2bc527f 365 if ((fp = cupsFileOpen(filename, "w")) != NULL)
08379093 366 {
59d67ae4 367 for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
08379093 368 cupsFileWrite(fp, (char *)&(ppd->record), sizeof(ppd_rec_t));
369
370 cupsFileClose(fp);
371
f2bc527f 372 fprintf(stderr, "INFO: [cups-driverd] Wrote \"%s\", %d PPDs...\n",
373 filename, NumPPDs);
08379093 374 }
375 else
f2bc527f 376 fprintf(stderr, "ERROR: [cups-driverd] Unable to write \"%s\" - %s",
377 filename, strerror(errno));
08379093 378 }
379 else
f2bc527f 380 fputs("INFO: [cups-driverd] No new or changed PPDs...\n", stderr);
08379093 381
382 /*
f2bc527f 383 * Scan for dynamic PPD files...
08379093 384 */
385
f2bc527f 386 load_drivers();
08379093 387
388 /*
f2bc527f 389 * Add the raw driver...
08379093 390 */
391
f2bc527f 392 add_ppd("raw", "en", "Raw", "Raw Queue", 0, 0);
08379093 393
394 /*
f2bc527f 395 * Sort the PPDs by make and model...
08379093 396 */
397
f2bc527f 398 if (NumPPDs > 1)
399 qsort(PPDs, NumPPDs, sizeof(ppd_info_t),
400 (int (*)(const void *, const void *))compare_ppds);
08379093 401
402 /*
f2bc527f 403 * Send IPP attributes...
08379093 404 */
405
f2bc527f 406 num_options = cupsParseOptions(opt, 0, &options);
08379093 407 requested = cupsGetOption("requested-attributes", num_options, options);
f2bc527f 408 make = cupsGetOption("ppd-make", num_options, options);
08379093 409
410 if (!requested || strstr(requested, "all"))
411 {
f2bc527f 412 send_name = 1;
413 send_make = 1;
414 send_make_and_model = 1;
415 send_natural_language = 1;
08379093 416 }
417 else
418 {
f2bc527f 419 send_name = strstr(requested, "ppd-name") != NULL;
420 send_make = strstr(requested, "ppd-make,") != NULL ||
421 strstr(requested, ",ppd-make") != NULL ||
422 !strcmp(requested, "ppd-make");
423 send_make_and_model = strstr(requested, "ppd-make-and-model") != NULL;
424 send_natural_language = strstr(requested, "ppd-natural-language") != NULL;
08379093 425 }
426
f2bc527f 427 puts("Content-Type: application/ipp\n");
08379093 428
f2bc527f 429 cupsdSendIPPHeader(IPP_OK, request_id);
430 cupsdSendIPPGroup(IPP_TAG_OPERATION);
431 cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
432 cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");
08379093 433
f2bc527f 434 if (limit <= 0 || limit > NumPPDs)
435 count = NumPPDs;
436 else
437 count = limit;
08379093 438
f2bc527f 439 for (i = NumPPDs, ppd = PPDs; count > 0 && i > 0; i --, ppd ++)
440 if (!make || !strcasecmp(ppd->record.make, make))
08379093 441 {
442 /*
f2bc527f 443 * Send this PPD...
08379093 444 */
445
f2bc527f 446 count --;
08379093 447
f2bc527f 448 cupsdSendIPPGroup(IPP_TAG_PRINTER);
08379093 449
f2bc527f 450 if (send_name)
451 cupsdSendIPPString(IPP_TAG_NAME, "ppd-name", ppd->record.name);
08379093 452
f2bc527f 453 if (send_natural_language)
454 cupsdSendIPPString(IPP_TAG_LANGUAGE, "ppd-natural-language",
455 ppd->record.natural_language);
08379093 456
f2bc527f 457 if (send_make)
458 cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make", ppd->record.make);
08379093 459
f2bc527f 460 if (send_make_and_model)
461 cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make-and-model",
462 ppd->record.make_and_model);
08379093 463
464 /*
f2bc527f 465 * If we have only requested the ppd-make attribute, then skip
466 * the remaining PPDs with this make...
08379093 467 */
468
f2bc527f 469 if (requested && !strcmp(requested, "ppd-make"))
08379093 470 {
f2bc527f 471 const char *this_make; /* This ppd-make */
08379093 472
08379093 473
f2bc527f 474 for (this_make = ppd->record.make, i --, ppd ++; i > 0; i --, ppd ++)
475 if (strcasecmp(this_make, ppd->record.make))
476 break;
477
478 i ++;
479 ppd --;
08379093 480 }
481 }
08379093 482
483 cupsdSendIPPTrailer();
484
08379093 485 return (0);
486}
487
488
489/*
490 * 'load_ppds()' - Load PPD files recursively.
491 */
492
59d67ae4 493int /* O - 1 on success, 0 on failure */
08379093 494load_ppds(const char *d, /* I - Actual directory */
495 const char *p) /* I - Virtual path in name */
496{
497 int i; /* Looping var */
498 cups_file_t *fp; /* Pointer to file */
59d67ae4 499 cups_dir_t *dir; /* Directory pointer */
500 cups_dentry_t *dent; /* Directory entry */
08379093 501 char filename[1024], /* Name of PPD or directory */
502 line[256], /* Line from backend */
503 *ptr, /* Pointer into name */
504 name[128], /* Name of PPD file */
505 language[64], /* PPD language version */
506 country[64], /* Country code */
507 manufacturer[256], /* Manufacturer */
508 make_model[256], /* Make and Model */
509 model_name[256], /* ModelName */
510 nick_name[256]; /* NickName */
511 ppd_info_t *ppd, /* New PPD file */
512 key; /* Search key */
513 int new_ppd; /* Is this a new PPD? */
514 struct /* LanguageVersion translation table */
515 {
516 const char *version, /* LanguageVersion string */
517 *language; /* Language code */
518 } languages[] =
519 {
520 { "chinese", "cn" },
521 { "danish", "da" },
522 { "dutch", "nl" },
523 { "english", "en" },
524 { "finnish", "fi" },
525 { "french", "fr" },
526 { "german", "de" },
527 { "greek", "el" },
528 { "italian", "it" },
529 { "japanese", "jp" },
530 { "norwegian", "no" },
531 { "polish", "pl" },
532 { "portuguese", "pt" },
533 { "russian", "ru" },
534 { "slovak", "sk" },
535 { "spanish", "es" },
536 { "swedish", "sv" },
537 { "turkish", "tr" }
538 };
539
540
59d67ae4 541 if ((dir = cupsDirOpen(d)) == NULL)
08379093 542 {
f2bc527f 543 fprintf(stderr, "ERROR: [cups-driverd] Unable to open PPD directory \"%s\": %s\n",
59d67ae4 544 d, strerror(errno));
545 return (0);
08379093 546 }
547
59d67ae4 548 while ((dent = cupsDirRead(dir)) != NULL)
08379093 549 {
08379093 550 /*
551 * See if this is a file...
552 */
553
59d67ae4 554 snprintf(filename, sizeof(filename), "%s/%s", d, dent->filename);
08379093 555
556 if (p[0])
59d67ae4 557 snprintf(name, sizeof(name), "%s/%s", p, dent->filename);
08379093 558 else
59d67ae4 559 strlcpy(name, dent->filename, sizeof(name));
08379093 560
59d67ae4 561 if (S_ISDIR(dent->fileinfo.st_mode))
08379093 562 {
563 /*
564 * Do subdirectory...
565 */
566
59d67ae4 567 if (!load_ppds(filename, name))
568 {
569 cupsDirClose(dir);
570 return (1);
571 }
572
08379093 573 continue;
574 }
575
576 /*
577 * See if this file has been scanned before...
578 */
579
59d67ae4 580 if (SortedPPDs > 0)
08379093 581 {
59d67ae4 582 strcpy(key.record.name, name);
08379093 583
59d67ae4 584 ppd = bsearch(&key, PPDs, SortedPPDs, sizeof(ppd_info_t),
08379093 585 (int (*)(const void *, const void *))compare_names);
586
587 if (ppd &&
f2bc527f 588 ppd->record.size == dent->fileinfo.st_size &&
589 ppd->record.mtime == dent->fileinfo.st_mtime)
08379093 590 {
591 ppd->found = 1;
592 continue;
593 }
594 }
595 else
596 ppd = NULL;
597
598 /*
599 * No, file is new/changed, so re-scan it...
600 */
601
f2bc527f 602 if ((fp = cupsFileOpen(filename, "r")) == NULL)
08379093 603 continue;
604
605 /*
606 * Now see if this is a PPD file...
607 */
608
609 line[0] = '\0';
610 cupsFileGets(fp, line, sizeof(line));
611
59d67ae4 612 if (strncmp(line, "*PPD-Adobe:", 11))
08379093 613 {
614 /*
615 * Nope, close the file and continue...
616 */
617
618 cupsFileClose(fp);
619
620 continue;
621 }
622
623 /*
624 * Now read until we get the NickName field...
625 */
626
627 model_name[0] = '\0';
628 nick_name[0] = '\0';
629 manufacturer[0] = '\0';
630 strcpy(language, "en");
631
632 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
633 {
59d67ae4 634 if (!strncmp(line, "*Manufacturer:", 14))
08379093 635 sscanf(line, "%*[^\"]\"%255[^\"]", manufacturer);
59d67ae4 636 else if (!strncmp(line, "*ModelName:", 11))
08379093 637 sscanf(line, "%*[^\"]\"%127[^\"]", model_name);
59d67ae4 638 else if (!strncmp(line, "*LanguageVersion:", 17))
08379093 639 sscanf(line, "%*[^:]:%63s", language);
59d67ae4 640 else if (!strncmp(line, "*NickName:", 10))
08379093 641 sscanf(line, "%*[^\"]\"%255[^\"]", nick_name);
59d67ae4 642 else if (!strncmp(line, "*OpenUI", 7))
08379093 643 {
644 /*
645 * Stop early if we have a NickName or ModelName attributes
646 * before the first OpenUI...
647 */
648
649 if (model_name[0] || nick_name[0])
650 break;
651 }
652
653 /*
654 * Stop early if we have both the Manufacturer and NickName
655 * attributes...
656 */
657
658 if (manufacturer[0] && nick_name[0])
659 break;
660 }
661
662 /*
663 * Close the file...
664 */
665
666 cupsFileClose(fp);
667
668 /*
669 * See if we got all of the required info...
670 */
671
672 if (nick_name[0])
673 strcpy(make_model, nick_name);
674 else
675 strcpy(make_model, model_name);
676
677 while (isspace(make_model[0] & 255))
678 cups_strcpy(make_model, make_model + 1);
679
680 if (!make_model[0])
681 continue; /* Nope... */
682
683 /*
684 * See if we got a manufacturer...
685 */
686
687 while (isspace(manufacturer[0] & 255))
688 cups_strcpy(manufacturer, manufacturer + 1);
689
59d67ae4 690 if (!manufacturer[0] || !strcmp(manufacturer, "ESP"))
08379093 691 {
692 /*
693 * Nope, copy the first part of the make and model then...
694 */
695
696 strlcpy(manufacturer, make_model, sizeof(manufacturer));
697
698 /*
699 * Truncate at the first space, dash, or slash, or make the
700 * manufacturer "Other"...
701 */
702
703 for (ptr = manufacturer; *ptr; ptr ++)
704 if (*ptr == ' ' || *ptr == '-' || *ptr == '/')
705 break;
706
707 if (*ptr && ptr > manufacturer)
708 *ptr = '\0';
59d67ae4 709 else if (!strncasecmp(manufacturer, "agfa", 4))
08379093 710 strcpy(manufacturer, "AGFA");
59d67ae4 711 else if (!strncasecmp(manufacturer, "herk", 4) ||
712 !strncasecmp(manufacturer, "linotype", 8))
08379093 713 strcpy(manufacturer, "LHAG");
714 else
715 strcpy(manufacturer, "Other");
716
717 /*
718 * Hack for various vendors...
719 */
720
59d67ae4 721 if (!strcasecmp(manufacturer, "XPrint"))
08379093 722 strcpy(manufacturer, "Xerox");
59d67ae4 723 else if (!strcasecmp(manufacturer, "Eastman"))
08379093 724 strcpy(manufacturer, "Kodak");
59d67ae4 725 else if (!strcasecmp(manufacturer, "laserwriter"))
08379093 726 strcpy(manufacturer, "Apple");
59d67ae4 727 else if (!strcasecmp(manufacturer, "colorpoint"))
08379093 728 strcpy(manufacturer, "Seiko");
59d67ae4 729 else if (!strcasecmp(manufacturer, "fiery"))
08379093 730 strcpy(manufacturer, "EFI");
59d67ae4 731 else if (!strcasecmp(manufacturer, "ps") ||
732 !strcasecmp(manufacturer, "colorpass"))
08379093 733 strcpy(manufacturer, "Canon");
59d67ae4 734 else if (!strncasecmp(manufacturer, "primera", 7))
08379093 735 strcpy(manufacturer, "Fargo");
59d67ae4 736 else if (!strcasecmp(manufacturer, "designjet"))
08379093 737 strcpy(manufacturer, "HP");
738 }
59d67ae4 739 else if (!strncasecmp(manufacturer, "LHAG", 4) ||
740 !strncasecmp(manufacturer, "linotype", 8))
08379093 741 strcpy(manufacturer, "LHAG");
742
743 /*
744 * Fix the language as needed...
745 */
746
747 if ((ptr = strchr(language, '-')) != NULL)
748 *ptr++ = '\0';
749 else if ((ptr = strchr(language, '_')) != NULL)
750 *ptr++ = '\0';
751
752 if (ptr)
753 {
754 /*
755 * Setup the country suffix...
756 */
757
758 country[0] = '_';
759 cups_strcpy(country + 1, ptr);
760 }
761 else
762 {
763 /*
764 * No country suffix...
765 */
766
767 country[0] = '\0';
768 }
769
770 for (i = 0; i < (int)(sizeof(languages) / sizeof(languages[0])); i ++)
59d67ae4 771 if (!strcasecmp(languages[i].version, language))
08379093 772 break;
773
774 if (i < (int)(sizeof(languages) / sizeof(languages[0])))
775 {
776 /*
777 * Found a known language...
778 */
779
780 snprintf(language, sizeof(language), "%s%s", languages[i].language,
781 country);
782 }
783 else
784 {
785 /*
786 * Unknown language; use "xx"...
787 */
788
789 strcpy(language, "xx");
790 }
791
792 /*
793 * Add the PPD file...
794 */
795
796 new_ppd = !ppd;
797
798 if (new_ppd)
799 {
800 /*
59d67ae4 801 * Add new PPD file...
08379093 802 */
803
f2bc527f 804 fprintf(stderr, "DEBUG: [cups-driverd] Adding ppd \"%s\"...\n", name);
08379093 805
f2bc527f 806 if (!add_ppd(name, language, manufacturer, make_model,
59d67ae4 807 dent->fileinfo.st_mtime, dent->fileinfo.st_size))
08379093 808 {
59d67ae4 809 cupsDirClose(dir);
810 return (0);
811 }
812 }
813 else
814 {
815 /*
816 * Update existing record...
817 */
08379093 818
f2bc527f 819 fprintf(stderr, "DEBUG: [cups-driverd] Updating ppd \"%s\"...\n", name);
08379093 820
59d67ae4 821 memset(ppd, 0, sizeof(ppd_info_t));
08379093 822
59d67ae4 823 ppd->found = 1;
824 ppd->record.mtime = dent->fileinfo.st_mtime;
825 ppd->record.size = dent->fileinfo.st_size;
08379093 826
59d67ae4 827 strlcpy(ppd->record.name, name, sizeof(ppd->record.name));
828 strlcpy(ppd->record.make, manufacturer, sizeof(ppd->record.make));
829 strlcpy(ppd->record.make_and_model, make_model,
830 sizeof(ppd->record.make_and_model));
831 strlcpy(ppd->record.natural_language, language,
832 sizeof(ppd->record.natural_language));
08379093 833 }
08379093 834
59d67ae4 835 ChangedPPD = 1;
836 }
08379093 837
59d67ae4 838 cupsDirClose(dir);
08379093 839
59d67ae4 840 return (1);
841}
08379093 842
08379093 843
59d67ae4 844/*
845 * 'load_drivers()' - Load driver-generated PPD files.
846 */
08379093 847
59d67ae4 848int /* O - 1 on success, 0 on failure */
849load_drivers(void)
850{
f2bc527f 851 const char *server_bin; /* CUPS_SERVERBIN environment variable */
852 char drivers[1024]; /* Location of driver programs */
853 FILE *fp; /* Pipe to driver program */
854 cups_dir_t *dir; /* Directory pointer */
855 cups_dentry_t *dent; /* Directory entry */
856 char filename[1024], /* Name of driver */
857 line[2048], /* Line from driver */
858 name[512], /* ppd-name */
859 natural_language[128], /* ppd-natural-language */
860 make[128], /* ppd-make */
861 make_and_model[256]; /* ppd-make-and-model */
862
863
864 /*
865 * Try opening the driver directory...
866 */
867
868 if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
869 server_bin = CUPS_SERVERBIN;
870
871 snprintf(drivers, sizeof(drivers), "%s/driver", server_bin);
872
873 if ((dir = cupsDirOpen(drivers)) == NULL)
874 {
875 fprintf(stderr, "ERROR: [cups-driverd] Unable to open driver directory \"%s\": %s",
876 drivers, strerror(errno));
877 return (0);
878 }
879
880 /*
881 * Loop through all of the device drivers...
882 */
883
884 while ((dent = cupsDirRead(dir)) != NULL)
885 {
886 /*
887 * Only look at executable files...
888 */
889
890 if (!(dent->fileinfo.st_mode & 0111) || !S_ISREG(dent->fileinfo.st_mode))
891 continue;
892
893 /*
894 * Run the driver with no arguments and collect the output...
895 */
896
897 snprintf(filename, sizeof(filename), "%s/%s", drivers, dent->filename);
898 if ((fp = popen(filename, "r")) != NULL)
899 {
900 while (fgets(line, sizeof(line), fp) != NULL)
901 {
902 /*
903 * Each line is of the form:
904 *
905 * \"ppd-name\" ppd-natural-language "ppd-make" "ppd-make-and-model"
906 */
907
908 if (sscanf(line, "\"%511[^\"]\"%127s%*[ \t]\"%127[^\"]\"%*[ \t]\"%256[^\"]\"",
909 name, natural_language, make, make_and_model) != 4)
910 {
911 /*
912 * Bad format; strip trailing newline and write an error message.
913 */
914
915 if (line[strlen(line) - 1] == '\n')
916 line[strlen(line) - 1] = '\0';
917
918 fprintf(stderr, "ERROR: [cups-driverd] Bad line from \"%s\": %s\n",
919 dent->filename, line);
920 break;
921 }
922 else
923 {
924 /*
925 * Add the device to the array of available devices...
926 */
927
928 if (!add_ppd(name, natural_language, make, make_and_model, 0, 0))
929 {
930 cupsDirClose(dir);
931 return (0);
932 }
933
934 fprintf(stderr, "DEBUG: [cups-driverd] Added dynamic PPD \"%s\"...\n",
935 name);
936 }
937 }
938
939 pclose(fp);
940 }
941 else
942 fprintf(stderr, "WARNING: [cups-driverd] Unable to execute \"%s\": %s\n",
943 filename, strerror(errno));
944 }
945
946 cupsDirClose(dir);
947
59d67ae4 948 return (1);
08379093 949}
950
951
952/*
59d67ae4 953 * End of "$Id$".
08379093 954 */