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