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