]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/mime.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / scheduler / mime.c
1 /*
2 * MIME database file routines for CUPS.
3 *
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
8 */
9
10 /*
11 * Include necessary headers...
12 */
13
14 #include <cups/string-private.h>
15 #include <cups/debug-private.h>
16 #include <cups/dir.h>
17 #include "mime-private.h"
18
19
20 /*
21 * Local types...
22 */
23
24 typedef struct _mime_fcache_s /**** Filter cache structure ****/
25 {
26 char *name, /* Filter name */
27 *path; /* Full path to filter if available */
28 } _mime_fcache_t;
29
30
31 /*
32 * Local functions...
33 */
34
35 static const char *mime_add_fcache(cups_array_t *filtercache, const char *name,
36 const char *filterpath);
37 static int mime_compare_fcache(_mime_fcache_t *a, _mime_fcache_t *b);
38 static void mime_delete_fcache(cups_array_t *filtercache);
39 static void mime_delete_rules(mime_magic_t *rules);
40 static void mime_load_convs(mime_t *mime, const char *filename,
41 const char *filterpath,
42 cups_array_t *filtercache);
43 static void mime_load_types(mime_t *mime, const char *filename);
44
45
46 /*
47 * 'mimeDelete()' - Delete (free) a MIME database.
48 */
49
50 void
51 mimeDelete(mime_t *mime) /* I - MIME database */
52 {
53 mime_type_t *type; /* Current type */
54 mime_filter_t *filter; /* Current filter */
55
56
57 DEBUG_printf(("mimeDelete(mime=%p)", mime));
58
59 if (!mime)
60 return;
61
62 /*
63 * Loop through filters and free them...
64 */
65
66 for (filter = (mime_filter_t *)cupsArrayFirst(mime->filters);
67 filter;
68 filter = (mime_filter_t *)cupsArrayNext(mime->filters))
69 mimeDeleteFilter(mime, filter);
70
71 /*
72 * Loop through the file types and delete any rules...
73 */
74
75 for (type = (mime_type_t *)cupsArrayFirst(mime->types);
76 type;
77 type = (mime_type_t *)cupsArrayNext(mime->types))
78 mimeDeleteType(mime, type);
79
80 /*
81 * Free the types and filters arrays, and then the MIME database structure.
82 */
83
84 cupsArrayDelete(mime->types);
85 cupsArrayDelete(mime->filters);
86 cupsArrayDelete(mime->srcs);
87 free(mime);
88 }
89
90
91 /*
92 * 'mimeDeleteFilter()' - Delete a filter from the MIME database.
93 */
94
95 void
96 mimeDeleteFilter(mime_t *mime, /* I - MIME database */
97 mime_filter_t *filter) /* I - Filter */
98 {
99 DEBUG_printf(("mimeDeleteFilter(mime=%p, filter=%p(%s/%s->%s/%s, cost=%d, "
100 "maxsize=" CUPS_LLFMT "))", mime, filter,
101 filter ? filter->src->super : "???",
102 filter ? filter->src->type : "???",
103 filter ? filter->dst->super : "???",
104 filter ? filter->dst->super : "???",
105 filter ? filter->cost : -1,
106 filter ? CUPS_LLCAST filter->maxsize : CUPS_LLCAST -1));
107
108 if (!mime || !filter)
109 return;
110
111 #ifdef DEBUG
112 if (!cupsArrayFind(mime->filters, filter))
113 DEBUG_puts("1mimeDeleteFilter: Filter not in MIME database.");
114 #endif /* DEBUG */
115
116 cupsArrayRemove(mime->filters, filter);
117 free(filter);
118
119 /*
120 * Deleting a filter invalidates the source lookup cache used by
121 * mimeFilter()...
122 */
123
124 if (mime->srcs)
125 {
126 DEBUG_puts("1mimeDeleteFilter: Deleting source lookup cache.");
127 cupsArrayDelete(mime->srcs);
128 mime->srcs = NULL;
129 }
130 }
131
132
133 /*
134 * 'mimeDeleteType()' - Delete a type from the MIME database.
135 */
136
137 void
138 mimeDeleteType(mime_t *mime, /* I - MIME database */
139 mime_type_t *mt) /* I - Type */
140 {
141 DEBUG_printf(("mimeDeleteType(mime=%p, mt=%p(%s/%s))", mime, mt,
142 mt ? mt->super : "???", mt ? mt->type : "???"));
143
144 if (!mime || !mt)
145 return;
146
147 #ifdef DEBUG
148 if (!cupsArrayFind(mime->types, mt))
149 DEBUG_puts("1mimeDeleteFilter: Type not in MIME database.");
150 #endif /* DEBUG */
151
152 cupsArrayRemove(mime->types, mt);
153
154 mime_delete_rules(mt->rules);
155 free(mt);
156 }
157
158
159 /*
160 * '_mimeError()' - Show an error message.
161 */
162
163 void
164 _mimeError(mime_t *mime, /* I - MIME database */
165 const char *message, /* I - Printf-style message string */
166 ...) /* I - Additional arguments as needed */
167 {
168 va_list ap; /* Argument pointer */
169 char buffer[8192]; /* Message buffer */
170
171
172 if (mime->error_cb)
173 {
174 va_start(ap, message);
175 vsnprintf(buffer, sizeof(buffer), message, ap);
176 va_end(ap);
177
178 (*mime->error_cb)(mime->error_ctx, buffer);
179 }
180 }
181
182
183 /*
184 * 'mimeFirstFilter()' - Get the first filter in the MIME database.
185 */
186
187 mime_filter_t * /* O - Filter or NULL */
188 mimeFirstFilter(mime_t *mime) /* I - MIME database */
189 {
190 DEBUG_printf(("6mimeFirstFilter(mime=%p)", mime));
191
192 if (!mime)
193 {
194 DEBUG_puts("7mimeFirstFilter: Returning NULL.");
195 return (NULL);
196 }
197 else
198 {
199 mime_filter_t *first = (mime_filter_t *)cupsArrayFirst(mime->filters);
200 /* First filter */
201
202 DEBUG_printf(("7mimeFirstFilter: Returning %p.", first));
203 return (first);
204 }
205 }
206
207
208 /*
209 * 'mimeFirstType()' - Get the first type in the MIME database.
210 */
211
212 mime_type_t * /* O - Type or NULL */
213 mimeFirstType(mime_t *mime) /* I - MIME database */
214 {
215 DEBUG_printf(("6mimeFirstType(mime=%p)", mime));
216
217 if (!mime)
218 {
219 DEBUG_puts("7mimeFirstType: Returning NULL.");
220 return (NULL);
221 }
222 else
223 {
224 mime_type_t *first = (mime_type_t *)cupsArrayFirst(mime->types);
225 /* First type */
226
227 DEBUG_printf(("7mimeFirstType: Returning %p.", first));
228 return (first);
229 }
230 }
231
232
233 /*
234 * 'mimeLoad()' - Create a new MIME database from disk.
235 *
236 * This function uses @link mimeLoadFilters@ and @link mimeLoadTypes@ to
237 * create a MIME database from a single directory.
238 */
239
240 mime_t * /* O - New MIME database */
241 mimeLoad(const char *pathname, /* I - Directory to load */
242 const char *filterpath) /* I - Directory to load */
243 {
244 mime_t *mime; /* New MIME database */
245
246 DEBUG_printf(("mimeLoad(pathname=\"%s\", filterpath=\"%s\")", pathname,
247 filterpath));
248
249 mime = mimeLoadFilters(mimeLoadTypes(NULL, pathname), pathname, filterpath);
250 DEBUG_printf(("1mimeLoad: Returning %p.", mime));
251
252 return (mime);
253 }
254
255
256 /*
257 * 'mimeLoadFilters()' - Load filter definitions from disk.
258 *
259 * This function loads all of the .convs files from the specified directory.
260 * Use @link mimeLoadTypes@ to load all types before you load the filters.
261 */
262
263 mime_t * /* O - MIME database */
264 mimeLoadFilters(mime_t *mime, /* I - MIME database */
265 const char *pathname, /* I - Directory to load from */
266 const char *filterpath) /* I - Default filter program directory */
267 {
268 cups_dir_t *dir; /* Directory */
269 cups_dentry_t *dent; /* Directory entry */
270 char filename[1024]; /* Full filename of .convs file */
271 cups_array_t *filtercache; /* Filter cache */
272
273
274 DEBUG_printf(("mimeLoadFilters(mime=%p, pathname=\"%s\", filterpath=\"%s\")",
275 mime, pathname, filterpath));
276
277 /*
278 * Range check input...
279 */
280
281 if (!mime || !pathname || !filterpath)
282 {
283 DEBUG_puts("1mimeLoadFilters: Bad arguments.");
284 return (mime);
285 }
286
287 /*
288 * Then open the directory specified by pathname...
289 */
290
291 if ((dir = cupsDirOpen(pathname)) == NULL)
292 {
293 DEBUG_printf(("1mimeLoadFilters: Unable to open \"%s\": %s", pathname,
294 strerror(errno)));
295 _mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno));
296 return (mime);
297 }
298
299 /*
300 * Read all the .convs files...
301 */
302
303 filtercache = cupsArrayNew((cups_array_func_t)mime_compare_fcache, NULL);
304
305 while ((dent = cupsDirRead(dir)) != NULL)
306 {
307 if (strlen(dent->filename) > 6 &&
308 !strcmp(dent->filename + strlen(dent->filename) - 6, ".convs"))
309 {
310 /*
311 * Load a mime.convs file...
312 */
313
314 snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
315 DEBUG_printf(("1mimeLoadFilters: Loading \"%s\".", filename));
316 mime_load_convs(mime, filename, filterpath, filtercache);
317 }
318 }
319
320 mime_delete_fcache(filtercache);
321
322 cupsDirClose(dir);
323
324 return (mime);
325 }
326
327
328 /*
329 * 'mimeLoadTypes()' - Load type definitions from disk.
330 *
331 * This function loads all of the .types files from the specified directory.
332 * Use @link mimeLoadFilters@ to load all filters after you load the types.
333 */
334
335 mime_t * /* O - MIME database */
336 mimeLoadTypes(mime_t *mime, /* I - MIME database or @code NULL@ to create a new one */
337 const char *pathname) /* I - Directory to load from */
338 {
339 cups_dir_t *dir; /* Directory */
340 cups_dentry_t *dent; /* Directory entry */
341 char filename[1024]; /* Full filename of .types file */
342
343
344 DEBUG_printf(("mimeLoadTypes(mime=%p, pathname=\"%s\")", mime, pathname));
345
346 /*
347 * First open the directory specified by pathname...
348 */
349
350 if ((dir = cupsDirOpen(pathname)) == NULL)
351 {
352 DEBUG_printf(("1mimeLoadTypes: Unable to open \"%s\": %s", pathname,
353 strerror(errno)));
354 DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime));
355 _mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno));
356 return (mime);
357 }
358
359 /*
360 * If "mime" is NULL, make a new, empty database...
361 */
362
363 if (!mime)
364 mime = mimeNew();
365
366 if (!mime)
367 {
368 cupsDirClose(dir);
369 DEBUG_puts("1mimeLoadTypes: Returning NULL.");
370 return (NULL);
371 }
372
373 /*
374 * Read all the .types files...
375 */
376
377 while ((dent = cupsDirRead(dir)) != NULL)
378 {
379 if (strlen(dent->filename) > 6 &&
380 !strcmp(dent->filename + strlen(dent->filename) - 6, ".types"))
381 {
382 /*
383 * Load a mime.types file...
384 */
385
386 snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
387 DEBUG_printf(("1mimeLoadTypes: Loading \"%s\".", filename));
388 mime_load_types(mime, filename);
389 }
390 }
391
392 cupsDirClose(dir);
393
394 DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime));
395
396 return (mime);
397 }
398
399
400 /*
401 * 'mimeNew()' - Create a new, empty MIME database.
402 */
403
404 mime_t * /* O - MIME database */
405 mimeNew(void)
406 {
407 return ((mime_t *)calloc(1, sizeof(mime_t)));
408 }
409
410
411 /*
412 * 'mimeNextFilter()' - Get the next filter in the MIME database.
413 */
414
415 mime_filter_t * /* O - Filter or NULL */
416 mimeNextFilter(mime_t *mime) /* I - MIME database */
417 {
418 DEBUG_printf(("6mimeNextFilter(mime=%p)", mime));
419
420 if (!mime)
421 {
422 DEBUG_puts("7mimeNextFilter: Returning NULL.");
423 return (NULL);
424 }
425 else
426 {
427 mime_filter_t *next = (mime_filter_t *)cupsArrayNext(mime->filters);
428 /* Next filter */
429
430 DEBUG_printf(("7mimeNextFilter: Returning %p.", next));
431 return (next);
432 }
433 }
434
435
436 /*
437 * 'mimeNextType()' - Get the next type in the MIME database.
438 */
439
440 mime_type_t * /* O - Type or NULL */
441 mimeNextType(mime_t *mime) /* I - MIME database */
442 {
443 DEBUG_printf(("6mimeNextType(mime=%p)", mime));
444
445 if (!mime)
446 {
447 DEBUG_puts("7mimeNextType: Returning NULL.");
448 return (NULL);
449 }
450 else
451 {
452 mime_type_t *next = (mime_type_t *)cupsArrayNext(mime->types);
453 /* Next type */
454
455 DEBUG_printf(("7mimeNextType: Returning %p.", next));
456 return (next);
457 }
458 }
459
460
461 /*
462 * 'mimeNumFilters()' - Get the number of filters in a MIME database.
463 */
464
465 int
466 mimeNumFilters(mime_t *mime) /* I - MIME database */
467 {
468 DEBUG_printf(("mimeNumFilters(mime=%p)", mime));
469
470 if (!mime)
471 {
472 DEBUG_puts("1mimeNumFilters: Returning 0.");
473 return (0);
474 }
475 else
476 {
477 DEBUG_printf(("1mimeNumFilters: Returning %d.",
478 cupsArrayCount(mime->filters)));
479 return (cupsArrayCount(mime->filters));
480 }
481 }
482
483
484 /*
485 * 'mimeNumTypes()' - Get the number of types in a MIME database.
486 */
487
488 int
489 mimeNumTypes(mime_t *mime) /* I - MIME database */
490 {
491 DEBUG_printf(("mimeNumTypes(mime=%p)", mime));
492
493 if (!mime)
494 {
495 DEBUG_puts("1mimeNumTypes: Returning 0.");
496 return (0);
497 }
498 else
499 {
500 DEBUG_printf(("1mimeNumTypes: Returning %d.",
501 cupsArrayCount(mime->types)));
502 return (cupsArrayCount(mime->types));
503 }
504 }
505
506
507 /*
508 * 'mimeSetErrorCallback()' - Set the callback for error messages.
509 */
510
511 void
512 mimeSetErrorCallback(
513 mime_t *mime, /* I - MIME database */
514 mime_error_cb_t cb, /* I - Callback function */
515 void *ctx) /* I - Context pointer for callback */
516 {
517 if (mime)
518 {
519 mime->error_cb = cb;
520 mime->error_ctx = ctx;
521 }
522 }
523
524
525 /*
526 * 'mime_add_fcache()' - Add a filter to the filter cache.
527 */
528
529 static const char * /* O - Full path to filter or NULL */
530 mime_add_fcache(
531 cups_array_t *filtercache, /* I - Filter cache */
532 const char *name, /* I - Filter name */
533 const char *filterpath) /* I - Filter path */
534 {
535 _mime_fcache_t key, /* Search key */
536 *temp; /* New filter cache */
537 char path[1024]; /* Full path to filter */
538
539
540 DEBUG_printf(("2mime_add_fcache(filtercache=%p, name=\"%s\", "
541 "filterpath=\"%s\")", filtercache, name, filterpath));
542
543 key.name = (char *)name;
544 if ((temp = (_mime_fcache_t *)cupsArrayFind(filtercache, &key)) != NULL)
545 {
546 DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path));
547 return (temp->path);
548 }
549
550 if ((temp = calloc(1, sizeof(_mime_fcache_t))) == NULL)
551 {
552 DEBUG_puts("3mime_add_fcache: Returning NULL.");
553 return (NULL);
554 }
555
556 temp->name = strdup(name);
557
558 if (cupsFileFind(name, filterpath, 1, path, sizeof(path)))
559 temp->path = strdup(path);
560
561 cupsArrayAdd(filtercache, temp);
562
563 DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path));
564 return (temp->path);
565 }
566
567
568 /*
569 * 'mime_compare_fcache()' - Compare two filter cache entries.
570 */
571
572 static int /* O - Result of comparison */
573 mime_compare_fcache(_mime_fcache_t *a, /* I - First entry */
574 _mime_fcache_t *b) /* I - Second entry */
575 {
576 return (strcmp(a->name, b->name));
577 }
578
579
580 /*
581 * 'mime_delete_fcache()' - Free all memory used by the filter cache.
582 */
583
584 static void
585 mime_delete_fcache(
586 cups_array_t *filtercache) /* I - Filter cache */
587 {
588 _mime_fcache_t *current; /* Current cache entry */
589
590
591 DEBUG_printf(("2mime_delete_fcache(filtercache=%p)", filtercache));
592
593 for (current = (_mime_fcache_t *)cupsArrayFirst(filtercache);
594 current;
595 current = (_mime_fcache_t *)cupsArrayNext(filtercache))
596 {
597 free(current->name);
598
599 if (current->path)
600 free(current->path);
601
602 free(current);
603 }
604
605 cupsArrayDelete(filtercache);
606 }
607
608
609 /*
610 * 'mime_delete_rules()' - Free all memory for the given rule tree.
611 */
612
613 static void
614 mime_delete_rules(mime_magic_t *rules) /* I - Rules to free */
615 {
616 mime_magic_t *next; /* Next rule to free */
617
618
619 DEBUG_printf(("2mime_delete_rules(rules=%p)", rules));
620
621 /*
622 * Free the rules list, descending recursively to free any child rules.
623 */
624
625 while (rules != NULL)
626 {
627 next = rules->next;
628
629 if (rules->child != NULL)
630 mime_delete_rules(rules->child);
631
632 if (rules->op == MIME_MAGIC_REGEX)
633 regfree(&(rules->value.rev));
634
635 free(rules);
636 rules = next;
637 }
638 }
639
640
641 /*
642 * 'mime_load_convs()' - Load a xyz.convs file.
643 */
644
645 static void
646 mime_load_convs(
647 mime_t *mime, /* I - MIME database */
648 const char *filename, /* I - Convs file to load */
649 const char *filterpath, /* I - Path for filters */
650 cups_array_t *filtercache) /* I - Filter program cache */
651 {
652 cups_file_t *fp; /* Convs file */
653 char line[1024], /* Input line from file */
654 *lineptr, /* Current position in line */
655 super[MIME_MAX_SUPER], /* Super-type name */
656 type[MIME_MAX_TYPE], /* Type name */
657 *temp, /* Temporary pointer */
658 *filter; /* Filter program */
659 mime_type_t *temptype, /* MIME type looping var */
660 *dsttype; /* Destination MIME type */
661 int cost; /* Cost of filter */
662
663
664 DEBUG_printf(("2mime_load_convs(mime=%p, filename=\"%s\", filterpath=\"%s\", "
665 "filtercache=%p)", mime, filename, filterpath, filtercache));
666
667 /*
668 * First try to open the file...
669 */
670
671 if ((fp = cupsFileOpen(filename, "r")) == NULL)
672 {
673 DEBUG_printf(("3mime_load_convs: Unable to open \"%s\": %s", filename,
674 strerror(errno)));
675 _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno));
676 return;
677 }
678
679 /*
680 * Then read each line from the file, skipping any comments in the file...
681 */
682
683 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
684 {
685 /*
686 * Skip blank lines and lines starting with a #...
687 */
688
689 if (!line[0] || line[0] == '#')
690 continue;
691
692 /*
693 * Strip trailing whitespace...
694 */
695
696 for (lineptr = line + strlen(line) - 1;
697 lineptr >= line && isspace(*lineptr & 255);
698 lineptr --)
699 *lineptr = '\0';
700
701 /*
702 * Extract the destination super-type and type names from the middle of
703 * the line.
704 */
705
706 lineptr = line;
707 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
708 lineptr ++;
709
710 while (*lineptr == ' ' || *lineptr == '\t')
711 lineptr ++;
712
713 temp = super;
714
715 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
716 (temp - super + 1) < MIME_MAX_SUPER)
717 *temp++ = (char)tolower(*lineptr++ & 255);
718
719 *temp = '\0';
720
721 if (*lineptr != '/')
722 continue;
723
724 lineptr ++;
725 temp = type;
726
727 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
728 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
729 *temp++ = (char)tolower(*lineptr++ & 255);
730
731 *temp = '\0';
732
733 if (*lineptr == '\0' || *lineptr == '\n')
734 continue;
735
736 if ((dsttype = mimeType(mime, super, type)) == NULL)
737 {
738 DEBUG_printf(("3mime_load_convs: Destination type %s/%s not found.",
739 super, type));
740 continue;
741 }
742
743 /*
744 * Then get the cost and filter program...
745 */
746
747 while (*lineptr == ' ' || *lineptr == '\t')
748 lineptr ++;
749
750 if (*lineptr < '0' || *lineptr > '9')
751 continue;
752
753 cost = atoi(lineptr);
754
755 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
756 lineptr ++;
757 while (*lineptr == ' ' || *lineptr == '\t')
758 lineptr ++;
759
760 if (*lineptr == '\0' || *lineptr == '\n')
761 continue;
762
763 filter = lineptr;
764
765 if (strcmp(filter, "-"))
766 {
767 /*
768 * Verify that the filter exists and is executable...
769 */
770
771 if (!mime_add_fcache(filtercache, filter, filterpath))
772 {
773 DEBUG_printf(("mime_load_convs: Filter %s not found in %s.", filter,
774 filterpath));
775 _mimeError(mime, "Filter \"%s\" not found.", filter);
776 continue;
777 }
778 }
779
780 /*
781 * Finally, get the source super-type and type names from the beginning of
782 * the line. We do it here so we can support wildcards...
783 */
784
785 lineptr = line;
786 temp = super;
787
788 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
789 (temp - super + 1) < MIME_MAX_SUPER)
790 *temp++ = (char)tolower(*lineptr++ & 255);
791
792 *temp = '\0';
793
794 if (*lineptr != '/')
795 continue;
796
797 lineptr ++;
798 temp = type;
799
800 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
801 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
802 *temp++ = (char)tolower(*lineptr++ & 255);
803
804 *temp = '\0';
805
806 if (!strcmp(super, "*") && !strcmp(type, "*"))
807 {
808 /*
809 * Force * / * to be "application/octet-stream"...
810 */
811
812 strlcpy(super, "application", sizeof(super));
813 strlcpy(type, "octet-stream", sizeof(type));
814 }
815
816 /*
817 * Add the filter to the MIME database, supporting wildcards as needed...
818 */
819
820 for (temptype = (mime_type_t *)cupsArrayFirst(mime->types);
821 temptype;
822 temptype = (mime_type_t *)cupsArrayNext(mime->types))
823 if ((super[0] == '*' || !strcmp(temptype->super, super)) &&
824 (type[0] == '*' || !strcmp(temptype->type, type)))
825 mimeAddFilter(mime, temptype, dsttype, cost, filter);
826 }
827
828 cupsFileClose(fp);
829 }
830
831
832 /*
833 * 'mime_load_types()' - Load a xyz.types file.
834 */
835
836 static void
837 mime_load_types(mime_t *mime, /* I - MIME database */
838 const char *filename) /* I - Types file to load */
839 {
840 cups_file_t *fp; /* Types file */
841 size_t linelen; /* Length of line */
842 char line[32768], /* Input line from file */
843 *lineptr, /* Current position in line */
844 super[MIME_MAX_SUPER], /* Super-type name */
845 type[MIME_MAX_TYPE], /* Type name */
846 *temp; /* Temporary pointer */
847 mime_type_t *typeptr; /* New MIME type */
848
849
850 DEBUG_printf(("2mime_load_types(mime=%p, filename=\"%s\")", mime, filename));
851
852 /*
853 * First try to open the file...
854 */
855
856 if ((fp = cupsFileOpen(filename, "r")) == NULL)
857 {
858 DEBUG_printf(("3mime_load_types: Unable to open \"%s\": %s", filename,
859 strerror(errno)));
860 _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno));
861 return;
862 }
863
864 /*
865 * Then read each line from the file, skipping any comments in the file...
866 */
867
868 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
869 {
870 /*
871 * Skip blank lines and lines starting with a #...
872 */
873
874 if (!line[0] || line[0] == '#')
875 continue;
876
877 /*
878 * While the last character in the line is a backslash, continue on to the
879 * next line (and the next, etc.)
880 */
881
882 linelen = strlen(line);
883
884 while (line[linelen - 1] == '\\')
885 {
886 linelen --;
887
888 if (cupsFileGets(fp, line + linelen, sizeof(line) - linelen) == NULL)
889 line[linelen] = '\0';
890 else
891 linelen += strlen(line + linelen);
892 }
893
894 /*
895 * Extract the super-type and type names from the beginning of the line.
896 */
897
898 lineptr = line;
899 temp = super;
900
901 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
902 (temp - super + 1) < MIME_MAX_SUPER)
903 *temp++ = (char)tolower(*lineptr++ & 255);
904
905 *temp = '\0';
906
907 if (*lineptr != '/')
908 continue;
909
910 lineptr ++;
911 temp = type;
912
913 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
914 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
915 *temp++ = (char)tolower(*lineptr++ & 255);
916
917 *temp = '\0';
918
919 /*
920 * Add the type and rules to the MIME database...
921 */
922
923 typeptr = mimeAddType(mime, super, type);
924 mimeAddTypeRule(typeptr, lineptr);
925 }
926
927 cupsFileClose(fp);
928 }