]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/mime.c
Merge changes from CUPS 1.5svn-r9049 (private header support)
[thirdparty/cups.git] / scheduler / mime.c
1 /*
2 * "$Id: mime.c 7694 2008-06-26 00:23:20Z mike $"
3 *
4 * MIME database file routines for CUPS.
5 *
6 * Copyright 2007-2010 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 * mimeFirstFilter() - Get the first filter in the MIME database.
21 * mimeFirstType() - Get the first type in the MIME database.
22 * mimeLoad() - Create a new MIME database from disk.
23 * mimeMerge() - Merge a MIME database from disk with the current one.
24 * mimeNew() - Create a new, empty MIME database.
25 * mimeNextFilter() - Get the next filter in the MIME database.
26 * mimeNextType() - Get the next type in the MIME database.
27 * mimeNumFilters() - Get the number of filters in a MIME database.
28 * mimeNumTypes() - Get the number of types in a MIME database.
29 * add_fcache() - Add a filter to the filter cache.
30 * compare_fcache() - Compare two filter cache entries.
31 * delete_fcache() - Free all memory used by the filter cache.
32 * delete_rules() - Free all memory for the given rule tree.
33 * load_convs() - Load a xyz.convs file...
34 * load_types() - Load a xyz.types file...
35 */
36
37 /*
38 * Include necessary headers...
39 */
40
41 #include <cups/string-private.h>
42 #include <cups/debug-private.h>
43 #include <cups/dir.h>
44 #include "mime.h"
45
46
47 /*
48 * Local types...
49 */
50
51 typedef struct _mime_fcache_s /**** Filter cache structure ****/
52 {
53 char *name, /* Filter name */
54 *path; /* Full path to filter if available */
55 } _mime_fcache_t;
56
57
58 /*
59 * Local functions...
60 */
61
62 static const char *add_fcache(cups_array_t *filtercache, const char *name,
63 const char *filterpath);
64 static int compare_fcache(_mime_fcache_t *a, _mime_fcache_t *b);
65 static void delete_fcache(cups_array_t *filtercache);
66 static void delete_rules(mime_magic_t *rules);
67 static void load_convs(mime_t *mime, const char *filename,
68 const char *filterpath,
69 cups_array_t *filtercache);
70 static void load_types(mime_t *mime, const char *filename);
71 static mime_t *mime_new(void);
72
73
74 /*
75 * 'mimeDelete()' - Delete (free) a MIME database.
76 */
77
78 void
79 mimeDelete(mime_t *mime) /* I - MIME database */
80 {
81 mime_type_t *type; /* Current type */
82 mime_filter_t *filter; /* Current filter */
83
84
85 if (!mime)
86 return;
87
88 /*
89 * Loop through filters and free them...
90 */
91
92 for (filter = (mime_filter_t *)cupsArrayFirst(mime->filters);
93 filter;
94 filter = (mime_filter_t *)cupsArrayNext(mime->filters))
95 mimeDeleteFilter(mime, filter);
96
97 /*
98 * Loop through the file types and delete any rules...
99 */
100
101 for (type = (mime_type_t *)cupsArrayFirst(mime->types);
102 type;
103 type = (mime_type_t *)cupsArrayNext(mime->types))
104 mimeDeleteType(mime, type);
105
106 /*
107 * Free the types and filters arrays, and then the MIME database structure.
108 */
109
110 cupsArrayDelete(mime->types);
111 cupsArrayDelete(mime->filters);
112 cupsArrayDelete(mime->srcs);
113 free(mime);
114 }
115
116
117 /*
118 * 'mimeDeleteFilter()' - Delete a filter from the MIME database.
119 */
120
121 void
122 mimeDeleteFilter(mime_t *mime, /* I - MIME database */
123 mime_filter_t *filter) /* I - Filter */
124 {
125 if (!mime || !filter)
126 return;
127
128 cupsArrayRemove(mime->filters, filter);
129 free(filter);
130
131 /*
132 * Deleting a filter invalidates the source lookup cache used by
133 * mimeFilter()...
134 */
135
136 if (mime->srcs)
137 {
138 cupsArrayDelete(mime->srcs);
139 mime->srcs = NULL;
140 }
141 }
142
143
144 /*
145 * 'mimeDeleteType()' - Delete a type from the MIME database.
146 */
147
148 void
149 mimeDeleteType(mime_t *mime, /* I - MIME database */
150 mime_type_t *mt) /* I - Type */
151 {
152 if (!mime || !mt)
153 return;
154
155 cupsArrayRemove(mime->types, mt);
156
157 delete_rules(mt->rules);
158 free(mt);
159 }
160
161
162 /*
163 * 'mimeFirstFilter()' - Get the first filter in the MIME database.
164 */
165
166 mime_filter_t * /* O - Filter or NULL */
167 mimeFirstFilter(mime_t *mime) /* I - MIME database */
168 {
169 if (!mime)
170 return (NULL);
171 else
172 return ((mime_filter_t *)cupsArrayFirst(mime->filters));
173 }
174
175
176 /*
177 * 'mimeFirstType()' - Get the first type in the MIME database.
178 */
179
180 mime_type_t * /* O - Type or NULL */
181 mimeFirstType(mime_t *mime) /* I - MIME database */
182 {
183 if (!mime)
184 return (NULL);
185 else
186 return ((mime_type_t *)cupsArrayFirst(mime->types));
187 }
188
189
190 /*
191 * 'mimeLoad()' - Create a new MIME database from disk.
192 *
193 * This function uses @link mimeLoadFilters@ and @link mimeLoadTypes@ to
194 * create a MIME database from a single directory.
195 */
196
197 mime_t * /* O - New MIME database */
198 mimeLoad(const char *pathname, /* I - Directory to load */
199 const char *filterpath) /* I - Directory to load */
200 {
201 return (mimeLoadFilters(mimeLoadTypes(NULL, pathname), pathname, filterpath));
202 }
203
204
205 /*
206 * 'mimeLoadFilters()' - Load filter definitions from disk.
207 *
208 * This function loads all of the .convs files from the specified directory.
209 * Use @link mimeLoadTypes@ to load all types before you load the filters.
210 */
211
212 mime_t * /* O - MIME database */
213 mimeLoadFilters(mime_t *mime, /* I - MIME database */
214 const char *pathname, /* I - Directory to load from */
215 const char *filterpath) /* I - Default filter program directory */
216 {
217 cups_dir_t *dir; /* Directory */
218 cups_dentry_t *dent; /* Directory entry */
219 char filename[1024]; /* Full filename of .convs file */
220 cups_array_t *filtercache; /* Filter cache */
221
222
223 /*
224 * Range check input...
225 */
226
227 if (!mime || !pathname || !filterpath)
228 return (mime);
229
230 /*
231 * Then open the directory specified by pathname...
232 */
233
234 if ((dir = cupsDirOpen(pathname)) == NULL)
235 return (mime);
236
237 /*
238 * Read all the .convs files...
239 */
240
241 filtercache = cupsArrayNew((cups_array_func_t)compare_fcache, NULL);
242
243 while ((dent = cupsDirRead(dir)) != NULL)
244 {
245 if (strlen(dent->filename) > 6 &&
246 !strcmp(dent->filename + strlen(dent->filename) - 6, ".convs"))
247 {
248 /*
249 * Load a mime.convs file...
250 */
251
252 snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
253 load_convs(mime, filename, filterpath, filtercache);
254 }
255 }
256
257 delete_fcache(filtercache);
258
259 cupsDirClose(dir);
260
261 return (mime);
262 }
263
264
265 /*
266 * 'mimeLoadTypes()' - Load type definitions from disk.
267 *
268 * This function loads all of the .types files from the specified directory.
269 * Use @link mimeLoadFilters@ to load all filters after you load the types.
270 */
271
272 mime_t * /* O - MIME database */
273 mimeLoadTypes(mime_t *mime, /* I - MIME database or @code NULL@ to create a new one */
274 const char *pathname) /* I - Directory to load from */
275 {
276 cups_dir_t *dir; /* Directory */
277 cups_dentry_t *dent; /* Directory entry */
278 char filename[1024]; /* Full filename of .types file */
279
280
281 /*
282 * First open the directory specified by pathname...
283 */
284
285 if ((dir = cupsDirOpen(pathname)) == NULL)
286 return (mime);
287
288 /*
289 * If "mime" is NULL, make a new, empty database...
290 */
291
292 if (!mime)
293 mime = mime_new();
294
295 if (!mime)
296 {
297 cupsDirClose(dir);
298 return (NULL);
299 }
300
301 /*
302 * Read all the .types files...
303 */
304
305 while ((dent = cupsDirRead(dir)) != NULL)
306 {
307 if (strlen(dent->filename) > 6 &&
308 !strcmp(dent->filename + strlen(dent->filename) - 6, ".types"))
309 {
310 /*
311 * Load a mime.types file...
312 */
313
314 snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
315 load_types(mime, filename);
316 }
317 }
318
319 cupsDirClose(dir);
320
321 return (mime);
322 }
323
324
325 /*
326 * 'mimeNextFilter()' - Get the next filter in the MIME database.
327 */
328
329 mime_filter_t * /* O - Filter or NULL */
330 mimeNextFilter(mime_t *mime) /* I - MIME database */
331 {
332 if (!mime)
333 return (NULL);
334 else
335 return ((mime_filter_t *)cupsArrayNext(mime->filters));
336 }
337
338
339 /*
340 * 'mimeNextType()' - Get the next type in the MIME database.
341 */
342
343 mime_type_t * /* O - Type or NULL */
344 mimeNextType(mime_t *mime) /* I - MIME database */
345 {
346 if (!mime)
347 return (NULL);
348 else
349 return ((mime_type_t *)cupsArrayNext(mime->types));
350 }
351
352
353 /*
354 * 'mimeNumFilters()' - Get the number of filters in a MIME database.
355 */
356
357 int
358 mimeNumFilters(mime_t *mime) /* I - MIME database */
359 {
360 if (!mime)
361 return (0);
362 else
363 return (cupsArrayCount(mime->filters));
364 }
365
366
367 /*
368 * 'mimeNumTypes()' - Get the number of types in a MIME database.
369 */
370
371 int
372 mimeNumTypes(mime_t *mime) /* I - MIME database */
373 {
374 if (!mime)
375 return (0);
376 else
377 return (cupsArrayCount(mime->types));
378 }
379
380
381 /*
382 * 'add_fcache()' - Add a filter to the filter cache.
383 */
384
385 static const char * /* O - Full path to filter or NULL */
386 add_fcache(cups_array_t *filtercache, /* I - Filter cache */
387 const char *name, /* I - Filter name */
388 const char *filterpath) /* I - Filter path */
389 {
390 _mime_fcache_t key, /* Search key */
391 *temp; /* New filter cache */
392 char path[1024]; /* Full path to filter */
393
394
395 key.name = (char *)name;
396 if ((temp = (_mime_fcache_t *)cupsArrayFind(filtercache, &key)) != NULL)
397 return (temp->path);
398
399 if ((temp = calloc(1, sizeof(_mime_fcache_t))) == NULL)
400 return (NULL);
401
402 temp->name = strdup(name);
403
404 if (cupsFileFind(name, filterpath, 1, path, sizeof(path)))
405 temp->path = strdup(path);
406
407 cupsArrayAdd(filtercache, temp);
408
409 return (temp->path);
410 }
411
412
413 /*
414 * 'compare_fcache()' - Compare two filter cache entries.
415 */
416
417 static int /* O - Result of comparison */
418 compare_fcache(_mime_fcache_t *a, /* I - First entry */
419 _mime_fcache_t *b) /* I - Second entry */
420 {
421 return (strcmp(a->name, b->name));
422 }
423
424
425 /*
426 * 'delete_fcache()' - Free all memory used by the filter cache.
427 */
428
429 static void
430 delete_fcache(cups_array_t *filtercache)/* I - Filter cache */
431 {
432 _mime_fcache_t *current; /* Current cache entry */
433
434
435 for (current = (_mime_fcache_t *)cupsArrayFirst(filtercache);
436 current;
437 current = (_mime_fcache_t *)cupsArrayNext(filtercache))
438 {
439 free(current->name);
440
441 if (current->path)
442 free(current->path);
443
444 free(current);
445 }
446
447 cupsArrayDelete(filtercache);
448 }
449
450
451 /*
452 * 'delete_rules()' - Free all memory for the given rule tree.
453 */
454
455 static void
456 delete_rules(mime_magic_t *rules) /* I - Rules to free */
457 {
458 mime_magic_t *next; /* Next rule to free */
459
460
461 /*
462 * Free the rules list, descending recursively to free any child rules.
463 */
464
465 while (rules != NULL)
466 {
467 next = rules->next;
468
469 if (rules->child != NULL)
470 delete_rules(rules->child);
471
472 free(rules);
473 rules = next;
474 }
475 }
476
477
478 /*
479 * 'load_convs()' - Load a xyz.convs file...
480 */
481
482 static void
483 load_convs(mime_t *mime, /* I - MIME database */
484 const char *filename, /* I - Convs file to load */
485 const char *filterpath, /* I - Path for filters */
486 cups_array_t *filtercache) /* I - Filter program cache */
487 {
488 cups_file_t *fp; /* Convs file */
489 char line[1024], /* Input line from file */
490 *lineptr, /* Current position in line */
491 super[MIME_MAX_SUPER], /* Super-type name */
492 type[MIME_MAX_TYPE], /* Type name */
493 *temp, /* Temporary pointer */
494 *filter; /* Filter program */
495 mime_type_t *temptype, /* MIME type looping var */
496 *dsttype; /* Destination MIME type */
497 int cost; /* Cost of filter */
498
499
500 DEBUG_printf(("load_convs(mime=%p, filename=\"%s\", filterpath=\"%s\", "
501 "filtercache=%p)\n", mime, filename, filterpath, filtercache));
502
503
504 /*
505 * First try to open the file...
506 */
507
508 if ((fp = cupsFileOpen(filename, "r")) == NULL)
509 return;
510
511 /*
512 * Then read each line from the file, skipping any comments in the file...
513 */
514
515 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
516 {
517 /*
518 * Skip blank lines and lines starting with a #...
519 */
520
521 if (!line[0] || line[0] == '#')
522 continue;
523
524 /*
525 * Strip trailing whitespace...
526 */
527
528 for (lineptr = line + strlen(line) - 1;
529 lineptr >= line && isspace(*lineptr & 255);
530 lineptr --)
531 *lineptr = '\0';
532
533 /*
534 * Extract the destination super-type and type names from the middle of
535 * the line.
536 */
537
538 lineptr = line;
539 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
540 lineptr ++;
541
542 while (*lineptr == ' ' || *lineptr == '\t')
543 lineptr ++;
544
545 temp = super;
546
547 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
548 (temp - super + 1) < MIME_MAX_SUPER)
549 *temp++ = tolower(*lineptr++ & 255);
550
551 *temp = '\0';
552
553 if (*lineptr != '/')
554 continue;
555
556 lineptr ++;
557 temp = type;
558
559 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
560 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
561 *temp++ = tolower(*lineptr++ & 255);
562
563 *temp = '\0';
564
565 if (*lineptr == '\0' || *lineptr == '\n')
566 continue;
567
568 if ((dsttype = mimeType(mime, super, type)) == NULL)
569 {
570 DEBUG_printf(("load_convs: Destination type %s/%s not found!\n",
571 super, type));
572 continue;
573 }
574
575 /*
576 * Then get the cost and filter program...
577 */
578
579 while (*lineptr == ' ' || *lineptr == '\t')
580 lineptr ++;
581
582 if (*lineptr < '0' || *lineptr > '9')
583 continue;
584
585 cost = atoi(lineptr);
586
587 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
588 lineptr ++;
589 while (*lineptr == ' ' || *lineptr == '\t')
590 lineptr ++;
591
592 if (*lineptr == '\0' || *lineptr == '\n')
593 continue;
594
595 filter = lineptr;
596
597 if (strcmp(filter, "-"))
598 {
599 /*
600 * Verify that the filter exists and is executable...
601 */
602
603 if (!add_fcache(filtercache, filter, filterpath))
604 {
605 DEBUG_printf(("load_convs: Filter %s not found in %s!\n", filter,
606 filterpath));
607 continue;
608 }
609 }
610
611 /*
612 * Finally, get the source super-type and type names from the beginning of
613 * the line. We do it here so we can support wildcards...
614 */
615
616 lineptr = line;
617 temp = super;
618
619 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
620 (temp - super + 1) < MIME_MAX_SUPER)
621 *temp++ = tolower(*lineptr++ & 255);
622
623 *temp = '\0';
624
625 if (*lineptr != '/')
626 continue;
627
628 lineptr ++;
629 temp = type;
630
631 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
632 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
633 *temp++ = tolower(*lineptr++ & 255);
634
635 *temp = '\0';
636
637 if (!strcmp(super, "*") && !strcmp(type, "*"))
638 {
639 /*
640 * Force * / * to be "application/octet-stream"...
641 */
642
643 strcpy(super, "application");
644 strcpy(type, "octet-stream");
645 }
646
647 /*
648 * Add the filter to the MIME database, supporting wildcards as needed...
649 */
650
651 for (temptype = (mime_type_t *)cupsArrayFirst(mime->types);
652 temptype;
653 temptype = (mime_type_t *)cupsArrayNext(mime->types))
654 if ((super[0] == '*' || !strcmp(temptype->super, super)) &&
655 (type[0] == '*' || !strcmp(temptype->type, type)))
656 mimeAddFilter(mime, temptype, dsttype, cost, filter);
657 }
658
659 cupsFileClose(fp);
660 }
661
662
663 /*
664 * 'load_types()' - Load a xyz.types file...
665 */
666
667 static void
668 load_types(mime_t *mime, /* I - MIME database */
669 const char *filename) /* I - Types file to load */
670 {
671 cups_file_t *fp; /* Types file */
672 int linelen; /* Length of line */
673 char line[32768], /* Input line from file */
674 *lineptr, /* Current position in line */
675 super[MIME_MAX_SUPER], /* Super-type name */
676 type[MIME_MAX_TYPE], /* Type name */
677 *temp; /* Temporary pointer */
678 mime_type_t *typeptr; /* New MIME type */
679
680
681 DEBUG_printf(("load_types(mime=%p, filename=\"%s\")\n", mime, filename));
682
683 /*
684 * First try to open the file...
685 */
686
687 if ((fp = cupsFileOpen(filename, "r")) == NULL)
688 return;
689
690 /*
691 * Then read each line from the file, skipping any comments in the file...
692 */
693
694 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
695 {
696 /*
697 * Skip blank lines and lines starting with a #...
698 */
699
700 if (!line[0] || line[0] == '#')
701 continue;
702
703 /*
704 * While the last character in the line is a backslash, continue on to the
705 * next line (and the next, etc.)
706 */
707
708 linelen = strlen(line);
709
710 while (line[linelen - 1] == '\\')
711 {
712 linelen --;
713
714 if (cupsFileGets(fp, line + linelen, sizeof(line) - linelen) == NULL)
715 line[linelen] = '\0';
716 else
717 linelen += strlen(line + linelen);
718 }
719
720 /*
721 * Extract the super-type and type names from the beginning of the line.
722 */
723
724 lineptr = line;
725 temp = super;
726
727 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
728 (temp - super + 1) < MIME_MAX_SUPER)
729 *temp++ = tolower(*lineptr++ & 255);
730
731 *temp = '\0';
732
733 if (*lineptr != '/')
734 continue;
735
736 lineptr ++;
737 temp = type;
738
739 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
740 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
741 *temp++ = tolower(*lineptr++ & 255);
742
743 *temp = '\0';
744
745 /*
746 * Add the type and rules to the MIME database...
747 */
748
749 typeptr = mimeAddType(mime, super, type);
750 mimeAddTypeRule(typeptr, lineptr);
751 }
752
753 cupsFileClose(fp);
754 }
755
756
757 /*
758 * 'mime_new()' - Create a new, empty MIME database.
759 */
760
761 static mime_t * /* O - MIME database */
762 mime_new(void)
763 {
764 return ((mime_t *)calloc(1, sizeof(mime_t)));
765 }
766
767
768 /*
769 * End of "$Id: mime.c 7694 2008-06-26 00:23:20Z mike $".
770 */