bumper patch from dwb

This commit is contained in:
Ron Pedde 2004-05-21 13:56:04 +00:00
parent e78545a53c
commit d895dc8b41
7 changed files with 595 additions and 168 deletions

View File

@ -429,33 +429,35 @@ void config_handler(WS_CONNINFO *pwsc) {
} }
if(strcasecmp(pwsc->uri,"/config-update.html")==0) { if(strcasecmp(pwsc->uri,"/config-update.html")==0) {
/* we need to update stuff */ /* don't update (and turn everything to (null)) the
pw=ws_getvar(pwsc,"admin_pw"); configuration file if what the user's really trying to do is
if(pw) { stop the server */
if(config.adminpassword)
free(config.adminpassword);
config.adminpassword=strdup(pw);
}
pw=ws_getvar(pwsc,"password");
if(pw) {
if(config.readpassword)
free(config.readpassword);
config.readpassword=strdup(pw);
}
if(!config_file_is_readonly()) {
DPRINTF(ERR_INFO,"Updating config file\n");
config_write(pwsc);
}
pw=ws_getvar(pwsc,"action"); pw=ws_getvar(pwsc,"action");
if(pw) { if(pw) {
/* ignore stopmdns and startmdns */ /* ignore stopmdns and startmdns */
if (strcasecmp(pw,"stopdaap")==0) { if (strcasecmp(pw,"stopdaap")==0) {
config.stop=1; config.stop=1;
} }
} else {
/* we need to update stuff */
pw=ws_getvar(pwsc,"admin_pw");
if(pw) {
if(config.adminpassword)
free(config.adminpassword);
config.adminpassword=strdup(pw);
}
pw=ws_getvar(pwsc,"password");
if(pw) {
if(config.readpassword)
free(config.readpassword);
config.readpassword=strdup(pw);
}
if(!config_file_is_readonly()) {
DPRINTF(ERR_INFO,"Updating config file\n");
config_write(pwsc);
}
} }
} }

View File

@ -27,6 +27,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include "daap-proto.h" #include "daap-proto.h"
#include "err.h" #include "err.h"
@ -267,6 +268,51 @@ int daap_serialize(DAAP_BLOCK *root, int fd, int gzip) {
return 0; return 0;
} }
/*
* daap_remove
*
* remove a node from it's parent node and release it
*/
void daap_remove(DAAP_BLOCK* node)
{
DAAP_BLOCK* parent = node->parent;
if(0 != parent)
{
DAAP_BLOCK** ptr = &parent->children;
while(*ptr && *ptr != node)
ptr = &(**ptr).next;
assert(0 != *ptr);
// remove us from the chain
*ptr = node->next;
// update sizes in parent chain
for(parent = node->parent ; parent ; parent = parent->parent)
parent->reported_size -= (8 + node->reported_size);
// clear parent and next pointers so daap_free doesn't get ambitious
node->parent = 0;
node->next = 0;
}
daap_free(node);
}
/*
* find a child block of the parent node
*/
DAAP_BLOCK *daap_find(DAAP_BLOCK *parent, char* tag)
{
for(parent = parent->children ; parent ; parent = parent->next)
if(!strncmp(parent->tag, tag, 4))
break;
return parent;
}
/* /*
* daap_free * daap_free
* *

View File

@ -45,5 +45,11 @@ DAAP_BLOCK *daap_add_long(DAAP_BLOCK *parent, char *tag, int v1, int v2);
int daap_serialize(DAAP_BLOCK *root, int fd, int gzip); int daap_serialize(DAAP_BLOCK *root, int fd, int gzip);
void daap_free(DAAP_BLOCK *root); void daap_free(DAAP_BLOCK *root);
// remove a block from it's parent (and free it)
void daap_remove(DAAP_BLOCK* root);
// search a block's direct children for a block with a given tag
DAAP_BLOCK *daap_find(DAAP_BLOCK *parent, char* tag);
#endif #endif

View File

@ -31,6 +31,7 @@
#include <sys/select.h> #include <sys/select.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <assert.h>
#include "configfile.h" #include "configfile.h"
#include "db-memory.h" #include "db-memory.h"
@ -222,16 +223,164 @@ DAAP_BLOCK *daap_response_login(char *hostname) {
* handle the daap block for the /databases/x/items URI * handle the daap block for the /databases/x/items URI
*/ */
DAAP_BLOCK *daap_response_songlist(void) { // fields requestable with meta=... these are really used as bit
// numbers in a long long, but are defined this way to simplify
// eventual implementation on platforms without long long support
typedef enum {
// generic meta data
metaItemId,
metaItemName,
metaItemKind,
metaPersistentId,
metaContainerItemId,
metaParentContainerId,
firstTypeSpecificMetaId,
// song meta data
metaSongAlbum = firstTypeSpecificMetaId,
metaSongArtist,
metaSongBPM, /* beats per minute */
metaSongBitRate,
metaSongComment,
metaSongCompilation,
metaSongComposer,
metaSongDataKind,
metaSongDataURL,
metaSongDateAdded,
metaSongDateModified,
metaSongDescription,
metaSongDisabled,
metaSongDiscCount,
metaSongDiscNumber,
metaSongEqPreset,
metaSongFormat,
metaSongGenre,
metaSongGrouping,
metaSongRelativeVolume,
metaSongSampleRate,
metaSongSize,
metaSongStartTime,
metaSongStopTime,
metaSongTime,
metaSongTrackCount,
metaSongTrackNumber,
metaSongUserRating,
metaSongYear
} MetaFieldName_t;
// structure mapping meta= tag names to bit numbers
typedef struct
{
const char* tag;
MetaFieldName_t bit;
} MetaDataMap;
// the dmap based tags, defined psuedo separately because they're also
// needed for DPAP, not that that's at all relevant here
#define INCLUDE_GENERIC_META_IDS \
{ "dmap.itemid", metaItemId }, \
{ "dmap.itemname", metaItemName }, \
{ "dmap.itemkind", metaItemKind }, \
{ "dmap.persistentid", metaPersistentId }, \
{ "dmap.containeritemid", metaContainerItemId }, \
{ "dmap.parentcontainerid", metaParentContainerId }
// map the string names specified in the meta= tag to bit numbers
static MetaDataMap gSongMetaDataMap[] = {
INCLUDE_GENERIC_META_IDS,
{ "daap.songalbum", metaSongAlbum },
{ "daap.songartist", metaSongArtist },
{ "daap.songbitrate", metaSongBitRate },
{ "daap.songbeatsperminute",metaSongBPM },
{ "daap.songcomment", metaSongComment },
{ "daap.songcompilation", metaSongCompilation },
{ "daap.songcomposer", metaSongComposer },
{ "daap.songdatakind", metaSongDataKind },
{ "daap.songdataurl", metaSongDataURL },
{ "daap.songdateadded", metaSongDateAdded },
{ "daap.songdatemodified", metaSongDateModified },
{ "daap.songdescription", metaSongDescription },
{ "daap.songdisabled", metaSongDisabled },
{ "daap.songdisccount", metaSongDiscCount },
{ "daap.songdiscnumber", metaSongDiscNumber },
{ "daap.songeqpreset", metaSongEqPreset },
{ "daap.songformat", metaSongFormat },
{ "daap.songgenre", metaSongGenre },
{ "daap.songgrouping", metaSongGrouping },
{ "daap.songrelativevolume",metaSongRelativeVolume },
{ "daap.songsamplerate", metaSongSampleRate },
{ "daap.songsize", metaSongSize },
{ "daap.songstarttime", metaSongStartTime },
{ "daap.songstoptime", metaSongStopTime },
{ "daap.songtime", metaSongTime },
{ "daap.songtrackcount", metaSongTrackCount },
{ "daap.songtracknumber", metaSongTrackNumber },
{ "daap.songuserrating", metaSongUserRating },
{ "daap.songyear", metaSongYear },
{ 0, 0 }
};
typedef unsigned long long MetaField_t;
// turn the meta= parameter into a bitfield representing the requested
// fields. The format is actually meta=<tag>[,<tag>...] where <tag>
// is any of the strings in the table above
MetaField_t encodeMetaRequest(char* meta, MetaDataMap* map)
{
MetaField_t bits = 0;
char* start;
char* end;
MetaDataMap* m;
for(start = meta ; *start ; start = end)
{
int len;
if(0 == (end = strchr(start, ',')))
end = start + strlen(start);
len = end - start;
if(*end != 0)
end++;
for(m = map ; m->tag ; ++m)
if(!strncmp(m->tag, start, len))
break;
if(m->tag)
bits |= (1 << m->bit);
else
DPRINTF(ERR_WARN, "Unknown meta code: %*s\n", len, start);
}
DPRINTF(ERR_DEBUG, "meta codes: %llu\n", bits);
return bits;
}
int wantsMeta(MetaField_t meta, MetaFieldName_t fieldNo)
{
return 0 != (meta & (1ll << fieldNo));
}
DAAP_BLOCK *daap_response_songlist(char* metaStr) {
DAAP_BLOCK *root; DAAP_BLOCK *root;
int g=1; int g=1;
DAAP_BLOCK *mlcl; DAAP_BLOCK *mlcl;
DAAP_BLOCK *mlit; DAAP_BLOCK *mlit;
ENUMHANDLE henum; ENUMHANDLE henum;
MP3FILE *current; MP3FILE *current;
char fdescr[50]; MetaField_t meta;
char *artist;
int artist_len; // if the meta tag is specified, encode it, if it's not specified
// we're given the latitude to select our own subset, for
// simplicity we just include everything.
if(0 == metaStr)
meta = (MetaField_t) -1ll;
else
meta = encodeMetaRequest(metaStr, gSongMetaDataMap);
DPRINTF(ERR_DEBUG,"Preparing to send db items\n"); DPRINTF(ERR_DEBUG,"Preparing to send db items\n");
@ -251,128 +400,11 @@ DAAP_BLOCK *daap_response_songlist(void) {
mlcl=daap_add_empty(root,"mlcl"); mlcl=daap_add_empty(root,"mlcl");
if(mlcl) { if(mlcl) {
while((current=db_enum(&henum))) { while(g && (current=db_enum(&henum))) {
DPRINTF(ERR_DEBUG,"Got entry for %s\n",current->fname); DPRINTF(ERR_DEBUG,"Got entry for %s\n",current->fname);
mlit=daap_add_empty(mlcl,"mlit"); // song entry generation extracted for usage with
if(mlit) { // playlists as well
g = g && daap_add_char(mlit,"mikd",2); /* audio */ g = 0 != daap_add_song_entry(mlcl, current, meta);
if(current->album)
g = g && daap_add_string(mlit,"asal",current->album);
artist=NULL;
artist_len=0;
if(current->orchestra || current->conductor) {
if(current->orchestra)
artist_len += strlen(current->orchestra);
if(current->conductor)
artist_len += strlen(current->conductor);
artist_len += 4;
artist=(char*)malloc(artist_len);
if(artist) {
memset(artist,0x0,artist_len);
if(current->orchestra)
strcat(artist,current->orchestra);
if(current->orchestra && current->conductor)
strcat(artist," - ");
if(current->conductor)
strcat(artist,current->conductor);
g = g && daap_add_string(mlit,"asar",artist);
free(artist);
artist=NULL;
} else
g=1;
} else if(current->artist) {
g = g && daap_add_string(mlit,"asar",current->artist);
}
// g = g && daap_add_short(mlit,"asbt",0); /* bpm */
if(current->bitrate)
g = g && daap_add_short(mlit,"asbr",current->bitrate); /* bitrate!! */
if(current->comment)
g = g && daap_add_string(mlit,"ascm",current->comment); /* comment */
// g = g && daap_add_char(mlit,"asco",0x0); /* compilation */
if(current->composer)
g = g && daap_add_string(mlit,"ascp",current->composer); /* composer */
if(current->grouping)
g = g && daap_add_string(mlit,"agrp",current->grouping); /* grouping */
if(current->time_added) {
g = g && daap_add_int(mlit,"asda",current->time_added); /* added */
}
if(current->time_modified) {
g = g && daap_add_int(mlit,"asdm",current->time_modified); /* modified */
}
if(current->total_discs) {
/* # of discs */
g = g && daap_add_short(mlit,"asdc",current->total_discs);
}
if(current->disc) {
/* disc number */
g = g && daap_add_short(mlit,"asdn",current->disc);
}
// g = g && daap_add_char(mlit,"asdk",0); /* song datakind? */
// aseq - null string!
if(current->genre)
g = g && daap_add_string(mlit,"asgn",current->genre); /* genre */
g = g && daap_add_int(mlit,"miid",current->id); /* id */
/* these quite go hand in hand */
g = g && daap_add_string(mlit,"asfm",(char*)&current->type[1]); /* song format */
if(!strcasecmp(current->type,".ogg")) {
sprintf(fdescr,"QuickTime movie file");
} else {
sprintf(fdescr,"%s audio file",current->type);
}
g = g && daap_add_string(mlit,"asdt",fdescr); /* descr */
// g = g && daap_add_string(mlit,"asdt","MPEG audio file"); /* descr */
if(current->title)
g = g && daap_add_string(mlit,"minm",current->title); /* descr */
else
g = g && daap_add_string(mlit,"minm",current->fname);
// mper (long)
// g = g && daap_add_char(mlit,"asdb",0); /* disabled */
// g = g && daap_add_char(mlit,"asrv",0); /* rel vol */
if(current->samplerate)
g = g && daap_add_int(mlit,"assr",current->samplerate); /* samp rate */
if(current->file_size)
g = g && daap_add_int(mlit,"assz",current->file_size); /* Size! */
g = g && daap_add_int(mlit,"asst",0); /* song start time? */
g = g && daap_add_int(mlit,"assp",0); /* songstoptime */
if(current->song_length)
g = g && daap_add_int(mlit,"astm",current->song_length*1000); /* song time */
if(current->total_tracks)
g = g && daap_add_short(mlit,"astc",current->total_tracks); /* track count */
if(current->track)
g = g && daap_add_short(mlit,"astn",current->track); /* track number */
// g = g && daap_add_char(mlit,"asur",3); /* rating */
if(current->year)
g = g && daap_add_short(mlit,"asyr",current->year);
} else g=0;
} }
} else g=0; } else g=0;
} }
@ -391,6 +423,161 @@ DAAP_BLOCK *daap_response_songlist(void) {
} }
//
// extracted song entry generation used by both database item lists
// and play list item lists
//
DAAP_BLOCK* daap_add_song_entry(DAAP_BLOCK* mlcl, MP3FILE* song, MetaField_t meta)
{
DAAP_BLOCK* mlit;
int g = 1;
mlit=daap_add_empty(mlcl,"mlit");
if(mlit) {
if(wantsMeta(meta, metaItemKind))
g = g && daap_add_char(mlit,"mikd",2); /* audio */
if(wantsMeta(meta, metaSongDataKind))
g = g && daap_add_char(mlit,"asdk",0); /* local file */
if(song->album && (wantsMeta(meta, metaSongAlbum)))
g = g && daap_add_string(mlit,"asal",song->album);
if(wantsMeta(meta, metaSongArtist))
{
char *artist;
int artist_len;
artist=NULL;
artist_len=0;
if(song->orchestra || song->conductor) {
if(song->orchestra)
artist_len += strlen(song->orchestra);
if(song->conductor)
artist_len += strlen(song->conductor);
artist_len += 3;
artist=(char*)malloc(artist_len);
if(artist) {
memset(artist,0x0,artist_len);
if(song->orchestra)
strcat(artist,song->orchestra);
if(song->orchestra && song->conductor)
strcat(artist," - ");
if(song->conductor)
strcat(artist,song->conductor);
g = g && daap_add_string(mlit,"asar",artist);
free(artist);
artist=NULL;
} else
g=1;
} else if(song->artist) {
g = g && daap_add_string(mlit,"asar",song->artist);
}
}
// g = g && daap_add_short(mlit,"asbt",0); /* bpm */
if(song->bitrate && (wantsMeta(meta, metaSongBitRate)))
g = g && daap_add_short(mlit,"asbr",song->bitrate); /* bitrate!! */
if(song->comment && (wantsMeta(meta, metaSongComment)))
g = g && daap_add_string(mlit,"ascm",song->comment); /* comment */
// g = g && daap_add_char(mlit,"asco",0x0); /* compilation */
if(song->composer && (wantsMeta(meta, metaSongComposer)))
g = g && daap_add_string(mlit,"ascp",song->composer); /* composer */
if(song->grouping && (wantsMeta(meta, metaSongGrouping)))
g = g && daap_add_string(mlit,"agrp",song->grouping); /* grouping */
if(song->time_added && (wantsMeta(meta, metaSongDateAdded)))
g = g && daap_add_int(mlit,"asda",song->time_added); /* added */
if(song->time_modified && (wantsMeta(meta, metaSongDateModified)))
g = g && daap_add_int(mlit,"asdm",song->time_modified); /* modified */
if(song->total_discs && (wantsMeta(meta, metaSongDiscCount)))
/* # of discs */
g = g && daap_add_short(mlit,"asdc",song->total_discs);
if(song->disc && (wantsMeta(meta, metaSongDiscNumber)))
/* disc number */
g = g && daap_add_short(mlit,"asdn",song->disc);
// asdk must be early in the item, moved to the top
// g = g && daap_add_char(mlit,"asdk",0); /* song datakind? */
// aseq - null string!
if(song->genre && (wantsMeta(meta, metaSongGenre)))
g = g && daap_add_string(mlit,"asgn",song->genre); /* genre */
if(wantsMeta(meta, metaItemId))
g = g && daap_add_int(mlit,"miid",song->id); /* id */
/* these quite go hand in hand */
if(wantsMeta(meta, metaSongFormat))
g = g && daap_add_string(mlit,"asfm",(char*)&song->type[1]); /* song format */
if(wantsMeta(meta, metaSongDescription))
{
char fdescr[50];
if(!strcasecmp(song->type,".ogg")) {
sprintf(fdescr,"QuickTime movie file");
} else {
sprintf(fdescr,"%s audio file",song->type);
}
g = g && daap_add_string(mlit,"asdt",fdescr); /* descr */
}
if(wantsMeta(meta, metaItemName))
{
if(song->title)
g = g && daap_add_string(mlit,"minm",song->title); /* descr */
else
g = g && daap_add_string(mlit,"minm",song->fname);
}
// mper (long)
// g = g && daap_add_char(mlit,"asdb",0); /* disabled */
// g = g && daap_add_char(mlit,"asrv",0); /* rel vol */
if(song->samplerate && (wantsMeta(meta, metaSongSampleRate)))
g = g && daap_add_int(mlit,"assr",song->samplerate); /* samp rate */
if(song->file_size && (wantsMeta(meta, metaSongSize)))
g = g && daap_add_int(mlit,"assz",song->file_size); /* Size! */
if(wantsMeta(meta, metaSongStartTime))
g = g && daap_add_int(mlit,"asst",0); /* song start time? */
if(wantsMeta(meta, metaSongStopTime))
g = g && daap_add_int(mlit,"assp",0); /* songstoptime */
if(song->song_length && (wantsMeta(meta, metaSongTime)))
g = g && daap_add_int(mlit,"astm",song->song_length*1000); /* song time */
if(song->total_tracks && (wantsMeta(meta, metaSongTrackCount)))
g = g && daap_add_short(mlit,"astc",song->total_tracks); /* track count */
if(song->track && (wantsMeta(meta, metaSongTrackNumber)))
g = g && daap_add_short(mlit,"astn",song->track); /* track number */
// g = g && daap_add_char(mlit,"asur",3); /* rating */
if(song->year && (wantsMeta(meta, metaSongYear)))
g = g && daap_add_short(mlit,"asyr",song->year);
}
if(g == 0)
{
daap_free(mlit);
mlit = 0;
}
return mlit;
}
/* /*
* daap_response_update * daap_response_update
* *
@ -582,16 +769,31 @@ DAAP_BLOCK *daap_response_server_info(char *name, char *client_version) {
} }
g = g && daap_add_string(root,"minm",name); /* server name */ g = g && daap_add_string(root,"minm",name); /* server name */
g = g && daap_add_char(root,"mslr",config.readpassword != NULL); /* logon required */
/* logon is always required, even if a password isn't */
g = g && daap_add_char(root,"mslr",1);
/* authentication method is 0 for nothing, 1 for name and
password, 2 for password only */
g = g && daap_add_char(root,"msau", config.readpassword != NULL ? 2 : 0);
/* actual time out seems faster then 30 minutes */
g = g && daap_add_int(root,"mstm",1800); /* timeout - iTunes=1800 */ g = g && daap_add_int(root,"mstm",1800); /* timeout - iTunes=1800 */
g = g && daap_add_char(root,"msal",0); /* autologout */
g = g && daap_add_char(root,"msup",1); /* update */ /* presence of most of the support* variables indicates
g = g && daap_add_char(root,"mspi",0); /* persistant ids */ support, the actual value is required to be zero, I've
commented out the ones I don't believe are actually
supported */
g = g && daap_add_char(root,"msex",0); /* extensions */ g = g && daap_add_char(root,"msex",0); /* extensions */
g = g && daap_add_char(root,"msix",0); /* indexing? */
#if 0
g = g && daap_add_char(root,"msal",0); /* autologout */
g = g && daap_add_char(root,"msup",0); /* update */
g = g && daap_add_char(root,"mspi",0); /* persistant ids */
g = g && daap_add_char(root,"msbr",0); /* browsing */ g = g && daap_add_char(root,"msbr",0); /* browsing */
g = g && daap_add_char(root,"msqy",0); /* queries */ g = g && daap_add_char(root,"msqy",0); /* queries */
g = g && daap_add_char(root,"msix",0); /* indexing? */
g = g && daap_add_char(root,"msrs",0); /* resolve? req. persist id */ g = g && daap_add_char(root,"msrs",0); /* resolve? req. persist id */
#endif
g = g && daap_add_int(root,"msdc",1); /* database count */ g = g && daap_add_int(root,"msdc",1); /* database count */
} }
@ -609,7 +811,7 @@ DAAP_BLOCK *daap_response_server_info(char *name, char *client_version) {
* *
* given a playlist number, return the items on the playlist * given a playlist number, return the items on the playlist
*/ */
DAAP_BLOCK *daap_response_playlist_items(unsigned int playlist) { DAAP_BLOCK *daap_response_playlist_items(unsigned int playlist, char* metaStr) {
DAAP_BLOCK *root; DAAP_BLOCK *root;
DAAP_BLOCK *mlcl; DAAP_BLOCK *mlcl;
DAAP_BLOCK *mlit; DAAP_BLOCK *mlit;
@ -617,6 +819,20 @@ DAAP_BLOCK *daap_response_playlist_items(unsigned int playlist) {
MP3FILE *current; MP3FILE *current;
int itemid; int itemid;
int g=1; int g=1;
unsigned long long meta;
// if no meta information is specifically requested, return only
// the base play list information. iTunes only requests the base
// information as it rebuilds the entire database locally so it's
// just replicated information
if(0 == metaStr)
meta = ((1ll << metaItemId) |
(1ll << metaItemName) |
(1ll << metaItemKind) |
(1ll << metaContainerItemId) |
(1ll << metaParentContainerId));
else
meta = encodeMetaRequest(metaStr, gSongMetaDataMap);
DPRINTF(ERR_DEBUG,"Preparing to send playlist items for pl #%d\n",playlist); DPRINTF(ERR_DEBUG,"Preparing to send playlist items for pl #%d\n",playlist);
@ -641,21 +857,22 @@ DAAP_BLOCK *daap_response_playlist_items(unsigned int playlist) {
if(mlcl) { if(mlcl) {
if(playlist == 1) { if(playlist == 1) {
while((current=db_enum(&henum))) { while((current=db_enum(&henum))) {
mlit=daap_add_empty(mlcl,"mlit"); mlit=daap_add_song_entry(mlcl, current, meta);
if(mlit) { if(0 != mlit) {
g = g && daap_add_char(mlit,"mikd",2); if(wantsMeta(meta, metaContainerItemId))
g = g && daap_add_int(mlit,"miid",current->id); g = g && daap_add_int(mlit,"mcti",playlist);
g = g && daap_add_int(mlit,"mcti",playlist);
} else g=0; } else g=0;
} }
} else { /* other playlist */ } else { /* other playlist */
while((itemid=db_playlist_items_enum(&henum)) != -1) { while((itemid=db_playlist_items_enum(&henum)) != -1) {
mlit=daap_add_empty(mlcl,"mlit"); current = db_find(itemid);
if(mlit) { if(0 != current) {
DPRINTF(ERR_DEBUG,"Adding itemid %d\n",itemid); DPRINTF(ERR_DEBUG,"Adding itemid %d\n",itemid);
g = g && daap_add_char(mlit,"mikd",2); mlit=daap_add_song_entry(mlcl,current,meta);
g = g && daap_add_int(mlit,"miid",itemid); if(0 != mlit) {
g = g && daap_add_int(mlit,"mcti",playlist); if(wantsMeta(meta, metaContainerItemId))
g = g && daap_add_int(mlit,"mcti",playlist);
} else g = 0;
} else g = 0; } else g = 0;
} }
} }
@ -675,4 +892,139 @@ DAAP_BLOCK *daap_response_playlist_items(unsigned int playlist) {
return root; return root;
} }
//
// handle the index= parameter
// format is:
// index=<item> a single item from the list by index
// index=<l>-<h> a range of items from the list by
// index from l to h inclusive
// index=<l>- a range of items from the list by
// index from l to the end of the list
// index=-<n> the last <n> items from the list
//
void daap_handle_index(DAAP_BLOCK* block, const char* index)
{
int first;
int count;
int size;
char* ptr;
DAAP_BLOCK* list;
DAAP_BLOCK* item;
DAAP_BLOCK**back;
int n;
// get the actual list
if(0 == (list = daap_find(block, "mlcl")))
return;
// count the items in the list
for(size = 0, item = list->children ; item ; item = item->next)
if(!strncmp(item->tag, "mlit", 4))
size++;
// range start
n = strtol(index, &ptr, 10);
// "-n": tail range, keep the last n entries
if(n < 0)
{
n *= -1;
// if we have too many entries, figure out which to keep
if(n < size)
{
first = size - n;
count = n;
}
// if we don't have enough entries, keep what we have
else
{
first = 0;
count = size;
}
}
// "n": single item
else if(0 == *ptr)
{
// item exists, return one item at the appropriate index
if(n < size)
{
first = n;
count = 1;
}
// item doesn't exist, return zero items
else
{
first = 0;
count = 0;
}
}
// "x-y": true range
else if('-' == *ptr)
{
// record range start
first = n;
// "x-": x to end
if(*++ptr == 0)
n = size;
// record range end
else
{
n = strtol(ptr, &ptr, 10) + 1;
// wanting more than there is, return fewer
if(n > size)
n = size;
}
count = n - first;
}
// update the returned record count entry, it's required, so
// should have already be created
assert(0 != (item = daap_find(block, "mrco")));
item->svalue[0] = count >> 24;
item->svalue[1] = count >> 16;
item->svalue[2] = count >> 8;
item->svalue[3] = count;
DPRINTF(ERR_INFO, "index:%s first:%d count:%d\n", index, first, count);
// remove the first first entries
for(back = &list->children ; *back && first ; )
if(!strncmp((**back).tag, "mlit", 4))
{
DPRINTF(ERR_INFO, "first:%d removing\n", first);
daap_remove(*back);
first--;
}
else
back = &(**back).next;
// keep the next count items
for( ; *back && count ; back = &(**back).next)
if(!strncmp((**back).tag, "mlit", 4))
{
DPRINTF(ERR_INFO, "count:%d keeping\n", count);
count--;
}
// remove the rest of items
while(*back)
{
if(!strncmp((**back).tag, "mlit", 4))
{
DPRINTF(ERR_INFO, "removing spare\n");
daap_remove(*back);
}
else
back = &(**back).next;
}
}

View File

@ -27,10 +27,11 @@ DAAP_BLOCK *daap_response_server_info(char *name, char *client_version);
DAAP_BLOCK *daap_response_content_codes(void); DAAP_BLOCK *daap_response_content_codes(void);
DAAP_BLOCK *daap_response_login(char *hostname); DAAP_BLOCK *daap_response_login(char *hostname);
DAAP_BLOCK *daap_response_update(int fd, int clientver); DAAP_BLOCK *daap_response_update(int fd, int clientver);
DAAP_BLOCK *daap_response_songlist(void); DAAP_BLOCK *daap_response_songlist(char* metaInfo);
DAAP_BLOCK *daap_response_playlists(char *name); DAAP_BLOCK *daap_response_playlists(char *name);
DAAP_BLOCK *daap_response_dbinfo(char *name); DAAP_BLOCK *daap_response_dbinfo(char *name);
DAAP_BLOCK *daap_response_playlist_items(unsigned int playlist); DAAP_BLOCK *daap_response_playlist_items(unsigned int playlist, char* metaStr);
void daap_handle_index(DAAP_BLOCK* block, const char* index);
DAAP_BLOCK* daap_add_song_entry(DAAP_BLOCK* mlcl, MP3FILE* song, unsigned long long meta);
#endif /* _DAAP_H_ */ #endif /* _DAAP_H_ */

View File

@ -100,6 +100,7 @@ void daap_handler(WS_CONNINFO *pwsc) {
int playlist_index; int playlist_index;
int item=0; int item=0;
char *first, *last; char *first, *last;
char* index = 0;
int streaming=0; int streaming=0;
MP3FILE *pmp3; MP3FILE *pmp3;
@ -156,6 +157,8 @@ void daap_handler(WS_CONNINFO *pwsc) {
} else if(strcmp(pwsc->uri,"/databases")==0) { } else if(strcmp(pwsc->uri,"/databases")==0) {
config_set_status(pwsc,session_id,"Sending database info"); config_set_status(pwsc,session_id,"Sending database info");
root=daap_response_dbinfo(config.servername); root=daap_response_dbinfo(config.servername);
if(0 != (index = ws_getvar(pwsc, "index")))
daap_handle_index(root, index);
} else if(strncmp(pwsc->uri,"/databases/",11) == 0) { } else if(strncmp(pwsc->uri,"/databases/",11) == 0) {
/* the /databases/ uri will either be: /* the /databases/ uri will either be:
@ -194,7 +197,8 @@ void daap_handler(WS_CONNINFO *pwsc) {
} else if (strncasecmp(last,"items",5)==0) { } else if (strncasecmp(last,"items",5)==0) {
/* songlist */ /* songlist */
free(uri); free(uri);
root=daap_response_songlist(); // pass the meta field request for processing
root=daap_response_songlist(ws_getvar(pwsc,"meta"));
config_set_status(pwsc,session_id,"Sending songlist"); config_set_status(pwsc,session_id,"Sending songlist");
} else if (strncasecmp(last,"containers/",11)==0) { } else if (strncasecmp(last,"containers/",11)==0) {
/* playlist elements */ /* playlist elements */
@ -207,7 +211,9 @@ void daap_handler(WS_CONNINFO *pwsc) {
if(*last) { if(*last) {
*last='\0'; *last='\0';
playlist_index=atoi(first); playlist_index=atoi(first);
root=daap_response_playlist_items(playlist_index); // pass the meta list info for processing
root=daap_response_playlist_items(playlist_index,
ws_getvar(pwsc,"meta"));
} }
free(uri); free(uri);
config_set_status(pwsc,session_id,"Sending playlist info"); config_set_status(pwsc,session_id,"Sending playlist info");
@ -218,6 +224,10 @@ void daap_handler(WS_CONNINFO *pwsc) {
config_set_status(pwsc,session_id,"Sending playlist info"); config_set_status(pwsc,session_id,"Sending playlist info");
} }
} }
// prune the full list if an index range was specified
if(0 != (index = ws_getvar(pwsc, "index")))
daap_handle_index(root, index);
} }
if((!root)&&(!streaming)) { if((!root)&&(!streaming)) {
@ -276,9 +286,17 @@ void daap_handler(WS_CONNINFO *pwsc) {
DPRINTF(ERR_DEBUG,"Thread %d: Length of file (remaining) is %ld\n", DPRINTF(ERR_DEBUG,"Thread %d: Length of file (remaining) is %ld\n",
pwsc->threadno,(long)file_len); pwsc->threadno,(long)file_len);
// DWB: fix content-type to correctly reflect data
// content type (dmap tagged) should only be used on
// dmap protocol requests, not the actually song data
if(pmp3->type)
ws_addresponseheader(pwsc,"Content-Type","audio/%s",(pmp3->type)+1);
ws_addresponseheader(pwsc,"Content-Length","%ld",(long)file_len); ws_addresponseheader(pwsc,"Content-Length","%ld",(long)file_len);
ws_addresponseheader(pwsc,"Connection","Close"); ws_addresponseheader(pwsc,"Connection","Close");
if(!offset) if(!offset)
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n"); ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
else { else {

View File

@ -452,7 +452,9 @@ int ws_getpostvars(WS_CONNINFO *pwsc) {
return -1; return -1;
} }
if((readtimed(pwsc->fd, buffer, length, 30.0)) == -1) { // make the read time out 30 minutes like we said in the
// /server-info response
if((readtimed(pwsc->fd, buffer, length, 1800.0)) == -1) {
DPRINTF(ERR_INFO,"Thread %d: Timeout reading post vars\n", DPRINTF(ERR_INFO,"Thread %d: Timeout reading post vars\n",
pwsc->threadno); pwsc->threadno);
pwsc->error=errno; pwsc->error=errno;