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