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