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