diff --git a/admin-root/hdr.html b/admin-root/hdr.html
index 480b0571..15513742 100644
--- a/admin-root/hdr.html
+++ b/admin-root/hdr.html
@@ -1,5 +1,4 @@
-
+
.: m t - d a a p d :.
diff --git a/contrib/mt-daapd.conf b/contrib/mt-daapd.conf
index 7c5e6c7e..2d24bdad 100644
--- a/contrib/mt-daapd.conf
+++ b/contrib/mt-daapd.conf
@@ -128,16 +128,28 @@ playlist /etc/mt-daapd.playlist
extensions .mp3,.m4a,.m4p,.ogg
#
-# ssc_extensions (optional)
+# ssc_codectypes (optional)
#
-# List of file extensions belonging to the files daap server
-# performs internal format conversion and present to clients
-# as WAV files. Extensions must also be present in 'extensions'
+# List of codectypes for files that the daap server should
+# perform internal format conversion and present to clients
+# as WAV files. The file extensions that these codectypes correspond
+# to must also be present in 'extensions'
# configuration value, or files are not probed in the first
# place.
#
+# Valid codectypes:
+#
+# mp4a - for AAC (.aac, .mp4, .m4a, .m4p)
+# mpeg - for mp3
+# wav - for wav
+# wma - for wma
+# ogg - for ogg
+# flac - for flac (.flac, .fla)
+# mpc for musepack (.mpc, .mpp, .mp+)
+# alac for alac (.m4a)
+#
-ssc_extensions .ogg
+ssc_codectypes ogg,flac,alac
#
# ssc_prog (optional)
diff --git a/src/configfile.c b/src/configfile.c
index 73898ee4..7dc8fc69 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -132,7 +132,7 @@ CONFIGELEMENT config_elements[] = {
{ 1,0,0,CONFIG_TYPE_STRING,"playlist",(void*)&config.playlist,config_emit_string },
{ 1,0,0,CONFIG_TYPE_STRING,"extensions",(void*)&config.extensions,config_emit_string },
{ 1,0,0,CONFIG_TYPE_STRING,"interface",(void*)&config.iface,config_emit_string },
- { 1,0,0,CONFIG_TYPE_STRING,"ssc_extensions",(void*)&config.ssc_extensions,config_emit_string },
+ { 1,0,0,CONFIG_TYPE_STRING,"ssc_codectypes",(void*)&config.ssc_codectypes,config_emit_string },
{ 1,0,0,CONFIG_TYPE_STRING,"ssc_prog",(void*)&config.ssc_prog,config_emit_string },
{ 1,0,0,CONFIG_TYPE_STRING,"password",(void*)&config.readpassword, config_emit_string },
{ 1,0,0,CONFIG_TYPE_STRING,"compdirs",(void*)&config.compdirs, config_emit_string },
@@ -307,7 +307,7 @@ int config_read(char *file) {
/* DWB: use alloced space so it can be freed without errors */
config.extensions=strdup(".mp3");
- config.ssc_extensions=strdup("");
+ config.ssc_codectypes=strdup("");
config.ssc_prog=strdup("");
/* DWB: use alloced space so it can be freed without errors */
@@ -564,7 +564,7 @@ int config_write(WS_CONNINFO *pwsc) {
if(ws_getvar(pwsc,"password") && strlen(ws_getvar(pwsc,"password")))
fprintf(configfile,"password\t%s\n",ws_getvar(pwsc,"password"));
fprintf(configfile,"extensions\t%s\n",ws_getvar(pwsc,"extensions"));
- fprintf(configfile,"ssc_extensions\t%s\n",ws_getvar(pwsc,"ssc_extensions"));
+ fprintf(configfile,"ssc_codectypes\t%s\n",ws_getvar(pwsc,"ssc_codectypes"));
fprintf(configfile,"ssc_prog\t%s\n",ws_getvar(pwsc,"ssc_prog"));
fprintf(configfile,"db_dir\t\t%s\n",ws_getvar(pwsc,"db_dir"));
fprintf(configfile,"rescan_interval\t%s\n",ws_getvar(pwsc,"rescan_interval"));
@@ -1085,9 +1085,13 @@ void config_emit_ispage(WS_CONNINFO *pwsc, void *value, char *arg) {
if((strlen(page) > strlen(pwsc->uri)) ||
(strcasecmp(page,(char*)&pwsc->uri[strlen(pwsc->uri) - strlen(page)]) != 0)) {
- ws_writefd(pwsc,"%s",false);
+ if(false) {
+ ws_writefd(pwsc,"%s",false);
+ }
} else {
- ws_writefd(pwsc,"%s",true);
+ if(true) {
+ ws_writefd(pwsc,"%s",true);
+ }
}
diff --git a/src/daapd.h b/src/daapd.h
index 31450a78..cd30e387 100644
--- a/src/daapd.h
+++ b/src/daapd.h
@@ -68,7 +68,7 @@ typedef struct tag_config {
char *runas; /**< Who to drop privs to (if run as root) */
char *dbdir; /**< Where to put the db file */
char *extensions; /**< What music file extentions to process */
- char *ssc_extensions; /**< What extensions are converted in server */
+ char *ssc_codectypes; /**< What codectypes are converted in server */
char *ssc_prog; /**< Server side music format converter prog */
char *artfilename; /**< What filename to merge coverart with */
char *logfile; /**< What file to use as a logfile */
diff --git a/src/dbs-sqlite.c b/src/dbs-sqlite.c
index 5ec61515..1d443578 100644
--- a/src/dbs-sqlite.c
+++ b/src/dbs-sqlite.c
@@ -1104,7 +1104,7 @@ int db_sqlite_get_size(DBQUERYINFO *pinfo, char **valarray) {
case queryTypeItems:
case queryTypePlaylistItems: /* essentially the same query */
/* see if this is going to be transcoded */
- transcode = server_side_convert(valarray[2]);
+ transcode = server_side_convert(valarray[37]);
/* Items that get changed by transcode:
*
@@ -1271,7 +1271,7 @@ int db_sqlite_build_dmap(DBQUERYINFO *pinfo, char **valarray, unsigned char *pre
case queryTypeItems:
case queryTypePlaylistItems: /* essentially the same query */
/* see if this is going to be transcoded */
- transcode = server_side_convert(valarray[2]);
+ transcode = server_side_convert(valarray[37]);
/* Items that get changed by transcode:
*
diff --git a/src/dispatch.c b/src/dispatch.c
index 299dcb00..1bd7b57f 100644
--- a/src/dispatch.c
+++ b/src/dispatch.c
@@ -143,6 +143,8 @@ void daap_handler(WS_CONNINFO *pwsc) {
ws_addresponseheader(pwsc,"Accept-Ranges","bytes");
ws_addresponseheader(pwsc,"DAAP-Server","mt-daapd/" VERSION);
ws_addresponseheader(pwsc,"Content-Type","application/x-dmap-tagged");
+ ws_addresponseheader(pwsc,"Cache-Control","no-cache"); /* anti-ie defense */
+ ws_addresponseheader(pwsc,"Expires","-1");
if(ws_getvar(pwsc,"session-id"))
pqi->session_id = atoi(ws_getvar(pwsc,"session-id"));
@@ -626,7 +628,7 @@ void dispatch_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
if(!pmp3) {
DPRINTF(E_LOG,L_DAAP|L_WS|L_DB,"Could not find requested item %lu\n",item);
ws_returnerror(pwsc,404,"File Not Found");
- } else if (server_side_convert(pmp3->fname)) {
+ } else if (server_side_convert(pmp3->codectype)) {
/************************
* Server side conversion
************************/
diff --git a/src/ssc.c b/src/ssc.c
index fa64e9fc..7c016579 100644
--- a/src/ssc.c
+++ b/src/ssc.c
@@ -48,120 +48,31 @@
# include "strcasestr.h"
#endif
-/**
- * If path is server side convertable, return the path to real file.
- *
- * @param path char * to the path in the database.
- */
-char *server_side_convert_path(char *path)
-{
- char *r = NULL;
-
- if (path &&
- (strlen(path) > strlen(SERVER_SIDE_CONVERT_SUFFIX)) &&
- (strcmp(path + strlen(path) - strlen(SERVER_SIDE_CONVERT_SUFFIX),
- SERVER_SIDE_CONVERT_SUFFIX) == 0)) {
- /* Lose the artificial suffix. Could use strndup here.*/
- r = strdup(path);
- r[strlen(path) - strlen(SERVER_SIDE_CONVERT_SUFFIX)] = '\0';
- }
-
- return r;
-}
-
-
/**
* Check if the file specified by fname should be converted in
* server to wav. Currently it does this by file extension, but
* could in the future decided to transcode based on user agent.
*
- * @param fname file name of file to check for conversion
+ * @param codectype codec type of the file we are checking for conversion
* @returns 1 if should be converted. 0 if not
*/
-int server_side_convert(char *fname) {
- char *ext;
-
- DPRINTF(E_SPAM,L_SCAN,"Checking for ssc: %s\n",fname);
-
- if ((!config.ssc_extensions) ||
- (!config.ssc_extensions[0]) ||
- (!config.ssc_prog) ||
- (!config.ssc_prog[0]) ||
- (!fname)) {
- DPRINTF(E_DBG,L_SCAN,"Nope\n");
- return 0;
+int server_side_convert(char *codectype) {
+ if ((!config.ssc_codectypes) ||
+ (!config.ssc_codectypes[0]) ||
+ (!config.ssc_prog) ||
+ (!config.ssc_prog[0]) ||
+ (!codectype)) {
+ DPRINTF(E_DBG,L_SCAN,"Nope\n");
+ return 0;
}
- if(((ext = strrchr(fname, '.')) != NULL) &&
- (strcasestr(config.ssc_extensions, ext))) {
- DPRINTF(E_SPAM,L_SCAN,"Yup\n");
- return 1;
+ if(strcasestr(config.ssc_codectypes, codectype)) {
+ return 1;
}
- DPRINTF(E_SPAM,L_SCAN,"Nope\n");
return 0;
}
-/**
- * Check if the file entry (otherwise complete) is such that
- * file should be converted in server end to wav-format.
- * If so, the info is modified accordingly and non-zero return
- * value is returned.
- *
- * @param song MP3FILE of the file to possibly set to server side conversion
- */
-int server_side_convert_set(MP3FILE *pmp3)
-{
- char *fname, *path, *description, *ext;
- DPRINTF(E_SPAM,L_SCAN,"Checking for ssc: %s\n",pmp3->fname);
- if ((!config.ssc_extensions) ||
- (!config.ssc_extensions[0]) ||
- (!config.ssc_prog) ||
- (!config.ssc_prog[0]) ||
- (!pmp3->fname) ||
- (!pmp3->path) ||
- (!pmp3->type) ||
- ((strlen(pmp3->fname) > strlen(SERVER_SIDE_CONVERT_SUFFIX)) &&
- (strcmp(pmp3->fname +
- strlen(pmp3->fname) -
- strlen(SERVER_SIDE_CONVERT_SUFFIX),
- SERVER_SIDE_CONVERT_SUFFIX) == 0))) {
- DPRINTF(E_SPAM,L_SCAN,"Nope\n");
- return 0;
- }
-
- DPRINTF(E_SPAM,L_SCAN,"Yup\n");
- if (((ext = strrchr(pmp3->path, '.')) != NULL) &&
- (strcasestr(config.ssc_extensions, ext))) {
- fname = (char *)malloc(strlen(pmp3->fname) +
- strlen(SERVER_SIDE_CONVERT_SUFFIX) + 1);
- path = (char *)malloc(strlen(pmp3->path) +
- strlen(SERVER_SIDE_CONVERT_SUFFIX) + 1);
- description = (char *)malloc(strlen(pmp3->description) +
- strlen(SERVER_SIDE_CONVERT_DESCR) + 1);
- strcpy(fname, pmp3->fname);
- strcat(fname, SERVER_SIDE_CONVERT_SUFFIX);
- free(pmp3->fname);
- pmp3->fname = fname;
- strcpy(path, pmp3->path);
- strcat(path, SERVER_SIDE_CONVERT_SUFFIX);
- free(pmp3->path);
- pmp3->path = path;
- strcpy(description, pmp3->description);
- strcat(description, SERVER_SIDE_CONVERT_DESCR);
- free(pmp3->description);
- pmp3->description = description;
- free(pmp3->type);
- pmp3->type = strdup("wav");
- if (pmp3->samplerate > 0) {
- // Here we guess that it's always 16 bit stereo samples,
- // which is accurate enough for now.
- pmp3->bitrate = (pmp3->samplerate * 4 * 8) / 1000;
- }
- return 1;
- }
- return 0;
-}
/**
* Open the source file with convert fiter.
@@ -169,17 +80,49 @@ int server_side_convert_set(MP3FILE *pmp3)
* @param path char * to the real filename.
* @param offset off_t to the point in file where the streaming starts.
*/
-FILE *server_side_convert_open(char *path, off_t offset, unsigned long len_ms)
-{
+FILE *server_side_convert_open(char *path, off_t offset, unsigned long len_ms) {
char *cmd;
FILE *f;
+ char *newpath;
+ char *metachars = "\"();"; /* More?? */
+ char metacount = 0;
+ char *src,*dst;
+
+ src=path;
+ while(*src) {
+ if(strchr(metachars,*src))
+ metacount++;
+ src++;
+ }
+
+ if(metachars) {
+ newpath = (char*)malloc(strlen(path) + metacount + 1);
+ if(!newpath) {
+ DPRINTF(E_FATAL,L_SCAN,"Malloc error.\n");
+ }
+ src=path;
+ dst=newpath;
+
+ while(*src) {
+ if(strchr(metachars,*src))
+ *dst++='\\';
+ *dst++=*src++;
+ }
+ *dst='\0';
+ } else {
+ newpath = strdup(path); /* becuase it will be freed... */
+ }
+ /* FIXME: is 64 enough? is there a better way to determine this? */
cmd=(char *)malloc(strlen(config.ssc_prog) +
- strlen(path) +
- 64);
+ strlen(path) +
+ 64);
sprintf(cmd, "%s \"%s\" %ld %lu.%03lu",
- config.ssc_prog, path, (long)offset, len_ms / 1000, len_ms % 1000);
+ config.ssc_prog, newpath, (long)offset, len_ms / 1000, len_ms % 1000);
+ DPRINTF(E_INF,L_SCAN,"Executing %s\n",cmd);
f = popen(cmd, "r");
+ free(newpath);
+ free(cmd); /* should really have in-place expanded the path */
return f;
}
@@ -191,7 +134,7 @@ FILE *server_side_convert_open(char *path, off_t offset, unsigned long len_ms)
void server_side_convert_close(FILE *f)
{
if (f)
- pclose(f);
+ pclose(f);
return;
}
diff --git a/src/ssc.h b/src/ssc.h
index ca2f4dca..c75892e5 100644
--- a/src/ssc.h
+++ b/src/ssc.h
@@ -25,7 +25,7 @@
#define SERVER_SIDE_CONVERT_SUFFIX ".-*-ssc-*-.wav"
#define SERVER_SIDE_CONVERT_DESCR " (converted to WAV)"
-extern int server_side_convert(char *fname);
+extern int server_side_convert(char *codectype);
extern int server_side_convert_set(MP3FILE *pmp3);
extern char *server_side_convert_path(char *path);
extern FILE *server_side_convert_open(char *path,
diff --git a/src/xml-rpc.c b/src/xml-rpc.c
index 3ec900c4..655cea56 100644
--- a/src/xml-rpc.c
+++ b/src/xml-rpc.c
@@ -15,10 +15,25 @@
#include "mp3-scanner.h"
#include "webserver.h"
+/* typedefs */
+typedef struct tag_xmlstruct {
+} XMLSTRUCT;
+
/* Forwards */
void xml_get_stats(WS_CONNINFO *pwsc);
char *xml_entity_encode(char *original);
+/**
+ * create an xml response structure, a helper struct for
+ * building xml responses.
+ *
+ * @returns XMLSTRUCT on success, or NULL if failure
+ */
+XMLSTRUCT *xml_init(void) {
+}
+
+
+
/**
* main entrypoint for the xmlrpc functions.
*