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