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