/*
- * "$Id: mime.c 181 2006-06-22 20:01:18Z jlovell $"
+ * "$Id$"
*
- * MIME database file routines for the Common UNIX Printing System (CUPS).
+ * MIME database file routines for CUPS.
*
+ * Copyright 2007-2012 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* Contents:
*
- * mimeDelete() - Delete (free) a MIME database.
- * mimeDeleteFilter() - Delete a filter from the MIME database.
- * mimeDeleteType() - Delete a type from the MIME database.
- * mimeFirstFilter() - Get the first filter in the MIME database.
- * mimeFirstType() - Get the first type in the MIME database.
- * mimeLoad() - Create a new MIME database from disk.
- * mimeMerge() - Merge a MIME database from disk with the current one.
- * mimeNew() - Create a new, empty MIME database.
- * mimeNextFilter() - Get the next filter in the MIME database.
- * mimeNextType() - Get the next type in the MIME database.
- * mimeNumFilters() - Get the number of filters in a MIME database.
- * mimeNumTypes() - Get the number of types in a MIME database.
- * add_fcache() - Add a filter to the filter cache.
- * compare_fcache() - Compare two filter cache entries.
- * delete_fcache() - Free all memory used by the filter cache.
- * delete_rules() - Free all memory for the given rule tree.
- * load_convs() - Load a xyz.convs file...
- * load_types() - Load a xyz.types file...
+ * mimeDelete() - Delete (free) a MIME database.
+ * mimeDeleteFilter() - Delete a filter from the MIME database.
+ * mimeDeleteType() - Delete a type from the MIME database.
+ * _mimeError() - Show an error message.
+ * mimeFirstFilter() - Get the first filter in the MIME database.
+ * mimeFirstType() - Get the first type in the MIME database.
+ * mimeLoad() - Create a new MIME database from disk.
+ * mimeLoadFilters() - Load filter definitions from disk.
+ * mimeLoadTypes() - Load type definitions from disk.
+ * mimeNew() - Create a new, empty MIME database.
+ * mimeNextFilter() - Get the next filter in the MIME database.
+ * mimeNextType() - Get the next type in the MIME database.
+ * mimeNumFilters() - Get the number of filters in a MIME database.
+ * mimeNumTypes() - Get the number of types in a MIME database.
+ * mimeSetErrorCallback() - Set the callback for error messages.
+ * mime_add_fcache() - Add a filter to the filter cache.
+ * mime_compare_fcache() - Compare two filter cache entries.
+ * mime_delete_fcache() - Free all memory used by the filter cache.
+ * mime_delete_rules() - Free all memory for the given rule tree.
+ * mime_load_convs() - Load a xyz.convs file.
+ * mime_load_types() - Load a xyz.types file.
*/
/*
* Include necessary headers...
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#include <cups/debug.h>
+#include <cups/string-private.h>
+#include <cups/debug-private.h>
#include <cups/dir.h>
-#include <cups/string.h>
-#include "mime.h"
+#include "mime-private.h"
/*
* Local functions...
*/
-static const char *add_fcache(cups_array_t *filtercache, const char *name,
- const char *filterpath);
-static int compare_fcache(_mime_fcache_t *a, _mime_fcache_t *b);
-static void delete_fcache(cups_array_t *filtercache);
-static void delete_rules(mime_magic_t *rules);
-static void load_convs(mime_t *mime, const char *filename,
- const char *filterpath,
- cups_array_t *filtercache);
-static void load_types(mime_t *mime, const char *filename);
+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);
/*
mime_filter_t *filter; /* Current filter */
+ DEBUG_printf(("mimeDelete(mime=%p)", mime));
+
if (!mime)
return;
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);
if (mime->srcs)
{
+ DEBUG_puts("1mimeDeleteFilter: Deleting source lookup cache.");
cupsArrayDelete(mime->srcs);
mime->srcs = NULL;
}
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);
- delete_rules(mt->rules);
+ 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
- return ((mime_filter_t *)cupsArrayFirst(mime->filters));
+ {
+ mime_filter_t *first = (mime_filter_t *)cupsArrayFirst(mime->filters);
+ /* First filter */
+
+ DEBUG_printf(("7mimeFirstFilter: Returning %p.", first));
+ return (first);
+ }
}
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
- return ((mime_type_t *)cupsArrayFirst(mime->types));
+ {
+ 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 */
{
- return (mimeMerge(NULL, pathname, filterpath));
+ 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);
}
/*
- * 'mimeMerge()' - Merge a MIME database from disk with the current one.
+ * '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 - Updated MIME database */
-mimeMerge(mime_t *mime, /* I - MIME database to add to */
- const char *pathname, /* I - Directory to load */
- const char *filterpath) /* I - Directory to load */
+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 types/converts file */
+ 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));
+
/*
- * First open the directory specified by pathname... Return NULL if nothing
- * was read or if the pathname is NULL...
+ * Range check input...
*/
- if (!pathname)
- return (NULL);
-
- if ((dir = cupsDirOpen(pathname)) == NULL)
- return (NULL);
+ if (!mime || !pathname || !filterpath)
+ {
+ DEBUG_puts("1mimeLoadFilters: Bad arguments.");
+ return (mime);
+ }
/*
- * If "mime" is NULL, make a new, blank database...
+ * Then open the directory specified by pathname...
*/
- if (!mime)
- mime = mimeNew();
- if (!mime)
- return (NULL);
+ 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 .types files...
+ * 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, ".types"))
+ !strcmp(dent->filename + strlen(dent->filename) - 6, ".convs"))
{
/*
- * Load a mime.types file...
+ * Load a mime.convs file...
*/
snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
- load_types(mime, filename);
+ DEBUG_printf(("1mimeLoadFilters: Loading \"%s\".", filename));
+ mime_load_convs(mime, filename, filterpath, filtercache);
}
}
- cupsDirRewind(dir);
+ 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));
/*
- * Read all the .convs files...
+ * 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...
*/
- filtercache = cupsArrayNew((cups_array_func_t)compare_fcache, NULL);
+ 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, ".convs"))
+ !strcmp(dent->filename + strlen(dent->filename) - 6, ".types"))
{
/*
- * Load a mime.convs file...
+ * Load a mime.types file...
*/
snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
- load_convs(mime, filename, filterpath, filtercache);
+ DEBUG_printf(("1mimeLoadTypes: Loading \"%s\".", filename));
+ mime_load_types(mime, filename);
}
}
- delete_fcache(filtercache);
-
cupsDirClose(dir);
+ DEBUG_printf(("1mimeLoadTypes: Returning %p.", mime));
+
return (mime);
}
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
- return ((mime_filter_t *)cupsArrayNext(mime->filters));
+ {
+ mime_filter_t *next = (mime_filter_t *)cupsArrayNext(mime->filters);
+ /* Next filter */
+
+ DEBUG_printf(("7mimeNextFilter: Returning %p.", next));
+ return (next);
+ }
}
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
- return ((mime_type_t *)cupsArrayNext(mime->types));
+ {
+ mime_type_t *next = (mime_type_t *)cupsArrayNext(mime->types);
+ /* Next type */
+
+ DEBUG_printf(("7mimeNextType: Returning %p.", next));
+ return (next);
+ }
}
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));
+ }
}
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;
+ }
}
/*
- * 'add_fcache()' - Add a filter to the filter cache.
+ * 'mime_add_fcache()' - Add a filter to the filter cache.
*/
static const char * /* O - Full path to filter or NULL */
-add_fcache(cups_array_t *filtercache, /* I - Filter cache */
- const char *name, /* I - Filter name */
- const char *filterpath) /* I - Filter path */
+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);
cupsArrayAdd(filtercache, temp);
+ DEBUG_printf(("3mime_add_fcache: Returning \"%s\".", temp->path));
return (temp->path);
}
/*
- * 'compare_fcache()' - Compare two filter cache entries.
+ * 'mime_compare_fcache()' - Compare two filter cache entries.
*/
static int /* O - Result of comparison */
-compare_fcache(_mime_fcache_t *a, /* I - First entry */
+mime_compare_fcache(_mime_fcache_t *a, /* I - First entry */
_mime_fcache_t *b) /* I - Second entry */
{
return (strcmp(a->name, b->name));
/*
- * 'delete_fcache()' - Free all memory used by the filter cache.
+ * 'mime_delete_fcache()' - Free all memory used by the filter cache.
*/
static void
-delete_fcache(cups_array_t *filtercache)/* I - Filter cache */
+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))
/*
- * 'delete_rules()' - Free all memory for the given rule tree.
+ * 'mime_delete_rules()' - Free all memory for the given rule tree.
*/
static void
-delete_rules(mime_magic_t *rules) /* I - Rules to free */
+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.
*/
next = rules->next;
if (rules->child != NULL)
- delete_rules(rules->child);
+ mime_delete_rules(rules->child);
free(rules);
rules = next;
/*
- * 'load_convs()' - Load a xyz.convs file...
+ * 'mime_load_convs()' - Load a xyz.convs file.
*/
static void
-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 */
+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 */
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;
-
- DEBUG_printf(("\"%s\":\n", filename));
+ }
/*
* Then read each line from the file, skipping any comments in the file...
* Skip blank lines and lines starting with a #...
*/
- DEBUG_puts(line);
-
if (!line[0] || line[0] == '#')
continue;
if ((dsttype = mimeType(mime, super, type)) == NULL)
{
- DEBUG_printf((" Destination type %s/%s not found!\n", super, type));
+ DEBUG_printf(("3mime_load_convs: Destination type %s/%s not found.",
+ super, type));
continue;
}
* Verify that the filter exists and is executable...
*/
- if (!add_fcache(filtercache, filter, filterpath))
+ if (!mime_add_fcache(filtercache, filter, filterpath))
{
- DEBUG_printf((" Filter %s not found in %s!\n", filter, filterpath));
+ DEBUG_printf(("mime_load_convs: Filter %s not found in %s.", filter,
+ filterpath));
+ _mimeError(mime, "Filter \"%s\" not found.", filter);
continue;
}
}
* Force * / * to be "application/octet-stream"...
*/
- strcpy(super, "application");
- strcpy(type, "octet-stream");
+ strlcpy(super, "application", sizeof(super));
+ strlcpy(type, "octet-stream", sizeof(type));
}
/*
/*
- * 'load_types()' - Load a xyz.types file...
+ * 'mime_load_types()' - Load a xyz.types file.
*/
static void
-load_types(mime_t *mime, /* I - MIME database */
- const char *filename) /* I - Types file to load */
+mime_load_types(mime_t *mime, /* I - MIME database */
+ const char *filename) /* I - Types file to load */
{
cups_file_t *fp; /* Types file */
int linelen; /* Length of line */
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;
-
- DEBUG_printf(("\"%s\":\n", filename));
+ }
/*
* Then read each line from the file, skipping any comments in the file...
* Skip blank lines and lines starting with a #...
*/
- DEBUG_puts(line);
-
if (!line[0] || line[0] == '#')
continue;
/*
- * End of "$Id: mime.c 181 2006-06-22 20:01:18Z jlovell $".
+ * End of "$Id$".
*/