You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
936 lines
21 KiB
936 lines
21 KiB
/*
|
|
* MIME database file routines 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 <cups/string-private.h>
|
|
#include <cups/dir.h>
|
|
#include "mime-private.h"
|
|
|
|
|
|
/*
|
|
* Debug macros that used to be private API...
|
|
*/
|
|
|
|
#define DEBUG_puts(x)
|
|
#define DEBUG_printf(...)
|
|
|
|
|
|
/*
|
|
* Local types...
|
|
*/
|
|
|
|
typedef struct _mime_fcache_s /**** Filter cache structure ****/
|
|
{
|
|
char *name, /* Filter name */
|
|
*path; /* Full path to filter if available */
|
|
} _mime_fcache_t;
|
|
|
|
|
|
/*
|
|
* Local functions...
|
|
*/
|
|
|
|
static const char *mime_add_fcache(cups_array_t *filtercache, const char *name,
|
|
const char *filterpath);
|
|
static int mime_compare_fcache(_mime_fcache_t *a, _mime_fcache_t *b);
|
|
static void mime_delete_fcache(cups_array_t *filtercache);
|
|
static void mime_delete_rules(mime_magic_t *rules);
|
|
static void mime_load_convs(mime_t *mime, const char *filename,
|
|
const char *filterpath,
|
|
cups_array_t *filtercache);
|
|
static void mime_load_types(mime_t *mime, const char *filename);
|
|
|
|
|
|
/*
|
|
* 'mimeDelete()' - Delete (free) a MIME database.
|
|
*/
|
|
|
|
void
|
|
mimeDelete(mime_t *mime) /* I - MIME database */
|
|
{
|
|
mime_type_t *type; /* Current type */
|
|
mime_filter_t *filter; /* Current filter */
|
|
|
|
|
|
DEBUG_printf(("mimeDelete(mime=%p)", mime));
|
|
|
|
if (!mime)
|
|
return;
|
|
|
|
/*
|
|
* Loop through filters and free them...
|
|
*/
|
|
|
|
for (filter = (mime_filter_t *)cupsArrayFirst(mime->filters);
|
|
filter;
|
|
filter = (mime_filter_t *)cupsArrayNext(mime->filters))
|
|
mimeDeleteFilter(mime, filter);
|
|
|
|
/*
|
|
* Loop through the file types and delete any rules...
|
|
*/
|
|
|
|
for (type = (mime_type_t *)cupsArrayFirst(mime->types);
|
|
type;
|
|
type = (mime_type_t *)cupsArrayNext(mime->types))
|
|
mimeDeleteType(mime, type);
|
|
|
|
/*
|
|
* Free the types and filters arrays, and then the MIME database structure.
|
|
*/
|
|
|
|
cupsArrayDelete(mime->types);
|
|
cupsArrayDelete(mime->filters);
|
|
cupsArrayDelete(mime->srcs);
|
|
free(mime);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeDeleteFilter()' - Delete a filter from the MIME database.
|
|
*/
|
|
|
|
void
|
|
mimeDeleteFilter(mime_t *mime, /* I - MIME database */
|
|
mime_filter_t *filter) /* I - Filter */
|
|
{
|
|
DEBUG_printf(("mimeDeleteFilter(mime=%p, filter=%p(%s/%s->%s/%s, cost=%d, "
|
|
"maxsize=" CUPS_LLFMT "))", mime, filter,
|
|
filter ? filter->src->super : "???",
|
|
filter ? filter->src->type : "???",
|
|
filter ? filter->dst->super : "???",
|
|
filter ? filter->dst->super : "???",
|
|
filter ? filter->cost : -1,
|
|
filter ? CUPS_LLCAST filter->maxsize : CUPS_LLCAST -1));
|
|
|
|
if (!mime || !filter)
|
|
return;
|
|
|
|
#ifdef DEBUG
|
|
if (!cupsArrayFind(mime->filters, filter))
|
|
DEBUG_puts("1mimeDeleteFilter: Filter not in MIME database.");
|
|
#endif /* DEBUG */
|
|
|
|
cupsArrayRemove(mime->filters, filter);
|
|
free(filter);
|
|
|
|
/*
|
|
* Deleting a filter invalidates the source lookup cache used by
|
|
* mimeFilter()...
|
|
*/
|
|
|
|
if (mime->srcs)
|
|
{
|
|
DEBUG_puts("1mimeDeleteFilter: Deleting source lookup cache.");
|
|
cupsArrayDelete(mime->srcs);
|
|
mime->srcs = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeDeleteType()' - Delete a type from the MIME database.
|
|
*/
|
|
|
|
void
|
|
mimeDeleteType(mime_t *mime, /* I - MIME database */
|
|
mime_type_t *mt) /* I - Type */
|
|
{
|
|
DEBUG_printf(("mimeDeleteType(mime=%p, mt=%p(%s/%s))", mime, mt,
|
|
mt ? mt->super : "???", mt ? mt->type : "???"));
|
|
|
|
if (!mime || !mt)
|
|
return;
|
|
|
|
#ifdef DEBUG
|
|
if (!cupsArrayFind(mime->types, mt))
|
|
DEBUG_puts("1mimeDeleteFilter: Type not in MIME database.");
|
|
#endif /* DEBUG */
|
|
|
|
cupsArrayRemove(mime->types, mt);
|
|
|
|
mime_delete_rules(mt->rules);
|
|
free(mt);
|
|
}
|
|
|
|
|
|
/*
|
|
* '_mimeError()' - Show an error message.
|
|
*/
|
|
|
|
void
|
|
_mimeError(mime_t *mime, /* I - MIME database */
|
|
const char *message, /* I - Printf-style message string */
|
|
...) /* I - Additional arguments as needed */
|
|
{
|
|
va_list ap; /* Argument pointer */
|
|
char buffer[8192]; /* Message buffer */
|
|
|
|
|
|
if (mime->error_cb)
|
|
{
|
|
va_start(ap, message);
|
|
vsnprintf(buffer, sizeof(buffer), message, ap);
|
|
va_end(ap);
|
|
|
|
(*mime->error_cb)(mime->error_ctx, buffer);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeFirstFilter()' - Get the first filter in the MIME database.
|
|
*/
|
|
|
|
mime_filter_t * /* O - Filter or NULL */
|
|
mimeFirstFilter(mime_t *mime) /* I - MIME database */
|
|
{
|
|
DEBUG_printf(("6mimeFirstFilter(mime=%p)", mime));
|
|
|
|
if (!mime)
|
|
{
|
|
DEBUG_puts("7mimeFirstFilter: Returning NULL.");
|
|
return (NULL);
|
|
}
|
|
else
|
|
{
|
|
mime_filter_t *first = (mime_filter_t *)cupsArrayFirst(mime->filters);
|
|
/* First filter */
|
|
|
|
DEBUG_printf(("7mimeFirstFilter: Returning %p.", first));
|
|
return (first);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeFirstType()' - Get the first type in the MIME database.
|
|
*/
|
|
|
|
mime_type_t * /* O - Type or NULL */
|
|
mimeFirstType(mime_t *mime) /* I - MIME database */
|
|
{
|
|
DEBUG_printf(("6mimeFirstType(mime=%p)", mime));
|
|
|
|
if (!mime)
|
|
{
|
|
DEBUG_puts("7mimeFirstType: Returning NULL.");
|
|
return (NULL);
|
|
}
|
|
else
|
|
{
|
|
mime_type_t *first = (mime_type_t *)cupsArrayFirst(mime->types);
|
|
/* First type */
|
|
|
|
DEBUG_printf(("7mimeFirstType: Returning %p.", first));
|
|
return (first);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeLoad()' - Create a new MIME database from disk.
|
|
*
|
|
* This function uses @link mimeLoadFilters@ and @link mimeLoadTypes@ to
|
|
* create a MIME database from a single directory.
|
|
*/
|
|
|
|
mime_t * /* O - New MIME database */
|
|
mimeLoad(const char *pathname, /* I - Directory to load */
|
|
const char *filterpath) /* I - Directory to load */
|
|
{
|
|
mime_t *mime; /* New MIME database */
|
|
|
|
DEBUG_printf(("mimeLoad(pathname=\"%s\", filterpath=\"%s\")", pathname,
|
|
filterpath));
|
|
|
|
mime = mimeLoadFilters(mimeLoadTypes(NULL, pathname), pathname, filterpath);
|
|
DEBUG_printf(("1mimeLoad: Returning %p.", mime));
|
|
|
|
return (mime);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeLoadFilters()' - Load filter definitions from disk.
|
|
*
|
|
* This function loads all of the .convs files from the specified directory.
|
|
* Use @link mimeLoadTypes@ to load all types before you load the filters.
|
|
*/
|
|
|
|
mime_t * /* O - MIME database */
|
|
mimeLoadFilters(mime_t *mime, /* I - MIME database */
|
|
const char *pathname, /* I - Directory to load from */
|
|
const char *filterpath) /* I - Default filter program directory */
|
|
{
|
|
cups_dir_t *dir; /* Directory */
|
|
cups_dentry_t *dent; /* Directory entry */
|
|
char filename[1024]; /* Full filename of .convs file */
|
|
cups_array_t *filtercache; /* Filter cache */
|
|
|
|
|
|
DEBUG_printf(("mimeLoadFilters(mime=%p, pathname=\"%s\", filterpath=\"%s\")",
|
|
mime, pathname, filterpath));
|
|
|
|
/*
|
|
* Range check input...
|
|
*/
|
|
|
|
if (!mime || !pathname || !filterpath)
|
|
{
|
|
DEBUG_puts("1mimeLoadFilters: Bad arguments.");
|
|
return (mime);
|
|
}
|
|
|
|
/*
|
|
* Then open the directory specified by pathname...
|
|
*/
|
|
|
|
if ((dir = cupsDirOpen(pathname)) == NULL)
|
|
{
|
|
DEBUG_printf(("1mimeLoadFilters: Unable to open \"%s\": %s", pathname,
|
|
strerror(errno)));
|
|
_mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno));
|
|
return (mime);
|
|
}
|
|
|
|
/*
|
|
* Read all the .convs files...
|
|
*/
|
|
|
|
filtercache = cupsArrayNew((cups_array_func_t)mime_compare_fcache, NULL);
|
|
|
|
while ((dent = cupsDirRead(dir)) != NULL)
|
|
{
|
|
if (strlen(dent->filename) > 6 &&
|
|
!strcmp(dent->filename + strlen(dent->filename) - 6, ".convs"))
|
|
{
|
|
/*
|
|
* Load a mime.convs file...
|
|
*/
|
|
|
|
snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
|
|
DEBUG_printf(("1mimeLoadFilters: Loading \"%s\".", filename));
|
|
mime_load_convs(mime, filename, filterpath, filtercache);
|
|
}
|
|
}
|
|
|
|
mime_delete_fcache(filtercache);
|
|
|
|
cupsDirClose(dir);
|
|
|
|
return (mime);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeLoadTypes()' - Load type definitions from disk.
|
|
*
|
|
* This function loads all of the .types files from the specified directory.
|
|
* Use @link mimeLoadFilters@ to load all filters after you load the types.
|
|
*/
|
|
|
|
mime_t * /* O - MIME database */
|
|
mimeLoadTypes(mime_t *mime, /* I - MIME database or @code NULL@ to create a new one */
|
|
const char *pathname) /* I - Directory to load from */
|
|
{
|
|
cups_dir_t *dir; /* Directory */
|
|
cups_dentry_t *dent; /* Directory entry */
|
|
char filename[1024]; /* Full filename of .types file */
|
|
|
|
|
|
DEBUG_printf(("mimeLoadTypes(mime=%p, pathname=\"%s\")", mime, pathname));
|
|
|
|
/*
|
|
* First open the directory specified by pathname...
|
|
*/
|
|
|
|
if ((dir = cupsDirOpen(pathname)) == NULL)
|
|
{
|
|
DEBUG_printf(("1mimeLoadTypes: Unable to open \"%s\": %s", pathname,
|
|
strerror(errno)));
|
|
DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime));
|
|
_mimeError(mime, "Unable to open \"%s\": %s", pathname, strerror(errno));
|
|
return (mime);
|
|
}
|
|
|
|
/*
|
|
* If "mime" is NULL, make a new, empty database...
|
|
*/
|
|
|
|
if (!mime)
|
|
mime = mimeNew();
|
|
|
|
if (!mime)
|
|
{
|
|
cupsDirClose(dir);
|
|
DEBUG_puts("1mimeLoadTypes: Returning NULL.");
|
|
return (NULL);
|
|
}
|
|
|
|
/*
|
|
* Read all the .types files...
|
|
*/
|
|
|
|
while ((dent = cupsDirRead(dir)) != NULL)
|
|
{
|
|
if (strlen(dent->filename) > 6 &&
|
|
!strcmp(dent->filename + strlen(dent->filename) - 6, ".types"))
|
|
{
|
|
/*
|
|
* Load a mime.types file...
|
|
*/
|
|
|
|
snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
|
|
DEBUG_printf(("1mimeLoadTypes: Loading \"%s\".", filename));
|
|
mime_load_types(mime, filename);
|
|
}
|
|
}
|
|
|
|
cupsDirClose(dir);
|
|
|
|
DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime));
|
|
|
|
return (mime);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeNew()' - Create a new, empty MIME database.
|
|
*/
|
|
|
|
mime_t * /* O - MIME database */
|
|
mimeNew(void)
|
|
{
|
|
return ((mime_t *)calloc(1, sizeof(mime_t)));
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeNextFilter()' - Get the next filter in the MIME database.
|
|
*/
|
|
|
|
mime_filter_t * /* O - Filter or NULL */
|
|
mimeNextFilter(mime_t *mime) /* I - MIME database */
|
|
{
|
|
DEBUG_printf(("6mimeNextFilter(mime=%p)", mime));
|
|
|
|
if (!mime)
|
|
{
|
|
DEBUG_puts("7mimeNextFilter: Returning NULL.");
|
|
return (NULL);
|
|
}
|
|
else
|
|
{
|
|
mime_filter_t *next = (mime_filter_t *)cupsArrayNext(mime->filters);
|
|
/* Next filter */
|
|
|
|
DEBUG_printf(("7mimeNextFilter: Returning %p.", next));
|
|
return (next);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeNextType()' - Get the next type in the MIME database.
|
|
*/
|
|
|
|
mime_type_t * /* O - Type or NULL */
|
|
mimeNextType(mime_t *mime) /* I - MIME database */
|
|
{
|
|
DEBUG_printf(("6mimeNextType(mime=%p)", mime));
|
|
|
|
if (!mime)
|
|
{
|
|
DEBUG_puts("7mimeNextType: Returning NULL.");
|
|
return (NULL);
|
|
}
|
|
else
|
|
{
|
|
mime_type_t *next = (mime_type_t *)cupsArrayNext(mime->types);
|
|
/* Next type */
|
|
|
|
DEBUG_printf(("7mimeNextType: Returning %p.", next));
|
|
return (next);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeNumFilters()' - Get the number of filters in a MIME database.
|
|
*/
|
|
|
|
int
|
|
mimeNumFilters(mime_t *mime) /* I - MIME database */
|
|
{
|
|
DEBUG_printf(("mimeNumFilters(mime=%p)", mime));
|
|
|
|
if (!mime)
|
|
{
|
|
DEBUG_puts("1mimeNumFilters: Returning 0.");
|
|
return (0);
|
|
}
|
|
else
|
|
{
|
|
DEBUG_printf(("1mimeNumFilters: Returning %d.",
|
|
cupsArrayCount(mime->filters)));
|
|
return (cupsArrayCount(mime->filters));
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeNumTypes()' - Get the number of types in a MIME database.
|
|
*/
|
|
|
|
int
|
|
mimeNumTypes(mime_t *mime) /* I - MIME database */
|
|
{
|
|
DEBUG_printf(("mimeNumTypes(mime=%p)", mime));
|
|
|
|
if (!mime)
|
|
{
|
|
DEBUG_puts("1mimeNumTypes: Returning 0.");
|
|
return (0);
|
|
}
|
|
else
|
|
{
|
|
DEBUG_printf(("1mimeNumTypes: Returning %d.",
|
|
cupsArrayCount(mime->types)));
|
|
return (cupsArrayCount(mime->types));
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mimeSetErrorCallback()' - Set the callback for error messages.
|
|
*/
|
|
|
|
void
|
|
mimeSetErrorCallback(
|
|
mime_t *mime, /* I - MIME database */
|
|
mime_error_cb_t cb, /* I - Callback function */
|
|
void *ctx) /* I - Context pointer for callback */
|
|
{
|
|
if (mime)
|
|
{
|
|
mime->error_cb = cb;
|
|
mime->error_ctx = ctx;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mime_add_fcache()' - Add a filter to the filter cache.
|
|
*/
|
|
|
|
static const char * /* O - Full path to filter or NULL */
|
|
mime_add_fcache(
|
|
cups_array_t *filtercache, /* I - Filter cache */
|
|
const char *name, /* I - Filter name */
|
|
const char *filterpath) /* I - Filter path */
|
|
{
|
|
_mime_fcache_t key, /* Search key */
|
|
*temp; /* New filter cache */
|
|
char path[1024]; /* Full path to filter */
|
|
|
|
|
|
DEBUG_printf(("2mime_add_fcache(filtercache=%p, name=\"%s\", "
|
|
"filterpath=\"%s\")", filtercache, name, filterpath));
|
|
|
|
key.name = (char *)name;
|
|
if ((temp = (_mime_fcache_t *)cupsArrayFind(filtercache, &key)) != NULL)
|
|
{
|
|
DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path));
|
|
return (temp->path);
|
|
}
|
|
|
|
if ((temp = calloc(1, sizeof(_mime_fcache_t))) == NULL)
|
|
{
|
|
DEBUG_puts("3mime_add_fcache: Returning NULL.");
|
|
return (NULL);
|
|
}
|
|
|
|
temp->name = strdup(name);
|
|
|
|
if (cupsFileFind(name, filterpath, 1, path, sizeof(path)))
|
|
temp->path = strdup(path);
|
|
|
|
cupsArrayAdd(filtercache, temp);
|
|
|
|
DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path));
|
|
return (temp->path);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mime_compare_fcache()' - Compare two filter cache entries.
|
|
*/
|
|
|
|
static int /* O - Result of comparison */
|
|
mime_compare_fcache(_mime_fcache_t *a, /* I - First entry */
|
|
_mime_fcache_t *b) /* I - Second entry */
|
|
{
|
|
return (strcmp(a->name, b->name));
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mime_delete_fcache()' - Free all memory used by the filter cache.
|
|
*/
|
|
|
|
static void
|
|
mime_delete_fcache(
|
|
cups_array_t *filtercache) /* I - Filter cache */
|
|
{
|
|
_mime_fcache_t *current; /* Current cache entry */
|
|
|
|
|
|
DEBUG_printf(("2mime_delete_fcache(filtercache=%p)", filtercache));
|
|
|
|
for (current = (_mime_fcache_t *)cupsArrayFirst(filtercache);
|
|
current;
|
|
current = (_mime_fcache_t *)cupsArrayNext(filtercache))
|
|
{
|
|
free(current->name);
|
|
|
|
if (current->path)
|
|
free(current->path);
|
|
|
|
free(current);
|
|
}
|
|
|
|
cupsArrayDelete(filtercache);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mime_delete_rules()' - Free all memory for the given rule tree.
|
|
*/
|
|
|
|
static void
|
|
mime_delete_rules(mime_magic_t *rules) /* I - Rules to free */
|
|
{
|
|
mime_magic_t *next; /* Next rule to free */
|
|
|
|
|
|
DEBUG_printf(("2mime_delete_rules(rules=%p)", rules));
|
|
|
|
/*
|
|
* Free the rules list, descending recursively to free any child rules.
|
|
*/
|
|
|
|
while (rules != NULL)
|
|
{
|
|
next = rules->next;
|
|
|
|
if (rules->child != NULL)
|
|
mime_delete_rules(rules->child);
|
|
|
|
if (rules->op == MIME_MAGIC_REGEX)
|
|
regfree(&(rules->value.rev));
|
|
|
|
free(rules);
|
|
rules = next;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mime_load_convs()' - Load a xyz.convs file.
|
|
*/
|
|
|
|
static void
|
|
mime_load_convs(
|
|
mime_t *mime, /* I - MIME database */
|
|
const char *filename, /* I - Convs file to load */
|
|
const char *filterpath, /* I - Path for filters */
|
|
cups_array_t *filtercache) /* I - Filter program cache */
|
|
{
|
|
cups_file_t *fp; /* Convs file */
|
|
char line[1024], /* Input line from file */
|
|
*lineptr, /* Current position in line */
|
|
super[MIME_MAX_SUPER], /* Super-type name */
|
|
type[MIME_MAX_TYPE], /* Type name */
|
|
*temp, /* Temporary pointer */
|
|
*filter; /* Filter program */
|
|
mime_type_t *temptype, /* MIME type looping var */
|
|
*dsttype; /* Destination MIME type */
|
|
int cost; /* Cost of filter */
|
|
|
|
|
|
DEBUG_printf(("2mime_load_convs(mime=%p, filename=\"%s\", filterpath=\"%s\", "
|
|
"filtercache=%p)", mime, filename, filterpath, filtercache));
|
|
|
|
/*
|
|
* First try to open the file...
|
|
*/
|
|
|
|
if ((fp = cupsFileOpen(filename, "r")) == NULL)
|
|
{
|
|
DEBUG_printf(("3mime_load_convs: Unable to open \"%s\": %s", filename,
|
|
strerror(errno)));
|
|
_mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno));
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Then read each line from the file, skipping any comments in the file...
|
|
*/
|
|
|
|
while (cupsFileGets(fp, line, sizeof(line)) != NULL)
|
|
{
|
|
/*
|
|
* Skip blank lines and lines starting with a #...
|
|
*/
|
|
|
|
if (!line[0] || line[0] == '#')
|
|
continue;
|
|
|
|
/*
|
|
* Strip trailing whitespace...
|
|
*/
|
|
|
|
for (lineptr = line + strlen(line) - 1;
|
|
lineptr >= line && isspace(*lineptr & 255);
|
|
lineptr --)
|
|
*lineptr = '\0';
|
|
|
|
/*
|
|
* Extract the destination super-type and type names from the middle of
|
|
* the line.
|
|
*/
|
|
|
|
lineptr = line;
|
|
while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
|
|
lineptr ++;
|
|
|
|
while (*lineptr == ' ' || *lineptr == '\t')
|
|
lineptr ++;
|
|
|
|
temp = super;
|
|
|
|
while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
|
|
(temp - super + 1) < MIME_MAX_SUPER)
|
|
*temp++ = (char)tolower(*lineptr++ & 255);
|
|
|
|
*temp = '\0';
|
|
|
|
if (*lineptr != '/')
|
|
continue;
|
|
|
|
lineptr ++;
|
|
temp = type;
|
|
|
|
while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
|
|
*lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
|
|
*temp++ = (char)tolower(*lineptr++ & 255);
|
|
|
|
*temp = '\0';
|
|
|
|
if (*lineptr == '\0' || *lineptr == '\n')
|
|
continue;
|
|
|
|
if ((dsttype = mimeType(mime, super, type)) == NULL)
|
|
{
|
|
DEBUG_printf(("3mime_load_convs: Destination type %s/%s not found.",
|
|
super, type));
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Then get the cost and filter program...
|
|
*/
|
|
|
|
while (*lineptr == ' ' || *lineptr == '\t')
|
|
lineptr ++;
|
|
|
|
if (*lineptr < '0' || *lineptr > '9')
|
|
continue;
|
|
|
|
cost = atoi(lineptr);
|
|
|
|
while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
|
|
lineptr ++;
|
|
while (*lineptr == ' ' || *lineptr == '\t')
|
|
lineptr ++;
|
|
|
|
if (*lineptr == '\0' || *lineptr == '\n')
|
|
continue;
|
|
|
|
filter = lineptr;
|
|
|
|
if (strcmp(filter, "-"))
|
|
{
|
|
/*
|
|
* Verify that the filter exists and is executable...
|
|
*/
|
|
|
|
if (!mime_add_fcache(filtercache, filter, filterpath))
|
|
{
|
|
DEBUG_printf(("mime_load_convs: Filter %s not found in %s.", filter,
|
|
filterpath));
|
|
_mimeError(mime, "Filter \"%s\" not found.", filter);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Finally, get the source super-type and type names from the beginning of
|
|
* the line. We do it here so we can support wildcards...
|
|
*/
|
|
|
|
lineptr = line;
|
|
temp = super;
|
|
|
|
while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
|
|
(temp - super + 1) < MIME_MAX_SUPER)
|
|
*temp++ = (char)tolower(*lineptr++ & 255);
|
|
|
|
*temp = '\0';
|
|
|
|
if (*lineptr != '/')
|
|
continue;
|
|
|
|
lineptr ++;
|
|
temp = type;
|
|
|
|
while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
|
|
*lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
|
|
*temp++ = (char)tolower(*lineptr++ & 255);
|
|
|
|
*temp = '\0';
|
|
|
|
if (!strcmp(super, "*") && !strcmp(type, "*"))
|
|
{
|
|
/*
|
|
* Force * / * to be "application/octet-stream"...
|
|
*/
|
|
|
|
strlcpy(super, "application", sizeof(super));
|
|
strlcpy(type, "octet-stream", sizeof(type));
|
|
}
|
|
|
|
/*
|
|
* Add the filter to the MIME database, supporting wildcards as needed...
|
|
*/
|
|
|
|
for (temptype = (mime_type_t *)cupsArrayFirst(mime->types);
|
|
temptype;
|
|
temptype = (mime_type_t *)cupsArrayNext(mime->types))
|
|
if ((super[0] == '*' || !strcmp(temptype->super, super)) &&
|
|
(type[0] == '*' || !strcmp(temptype->type, type)))
|
|
mimeAddFilter(mime, temptype, dsttype, cost, filter);
|
|
}
|
|
|
|
cupsFileClose(fp);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'mime_load_types()' - Load a xyz.types file.
|
|
*/
|
|
|
|
static void
|
|
mime_load_types(mime_t *mime, /* I - MIME database */
|
|
const char *filename) /* I - Types file to load */
|
|
{
|
|
cups_file_t *fp; /* Types file */
|
|
size_t linelen; /* Length of line */
|
|
char line[32768], /* Input line from file */
|
|
*lineptr, /* Current position in line */
|
|
super[MIME_MAX_SUPER], /* Super-type name */
|
|
type[MIME_MAX_TYPE], /* Type name */
|
|
*temp; /* Temporary pointer */
|
|
mime_type_t *typeptr; /* New MIME type */
|
|
|
|
|
|
DEBUG_printf(("2mime_load_types(mime=%p, filename=\"%s\")", mime, filename));
|
|
|
|
/*
|
|
* First try to open the file...
|
|
*/
|
|
|
|
if ((fp = cupsFileOpen(filename, "r")) == NULL)
|
|
{
|
|
DEBUG_printf(("3mime_load_types: Unable to open \"%s\": %s", filename,
|
|
strerror(errno)));
|
|
_mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno));
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Then read each line from the file, skipping any comments in the file...
|
|
*/
|
|
|
|
while (cupsFileGets(fp, line, sizeof(line)) != NULL)
|
|
{
|
|
/*
|
|
* Skip blank lines and lines starting with a #...
|
|
*/
|
|
|
|
if (!line[0] || line[0] == '#')
|
|
continue;
|
|
|
|
/*
|
|
* While the last character in the line is a backslash, continue on to the
|
|
* next line (and the next, etc.)
|
|
*/
|
|
|
|
linelen = strlen(line);
|
|
|
|
while (line[linelen - 1] == '\\')
|
|
{
|
|
linelen --;
|
|
|
|
if (cupsFileGets(fp, line + linelen, sizeof(line) - linelen) == NULL)
|
|
line[linelen] = '\0';
|
|
else
|
|
linelen += strlen(line + linelen);
|
|
}
|
|
|
|
/*
|
|
* Extract the super-type and type names from the beginning of the line.
|
|
*/
|
|
|
|
lineptr = line;
|
|
temp = super;
|
|
|
|
while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
|
|
(temp - super + 1) < MIME_MAX_SUPER)
|
|
*temp++ = (char)tolower(*lineptr++ & 255);
|
|
|
|
*temp = '\0';
|
|
|
|
if (*lineptr != '/')
|
|
continue;
|
|
|
|
lineptr ++;
|
|
temp = type;
|
|
|
|
while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
|
|
*lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
|
|
*temp++ = (char)tolower(*lineptr++ & 255);
|
|
|
|
*temp = '\0';
|
|
|
|
/*
|
|
* Add the type and rules to the MIME database...
|
|
*/
|
|
|
|
typeptr = mimeAddType(mime, super, type);
|
|
mimeAddTypeRule(typeptr, lineptr);
|
|
}
|
|
|
|
cupsFileClose(fp);
|
|
}
|