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