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