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