1/* 2 * "$Id: mime.c 11560 2014-02-06 20:10:19Z msweet $" 3 * 4 * MIME database file routines for CUPS. 5 * 6 * Copyright 2007-2014 by Apple Inc. 7 * Copyright 1997-2006 by Easy Software Products, all rights reserved. 8 * 9 * These coded instructions, statements, and computer programs are the 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/". 14 */ 15 16/* 17 * Include necessary headers... 18 */ 19 20#include <cups/string-private.h> 21#include <cups/debug-private.h> 22#include <cups/dir.h> 23#include "mime-private.h" 24 25 26/* 27 * Local types... 28 */ 29 30typedef struct _mime_fcache_s /**** Filter cache structure ****/ 31{ 32 char *name, /* Filter name */ 33 *path; /* Full path to filter if available */ 34} _mime_fcache_t; 35 36 37/* 38 * Local functions... 39 */ 40 41static const char *mime_add_fcache(cups_array_t *filtercache, const char *name, 42 const char *filterpath); 43static int mime_compare_fcache(_mime_fcache_t *a, _mime_fcache_t *b); 44static void mime_delete_fcache(cups_array_t *filtercache); 45static void mime_delete_rules(mime_magic_t *rules); 46static void mime_load_convs(mime_t *mime, const char *filename, 47 const char *filterpath, 48 cups_array_t *filtercache); 49static void mime_load_types(mime_t *mime, const char *filename); 50 51 52/* 53 * 'mimeDelete()' - Delete (free) a MIME database. 54 */ 55 56void 57mimeDelete(mime_t *mime) /* I - MIME database */ 58{ 59 mime_type_t *type; /* Current type */ 60 mime_filter_t *filter; /* Current filter */ 61 62 63 DEBUG_printf(("mimeDelete(mime=%p)", mime)); 64 65 if (!mime) 66 return; 67 68 /* 69 * Loop through filters and free them... 70 */ 71 72 for (filter = (mime_filter_t *)cupsArrayFirst(mime->filters); 73 filter; 74 filter = (mime_filter_t *)cupsArrayNext(mime->filters)) 75 mimeDeleteFilter(mime, filter); 76 77 /* 78 * Loop through the file types and delete any rules... 79 */ 80 81 for (type = (mime_type_t *)cupsArrayFirst(mime->types); 82 type; 83 type = (mime_type_t *)cupsArrayNext(mime->types)) 84 mimeDeleteType(mime, type); 85 86 /* 87 * Free the types and filters arrays, and then the MIME database structure. 88 */ 89 90 cupsArrayDelete(mime->types); 91 cupsArrayDelete(mime->filters); 92 cupsArrayDelete(mime->srcs); 93 free(mime); 94} 95 96 97/* 98 * 'mimeDeleteFilter()' - Delete a filter from the MIME database. 99 */ 100 101void 102mimeDeleteFilter(mime_t *mime, /* I - MIME database */ 103 mime_filter_t *filter) /* I - Filter */ 104{ 105 DEBUG_printf(("mimeDeleteFilter(mime=%p, filter=%p(%s/%s->%s/%s, cost=%d, " 106 "maxsize=" CUPS_LLFMT "))", mime, filter, 107 filter ? filter->src->super : "???", 108 filter ? filter->src->type : "???", 109 filter ? filter->dst->super : "???", 110 filter ? filter->dst->super : "???", 111 filter ? filter->cost : -1, 112 filter ? CUPS_LLCAST filter->maxsize : CUPS_LLCAST -1)); 113 114 if (!mime || !filter) 115 return; 116 117#ifdef DEBUG 118 if (!cupsArrayFind(mime->filters, filter)) 119 DEBUG_puts("1mimeDeleteFilter: Filter not in MIME database."); 120#endif /* DEBUG */ 121 122 cupsArrayRemove(mime->filters, filter); 123 free(filter); 124 125 /* 126 * Deleting a filter invalidates the source lookup cache used by 127 * mimeFilter()... 128 */ 129 130 if (mime->srcs) 131 { 132 DEBUG_puts("1mimeDeleteFilter: Deleting source lookup cache."); 133 cupsArrayDelete(mime->srcs); 134 mime->srcs = NULL; 135 } 136} 137 138 139/* 140 * 'mimeDeleteType()' - Delete a type from the MIME database. 141 */ 142 143void 144mimeDeleteType(mime_t *mime, /* I - MIME database */ 145 mime_type_t *mt) /* I - Type */ 146{ 147 DEBUG_printf(("mimeDeleteType(mime=%p, mt=%p(%s/%s))", mime, mt, 148 mt ? mt->super : "???", mt ? mt->type : "???")); 149 150 if (!mime || !mt) 151 return; 152 153#ifdef DEBUG 154 if (!cupsArrayFind(mime->types, mt)) 155 DEBUG_puts("1mimeDeleteFilter: Type not in MIME database."); 156#endif /* DEBUG */ 157 158 cupsArrayRemove(mime->types, mt); 159 160 mime_delete_rules(mt->rules); 161 free(mt); 162} 163 164 165/* 166 * '_mimeError()' - Show an error message. 167 */ 168 169void 170_mimeError(mime_t *mime, /* I - MIME database */ 171 const char *message, /* I - Printf-style message string */ 172 ...) /* I - Additional arguments as needed */ 173{ 174 va_list ap; /* Argument pointer */ 175 char buffer[8192]; /* Message buffer */ 176 177 178 if (mime->error_cb) 179 { 180 va_start(ap, message); 181 vsnprintf(buffer, sizeof(buffer), message, ap); 182 va_end(ap); 183 184 (*mime->error_cb)(mime->error_ctx, buffer); 185 } 186} 187 188 189/* 190 * 'mimeFirstFilter()' - Get the first filter in the MIME database. 191 */ 192 193mime_filter_t * /* O - Filter or NULL */ 194mimeFirstFilter(mime_t *mime) /* I - MIME database */ 195{ 196 DEBUG_printf(("6mimeFirstFilter(mime=%p)", mime)); 197 198 if (!mime) 199 { 200 DEBUG_puts("7mimeFirstFilter: Returning NULL."); 201 return (NULL); 202 } 203 else 204 { 205 mime_filter_t *first = (mime_filter_t *)cupsArrayFirst(mime->filters); 206 /* First filter */ 207 208 DEBUG_printf(("7mimeFirstFilter: Returning %p.", first)); 209 return (first); 210 } 211} 212 213 214/* 215 * 'mimeFirstType()' - Get the first type in the MIME database. 216 */ 217 218mime_type_t * /* O - Type or NULL */ 219mimeFirstType(mime_t *mime) /* I - MIME database */ 220{ 221 DEBUG_printf(("6mimeFirstType(mime=%p)", mime)); 222 223 if (!mime) 224 { 225 DEBUG_puts("7mimeFirstType: Returning NULL."); 226 return (NULL); 227 } 228 else 229 { 230 mime_type_t *first = (mime_type_t *)cupsArrayFirst(mime->types); 231 /* First type */ 232 233 DEBUG_printf(("7mimeFirstType: Returning %p.", first)); 234 return (first); 235 } 236} 237 238 239/* 240 * 'mimeLoad()' - Create a new MIME database from disk. 241 * 242 * This function uses @link mimeLoadFilters@ and @link mimeLoadTypes@ to 243 * create a MIME database from a single directory. 244 */ 245 246mime_t * /* O - New MIME database */ 247mimeLoad(const char *pathname, /* I - Directory to load */ 248 const char *filterpath) /* I - Directory to load */ 249{ 250 mime_t *mime; /* New MIME database */ 251 252 DEBUG_printf(("mimeLoad(pathname=\"%s\", filterpath=\"%s\")", pathname, 253 filterpath)); 254 255 mime = mimeLoadFilters(mimeLoadTypes(NULL, pathname), pathname, filterpath); 256 DEBUG_printf(("1mimeLoad: Returning %p.", mime)); 257 258 return (mime); 259} 260 261 262/* 263 * 'mimeLoadFilters()' - Load filter definitions from disk. 264 * 265 * This function loads all of the .convs files from the specified directory. 266 * Use @link mimeLoadTypes@ to load all types before you load the filters. 267 */ 268 269mime_t * /* O - MIME database */ 270mimeLoadFilters(mime_t *mime, /* I - MIME database */ 271 const char *pathname, /* I - Directory to load from */ 272 const char *filterpath) /* I - Default filter program directory */ 273{ 274 cups_dir_t *dir; /* Directory */ 275 cups_dentry_t *dent; /* Directory entry */ 276 char filename[1024]; /* Full filename of .convs file */ 277 cups_array_t *filtercache; /* Filter cache */ 278 279 280 DEBUG_printf(("mimeLoadFilters(mime=%p, pathname=\"%s\", filterpath=\"%s\")", 281 mime, pathname, filterpath)); 282 283 /* 284 * Range check input... 285 */ 286 287 if (!mime || !pathname || !filterpath) 288 { 289 DEBUG_puts("1mimeLoadFilters: Bad arguments."); 290 return (mime); 291 } 292 293 /* 294 * Then open the directory specified by pathname... 295 */ 296 297 if ((dir = cupsDirOpen(pathname)) == NULL) 298 { 299 DEBUG_printf(("1mimeLoadFilters: Unable to open \"%s\": %s", pathname, 300 strerror(errno))); 301 _mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno)); 302 return (mime); 303 } 304 305 /* 306 * Read all the .convs files... 307 */ 308 309 filtercache = cupsArrayNew((cups_array_func_t)mime_compare_fcache, NULL); 310 311 while ((dent = cupsDirRead(dir)) != NULL) 312 { 313 if (strlen(dent->filename) > 6 && 314 !strcmp(dent->filename + strlen(dent->filename) - 6, ".convs")) 315 { 316 /* 317 * Load a mime.convs file... 318 */ 319 320 snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename); 321 DEBUG_printf(("1mimeLoadFilters: Loading \"%s\".", filename)); 322 mime_load_convs(mime, filename, filterpath, filtercache); 323 } 324 } 325 326 mime_delete_fcache(filtercache); 327 328 cupsDirClose(dir); 329 330 return (mime); 331} 332 333 334/* 335 * 'mimeLoadTypes()' - Load type definitions from disk. 336 * 337 * This function loads all of the .types files from the specified directory. 338 * Use @link mimeLoadFilters@ to load all filters after you load the types. 339 */ 340 341mime_t * /* O - MIME database */ 342mimeLoadTypes(mime_t *mime, /* I - MIME database or @code NULL@ to create a new one */ 343 const char *pathname) /* I - Directory to load from */ 344{ 345 cups_dir_t *dir; /* Directory */ 346 cups_dentry_t *dent; /* Directory entry */ 347 char filename[1024]; /* Full filename of .types file */ 348 349 350 DEBUG_printf(("mimeLoadTypes(mime=%p, pathname=\"%s\")", mime, pathname)); 351 352 /* 353 * First open the directory specified by pathname... 354 */ 355 356 if ((dir = cupsDirOpen(pathname)) == NULL) 357 { 358 DEBUG_printf(("1mimeLoadTypes: Unable to open \"%s\": %s", pathname, 359 strerror(errno))); 360 DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime)); 361 _mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno)); 362 return (mime); 363 } 364 365 /* 366 * If "mime" is NULL, make a new, empty database... 367 */ 368 369 if (!mime) 370 mime = mimeNew(); 371 372 if (!mime) 373 { 374 cupsDirClose(dir); 375 DEBUG_puts("1mimeLoadTypes: Returning NULL."); 376 return (NULL); 377 } 378 379 /* 380 * Read all the .types files... 381 */ 382 383 while ((dent = cupsDirRead(dir)) != NULL) 384 { 385 if (strlen(dent->filename) > 6 && 386 !strcmp(dent->filename + strlen(dent->filename) - 6, ".types")) 387 { 388 /* 389 * Load a mime.types file... 390 */ 391 392 snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename); 393 DEBUG_printf(("1mimeLoadTypes: Loading \"%s\".", filename)); 394 mime_load_types(mime, filename); 395 } 396 } 397 398 cupsDirClose(dir); 399 400 DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime)); 401 402 return (mime); 403} 404 405 406/* 407 * 'mimeNew()' - Create a new, empty MIME database. 408 */ 409 410mime_t * /* O - MIME database */ 411mimeNew(void) 412{ 413 return ((mime_t *)calloc(1, sizeof(mime_t))); 414} 415 416 417/* 418 * 'mimeNextFilter()' - Get the next filter in the MIME database. 419 */ 420 421mime_filter_t * /* O - Filter or NULL */ 422mimeNextFilter(mime_t *mime) /* I - MIME database */ 423{ 424 DEBUG_printf(("6mimeNextFilter(mime=%p)", mime)); 425 426 if (!mime) 427 { 428 DEBUG_puts("7mimeNextFilter: Returning NULL."); 429 return (NULL); 430 } 431 else 432 { 433 mime_filter_t *next = (mime_filter_t *)cupsArrayNext(mime->filters); 434 /* Next filter */ 435 436 DEBUG_printf(("7mimeNextFilter: Returning %p.", next)); 437 return (next); 438 } 439} 440 441 442/* 443 * 'mimeNextType()' - Get the next type in the MIME database. 444 */ 445 446mime_type_t * /* O - Type or NULL */ 447mimeNextType(mime_t *mime) /* I - MIME database */ 448{ 449 DEBUG_printf(("6mimeNextType(mime=%p)", mime)); 450 451 if (!mime) 452 { 453 DEBUG_puts("7mimeNextType: Returning NULL."); 454 return (NULL); 455 } 456 else 457 { 458 mime_type_t *next = (mime_type_t *)cupsArrayNext(mime->types); 459 /* Next type */ 460 461 DEBUG_printf(("7mimeNextType: Returning %p.", next)); 462 return (next); 463 } 464} 465 466 467/* 468 * 'mimeNumFilters()' - Get the number of filters in a MIME database. 469 */ 470 471int 472mimeNumFilters(mime_t *mime) /* I - MIME database */ 473{ 474 DEBUG_printf(("mimeNumFilters(mime=%p)", mime)); 475 476 if (!mime) 477 { 478 DEBUG_puts("1mimeNumFilters: Returning 0."); 479 return (0); 480 } 481 else 482 { 483 DEBUG_printf(("1mimeNumFilters: Returning %d.", 484 cupsArrayCount(mime->filters))); 485 return (cupsArrayCount(mime->filters)); 486 } 487} 488 489 490/* 491 * 'mimeNumTypes()' - Get the number of types in a MIME database. 492 */ 493 494int 495mimeNumTypes(mime_t *mime) /* I - MIME database */ 496{ 497 DEBUG_printf(("mimeNumTypes(mime=%p)", mime)); 498 499 if (!mime) 500 { 501 DEBUG_puts("1mimeNumTypes: Returning 0."); 502 return (0); 503 } 504 else 505 { 506 DEBUG_printf(("1mimeNumTypes: Returning %d.", 507 cupsArrayCount(mime->types))); 508 return (cupsArrayCount(mime->types)); 509 } 510} 511 512 513/* 514 * 'mimeSetErrorCallback()' - Set the callback for error messages. 515 */ 516 517void 518mimeSetErrorCallback( 519 mime_t *mime, /* I - MIME database */ 520 mime_error_cb_t cb, /* I - Callback function */ 521 void *ctx) /* I - Context pointer for callback */ 522{ 523 if (mime) 524 { 525 mime->error_cb = cb; 526 mime->error_ctx = ctx; 527 } 528} 529 530 531/* 532 * 'mime_add_fcache()' - Add a filter to the filter cache. 533 */ 534 535static const char * /* O - Full path to filter or NULL */ 536mime_add_fcache( 537 cups_array_t *filtercache, /* I - Filter cache */ 538 const char *name, /* I - Filter name */ 539 const char *filterpath) /* I - Filter path */ 540{ 541 _mime_fcache_t key, /* Search key */ 542 *temp; /* New filter cache */ 543 char path[1024]; /* Full path to filter */ 544 545 546 DEBUG_printf(("2mime_add_fcache(filtercache=%p, name=\"%s\", " 547 "filterpath=\"%s\")", filtercache, name, filterpath)); 548 549 key.name = (char *)name; 550 if ((temp = (_mime_fcache_t *)cupsArrayFind(filtercache, &key)) != NULL) 551 { 552 DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path)); 553 return (temp->path); 554 } 555 556 if ((temp = calloc(1, sizeof(_mime_fcache_t))) == NULL) 557 { 558 DEBUG_puts("3mime_add_fcache: Returning NULL."); 559 return (NULL); 560 } 561 562 temp->name = strdup(name); 563 564 if (cupsFileFind(name, filterpath, 1, path, sizeof(path))) 565 temp->path = strdup(path); 566 567 cupsArrayAdd(filtercache, temp); 568 569 DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path)); 570 return (temp->path); 571} 572 573 574/* 575 * 'mime_compare_fcache()' - Compare two filter cache entries. 576 */ 577 578static int /* O - Result of comparison */ 579mime_compare_fcache(_mime_fcache_t *a, /* I - First entry */ 580 _mime_fcache_t *b) /* I - Second entry */ 581{ 582 return (strcmp(a->name, b->name)); 583} 584 585 586/* 587 * 'mime_delete_fcache()' - Free all memory used by the filter cache. 588 */ 589 590static void 591mime_delete_fcache( 592 cups_array_t *filtercache) /* I - Filter cache */ 593{ 594 _mime_fcache_t *current; /* Current cache entry */ 595 596 597 DEBUG_printf(("2mime_delete_fcache(filtercache=%p)", filtercache)); 598 599 for (current = (_mime_fcache_t *)cupsArrayFirst(filtercache); 600 current; 601 current = (_mime_fcache_t *)cupsArrayNext(filtercache)) 602 { 603 free(current->name); 604 605 if (current->path) 606 free(current->path); 607 608 free(current); 609 } 610 611 cupsArrayDelete(filtercache); 612} 613 614 615/* 616 * 'mime_delete_rules()' - Free all memory for the given rule tree. 617 */ 618 619static void 620mime_delete_rules(mime_magic_t *rules) /* I - Rules to free */ 621{ 622 mime_magic_t *next; /* Next rule to free */ 623 624 625 DEBUG_printf(("2mime_delete_rules(rules=%p)", rules)); 626 627 /* 628 * Free the rules list, descending recursively to free any child rules. 629 */ 630 631 while (rules != NULL) 632 { 633 next = rules->next; 634 635 if (rules->child != NULL) 636 mime_delete_rules(rules->child); 637 638 if (rules->op == MIME_MAGIC_REGEX) 639 regfree(&(rules->value.rev)); 640 641 free(rules); 642 rules = next; 643 } 644} 645 646 647/* 648 * 'mime_load_convs()' - Load a xyz.convs file. 649 */ 650 651static void 652mime_load_convs( 653 mime_t *mime, /* I - MIME database */ 654 const char *filename, /* I - Convs file to load */ 655 const char *filterpath, /* I - Path for filters */ 656 cups_array_t *filtercache) /* I - Filter program cache */ 657{ 658 cups_file_t *fp; /* Convs file */ 659 char line[1024], /* Input line from file */ 660 *lineptr, /* Current position in line */ 661 super[MIME_MAX_SUPER], /* Super-type name */ 662 type[MIME_MAX_TYPE], /* Type name */ 663 *temp, /* Temporary pointer */ 664 *filter; /* Filter program */ 665 mime_type_t *temptype, /* MIME type looping var */ 666 *dsttype; /* Destination MIME type */ 667 int cost; /* Cost of filter */ 668 669 670 DEBUG_printf(("2mime_load_convs(mime=%p, filename=\"%s\", filterpath=\"%s\", " 671 "filtercache=%p)", mime, filename, filterpath, filtercache)); 672 673 /* 674 * First try to open the file... 675 */ 676 677 if ((fp = cupsFileOpen(filename, "r")) == NULL) 678 { 679 DEBUG_printf(("3mime_load_convs: Unable to open \"%s\": %s", filename, 680 strerror(errno))); 681 _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno)); 682 return; 683 } 684 685 /* 686 * Then read each line from the file, skipping any comments in the file... 687 */ 688 689 while (cupsFileGets(fp, line, sizeof(line)) != NULL) 690 { 691 /* 692 * Skip blank lines and lines starting with a #... 693 */ 694 695 if (!line[0] || line[0] == '#') 696 continue; 697 698 /* 699 * Strip trailing whitespace... 700 */ 701 702 for (lineptr = line + strlen(line) - 1; 703 lineptr >= line && isspace(*lineptr & 255); 704 lineptr --) 705 *lineptr = '\0'; 706 707 /* 708 * Extract the destination super-type and type names from the middle of 709 * the line. 710 */ 711 712 lineptr = line; 713 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0') 714 lineptr ++; 715 716 while (*lineptr == ' ' || *lineptr == '\t') 717 lineptr ++; 718 719 temp = super; 720 721 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' && 722 (temp - super + 1) < MIME_MAX_SUPER) 723 *temp++ = (char)tolower(*lineptr++ & 255); 724 725 *temp = '\0'; 726 727 if (*lineptr != '/') 728 continue; 729 730 lineptr ++; 731 temp = type; 732 733 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' && 734 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE) 735 *temp++ = (char)tolower(*lineptr++ & 255); 736 737 *temp = '\0'; 738 739 if (*lineptr == '\0' || *lineptr == '\n') 740 continue; 741 742 if ((dsttype = mimeType(mime, super, type)) == NULL) 743 { 744 DEBUG_printf(("3mime_load_convs: Destination type %s/%s not found.", 745 super, type)); 746 continue; 747 } 748 749 /* 750 * Then get the cost and filter program... 751 */ 752 753 while (*lineptr == ' ' || *lineptr == '\t') 754 lineptr ++; 755 756 if (*lineptr < '0' || *lineptr > '9') 757 continue; 758 759 cost = atoi(lineptr); 760 761 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0') 762 lineptr ++; 763 while (*lineptr == ' ' || *lineptr == '\t') 764 lineptr ++; 765 766 if (*lineptr == '\0' || *lineptr == '\n') 767 continue; 768 769 filter = lineptr; 770 771 if (strcmp(filter, "-")) 772 { 773 /* 774 * Verify that the filter exists and is executable... 775 */ 776 777 if (!mime_add_fcache(filtercache, filter, filterpath)) 778 { 779 DEBUG_printf(("mime_load_convs: Filter %s not found in %s.", filter, 780 filterpath)); 781 _mimeError(mime, "Filter \"%s\" not found.", filter); 782 continue; 783 } 784 } 785 786 /* 787 * Finally, get the source super-type and type names from the beginning of 788 * the line. We do it here so we can support wildcards... 789 */ 790 791 lineptr = line; 792 temp = super; 793 794 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' && 795 (temp - super + 1) < MIME_MAX_SUPER) 796 *temp++ = (char)tolower(*lineptr++ & 255); 797 798 *temp = '\0'; 799 800 if (*lineptr != '/') 801 continue; 802 803 lineptr ++; 804 temp = type; 805 806 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' && 807 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE) 808 *temp++ = (char)tolower(*lineptr++ & 255); 809 810 *temp = '\0'; 811 812 if (!strcmp(super, "*") && !strcmp(type, "*")) 813 { 814 /* 815 * Force * / * to be "application/octet-stream"... 816 */ 817 818 strlcpy(super, "application", sizeof(super)); 819 strlcpy(type, "octet-stream", sizeof(type)); 820 } 821 822 /* 823 * Add the filter to the MIME database, supporting wildcards as needed... 824 */ 825 826 for (temptype = (mime_type_t *)cupsArrayFirst(mime->types); 827 temptype; 828 temptype = (mime_type_t *)cupsArrayNext(mime->types)) 829 if ((super[0] == '*' || !strcmp(temptype->super, super)) && 830 (type[0] == '*' || !strcmp(temptype->type, type))) 831 mimeAddFilter(mime, temptype, dsttype, cost, filter); 832 } 833 834 cupsFileClose(fp); 835} 836 837 838/* 839 * 'mime_load_types()' - Load a xyz.types file. 840 */ 841 842static void 843mime_load_types(mime_t *mime, /* I - MIME database */ 844 const char *filename) /* I - Types file to load */ 845{ 846 cups_file_t *fp; /* Types file */ 847 size_t linelen; /* Length of line */ 848 char line[32768], /* Input line from file */ 849 *lineptr, /* Current position in line */ 850 super[MIME_MAX_SUPER], /* Super-type name */ 851 type[MIME_MAX_TYPE], /* Type name */ 852 *temp; /* Temporary pointer */ 853 mime_type_t *typeptr; /* New MIME type */ 854 855 856 DEBUG_printf(("2mime_load_types(mime=%p, filename=\"%s\")", mime, filename)); 857 858 /* 859 * First try to open the file... 860 */ 861 862 if ((fp = cupsFileOpen(filename, "r")) == NULL) 863 { 864 DEBUG_printf(("3mime_load_types: Unable to open \"%s\": %s", filename, 865 strerror(errno))); 866 _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno)); 867 return; 868 } 869 870 /* 871 * Then read each line from the file, skipping any comments in the file... 872 */ 873 874 while (cupsFileGets(fp, line, sizeof(line)) != NULL) 875 { 876 /* 877 * Skip blank lines and lines starting with a #... 878 */ 879 880 if (!line[0] || line[0] == '#') 881 continue; 882 883 /* 884 * While the last character in the line is a backslash, continue on to the 885 * next line (and the next, etc.) 886 */ 887 888 linelen = strlen(line); 889 890 while (line[linelen - 1] == '\\') 891 { 892 linelen --; 893 894 if (cupsFileGets(fp, line + linelen, sizeof(line) - linelen) == NULL) 895 line[linelen] = '\0'; 896 else 897 linelen += strlen(line + linelen); 898 } 899 900 /* 901 * Extract the super-type and type names from the beginning of the line. 902 */ 903 904 lineptr = line; 905 temp = super; 906 907 while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' && 908 (temp - super + 1) < MIME_MAX_SUPER) 909 *temp++ = (char)tolower(*lineptr++ & 255); 910 911 *temp = '\0'; 912 913 if (*lineptr != '/') 914 continue; 915 916 lineptr ++; 917 temp = type; 918 919 while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' && 920 *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE) 921 *temp++ = (char)tolower(*lineptr++ & 255); 922 923 *temp = '\0'; 924 925 /* 926 * Add the type and rules to the MIME database... 927 */ 928 929 typeptr = mimeAddType(mime, super, type); 930 mimeAddTypeRule(typeptr, lineptr); 931 } 932 933 cupsFileClose(fp); 934} 935 936 937/* 938 * End of "$Id: mime.c 11560 2014-02-06 20:10:19Z msweet $". 939 */ 940