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