mime_filter_t * /* O - New filter */ mimeAddFilter(mime_t *mime, /* I - MIME database */ mime_type_t *src, /* I - Source type */ mime_type_t *dst, /* I - Destination type */ int cost, /* I - Relative time/resource cost */ const char *filter) /* I - Filter program to run */ { mime_filter_t *temp; /* New filter */ DEBUG_printf(("mimeAddFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), cost=%d, " "filter=\"%s\")", mime, src, src ? src->super : "???", src ? src->type : "???", dst, dst ? dst->super : "???", dst ? dst->type : "???", cost, filter)); /* * Range-check the input... */ if (!mime || !src || !dst || !filter) { DEBUG_puts("1mimeAddFilter: Returning NULL."); return (NULL); } /* * See if we already have an existing filter for the given source and * destination... */ if ((temp = mimeFilterLookup(mime, src, dst)) != NULL) { /* * Yup, does the existing filter have a higher cost? If so, copy the * filter and cost to the existing filter entry and return it... */ if (temp->cost > cost) { DEBUG_printf(("1mimeAddFilter: Replacing filter \"%s\", cost %d.", temp->filter, temp->cost)); temp->cost = cost; strlcpy(temp->filter, filter, sizeof(temp->filter)); } } else { /* * Nope, add a new one... */ if (!mime->filters) mime->filters = cupsArrayNew((cups_array_func_t)mime_compare_filters, NULL); if (!mime->filters) return (NULL); if ((temp = calloc(1, sizeof(mime_filter_t))) == NULL) return (NULL); /* * Copy the information over and sort if necessary... */ temp->src = src; temp->dst = dst; temp->cost = cost; strlcpy(temp->filter, filter, sizeof(temp->filter)); DEBUG_puts("1mimeAddFilter: Adding new filter."); cupsArrayAdd(mime->filters, temp); cupsArrayAdd(mime->srcs, temp); } /* * Return the new/updated filter... */ DEBUG_printf(("1mimeAddFilter: Returning %p.", temp)); return (temp); }
static cups_array_t * /* O - Array of filters to run */ mime_find_filters( mime_t *mime, /* I - MIME database */ mime_type_t *src, /* I - Source file type */ size_t srcsize, /* I - Size of source file */ mime_type_t *dst, /* I - Destination file type */ int *cost, /* O - Cost of filters */ _mime_typelist_t *list) /* I - Source types we've used */ { int tempcost, /* Temporary cost */ mincost; /* Current minimum */ cups_array_t *temp, /* Temporary filter */ *mintemp; /* Current minimum */ mime_filter_t *current, /* Current filter */ srckey; /* Source type key */ _mime_typelist_t listnode, /* New list node */ *listptr; /* Pointer in list */ DEBUG_printf(("2mime_find_filters(mime=%p, src=%p(%s/%s), srcsize=" CUPS_LLFMT ", dst=%p(%s/%s), cost=%p, list=%p)", mime, src, src->super, src->type, CUPS_LLCAST srcsize, dst, dst->super, dst->type, cost, list)); /* * See if there is a filter that can convert the files directly... */ if ((current = mimeFilterLookup(mime, src, dst)) != NULL && (current->maxsize == 0 || srcsize <= current->maxsize)) { /* * Got a direct filter! */ DEBUG_puts("3mime_find_filters: Direct filter found."); if ((mintemp = cupsArrayNew(NULL, NULL)) == NULL) { DEBUG_puts("3mime_find_filters: Returning NULL (out of memory)."); return (NULL); } cupsArrayAdd(mintemp, current); mincost = current->cost; if (!cost) { DEBUG_printf(("3mime_find_filters: Returning 1 filter, cost %d:", mincost)); DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s", current->src->super, current->src->type, current->dst->super, current->dst->type, current->cost, current->filter)); return (mintemp); } } else { /* * No direct filter... */ mintemp = NULL; mincost = 9999999; } /* * Initialize this node in the type list... */ listnode.next = list; /* * OK, now look for filters from the source type to any other type... */ srckey.src = src; for (current = (mime_filter_t *)cupsArrayFind(mime->srcs, &srckey); current && current->src == src; current = (mime_filter_t *)cupsArrayNext(mime->srcs)) { /* * See if we have already tried the destination type as a source * type (this avoids extra filter looping...) */ mime_type_t *current_dst; /* Current destination type */ if (current->maxsize > 0 && srcsize > current->maxsize) continue; for (listptr = list, current_dst = current->dst; listptr; listptr = listptr->next) if (current_dst == listptr->src) break; if (listptr) continue; /* * See if we have any filters that can convert from the destination type * of this filter to the final type... */ listnode.src = current->src; cupsArraySave(mime->srcs); temp = mime_find_filters(mime, current->dst, srcsize, dst, &tempcost, &listnode); cupsArrayRestore(mime->srcs); if (!temp) continue; if (!cost) { DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:", cupsArrayCount(temp), tempcost)); #ifdef DEBUG for (current = (mime_filter_t *)cupsArrayFirst(temp); current; current = (mime_filter_t *)cupsArrayNext(temp)) DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s", current->src->super, current->src->type, current->dst->super, current->dst->type, current->cost, current->filter)); #endif /* DEBUG */ return (temp); } /* * Found a match; see if this one is less costly than the last (if * any...) */ tempcost += current->cost; if (tempcost < mincost) { cupsArrayDelete(mintemp); /* * Hey, we got a match! Add the current filter to the beginning of the * filter list... */ mintemp = temp; mincost = tempcost; cupsArrayInsert(mintemp, current); } else cupsArrayDelete(temp); } if (mintemp) { /* * Hey, we got a match! */ DEBUG_printf(("3mime_find_filters: Returning %d filter(s), cost %d:", cupsArrayCount(mintemp), mincost)); #ifdef DEBUG for (current = (mime_filter_t *)cupsArrayFirst(mintemp); current; current = (mime_filter_t *)cupsArrayNext(mintemp)) DEBUG_printf(("3mime_find_filters: %s/%s %s/%s %d %s", current->src->super, current->src->type, current->dst->super, current->dst->type, current->cost, current->filter)); #endif /* DEBUG */ if (cost) *cost = mincost; return (mintemp); } DEBUG_puts("3mime_find_filters: Returning NULL (no matches)."); return (NULL); }
static void add_printer_filter( const char *command, /* I - Command name */ mime_t *mime, /* I - MIME database */ mime_type_t *filtertype, /* I - Printer 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), "%s/%s/%s", filtertype->type, 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 { _cupsLangPrintf(stderr, _("%s: Invalid filter string \"%s\"."), command, 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); } /* * See if the filter program exists; if not, stop the printer and flag * the error! */ if (strcmp(program, "-")) { char filename[1024]; /* Full path to program */ if (program[0] == '/') strlcpy(filename, program, sizeof(filename)); else snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program); if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !geteuid(), check_cb, (void *)command)) return; } /* * 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; } }
int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line arguments */ { int i, /* Looping vars */ list_filters = 0; /* Just list the filters? */ const char *command, /* Command name */ *opt, /* Current option */ *printer; /* Printer name */ mime_type_t *printer_type, /* Printer MIME type */ *prefilter_type; /* Printer prefilter MIME type */ char *srctype, /* Source type */ *dsttype, /* Destination type */ 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 */ char mimedir[1024]; /* MIME directory */ char *infile, /* File to filter */ *outfile; /* File to create */ char cupsfilesconf[1024]; /* cups-files.conf file */ const char *server_root; /* CUPS_SERVERROOT environment variable */ mime_type_t *src, /* Source type */ *dst; /* Destination type */ cups_array_t *filters; /* Filters for the file */ int num_options; /* Number of options */ cups_option_t *options; /* Options */ const char *ppdfile; /* PPD file */ const char *title, /* Title string */ *user; /* Username */ int all_filters, /* Use all filters */ removeppd, /* Remove PPD file */ removeinfile; /* Remove input file */ int status; /* Execution status */ /* * Setup defaults... */ if ((command = strrchr(argv[0], '/')) != NULL) command ++; else command = argv[0]; printer = !strcmp(command, "convert") ? "tofile" : "cupsfilter"; mime = NULL; srctype = NULL; compression = 0; dsttype = "application/pdf"; infile = NULL; outfile = NULL; num_options = 0; options = NULL; ppdfile = NULL; title = NULL; user = cupsUser(); all_filters = 0; removeppd = 0; removeinfile = 0; if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) server_root = CUPS_SERVERROOT; snprintf(cupsfilesconf, sizeof(cupsfilesconf), "%s/cups-files.conf", server_root); /* * Process command-line arguments... */ _cupsSetLocale(argv); for (i = 1; i < argc; i ++) { if (argv[i][0] == '-') { if (!strcmp(argv[i], "--list-filters")) { list_filters = 1; } else if (!strcmp(argv[i], "--")) { i ++; if (i < argc && !infile) infile = argv[i]; else usage(NULL); } else { for (opt = argv[i] + 1; *opt; opt ++) { switch (*opt) { case 'a' : /* Specify option... */ i ++; if (i < argc) num_options = cupsParseOptions(argv[i], num_options, &options); else usage(opt); break; case 'c' : /* Specify cups-files.conf file location... */ i ++; if (i < argc) { if (!strcmp(command, "convert")) num_options = cupsAddOption("copies", argv[i], num_options, &options); else strlcpy(cupsfilesconf, argv[i], sizeof(cupsfilesconf)); } else usage(opt); break; case 'd' : /* Specify the real printer name */ i ++; if (i < argc) printer = argv[i]; else usage(opt); break; case 'D' : /* Delete input file after conversion */ removeinfile = 1; break; case 'e' : /* Use every filter from the PPD file */ all_filters = 1; break; case 'f' : /* Specify input file... */ i ++; if (i < argc && !infile) infile = argv[i]; else usage(opt); break; case 'i' : /* Specify source MIME type... */ i ++; if (i < argc) { if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2) usage(opt); srctype = argv[i]; } else usage(opt); break; case 'j' : /* Get job file or specify destination MIME type... */ if (strcmp(command, "convert")) { i ++; if (i < argc) { get_job_file(argv[i]); infile = TempFile; } else usage(opt); break; } case 'm' : /* Specify destination MIME type... */ i ++; if (i < argc) { if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2) usage(opt); dsttype = argv[i]; } else usage(opt); break; case 'n' : /* Specify number of copies... */ i ++; if (i < argc) num_options = cupsAddOption("copies", argv[i], num_options, &options); else usage(opt); break; case 'o' : /* Specify option(s) or output filename */ i ++; if (i < argc) { if (!strcmp(command, "convert")) { if (outfile) usage(NULL); else outfile = argv[i]; } else num_options = cupsParseOptions(argv[i], num_options, &options); } else usage(opt); break; case 'p' : /* Specify PPD file... */ case 'P' : /* Specify PPD file... */ i ++; if (i < argc) ppdfile = argv[i]; else usage(opt); break; case 't' : /* Specify title... */ case 'J' : /* Specify title... */ i ++; if (i < argc) title = argv[i]; else usage(opt); break; case 'u' : /* Delete PPD file after conversion */ removeppd = 1; break; case 'U' : /* Specify username... */ i ++; if (i < argc) user = argv[i]; else usage(opt); break; default : /* Something we don't understand... */ usage(opt); break; } } } } else if (!infile) { if (strcmp(command, "convert")) infile = argv[i]; else usage(NULL); } else { _cupsLangPuts(stderr, _("cupsfilter: Only one filename can be specified.")); usage(NULL); } } if (!infile && !srctype) usage(NULL); if (!title) { if (!infile) title = "(stdin)"; else if ((title = strrchr(infile, '/')) != NULL) title ++; else title = infile; } /* * Load the cups-files.conf file and create the MIME database... */ if (read_cups_files_conf(cupsfilesconf)) return (1); snprintf(mimedir, sizeof(mimedir), "%s/mime", DataDir); mime = mimeLoadTypes(NULL, mimedir); mime = mimeLoadTypes(mime, ServerRoot); mime = mimeLoadFilters(mime, mimedir, Path); mime = mimeLoadFilters(mime, ServerRoot, Path); if (!mime) { _cupsLangPrintf(stderr, _("%s: Unable to read MIME database from \"%s\" or " "\"%s\"."), command, mimedir, ServerRoot); return (1); } prefilter_type = NULL; if (all_filters) printer_type = add_printer_filters(command, mime, printer, ppdfile, &prefilter_type); else printer_type = mimeType(mime, "application", "vnd.cups-postscript"); /* * Get the source and destination types... */ if (srctype) { /* sscanf return value already checked above */ sscanf(srctype, "%15[^/]/%255s", super, type); if ((src = mimeType(mime, super, type)) == NULL) { _cupsLangPrintf(stderr, _("%s: Unknown source MIME type %s/%s."), command, super, type); return (1); } } else if ((src = mimeFileType(mime, infile, infile, &compression)) == NULL) { _cupsLangPrintf(stderr, _("%s: Unable to determine MIME type of \"%s\"."), command, infile); return (1); } /* sscanf return value already checked above */ sscanf(dsttype, "%15[^/]/%255s", super, type); if (!_cups_strcasecmp(super, "printer")) dst = printer_type; else if ((dst = mimeType(mime, super, type)) == NULL) { _cupsLangPrintf(stderr, _("%s: Unknown destination MIME type %s/%s."), command, super, type); return (1); } /* * Figure out how to filter the file... */ if (src == dst) { /* * Special case - no filtering needed... */ filters = cupsArrayNew(NULL, NULL); cupsArrayAdd(filters, &GZIPFilter); GZIPFilter.src = src; GZIPFilter.dst = dst; } else if ((filters = mimeFilter(mime, src, dst, &cost)) == NULL) { _cupsLangPrintf(stderr, _("%s: No filter to convert from %s/%s to %s/%s."), command, src->super, src->type, dst->super, dst->type); return (1); } else if (compression) cupsArrayInsert(filters, &GZIPFilter); if (prefilter_type) { /* * Add pre-filters... */ mime_filter_t *filter, /* Current filter */ *prefilter; /* Current pre-filter */ cups_array_t *prefilters = cupsArrayNew(NULL, NULL); /* New filters array */ for (filter = (mime_filter_t *)cupsArrayFirst(filters); filter; filter = (mime_filter_t *)cupsArrayNext(filters)) { if ((prefilter = mimeFilterLookup(mime, filter->src, prefilter_type)) != NULL) cupsArrayAdd(prefilters, prefilter); cupsArrayAdd(prefilters, filter); } cupsArrayDelete(filters); filters = prefilters; } if (list_filters) { /* * List filters... */ mime_filter_t *filter; /* Current filter */ for (filter = (mime_filter_t *)cupsArrayFirst(filters); filter; filter = (mime_filter_t *)cupsArrayNext(filters)) if (strcmp(filter->filter, "-")) _cupsLangPuts(stdout, filter->filter); status = 0; } else { /* * Run filters... */ status = exec_filters(src, filters, infile, outfile, ppdfile, printer, user, title, num_options, options); } /* * Remove files as needed, then exit... */ if (TempFile[0]) unlink(TempFile); if (removeppd && ppdfile) unlink(ppdfile); if (removeinfile && infile) unlink(infile); return (status); }
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 */ DEBUG_printf(("add_ppd_filter(mime=%p, filtertype=%p(%s/%s), filter=\"%s\")", mime, filtertype, filtertype->super, filtertype->type, 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 = 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) { DEBUG_printf(("add_ppd_filter: Adding filter %s/%s %s/%s %d %s", temptype->super, temptype->type, desttype->super, desttype->type, cost, program)); filterptr = mimeAddFilter(mime, temptype, desttype, cost, program); if (!mimeFilterLookup(mime, desttype, filtertype)) { DEBUG_printf(("add_printer_filter: Adding filter %s/%s %s/%s 0 -", desttype->super, desttype->type, filtertype->super, filtertype->type)); mimeAddFilter(mime, desttype, filtertype, 0, "-"); } } else { DEBUG_printf(("add_printer_filter: Adding filter %s/%s %s/%s %d %s", temptype->super, temptype->type, filtertype->super, filtertype->type, cost, program)); filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program); } if (filterptr) filterptr->maxsize = maxsize; } }