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