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