/*
** mod_annodex.c -- Apache sample annodex module
** [Autogenerated via ``apxs -n annodex -g'']
**
** To play with this sample module first compile it into a
** DSO file and install it into Apache's modules directory
** by running:
**
** $ apxs -c -i mod_annodex.c
**
** Then activate it in Apache's httpd.conf file for instance
** for the URL /annodex in as follows:
**
** # httpd.conf
** LoadModule annodex_module modules/mod_annodex.so
**
** SetHandler annodex
**
**
** Then after restarting Apache via
**
** $ apachectl restart
**
** you immediately can request the URL /annodex and watch for the
** output of this module. This can be achieved for instance via:
**
** $ lynx -mime_header http://localhost/annodex
**
** The output should be similar to the following one:
**
** HTTP/1.1 200 OK
** Date: Tue, 31 Mar 1998 14:42:22 GMT
** Server: Apache/1.3.4 (Unix)
** Connection: close
** Content-Type: text/html
**
** The sample page from mod_annodex.c
*/
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"
#include "http_core.h"
#include "http_log.h"
#include "ap_compat.h"
#include
#include
#include /* chdir */
#include
#include
#include
/* define __PROTOTYPE to enable mode= parameter */
/* #define __PROTOTYPE */
#define DEBUG
#define ANX_MIME_TYPE "application/annodex"
#define CMML_MIME_TYPE "text/cmml"
#define CMML_PREAMBLE \
"\n"
#define MOD_ANNODEX_TYPE_UNKNOWN -1
#define MOD_ANNODEX_TYPE_ANX 0
#define MOD_ANNODEX_TYPE_CMML 1
#ifdef __PROTOTYPE
#define MOD_ANNODEX_TYPE_MEDIA 2
#endif
#define MAX_CLIP_LEN 32768
/**
* Print a time as npt using ap_rprintf
* \param r the request record
* \param seconds the time to print
* \returns the ap_rprintf return value
*/
static int
rprintf_time_npt (request_rec * r, double seconds)
{
int hrs, min;
double sec;
char * sign;
sign = (seconds < 0.0) ? "-" : "";
if (seconds < 0.0) seconds = -seconds;
hrs = (int) (seconds/3600.0);
min = (int) ((seconds - ((double)hrs * 3600.0)) / 60.0);
sec = seconds - ((double)hrs * 3600.0)- ((double)min * 60.0);
/* XXX: %02.3f workaround */
if (sec < 10.0) {
return ap_rprintf (r, "%s%02d:%02d:0%2.3f", sign, hrs, min, sec);
} else {
return ap_rprintf (r, "%s%02d:%02d:%02.3f", sign, hrs, min, sec);
}
}
/**
* Create a table corresponding to name=value pairs in the query string
* @param r The resource request
* @param query The query string
* @return A newly created table with corresponding name=value keys.
*/
static table *
make_cgi_table (request_rec * r, char * query)
{
table * t;
char * key, * val, * end;
t = make_table (r->pool, 3);
if (!query) return t;
key = query;
do {
val = strchr (key, '=');
end = strchr (key, '&');
if (end) {
if (val) {
if (val < end) {
*val++ = '\0';
} else {
val = NULL;
}
}
*end++ = '\0';
} else {
if (val) *val++ = '\0';
}
/*ap_rprintf (r, "%s = %s\n", key, val);*/
table_set (t, key, val);
key = end;
} while (end != NULL);
return t;
}
/**
* Determine the relative quality factor of a mime_type given the Accept:
* header of a resource request, following rules of RFC2616 Sec. 14.1
* @param r The resource request
* @param mime_type The mime_type to check
* @return The relative quality factor
*/
static float
get_accept_quality (request_rec * r, char * mime_type)
{
char * a, * accept, *next, * last, * pnext, * plast;
float q = 0.0, type_q = 0.0, all_q = 0.0;
char * m_sep, * m_major;
size_t m_major_len;
a = (char *)table_get (r->headers_in, (const char *)"Accept");
/* If there was no Accept: header, accept all types equally */
if (a == NULL) return 1.0;
/* Form a 'major / *' mime type range for later comparison */
m_sep = strchr (mime_type, '/');
m_major_len = (size_t)(m_sep - mime_type);
m_major = pstrndup (r->pool, mime_type, m_major_len + 2);
*(m_major+m_major_len+1) = '*';
*(m_major+m_major_len+2) = '\0';
/* Copy the Accept line for tokenization */
accept = ap_pstrdup (r->pool, a);
#if 0
/* XXX: ??? how to backport to apache 1.3?*/
apr_collapse_spaces (accept, accept);
#endif
next = strtok_r (accept, ",", &last);
while (next) {
pnext = strtok_r (next, ";", &plast);
if (!strcmp (pnext, mime_type)) {
while (pnext) {
pnext = strtok_r (NULL, ";", &plast);
if (pnext && sscanf (pnext, "q=%f", &q) == 1) {
return q;
}
}
return 1.0;
} else if (!strcmp (pnext, "*/*")) {
while (pnext) {
pnext = strtok_r (NULL, ";", &plast);
if (pnext && sscanf (pnext, "q=%f", &q) == 1) {
all_q = q;
}
}
all_q = 1.0;
} else if (!strcmp (pnext, m_major)) {
while (pnext) {
pnext = strtok_r (NULL, ";", &plast);
if (pnext && sscanf (pnext, "q=%f", &q) == 1) {
type_q = q;
}
}
type_q = 1.0;
}
next = strtok_r (NULL, ",", &last);
}
if (q > 0.0) return q;
else if (type_q > 0.0) return type_q;
else return all_q;
}
#ifdef __PROTOTYPE
static int
get_cgi_mode (request_rec * r, table * cgi_table)
{
char * cgi_mode;
cgi_mode = (char *)table_get (cgi_table, "mode");
if (cgi_mode == NULL)
return MOD_ANNODEX_TYPE_UNKNOWN;
#ifdef DEBUG
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"cgi mode %s", cgi_mode);
#endif
if (!strcmp (cgi_mode, "cmml"))
return MOD_ANNODEX_TYPE_CMML;
else if (!strcmp (cgi_mode, "media"))
return MOD_ANNODEX_TYPE_MEDIA;
else
return MOD_ANNODEX_TYPE_UNKNOWN;
}
#endif /* __PROTOTYPE */
static int
prefer_cmml (request_rec * r)
{
float qc, qa;
qc = get_accept_quality (r, CMML_MIME_TYPE);
qa = get_accept_quality (r, ANX_MIME_TYPE);
#ifdef DEBUG
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"Accept CMML %f, Accept ANX %f", qc, qa);
#endif
return (qc > qa);
}
/**
* Parse the first time range in a string; multiple time ranges may be
* separated by commas.
* @param s The string to parse.
* @param range_start The location to store the start of the range.
* @param range_end The location to store the end of the range.
* @return a pointer to the start of the next time range, or NULL if
* no further ranges are specified in s.
*/
static char *
ma_parse_time (char * s, double * range_start, double * range_end)
{
char * sep, * end;
sep = strchr (s, '/');
end = strchr (s, ',');
if (end != NULL) {
/* If we found the separator for the following range, then
* ignore it while processing this range. */
if (sep && end < sep) sep = NULL;
/* Terminate the range for string processing */
*end++ = '\0';
}
if (sep == NULL) {
*range_start = anx_parse_time (s);
*range_end = -1.0;
} else {
/* Terminate the range start */
*sep++ = '\0';
*range_start = anx_parse_time (s);
*range_end = anx_parse_time (sep);
}
return end;
}
static double
ma_anxenc_clip_time (char * filename, char * content_type, char * id)
{
ANNODEX * anx;
int ret;
unsigned char buf[1024];
long n = 1024;
double clip_offset;
anx = anx_new (ANX_WRITE);
ret = anx_write_import (anx, filename, NULL, content_type, 0.0, -1.0, 0);
/* Only spin through the file if the requested clip has not yet been
* inserted; avoid scanning media if 'filename' is a cmml file. */
if ((clip_offset = anx_get_clip_time_by_id (anx, id)) == -1.0) {
while ((n = anx_write_output (anx, buf, 1024)) > 0);
if ((clip_offset = anx_get_clip_time_by_id (anx, id)) == -1.0) {
clip_offset = 0.0;
}
}
if (anx_close (anx) != NULL) {
}
return clip_offset;
}
static int
ma_anxenc (request_rec * r, char * filename, char * mime_type,
table * cgi_table)
{
ANNODEX * anx;
int ret;
char * val, * id = NULL;
double seek_offset = 0.0, seek_end = -1.0;
char buf[1024];
long n = 1024;
long ntotal = 0;
double header_value;
char header_buf[64];
char olddir[PATH_MAX], * newdir, * sep_pos;
anx = anx_new (ANX_WRITE);
/*anx_init_importers (ANX_MIME_TYPE);*/
anx_init_importers ("*/*");
/* Retrieve the current working directory */
getcwd (olddir, PATH_MAX);
/* Chdir to the directory of the requested file */
newdir = ap_pstrdup (r->pool, filename);
sep_pos = strrchr (newdir, '/');
if (sep_pos) *sep_pos = '\0';
chdir (newdir);
/* Get the start/end times or id */
val = (char *)table_get (cgi_table, "t");
id = (char *)table_get (cgi_table, "id");
if (val) {
ma_parse_time (val, &seek_offset, &seek_end);
} else if (id) {
seek_offset = ma_anxenc_clip_time (filename, mime_type, id);
}
#ifdef DEBUG
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"ma_anxenc: t=%s id=%s (%f/%f)",
val, id, seek_offset, seek_end);
#endif
anx_set_presentation_time (anx, seek_offset);
anx_set_basetime (anx, 0.0);
ret = anx_write_import (anx, filename, NULL, mime_type,
seek_offset, seek_end, 0);
#ifdef DEBUG
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"ma_anxenc: anx_write_import returned %d", ret);
#endif
if ((header_value = anx_get_duration (anx)) != -1.0) {
snprintf (header_buf, 64, "%ld", (long)header_value);
#ifdef DEBUG
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"ma_anxenc: duration %s", header_buf);
#endif
table_set (r->headers_out, (const char *)"X-Content-Duration",
header_buf);
}
if ((header_value = anx_get_bitrate (anx)) != -1.0) {
snprintf (header_buf, 64, "%ld", (long)header_value);
table_set (r->headers_out, (const char *)"X-Content-Bitrate-Average",
header_buf);
}
ap_send_http_header(r);
while ((n = anx_write_output (anx, buf, 1024)) > 0) {
ntotal += n;
ap_rwrite (buf, n, r);
}
#ifdef DEBUG
if (n == -1) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"ma_anxenc: %s", anx_strerror (anx));
}
#endif
#ifdef DEBUG
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"ma_anxenc: done, with n=%ld (ntotal=%ld)", n, ntotal);
#endif
if (anx_close (anx) != NULL) {
return -1;
}
/* Return to the previously current working directory */
chdir (olddir);
return 0;
}
/* ma_anxrip callbacks */
struct ma_anxrip_data_t {
request_rec * r;
AnxClip * prev_clip;
double prev_start_time;
};
static int
read_head (ANNODEX * anx, const AnxHead * head, void * user_data)
{
struct ma_anxrip_data_t * mad = (struct ma_anxrip_data_t *)user_data;
request_rec * r = mad->r;
char buf[MAX_CLIP_LEN];
anx_head_snprint (buf, MAX_CLIP_LEN, (AnxHead *)head);
ap_rputs (buf, r);
ap_rputc ('\n', r);
return ANX_CONTINUE;
}
static int
read_clip (ANNODEX * anx, const AnxClip * clip, void * user_data)
{
struct ma_anxrip_data_t * mad = (struct ma_anxrip_data_t *)user_data;
request_rec * r = mad->r;
char buf[MAX_CLIP_LEN];
double t;
t = anx_tell_time (anx);
/* fprintf (outfile, "%.3f (%ld)\t", t, anx_tell (anx));*/
if (mad->prev_clip != NULL) {
anx_clip_snprint (buf, MAX_CLIP_LEN, mad->prev_clip,
mad->prev_start_time, t);
ap_rputs (buf, r);
ap_rputc ('\n', r);
anx_clip_free (mad->prev_clip);
}
mad->prev_clip = anx_clip_clone ((AnxClip *)clip);
mad->prev_start_time = t;
return ANX_CONTINUE;
}
static int
ma_anxrip (request_rec * r, char * filename)
{
ANNODEX * anx;
char buf[MAX_CLIP_LEN];
size_t n = MAX_CLIP_LEN;
#if 0
AnxList * l;
AnxTrack * s;
#endif
double timebase;
struct ma_anxrip_data_t mad;
ap_send_http_header(r);
mad.r = r;
mad.prev_clip = NULL;
anx = anx_open (filename, ANX_READ);
anx_set_read_head_callback (anx, read_head, &mad);
anx_set_read_clip_callback (anx, read_clip, &mad);
ap_rprintf (r, CMML_PREAMBLE);
ap_rprintf (r, "\n");
ap_rprintf (r, "\n"); /* XXX: and UTC */
#if 0
for (l = anx_get_track_list (anx); l; l = l->next) {
s = (AnxTrack *)l->data;
if (!(s->mime_type && !strncmp (s->mime_type, CMML_MIME_TYPE, 11))) {
ap_rprintf (r, "id) ap_rprintf (r, " id=\"%s\"", s->id);
if (s->mime_type) ap_rprintf (r, " contenttype=\"%s\"", s->mime_type);
/*
if (s->granule_rate_n != 0 && s->granule_rate_d != 0)
ap_rprintf (r, " granulerate=\"%ld/%ld\"",
(long)s->granule_rate_n, (long)s->granule_rate_d);
*/
ap_rprintf (r, "/>\n");
}
}
#endif
ap_rprintf (r, "\n");
while ((n = anx_read (anx, 1024)) > 0);
if (mad.prev_clip != NULL) {
anx_clip_snprint (buf, MAX_CLIP_LEN, mad.prev_clip,
mad.prev_start_time, anx_tell_time (anx));
ap_rputs (buf, r);
ap_rputc ('\n', r);
anx_clip_free (mad.prev_clip);
}
ap_rprintf (r, "\n");
if (anx_close (anx) != NULL) {
return -1;
}
return 0;
}
#ifdef __PROTOTYPE
/* ma_anxrip_media callbacks */
static int
read_m_stream (ANNODEX * anx, double timebase, char * utc, void * user_data)
{
return ANX_CONTINUE;
}
static int
read_m_track (ANNODEX * anx, long serialno, char * id, char * mime_type,
anx_int64_t granule_rate_n, anx_int64_t granule_rate_d,
int nr_header_packets, void * user_data)
{
request_rec * r = (request_rec *)user_data;
if (!(mime_type && !strncmp (mime_type, "text/x-annodex", 14))) {
r->content_type = mime_type;
#ifdef DEBUG
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"Rip media: mime type %s", r->content_type);
#endif
}
return ANX_CONTINUE;
}
static int
read_media (ANNODEX * anx, unsigned char * data, long len, long serialno,
anx_int64_t granulepos, void * user_data)
{
request_rec * r = (request_rec *)user_data;
size_t remaining = (size_t)len, n;
#if 0
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"%f\t%f", anx_tell_time (anx), s_seek_offset);
if (anx_tell_time (anx) >= s_seek_offset)
#endif
while (remaining > 0) {
n = ap_rwrite (data, remaining, r);
remaining -= n;
}
return ANX_CONTINUE;
}
static int
read_media_1 (ANNODEX * anx, unsigned char * data, long len, long serialno,
anx_int64_t granulepos, void * user_data)
{
request_rec * r = (request_rec *)user_data;
r->content_type = anx_track_get_content_type (anx, serialno);
ap_send_http_header(r);
if (r->header_only) {
/* XXX: Should be smarter , ie. drop out properly :) */
anx_set_read_raw_callback (anx, NULL, user_data);
return ANX_STOP_OK;
}
read_media (anx, data, len, serialno, granulepos, user_data);
anx_set_read_raw_callback (anx, read_media, user_data);
return ANX_CONTINUE;
}
static int
ma_anxrip_media (request_rec * r, char * filename, table * cgi_table)
{
ANNODEX * anx;
double seek_offset = 0.0;
char * val;
long n;
ap_send_http_header(r);
val = (char *)table_get (cgi_table, "t");
if (val) {
seek_offset = anx_parse_time (val);
}
anx = anx_open (filename, ANX_READ);
anx_set_read_stream_callback (anx, read_m_stream, r);
anx_set_read_track_callback (anx, read_m_track, r);
anx_set_read_raw_callback (anx, read_media_1, r);
if (seek_offset > 0.0)
anx_seek_time (anx, seek_offset, ANX_SEEK_SET);
/*s_seek_offset = seek_offset;*/
while ((n = anx_read (anx, 1024)) > 0);
if (anx_close (anx) != NULL) {
return -1;
}
return 0;
}
#endif
#ifdef UNUSED
static int
ma_send (request_rec * r, char * filename)
{
FILE * f;
char buf[1024];
size_t n = 1024;
ap_send_http_header(r);
if (!(f = ap_pfopen (r->pool, filename, "r"))) {
ap_log_rerror (APLOG_MARK, APLOG_ERR, r,
"Permissions deny server access: %s", filename);
return HTTP_FORBIDDEN;
}
#ifdef DEBUG
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"ma_send: %s", filename);
#endif
while ((n = fread ((void *)buf, 1, 1024, f)) > 0) {
ap_rwrite (buf, n, r);
}
ap_pfclose (r->pool, f);
return 0;
}
#endif
static int
read_cmml_stream (CMML * cmml, const CMML_Stream * stream, void * user_data)
{
request_rec * r = (request_rec *)user_data;
CMML_Preamble * preamble;
static char buf[1024];
int n;
preamble = cmml_get_preamble (cmml);
n = cmml_preamble_snprint (buf, 1024, preamble);
if (n > 0) {
ap_rwrite (buf, n, r);
}
return 0;
}
static int
read_cmml_head (CMML * cmml, const CMML_Head * head, void * user_data)
{
request_rec * r = (request_rec *)user_data;
static char buf[MAX_CLIP_LEN];
int n;
n = cmml_head_pretty_snprint (buf, MAX_CLIP_LEN, (CMML_Head *)head);
if (n > 0) {
ap_rwrite (buf, n, r);
}
return 0;
}
static int
read_cmml_clip (CMML * cmml, const CMML_Clip * clip, void * user_data)
{
request_rec * r = (request_rec *)user_data;
static char buf[MAX_CLIP_LEN];
int n;
n = cmml_clip_pretty_snprint (buf, MAX_CLIP_LEN, (CMML_Clip *)clip);
if (n > 0) {
ap_rwrite (buf, n, r);
}
return 0;
}
static int
ma_send_cmml (request_rec * r, char * filename)
{
CMML * doc;
size_t nread = 0;
long n;
static char * cmml_tail = "\n";
ap_send_http_header(r);
doc = cmml_open (filename);
cmml_set_read_callbacks (doc, read_cmml_stream, read_cmml_head,
read_cmml_clip, r);
while ((n = cmml_read (doc, 1024)) > 0) nread += n;
if (n < 0) {
/* ERROR */
}
n = strlen (cmml_tail);
if (n > 0) {
ap_rwrite (cmml_tail, n, r);
}
cmml_destroy (doc);
return 0;
}
static char *
ma_extsub (request_rec * r, char * filename,
char * oldext, int oldext_len,
char * newext, int newext_len)
{
char * extpos;
char * srcfile;
int filename_len;
int diff; /* how many bytes longer the new extension is */
char * ret;
extpos = strrchr (r->filename, '.');
if (extpos == NULL) return NULL;
if (strncmp (++extpos, oldext, oldext_len)) return NULL;
/* s/.oldext/.newext/ */
diff = newext_len - oldext_len;
filename_len = strlen (filename);
srcfile = palloc (r->pool, filename_len + diff + 1 /* '\0' */);
strncpy (srcfile, filename, filename_len-oldext_len+1);
strncpy (srcfile+filename_len-oldext_len, newext, newext_len+1);
ret = r->path_info ?
pstrcat (r->pool, srcfile, r->path_info, NULL) : srcfile;
return ret;
}
/* The annodex content handler */
static int annodex_handler(request_rec *r)
{
uri_components * uri;
char * filename;
char * srcpath = NULL, * cmmlpath = NULL;
int input_type, output_type;
table * cgi_table;
uri = &(r->parsed_uri);
/* usually filename is request filename */
filename = r->filename;
/* but we still need to determine the output type */
output_type = MOD_ANNODEX_TYPE_UNKNOWN;
if (strcmp(r->handler, "annodex")) {
return DECLINED;
}
if (r->method_number == M_OPTIONS) {
r->allowed = (1 << M_GET);
return DECLINED;
}
if (r->method_number != M_GET) {
return HTTP_METHOD_NOT_ALLOWED;
}
/* check if file exists */
if (r->finfo.st_mode == 0) {
struct stat statbuf;
if ((srcpath = ma_extsub (r, r->filename, "anx", 3, "cmml", 4))) {
if (stat (srcpath, &statbuf) < 0) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"Requested file does not exist, nor does CMML %s",
srcpath);
return HTTP_NOT_FOUND;
}
input_type = MOD_ANNODEX_TYPE_CMML;
filename = srcpath;
} else if ((srcpath = ma_extsub (r, r->filename, "cmml", 4, "anx", 3))) {
if (stat (srcpath, &statbuf) < 0) {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"Requested file %s does not exist, nor does ANX %s",
r->filename, srcpath);
return HTTP_NOT_FOUND;
}
input_type = MOD_ANNODEX_TYPE_ANX;
output_type = MOD_ANNODEX_TYPE_CMML;
filename = srcpath;
} else {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"Requested file does not exist: %s",
(r->path_info
? pstrcat(r->pool, r->filename, r->path_info, NULL)
: r->filename));
return HTTP_NOT_FOUND;
}
} else {
struct stat statbuf;
if ((cmmlpath = ma_extsub (r, r->filename, "anx", 3, "cmml", 4))) {
if (stat (cmmlpath, &statbuf) < 0) {
cmmlpath = NULL;
} else {
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
"Using stored CMML file %s", cmmlpath);
}
}
input_type = MOD_ANNODEX_TYPE_ANX;
}
cgi_table = make_cgi_table (r, uri->query);
#ifdef __PROTOTYPE
if (output_type == MOD_ANNODEX_TYPE_UNKNOWN)
output_type = get_cgi_mode (r, cgi_table);
#endif
if (output_type == MOD_ANNODEX_TYPE_UNKNOWN) {
if (prefer_cmml (r)) {
output_type = MOD_ANNODEX_TYPE_CMML;
} else {
output_type = MOD_ANNODEX_TYPE_ANX;
}
}
if (output_type == MOD_ANNODEX_TYPE_CMML) {
r->content_type = CMML_MIME_TYPE;
} else {
r->content_type = ANX_MIME_TYPE;
}
table_set (r->headers_out, (const char *)"X-Accept-TimeURI",
ANX_MIME_TYPE);
#ifdef BLAHBLIMBLAM__PROTOTYPE
if (!(input_type == MOD_ANNODEX_TYPE_ANX &&
output_type == MOD_ANNODEX_TYPE_MEDIA)) {
ap_send_http_header(r);
if (r->header_only) {
return OK;
}
}
#else
if (r->header_only) {
ap_send_http_header(r);
return OK;
}
#endif
if (input_type == MOD_ANNODEX_TYPE_ANX &&
output_type == MOD_ANNODEX_TYPE_ANX) {
/* anx import anx */
ma_anxenc (r, r->filename, ANX_MIME_TYPE, cgi_table);
} else if (input_type == MOD_ANNODEX_TYPE_CMML &&
output_type == MOD_ANNODEX_TYPE_ANX) {
/* anx import cmml */
ma_anxenc (r, srcpath, CMML_MIME_TYPE, cgi_table);
} else if (input_type == MOD_ANNODEX_TYPE_ANX &&
output_type == MOD_ANNODEX_TYPE_CMML) {
if (cmmlpath != NULL) {
/* push out cmml */
ma_send_cmml (r, cmmlpath);
} else {
/* anx rip cmml */
ma_anxrip (r, filename);
}
} else if (input_type == MOD_ANNODEX_TYPE_CMML &&
output_type == MOD_ANNODEX_TYPE_CMML) {
/* push out cmml */
ma_send_cmml (r, srcpath);
#ifdef __PROTOTYPE
} else if (input_type == MOD_ANNODEX_TYPE_ANX &&
output_type == MOD_ANNODEX_TYPE_MEDIA) {
r->content_type = "video/mpeg";
ma_anxrip_media (r, r->filename, cgi_table);
#endif
}
return OK;
}
/* Dispatch list of content handlers */
static const handler_rec annodex_handlers[] = {
{ "annodex", annodex_handler },
{ NULL, NULL }
};
/* Dispatch list for API hooks */
module MODULE_VAR_EXPORT annodex_module = {
STANDARD_MODULE_STUFF,
NULL, /* module initializer */
NULL, /* create per-dir config structures */
NULL, /* merge per-dir config structures */
NULL, /* create per-server config structures */
NULL, /* merge per-server config structures */
NULL, /* table of config file commands */
annodex_handlers, /* [#8] MIME-typed-dispatched handlers */
NULL, /* [#1] URI to filename translation */
NULL, /* [#4] validate user id from request */
NULL, /* [#5] check if the user is ok _here_ */
NULL, /* [#3] check access by host address */
NULL, /* [#6] determine MIME type */
NULL, /* [#7] pre-run fixups */
NULL, /* [#9] log a transaction */
NULL, /* [#2] header parser */
NULL, /* child_init */
NULL, /* child_exit */
NULL /* [#0] post read-request */
#ifdef EAPI
,NULL, /* EAPI: add_module */
NULL, /* EAPI: remove_module */
NULL, /* EAPI: rewrite_command */
NULL /* EAPI: new_connection */
#endif
};