/* * MIME test program for CUPS. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more information. */ /* * Include necessary headers... */ #include #include #include #include #include "mime.h" /* * Local functions... */ static void add_ppd_filter(mime_t *mime, mime_type_t *filtertype, const char *filter); static void add_ppd_filters(mime_t *mime, ppd_file_t *ppd); static void print_rules(mime_magic_t *rules); static void type_dir(mime_t *mime, const char *dirname); /* * 'main()' - Main entry for the test program. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping vars */ const char *filter_path; /* Filter path */ char super[MIME_MAX_SUPER], /* Super-type name */ type[MIME_MAX_TYPE]; /* Type name */ int compression; /* Compression of file */ int cost; /* Cost of filters */ mime_t *mime; /* MIME database */ mime_type_t *src, /* Source type */ *dst; /* Destination type */ struct stat srcinfo; /* Source information */ ppd_file_t *ppd; /* PPD file */ cups_array_t *filters; /* Filters for the file */ mime_filter_t *filter; /* Current filter */ mime = NULL; src = NULL; dst = NULL; ppd = NULL; filter_path = "../filter:" CUPS_SERVERBIN "/filter"; srcinfo.st_size = 0; for (i = 1; i < argc; i ++) if (!strcmp(argv[i], "-d")) { i ++; if (i < argc) { mime = mimeLoad(argv[i], filter_path); if (ppd) add_ppd_filters(mime, ppd); } } else if (!strcmp(argv[i], "-f")) { i ++; if (i < argc) filter_path = argv[i]; } else if (!strcmp(argv[i], "-p")) { i ++; if (i < argc) { ppd = ppdOpenFile(argv[i]); if (mime) add_ppd_filters(mime, ppd); } } else if (!src) { if (!mime) mime = mimeLoad("../conf", filter_path); if (ppd) add_ppd_filters(mime, ppd); src = mimeFileType(mime, argv[i], NULL, &compression); stat(argv[i], &srcinfo); if (src) printf("%s: %s/%s%s\n", argv[i], src->super, src->type, compression ? " (gzipped)" : ""); else if ((src = mimeType(mime, "application", "octet-stream")) != NULL) printf("%s: application/octet-stream\n", argv[i]); else { printf("%s: unknown\n", argv[i]); if (mime) mimeDelete(mime); return (1); } } else { sscanf(argv[i], "%15[^/]/%255s", super, type); dst = mimeType(mime, super, type); filters = mimeFilter2(mime, src, (size_t)srcinfo.st_size, dst, &cost); if (!filters) { printf("No filters to convert from %s/%s to %s.\n", src->super, src->type, argv[i]); } else { int first = 1; /* First filter shown? */ printf("Filter cost = %d\n", cost); for (filter = (mime_filter_t *)cupsArrayFirst(filters); filter; filter = (mime_filter_t *)cupsArrayNext(filters)) { if (!strcmp(filter->filter, "-")) continue; if (first) { first = 0; fputs(filter->filter, stdout); } else printf(" | %s", filter->filter); } putchar('\n'); cupsArrayDelete(filters); } } if (!mime) { mime = mimeLoad("../conf", filter_path); if (ppd) add_ppd_filters(mime, ppd); } if (!src) { puts("MIME database types:"); for (src = mimeFirstType(mime); src; src = mimeNextType(mime)) { printf("\t%s/%s (%d):\n", src->super, src->type, src->priority); print_rules(src->rules); puts(""); } puts(""); puts("MIME database filters:"); for (filter = mimeFirstFilter(mime); filter; filter = mimeNextFilter(mime)) printf("\t%s/%s to %s/%s: %s (%d)\n", filter->src->super, filter->src->type, filter->dst->super, filter->dst->type, filter->filter, filter->cost); type_dir(mime, "../doc"); } return (0); } /* * 'add_printer_filter()' - Add a printer filter from a PPD. */ static void add_ppd_filter(mime_t *mime, /* I - MIME database */ mime_type_t *filtertype, /* I - Filter or prefilter MIME type */ const char *filter) /* I - Filter to add */ { char super[MIME_MAX_SUPER], /* Super-type for filter */ type[MIME_MAX_TYPE], /* Type for filter */ dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */ dtype[MIME_MAX_TYPE], /* Destination type for filter */ dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2], /* Destination super/type */ program[1024]; /* Program/filter name */ int cost; /* Cost of filter */ size_t maxsize = 0; /* Maximum supported file size */ mime_type_t *temptype, /* MIME type looping var */ *desttype; /* Destination MIME type */ mime_filter_t *filterptr; /* MIME filter */ /* * Parse the filter string; it should be in one of the following formats: * * source/type cost program * source/type cost maxsize(nnnn) program * source/type dest/type cost program * source/type dest/type cost maxsize(nnnn) program */ if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, dsuper, dtype, &cost, program) == 6) { snprintf(dest, sizeof(dest), "test/%s/%s", dsuper, dtype); if ((desttype = mimeType(mime, "printer", dest)) == NULL) desttype = mimeAddType(mime, "printer", dest); } else { if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost, program) == 4) { desttype = filtertype; } else { printf("testmime: Invalid filter string \"%s\".\n", filter); return; } } if (!strncmp(program, "maxsize(", 8)) { char *ptr; /* Pointer into maxsize(nnnn) program */ maxsize = (size_t)strtoll(program + 8, &ptr, 10); if (*ptr != ')') { printf("testmime: Invalid filter string \"%s\".\n", filter); return; } ptr ++; while (_cups_isspace(*ptr)) ptr ++; _cups_strcpy(program, ptr); } /* * Add the filter to the MIME database, supporting wildcards as needed... */ for (temptype = mimeFirstType(mime); temptype; temptype = mimeNextType(mime)) if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) || !_cups_strcasecmp(temptype->super, super)) && (type[0] == '*' || !_cups_strcasecmp(temptype->type, type))) { if (desttype != filtertype) { filterptr = mimeAddFilter(mime, temptype, desttype, cost, program); if (!mimeFilterLookup(mime, desttype, filtertype)) mimeAddFilter(mime, desttype, filtertype, 0, "-"); } else filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program); if (filterptr) filterptr->maxsize = maxsize; } } /* * 'add_ppd_filters()' - Add all filters from a PPD. */ static void add_ppd_filters(mime_t *mime, /* I - MIME database */ ppd_file_t *ppd) /* I - PPD file */ { _ppd_cache_t *pc; /* Cache data for PPD */ const char *value; /* Filter definition value */ mime_type_t *filter, /* Filter type */ *prefilter; /* Pre-filter type */ pc = _ppdCacheCreateWithPPD(ppd); if (!pc) return; filter = mimeAddType(mime, "printer", "test"); if (pc->filters) { for (value = (const char *)cupsArrayFirst(pc->filters); value; value = (const char *)cupsArrayNext(pc->filters)) add_ppd_filter(mime, filter, value); } else { add_ppd_filter(mime, filter, "application/vnd.cups-raw 0 -"); add_ppd_filter(mime, filter, "application/vnd.cups-postscript 0 -"); } if (pc->prefilters) { prefilter = mimeAddType(mime, "prefilter", "test"); for (value = (const char *)cupsArrayFirst(pc->prefilters); value; value = (const char *)cupsArrayNext(pc->prefilters)) add_ppd_filter(mime, prefilter, value); } } /* * 'print_rules()' - Print the rules for a file type... */ static void print_rules(mime_magic_t *rules) /* I - Rules to print */ { int i; /* Looping var */ static char indent[255] = "\t"; /* Indentation for rules */ if (rules == NULL) return; while (rules != NULL) { printf("%s[%p] ", indent, rules); if (rules->invert) printf("NOT "); switch (rules->op) { case MIME_MAGIC_MATCH : printf("match(%s)", rules->value.matchv); break; case MIME_MAGIC_LOCALE : printf("locale(%s)", rules->value.localev); break; case MIME_MAGIC_ASCII : printf("ascii(%d,%d)", rules->offset, rules->length); break; case MIME_MAGIC_PRINTABLE : printf("printable(%d,%d)", rules->offset, rules->length); break; case MIME_MAGIC_STRING : printf("string(%d,", rules->offset); for (i = 0; i < rules->length; i ++) if (rules->value.stringv[i] < ' ' || rules->value.stringv[i] > 126) printf("<%02X>", rules->value.stringv[i]); else putchar(rules->value.stringv[i]); putchar(')'); break; case MIME_MAGIC_CHAR : printf("char(%d,%d)", rules->offset, rules->value.charv); break; case MIME_MAGIC_SHORT : printf("short(%d,%d)", rules->offset, rules->value.shortv); break; case MIME_MAGIC_INT : printf("int(%d,%d)", rules->offset, rules->value.intv); break; case MIME_MAGIC_CONTAINS : printf("contains(%d,%d,", rules->offset, rules->region); for (i = 0; i < rules->length; i ++) if (rules->value.stringv[i] < ' ' || rules->value.stringv[i] > 126) printf("<%02X>", rules->value.stringv[i]); else putchar(rules->value.stringv[i]); putchar(')'); break; default : break; } if (rules->child != NULL) { if (rules->op == MIME_MAGIC_OR) puts("OR ("); else puts("AND ("); strcat(indent, "\t"); print_rules(rules->child); indent[strlen(indent) - 1] = '\0'; printf("%s)\n", indent); } else putchar('\n'); rules = rules->next; } } /* * 'type_dir()' - Show the MIME types for a given directory. */ static void type_dir(mime_t *mime, /* I - MIME database */ const char *dirname) /* I - Directory */ { cups_dir_t *dir; /* Directory */ cups_dentry_t *dent; /* Directory entry */ char filename[1024]; /* File to type */ mime_type_t *filetype; /* File type */ int compression; /* Compressed file? */ mime_type_t *pstype; /* application/vnd.cups-postscript */ cups_array_t *filters; /* Filters to pstype */ mime_filter_t *filter; /* Current filter */ int cost; /* Filter cost */ dir = cupsDirOpen(dirname); if (!dir) return; pstype = mimeType(mime, "application", "vnd.cups-postscript"); while ((dent = cupsDirRead(dir)) != NULL) { if (dent->filename[0] == '.') continue; snprintf(filename, sizeof(filename), "%s/%s", dirname, dent->filename); if (S_ISDIR(dent->fileinfo.st_mode)) type_dir(mime, filename); if (!S_ISREG(dent->fileinfo.st_mode)) continue; filetype = mimeFileType(mime, filename, NULL, &compression); if (filetype) { printf("%s: %s/%s%s\n", filename, filetype->super, filetype->type, compression ? " (compressed)" : ""); filters = mimeFilter(mime, filetype, pstype, &cost); if (!filters) puts(" No filters to convert application/vnd.cups-postscript."); else { printf(" Filter cost = %d\n", cost); filter = (mime_filter_t *)cupsArrayFirst(filters); printf(" %s", filter->filter); for (filter = (mime_filter_t *)cupsArrayNext(filters); filter; filter = (mime_filter_t *)cupsArrayNext(filters)) printf(" | %s", filter->filter); putchar('\n'); cupsArrayDelete(filters); } } else printf("%s: unknown%s\n", filename, compression ? " (compressed)" : ""); } cupsDirClose(dir); }