#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <cups/string.h>
#include "mime.h"
#include "cupsd.h"
#ifdef WIN32
# include <windows.h>
#elif HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
#else
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
# define NAMLEN(dirent) (dirent)->d_namlen
#endif
static void load_types(mime_t *mime, const char *filename);
static void load_convs(mime_t *mime, const char *filename,
const char *filterpath);
static void delete_rules(mime_magic_t *rules);
void
mimeDelete(mime_t *mime)
{
int i;
if (mime == NULL)
return;
for (i = 0; i < mime->num_types; i ++)
{
delete_rules(mime->types[i]->rules);
free(mime->types[i]->type);
free(mime->types[i]);
}
free(mime->types);
free(mime->filters);
free(mime);
}
mime_t *
mimeMerge(mime_t *mime,
const char *pathname,
const char *filterpath)
{
#ifdef WIN32
HANDLE dir;
WIN32_FIND_DATA dent;
char filename[1024],
*pathsep;
if (pathname == NULL)
return (NULL);
strlcpy(filename, pathname, sizeof(filename));
pathsep = filename + strlen(filename);
if ((pathsep - filename + 9) > sizeof(filename))
return (NULL);
if (pathsep == filename ||
(pathsep[-1] != '/' && pathsep[-1] != '\\'))
{
strcpy(pathsep, "/");
pathsep ++;
}
strcpy(pathsep, "*.types");
if ((dir = FindFirstFile(filename, &dent)) == 0)
return (NULL);
if (mime == NULL)
if ((mime = mimeNew()) == NULL)
return (NULL);
do
{
if ((pathsep - filename + strlen(dent.cFileName)) >= sizeof(filename))
continue;
strcpy(pathsep, dent.cFileName);
load_types(mime, filename);
}
while (FindNextFile(dir, &dent));
FindClose(dir);
strcpy(pathsep, "*.convs");
if ((dir = FindFirstFile(filename, &dent)) == 0)
return (mime);
do
{
if ((pathsep - filename + strlen(dent.cFileName)) >= sizeof(filename))
continue;
strcpy(pathsep, dent.cFileName);
load_convs(mime, filename);
}
while (FindNextFile(dir, &dent));
FindClose(dir);
return (mime);
#else
DIR *dir;
DIRENT *dent;
char filename[1024];
if (pathname == NULL)
return (NULL);
if ((dir = opendir(pathname)) == NULL)
return (NULL);
if (mime == NULL)
if ((mime = mimeNew()) == NULL)
return (NULL);
while ((dent = readdir(dir)) != NULL)
{
if (NAMLEN(dent) > 6 &&
strcmp(dent->d_name + NAMLEN(dent) - 6, ".types") == 0)
{
snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->d_name);
load_types(mime, filename);
}
}
rewinddir(dir);
while ((dent = readdir(dir)) != NULL)
{
if (NAMLEN(dent) > 6 &&
strcmp(dent->d_name + NAMLEN(dent) - 6, ".convs") == 0)
{
snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->d_name);
load_convs(mime, filename, filterpath);
}
}
closedir(dir);
return (mime);
#endif
}
mime_t *
mimeNew(void)
{
return ((mime_t *)calloc(1, sizeof(mime_t)));
}
static void
load_types(mime_t *mime,
const char *filename)
{
FILE *fp;
int linelen;
char line[65536],
*lineptr,
super[MIME_MAX_SUPER],
type[MIME_MAX_TYPE],
*temp;
mime_type_t *typeptr;
if ((fp = fopen(filename, "r")) == NULL)
return;
while (fgets(line, sizeof(line), fp) != NULL)
{
linelen = strlen(line);
if (line[linelen - 1] == '\n')
{
line[linelen - 1] = '\0';
linelen --;
}
while (line[linelen - 1] == '\\')
{
linelen --;
if (fgets(line + linelen, sizeof(line) - linelen, fp) == NULL)
line[linelen] = '\0';
else
{
linelen += strlen(line + linelen);
if (line[linelen - 1] == '\n')
{
line[linelen - 1] = '\0';
linelen --;
}
}
}
if (line[0] == '\n' || line[0] == '#')
continue;
lineptr = line;
temp = super;
while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
(temp - super + 1) < MIME_MAX_SUPER)
*temp++ = tolower(*lineptr++);
*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++);
*temp = '\0';
typeptr = mimeAddType(mime, super, type);
mimeAddTypeRule(typeptr, lineptr);
}
fclose(fp);
}
static void
load_convs(mime_t *mime,
const char *filename,
const char *filterpath)
{
int i;
FILE *fp;
char line[1024],
*lineptr,
super[MIME_MAX_SUPER],
type[MIME_MAX_TYPE],
*temp,
*filter;
mime_type_t **temptype,
*dsttype;
int cost;
char filterprog[1024];
if ((fp = fopen(filename, "r")) == NULL)
return;
while (fgets(line, sizeof(line), fp) != NULL)
{
if (line[0] == '\n' || line[0] == '#')
continue;
for (lineptr = line + strlen(line) - 1;
lineptr >= line && isspace(*lineptr);
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++);
*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++);
*temp = '\0';
if (*lineptr == '\0' || *lineptr == '\n')
continue;
if ((dsttype = mimeType(mime, super, type)) == NULL)
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;
#ifndef WIN32
if (strcmp(filter, "-") != 0)
{
if (filter[0] == '/')
strlcpy(filterprog, filter, sizeof(filterprog));
else
snprintf(filterprog, sizeof(filterprog), "%s/%s", filterpath, filter);
if (access(filterprog, X_OK))
{
LogMessage(L_ERROR, "Filter \"%s\" cannot be found!", filter);
continue;
}
}
#endif
lineptr = line;
temp = super;
while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
(temp - super + 1) < MIME_MAX_SUPER)
*temp++ = tolower(*lineptr++);
*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++);
*temp = '\0';
if (strcmp(super, "*") == 0 && strcmp(type, "*") == 0)
{
strcpy(super, "application");
strcpy(type, "octet-stream");
}
for (temptype = mime->types, i = 0; i < mime->num_types; i ++, temptype ++)
if ((super[0] == '*' || strcmp((*temptype)->super, super) == 0) &&
(type[0] == '*' || strcmp((*temptype)->type, type) == 0))
mimeAddFilter(mime, *temptype, dsttype, cost, filter);
}
fclose(fp);
}
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;
}
}