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