#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <cups/debug.h>
#include <cups/dir.h>
#include <cups/string.h>
#include "mime.h"
typedef struct _mime_fcache_s
{
char *name,
*path;
} _mime_fcache_t;
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);
void
mimeDelete(mime_t *mime)
{
mime_type_t *type;
mime_filter_t *filter;
if (!mime)
return;
for (filter = (mime_filter_t *)cupsArrayFirst(mime->filters);
filter;
filter = (mime_filter_t *)cupsArrayNext(mime->filters))
mimeDeleteFilter(mime, filter);
for (type = (mime_type_t *)cupsArrayFirst(mime->types);
type;
type = (mime_type_t *)cupsArrayNext(mime->types))
mimeDeleteType(mime, type);
cupsArrayDelete(mime->types);
cupsArrayDelete(mime->filters);
cupsArrayDelete(mime->srcs);
free(mime);
}
void
mimeDeleteFilter(mime_t *mime,
mime_filter_t *filter)
{
if (!mime || !filter)
return;
cupsArrayRemove(mime->filters, filter);
free(filter);
if (mime->srcs)
{
cupsArrayDelete(mime->srcs);
mime->srcs = NULL;
}
}
void
mimeDeleteType(mime_t *mime,
mime_type_t *mt)
{
if (!mime || !mt)
return;
cupsArrayRemove(mime->types, mt);
delete_rules(mt->rules);
free(mt);
}
mime_filter_t *
mimeFirstFilter(mime_t *mime)
{
if (!mime)
return (NULL);
else
return ((mime_filter_t *)cupsArrayFirst(mime->filters));
}
mime_type_t *
mimeFirstType(mime_t *mime)
{
if (!mime)
return (NULL);
else
return ((mime_type_t *)cupsArrayFirst(mime->types));
}
mime_t *
mimeLoad(const char *pathname,
const char *filterpath)
{
return (mimeMerge(NULL, pathname, filterpath));
}
mime_t *
mimeMerge(mime_t *mime,
const char *pathname,
const char *filterpath)
{
cups_dir_t *dir;
cups_dentry_t *dent;
char filename[1024];
cups_array_t *filtercache;
if (!pathname)
return (NULL);
if ((dir = cupsDirOpen(pathname)) == NULL)
return (NULL);
if (!mime)
mime = mimeNew();
if (!mime)
return (NULL);
while ((dent = cupsDirRead(dir)) != NULL)
{
if (strlen(dent->filename) > 6 &&
!strcmp(dent->filename + strlen(dent->filename) - 6, ".types"))
{
snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
load_types(mime, filename);
}
}
cupsDirRewind(dir);
filtercache = cupsArrayNew((cups_array_func_t)compare_fcache, NULL);
while ((dent = cupsDirRead(dir)) != NULL)
{
if (strlen(dent->filename) > 6 &&
!strcmp(dent->filename + strlen(dent->filename) - 6, ".convs"))
{
snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->filename);
load_convs(mime, filename, filterpath, filtercache);
}
}
delete_fcache(filtercache);
cupsDirClose(dir);
return (mime);
}
mime_t *
mimeNew(void)
{
return ((mime_t *)calloc(1, sizeof(mime_t)));
}
mime_filter_t *
mimeNextFilter(mime_t *mime)
{
if (!mime)
return (NULL);
else
return ((mime_filter_t *)cupsArrayNext(mime->filters));
}
mime_type_t *
mimeNextType(mime_t *mime)
{
if (!mime)
return (NULL);
else
return ((mime_type_t *)cupsArrayNext(mime->types));
}
int
mimeNumFilters(mime_t *mime)
{
if (!mime)
return (0);
else
return (cupsArrayCount(mime->filters));
}
int
mimeNumTypes(mime_t *mime)
{
if (!mime)
return (0);
else
return (cupsArrayCount(mime->types));
}
static const char *
add_fcache(cups_array_t *filtercache,
const char *name,
const char *filterpath)
{
_mime_fcache_t key,
*temp;
char path[1024];
key.name = (char *)name;
if ((temp = (_mime_fcache_t *)cupsArrayFind(filtercache, &key)) != NULL)
return (temp->path);
if ((temp = calloc(1, sizeof(_mime_fcache_t))) == NULL)
return (NULL);
temp->name = strdup(name);
if (cupsFileFind(name, filterpath, 1, path, sizeof(path)))
temp->path = strdup(path);
cupsArrayAdd(filtercache, temp);
return (temp->path);
}
static int
compare_fcache(_mime_fcache_t *a,
_mime_fcache_t *b)
{
return (strcmp(a->name, b->name));
}
static void
delete_fcache(cups_array_t *filtercache)
{
_mime_fcache_t *current;
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);
}
static void
delete_rules(mime_magic_t *rules)
{
mime_magic_t *next;
while (rules != NULL)
{
next = rules->next;
if (rules->child != NULL)
delete_rules(rules->child);
free(rules);
rules = next;
}
}
static void
load_convs(mime_t *mime,
const char *filename,
const char *filterpath,
cups_array_t *filtercache)
{
cups_file_t *fp;
char line[1024],
*lineptr,
super[MIME_MAX_SUPER],
type[MIME_MAX_TYPE],
*temp,
*filter;
mime_type_t *temptype,
*dsttype;
int cost;
if ((fp = cupsFileOpen(filename, "r")) == NULL)
return;
DEBUG_printf(("\"%s\":\n", filename));
while (cupsFileGets(fp, line, sizeof(line)) != NULL)
{
DEBUG_puts(line);
if (!line[0] || line[0] == '#')
continue;
for (lineptr = line + strlen(line) - 1;
lineptr >= line && isspace(*lineptr & 255);
lineptr --)
*lineptr = '\0';
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++ = 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++ = tolower(*lineptr++ & 255);
*temp = '\0';
if (*lineptr == '\0' || *lineptr == '\n')
continue;
if ((dsttype = mimeType(mime, super, type)) == NULL)
{
DEBUG_printf((" Destination type %s/%s not found!\n", super, type));
continue;
}
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, "-"))
{
if (!add_fcache(filtercache, filter, filterpath))
{
DEBUG_printf((" Filter %s not found in %s!\n", filter, filterpath));
continue;
}
}
lineptr = line;
temp = super;
while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
(temp - super + 1) < MIME_MAX_SUPER)
*temp++ = 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++ = tolower(*lineptr++ & 255);
*temp = '\0';
if (!strcmp(super, "*") && !strcmp(type, "*"))
{
strcpy(super, "application");
strcpy(type, "octet-stream");
}
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);
}
static void
load_types(mime_t *mime,
const char *filename)
{
cups_file_t *fp;
int linelen;
char line[32768],
*lineptr,
super[MIME_MAX_SUPER],
type[MIME_MAX_TYPE],
*temp;
mime_type_t *typeptr;
if ((fp = cupsFileOpen(filename, "r")) == NULL)
return;
DEBUG_printf(("\"%s\":\n", filename));
while (cupsFileGets(fp, line, sizeof(line)) != NULL)
{
DEBUG_puts(line);
if (!line[0] || line[0] == '#')
continue;
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);
}
lineptr = line;
temp = super;
while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
(temp - super + 1) < MIME_MAX_SUPER)
*temp++ = 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++ = tolower(*lineptr++ & 255);
*temp = '\0';
typeptr = mimeAddType(mime, super, type);
mimeAddTypeRule(typeptr, lineptr);
}
cupsFileClose(fp);
}