diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index ef5d6454..949acb1b 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -1,17 +1,11 @@ rspdir = ${pkglibdir}/plugins -out_daapdir = ${pkglibdir}/plugins rsp_LTLIBRARIES=rsp.la rsp_la_LDFLAGS=-module -avoid-version rsp_la_SOURCES = rsp.c xml-rpc.c -out_daap_LTLIBRARIES=out-daap.la -out_daap_la_LDFLAGS=-module -avoid-version -out_daap_la_SOURCES=out-daap.c out-daap-proto.c - -EXTRA_DIST = rsp.h xml-rpc.h out-daap.h \ - out-daap-proto.h +EXTRA_DIST = rsp.h xml-rpc.h AM_CFLAGS = -I.. diff --git a/src/plugins/out-daap-proto.c b/src/plugins/out-daap-proto.c deleted file mode 100644 index e4084d26..00000000 --- a/src/plugins/out-daap-proto.c +++ /dev/null @@ -1,929 +0,0 @@ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#ifdef HAVE_STDINT_H -#include -#endif - -#include "ff-dbstruct.h" -#include "ff-plugins.h" -#include "out-daap.h" -#include "out-daap-proto.h" - -DAAP_ITEMS taglist[] = { - { 0x05, "miid", "dmap.itemid" }, - { 0x09, "minm", "dmap.itemname" }, - { 0x01, "mikd", "dmap.itemkind" }, - { 0x07, "mper", "dmap.persistentid" }, - { 0x0C, "mcon", "dmap.container" }, - { 0x05, "mcti", "dmap.containeritemid" }, - { 0x05, "mpco", "dmap.parentcontainerid" }, - { 0x05, "mstt", "dmap.status" }, - { 0x09, "msts", "dmap.statusstring" }, - { 0x05, "mimc", "dmap.itemcount" }, - { 0x05, "mctc", "dmap.containercount" }, - { 0x05, "mrco", "dmap.returnedcount" }, - { 0x05, "mtco", "dmap.specifiedtotalcount" }, - { 0x0C, "mlcl", "dmap.listing" }, - { 0x0C, "mlit", "dmap.listingitem" }, - { 0x0C, "mbcl", "dmap.bag" }, - { 0x0C, "mdcl", "dmap.dictionary" }, - { 0x0C, "msrv", "dmap.serverinforesponse" }, - { 0x01, "msau", "dmap.authenticationmethod" }, - { 0x01, "mslr", "dmap.loginrequired" }, - { 0x0B, "mpro", "dmap.protocolversion" }, - { 0x01, "msal", "dmap.supportsautologout" }, - { 0x01, "msup", "dmap.supportsupdate" }, - { 0x01, "mspi", "dmap.supportspersistentids" }, - { 0x01, "msex", "dmap.supportsextensions" }, - { 0x01, "msbr", "dmap.supportsbrowse" }, - { 0x01, "msqy", "dmap.supportsquery" }, - { 0x01, "msix", "dmap.supportsindex" }, - { 0x01, "msrs", "dmap.supportsresolve" }, - { 0x05, "mstm", "dmap.timeoutinterval" }, - { 0x05, "msdc", "dmap.databasescount" }, - { 0x0C, "mlog", "dmap.loginresponse" }, - { 0x05, "mlid", "dmap.sessionid" }, - { 0x0C, "mupd", "dmap.updateresponse" }, - { 0x05, "musr", "dmap.serverrevision" }, - { 0x01, "muty", "dmap.updatetype" }, - { 0x0C, "mudl", "dmap.deletedidlisting" }, - { 0x0C, "mccr", "dmap.contentcodesresponse" }, - { 0x05, "mcnm", "dmap.contentcodesnumber" }, - { 0x09, "mcna", "dmap.contentcodesname" }, - { 0x03, "mcty", "dmap.contentcodestype" }, - { 0x0B, "apro", "daap.protocolversion" }, - { 0x0C, "avdb", "daap.serverdatabases" }, - { 0x0C, "abro", "daap.databasebrowse" }, - { 0x0C, "abal", "daap.browsealbumlisting" }, - { 0x0C, "abar", "daap.browseartistlisting" }, - { 0x0C, "abcp", "daap.browsecomposerlisting" }, - { 0x0C, "abgn", "daap.browsegenrelisting" }, - { 0x0C, "adbs", "daap.databasesongs" }, - { 0x09, "asal", "daap.songalbum" }, - { 0x09, "asar", "daap.songartist" }, - { 0x03, "asbt", "daap.songbeatsperminute" }, - { 0x03, "asbr", "daap.songbitrate" }, - { 0x09, "ascm", "daap.songcomment" }, - { 0x01, "asco", "daap.songcompilation" }, - { 0x09, "ascp", "daap.songcomposer" }, - { 0x0A, "asda", "daap.songdateadded" }, - { 0x0A, "asdm", "daap.songdatemodified" }, - { 0x03, "asdc", "daap.songdisccount" }, - { 0x03, "asdn", "daap.songdiscnumber" }, - { 0x01, "asdb", "daap.songdisabled" }, - { 0x09, "aseq", "daap.songeqpreset" }, - { 0x09, "asfm", "daap.songformat" }, - { 0x09, "asgn", "daap.songgenre" }, - { 0x09, "asdt", "daap.songdescription" }, - { 0x02, "asrv", "daap.songrelativevolume" }, - { 0x05, "assr", "daap.songsamplerate" }, - { 0x05, "assz", "daap.songsize" }, - { 0x05, "asst", "daap.songstarttime" }, - { 0x05, "assp", "daap.songstoptime" }, - { 0x05, "astm", "daap.songtime" }, - { 0x03, "astc", "daap.songtrackcount" }, - { 0x03, "astn", "daap.songtracknumber" }, - { 0x01, "asur", "daap.songuserrating" }, - { 0x03, "asyr", "daap.songyear" }, - { 0x01, "asdk", "daap.songdatakind" }, - { 0x09, "asul", "daap.songdataurl" }, - { 0x0C, "aply", "daap.databaseplaylists" }, - { 0x01, "abpl", "daap.baseplaylist" }, - { 0x0C, "apso", "daap.playlistsongs" }, - { 0x0C, "arsv", "daap.resolve" }, - { 0x0C, "arif", "daap.resolveinfo" }, - { 0x05, "aeNV", "com.apple.itunes.norm-volume" }, - { 0x01, "aeSP", "com.apple.itunes.smart-playlist" }, - - /* iTunes 4.5+ */ - { 0x01, "msas", "dmap.authenticationschemes" }, - { 0x05, "ascd", "daap.songcodectype" }, - { 0x05, "ascs", "daap.songcodecsubtype" }, - { 0x09, "agrp", "daap.songgrouping" }, - { 0x05, "aeSV", "com.apple.itunes.music-sharing-version" }, - { 0x05, "aePI", "com.apple.itunes.itms-playlistid" }, - { 0x05, "aeCI", "com.apple.iTunes.itms-composerid" }, - { 0x05, "aeGI", "com.apple.iTunes.itms-genreid" }, - { 0x05, "aeAI", "com.apple.iTunes.itms-artistid" }, - { 0x05, "aeSI", "com.apple.iTunes.itms-songid" }, - { 0x05, "aeSF", "com.apple.iTunes.itms-storefrontid" }, - - /* iTunes 5.0+ */ - { 0x01, "ascr", "daap.songcontentrating" }, - { 0x01, "f" "\x8d" "ch", "dmap.haschildcontainers" }, - - /* iTunes 6.0.2+ */ - { 0x01, "aeHV", "com.apple.itunes.has-video" }, - - /* iTunes 6.0.4+ */ - { 0x05, "msas", "dmap.authenticationschemes" }, - { 0x09, "asct", "daap.songcategory" }, - { 0x09, "ascn", "daap.songcontentdescription" }, - { 0x09, "aslc", "daap.songlongcontentdescription" }, - { 0x09, "asky", "daap.songkeywords" }, - { 0x01, "apsm", "daap.playlistshufflemode" }, - { 0x01, "aprm", "daap.playlistrepeatmode" }, - { 0x01, "aePC", "com.apple.itunes.is-podcast" }, - { 0x01, "aePP", "com.apple.itunes.is-podcast-playlist" }, - { 0x01, "aeMK", "com.apple.itunes.mediakind" }, - { 0x09, "aeSN", "com.apple.itunes.series-name" }, - { 0x09, "aeNN", "com.apple.itunes.network-name" }, - { 0x09, "aeEN", "com.apple.itunes.episode-num-str" }, - { 0x05, "aeES", "com.apple.itunes.episode-sort" }, - { 0x05, "aeSU", "com.apple.itunes.season-num" }, - - /* mt-daapd specific */ - { 0x09, "MSPS", "org.mt-daapd.smart-playlist-spec" }, - { 0x01, "MPTY", "org.mt-daapd.playlist-type" }, - { 0x0C, "MAPR", "org.mt-daapd.addplaylist" }, - { 0x0C, "MAPI", "org.mt-daapd.addplaylistitem" }, - { 0x0C, "MDPR", "org.mt-daapd.delplaylist" }, - { 0x0C, "MDPI", "org.mt-daapd.delplaylistitem" }, - { 0x0C, "MEPR", "org.mt-daapd.editplaylist" }, - - { 0x00, NULL, NULL } -}; - -typedef struct { - const char* tag; - MetaFieldName_t bit; -} METAMAP; - -/** map the string names specified in the meta= tag to bit numbers */ -static METAMAP db_metamap[] = { - { "dmap.itemid", metaItemId }, - { "dmap.itemname", metaItemName }, - { "dmap.itemkind", metaItemKind }, - { "dmap.persistentid", metaPersistentId }, - { "dmap.containeritemid", metaContainerItemId }, - { "dmap.parentcontainerid", metaParentContainerId }, - /* end generics */ - { "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 }, - - /* iTunes 4.5+ (forgot exactly when) */ - { "daap.songcodectype", metaSongCodecType }, - { "daap.songcodecsubtype", metaSongCodecSubType }, - { "com.apple.itunes.norm-volume", metaItunesNormVolume }, - { "com.apple.itunes.itms-songid", metaItmsSongId }, - { "com.apple.itunes.itms-artistid", metaItmsArtistId }, - { "com.apple.itunes.itms-playlistid", metaItmsPlaylistId }, - { "com.apple.itunes.itms-composerid", metaItmsComposerId }, - { "com.apple.itunes.itms-genreid", metaItmsGenreId }, - { "com.apple.itunes.itms-storefrontid",metaItmsStorefrontId }, - { "com.apple.itunes.smart-playlist", metaItunesSmartPlaylist }, - - /* iTunes 5.0+ */ - { "daap.songcontentrating", metaSongContentRating }, - { "dmap.haschildcontainers", metaHasChildContainers }, - - /* iTunes 6.0.2+ */ - { "com.apple.itunes.has-video", metaItunesHasVideo }, - - /* mt-daapd specific */ - { "org.mt-daapd.smart-playlist-spec", metaMPlaylistSpec }, - { "org.mt-daapd.playlist-type", metaMPlaylistType }, - - { 0, 0 } -}; - -int out_daap_session=0; - -#define DMAPLEN(a) (((a) && strlen(a)) ? (8+(int)strlen((a))) : \ - ((pinfo->empty_strings) ? 8 : 0)) -#define EMIT(a) (pinfo->empty_strings ? 1 : ((a) && strlen((a))) ? 1 : 0) - -/* Forwards */ -int daap_get_size(PRIVINFO *pinfo, char **valarray); -int daap_build_dmap(PRIVINFO *pinfo, char **valarray, unsigned char *presult, int len); - -/** - * encode a string meta request into a MetaField_t - * - * \param meta meta string variable from GET request - */ -MetaField_t daap_encode_meta(char *meta) { - MetaField_t bits = 0; - char *start; - char *end; - METAMAP *m; - - for(start = meta ; *start ; start = end) { - int len; - - if(0 == (end = strchr(start, ','))) - end = start + strlen(start); - - len = (int)(end - start); - - if(*end != 0) - end++; - - for(m = db_metamap ; m->tag ; ++m) - if(!strncmp(m->tag, start, len)) - break; - - if(m->tag) - bits |= (((MetaField_t) 1) << m->bit); - else - pi_log(E_WARN,"Unknown meta code: %.*s\n", len, start); - } - - pi_log(E_DBG, "meta codes: %llu\n", bits); - - return bits; -} - -/** - * see if a specific metafield was requested - * - * \param meta encoded list of requested metafields - * \param fieldNo field to test for - */ -int daap_wantsmeta(MetaField_t meta, MetaFieldName_t fieldNo) { - return 0 != (meta & (((MetaField_t) 1) << fieldNo)); -} - -/** - * add a character type to a dmap block (type 0x01) - * - * \param where where to serialize the dmap info - * \tag what four byte tag - * \value what character value - */ -int dmap_add_char(unsigned char *where, char *tag, char value) { - /* tag */ - memcpy(where,tag,4); - - /* len */ - where[4]=where[5]=where[6]=0; - where[7]=1; - - /* value */ - where[8] = value; - return 9; -} - -/** - * add a short type to a dmap block (type 0x03) - * - * \param where where to serialize the dmap info - * \tag what four byte tag - * \value what character value - */ -int dmap_add_short(unsigned char *where, char *tag, short value) { - /* tag */ - memcpy(where,tag,4); - - /* len */ - where[4]=where[5]=where[6]=0; - where[7]=2; - - /* value */ - where[8] = (value >> 8) & 0xFF; - where[9] = value & 0xFF; - return 10; -} - - -/** - * add an int type to a dmap block (type 0x05) - * - * \param where where to serialize the dmap info - * \tag what four byte tag - * \value what character value - */ - -int dmap_add_int(unsigned char *where, char *tag, int value) { - /* tag */ - memcpy(where,tag,4); - /* len */ - where[4]=where[5]=where[6]=0; - where[7]=4; - - /* value */ - where[8] = (value >> 24) & 0xFF; - where[9] = (value >> 16) & 0xFF; - where[10] = (value >> 8) & 0xFF; - where[11] = value & 0xFF; - - return 12; -} - -int dmap_add_long(unsigned char *where, char *tag, uint64_t value) { - uint32_t v_hi; - uint32_t v_lo; - - /* tag */ - memcpy(where,tag,4); - /* len */ - where[4]=where[5]=where[6]=0; - where[7]=8; - - v_hi = (uint32_t)((value >> 32) & 0xFFFFFFFF); - v_lo = (uint32_t)(value & 0xFFFFFFFF); - - /* value */ - where[8] = (v_hi >> 24) & 0xFF; - where[9] = (v_hi >> 16) & 0xFF; - where[10] = (v_hi >> 8) & 0xFF; - where[11] = v_hi & 0xFF; - - where[12] = (v_lo >> 24) & 0xFF; - where[13] = (v_lo >> 16) & 0xFF; - where[14] = (v_lo >> 8) & 0xFF; - where[15] = v_lo & 0xFF; - - return 16; -} - - -/** - * add a string type to a dmap block (type 0x09) - * - * \param where where to serialize the dmap info - * \tag what four byte tag - * \value what character value - */ - -int dmap_add_string(unsigned char *where, char *tag, char *value) { - int len=0; - - if(value) - len = (int)strlen(value); - - /* tag */ - memcpy(where,tag,4); - - /* length */ - where[4]=(len >> 24) & 0xFF; - where[5]=(len >> 16) & 0xFF; - where[6]=(len >> 8) & 0xFF; - where[7]=len & 0xFF; - - if(len) - strncpy((char*)where+8,value,len); - return 8 + len; -} - -/** - * add a literal chunk of data to a dmap block - * - * \param where where to serialize the dmap info - * \param tag what four byte tag - * \param value what to put there - * \param size how much data to cram in there - */ -int dmap_add_literal(unsigned char *where, char *tag, - char *value, int size) { - /* tag */ - memcpy(where,tag,4); - - /* length */ - where[4]=(size >> 24) & 0xFF; - where[5]=(size >> 16) & 0xFF; - where[6]=(size >> 8) & 0xFF; - where[7]=size & 0xFF; - - memcpy(where+8,value,size); - return 8+size; -} - - -/** - * add a container type to a dmap block (type 0x0C) - * - * \param where where to serialize the dmap info - * \tag what four byte tag - * \value what character value - */ - -int dmap_add_container(unsigned char *where, char *tag, int size) { - int len=size; - - /* tag */ - memcpy(where,tag,4); - - /* length */ - where[4]=(len >> 24) & 0xFF; - where[5]=(len >> 16) & 0xFF; - where[6]=(len >> 8) & 0xFF; - where[7]=len & 0xFF; - - return 8; -} - -/** - * Get the next available session id. - * This is vulnerable to races, but we don't track sessions, - * so there really isn't a point anyway. - * - * @returns duh... the next available session id - */ -int daap_get_next_session(void) { - int session; - - session=++out_daap_session; - - return session; -} - -/** - * find the size of the response by walking through the query and - * sizing it - * - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int daap_enum_size(char **pe, PRIVINFO *pinfo, int *count, int *total_size) { - int err; - int record_size; - char **row; - - pi_log(E_DBG,"Enumerating size\n"); - - *count=0; - *total_size = 0; - - while((!(err=pi_db_enum_fetch_row(pe,&row,&pinfo->dq))) && (row)) { - if((record_size = daap_get_size(pinfo,row))) { - *total_size += record_size; - *count = *count + 1; - } - } - - if(err) { - pi_db_enum_end(NULL); - pi_db_enum_dispose(NULL,&pinfo->dq); - return err; - } - - err=pi_db_enum_restart(pe, &pinfo->dq); - - pi_log(E_DBG,"Got size: %d\n",*total_size); - return err; -} - -/** - * fetch the next record from the enum - */ -int daap_enum_fetch(char **pe, PRIVINFO *pinfo, int *size, unsigned char **pdmap) { - int err; - int result_size=0; - unsigned char *presult; - char **row; - - err=pi_db_enum_fetch_row(pe, &row, &pinfo->dq); - if(err) { - pi_db_enum_end(NULL); - pi_db_enum_dispose(NULL,&pinfo->dq); - return err; - } - - if(row) { - result_size = daap_get_size(pinfo,row); - if(result_size) { - presult = (unsigned char*)malloc(result_size); - if(!presult) { - pi_log(E_FATAL,"Malloc error\n"); - } - - daap_build_dmap(pinfo,row,presult,result_size); - *pdmap=presult; - *size = result_size; - } - } else { - *size = 0; - } - - return 0; -} - -/** - * get the size of the generated dmap, given a specific meta - */ -int daap_get_size(PRIVINFO *pinfo, char **valarray) { - int size; - int transcode; - - switch(pinfo->dq.query_type) { - case QUERY_TYPE_DISTINCT: /* simple 'mlit' entry */ - return valarray[0] ? (8 + (int) strlen(valarray[0])) : 0; - case QUERY_TYPE_PLAYLISTS: - size = 8; /* mlit */ - size += 12; /* mimc - you get it whether you want it or not */ - if(daap_wantsmeta(pinfo->meta, metaItemId)) - size += 12; /* miid */ - if(daap_wantsmeta(pinfo->meta, metaItunesSmartPlaylist)) { - if(valarray[PL_TYPE] && (atoi(valarray[PL_TYPE])==1) && - (atoi(valarray[PL_ID]) != 1)) - size += 9; /* aeSP */ - } - - if(atoi(valarray[PL_ID]) == 1) { - size += 9; /* abpl */ - } - - if(daap_wantsmeta(pinfo->meta, metaItemName)) - size += (8 + (int) strlen(valarray[PL_TITLE])); /* minm */ - if(valarray[PL_TYPE] && (atoi(valarray[PL_TYPE])==1) && - daap_wantsmeta(pinfo->meta, metaMPlaylistSpec)) - size += (8 + (int) strlen(valarray[PL_QUERY])); /* MSPS */ - if(daap_wantsmeta(pinfo->meta, metaMPlaylistType)) - size += 9; /* MPTY */ - return size; - break; - case QUERY_TYPE_ITEMS: - /* see if this is going to be transcoded */ - transcode = pi_should_transcode(pinfo->pwsc,valarray[SG_CODECTYPE]); - - /* Items that get changed by transcode: - * - * type: item 8: changes to 'wav' - * description: item 29: changes to 'wav audio file' - * bitrate: item 15: guestimated, based on item 15, samplerate - * - * probably file size should change as well, but currently doesn't - */ - - size = 8; /* mlit */ - if(daap_wantsmeta(pinfo->meta, metaItemKind)) - /* mikd */ - size += 9; - if(daap_wantsmeta(pinfo->meta, metaSongDataKind)) - /* asdk */ - size += 9; - if(daap_wantsmeta(pinfo->meta, metaSongDataURL)) - /* asul */ - size += DMAPLEN(valarray[SG_URL]); - if(daap_wantsmeta(pinfo->meta, metaSongAlbum)) - /* asal */ - size += DMAPLEN(valarray[SG_ALBUM]); - if(daap_wantsmeta(pinfo->meta, metaSongArtist)) - /* asar */ - size += DMAPLEN(valarray[SG_ARTIST]); - if(daap_wantsmeta(pinfo->meta, metaSongBPM)) - /* asbt */ - size += 10; - if(daap_wantsmeta(pinfo->meta, metaSongBitRate)) { - /* asbr */ - if(transcode) { - if(valarray[SG_SAMPLERATE] && atoi(valarray[SG_SAMPLERATE])) { - size += 10; - } - } else { - if(valarray[SG_BITRATE] && atoi(valarray[SG_BITRATE])) { - size += 10; - } - } - } - if(daap_wantsmeta(pinfo->meta, metaSongComment)) - /* ascm */ - size += DMAPLEN(valarray[SG_COMMENT]); - if(valarray[SG_COMPILATION] && atoi(valarray[SG_COMPILATION]) && - daap_wantsmeta(pinfo->meta,metaSongCompilation)) - /* asco */ - size += 9; - if(daap_wantsmeta(pinfo->meta, metaSongComposer)) - /* ascp */ - size += DMAPLEN(valarray[SG_COMPOSER]); - if(daap_wantsmeta(pinfo->meta, metaSongGrouping)) - /* agrp */ - size += DMAPLEN(valarray[SG_GROUPING]); - if(valarray[SG_TIME_ADDED] && atoi(valarray[SG_TIME_ADDED]) && - daap_wantsmeta(pinfo->meta, metaSongDateAdded)) - /* asda */ - size += 12; - if(valarray[SG_TIME_MODIFIED] && atoi(valarray[SG_TIME_MODIFIED]) && - daap_wantsmeta(pinfo->meta,metaSongDateModified)) - /* asdm */ - size += 12; - if(daap_wantsmeta(pinfo->meta, metaSongDiscCount)) - /* asdc */ - size += 10; - if(daap_wantsmeta(pinfo->meta, metaSongDiscNumber)) - /* asdn */ - size += 10; - if(daap_wantsmeta(pinfo->meta, metaSongGenre)) - /* asgn */ - size += DMAPLEN(valarray[SG_GENRE]); - if(daap_wantsmeta(pinfo->meta,metaItemId)) - /* miid */ - size += 12; - if(daap_wantsmeta(pinfo->meta,metaSongFormat)) { - /* asfm */ - if(transcode) { - size += 11; /* 'wav' */ - } else { - size += DMAPLEN(valarray[SG_TYPE]); - } - } - if(daap_wantsmeta(pinfo->meta,metaSongDescription)) { - /* asdt */ - if(transcode) { - size += 22; /* 'wav audio file' */ - } else { - size += DMAPLEN(valarray[SG_DESCRIPTION]); - } - } - if(daap_wantsmeta(pinfo->meta,metaItemName)) - /* minm */ - size += DMAPLEN(valarray[SG_TITLE]); - if(valarray[SG_DISABLED] && atoi(valarray[SG_DISABLED]) && - daap_wantsmeta(pinfo->meta,metaSongDisabled)) - /* asdb */ - size += 9; - if(valarray[SG_SAMPLERATE] && atoi(valarray[SG_SAMPLERATE]) && - daap_wantsmeta(pinfo->meta,metaSongSampleRate)) - /* assr */ - size += 12; - if(valarray[SG_FILE_SIZE] && atoi(valarray[SG_FILE_SIZE]) && - daap_wantsmeta(pinfo->meta,metaSongSize)) - /* assz */ - size += 12; - - /* In the old daap code, we always returned 0 for asst and assp - * (song start time, song stop time). I don't know if this - * is required, so I'm going to disabled it - */ - - if(valarray[SG_SONG_LENGTH] && atoi(valarray[SG_SONG_LENGTH]) && - daap_wantsmeta(pinfo->meta, metaSongTime)) - /* astm */ - size += 12; - if(valarray[SG_TOTAL_TRACKS] && atoi(valarray[SG_TOTAL_TRACKS]) && - daap_wantsmeta(pinfo->meta, metaSongTrackCount)) - /* astc */ - size += 10; - if(valarray[SG_TRACK] && atoi(valarray[SG_TRACK]) && - daap_wantsmeta(pinfo->meta, metaSongTrackNumber)) - /* astn */ - size += 10; - if(daap_wantsmeta(pinfo->meta, metaSongUserRating)) - /* asur */ - size += 9; - if(valarray[SG_YEAR] && atoi(valarray[SG_YEAR]) && - daap_wantsmeta(pinfo->meta, metaSongYear)) - /* asyr */ - size += 10; - if(daap_wantsmeta(pinfo->meta, metaContainerItemId)) - /* mcti */ - size += 12; - /* FIXME: This is not right - doesn't have to be 4 */ - if((valarray[SG_CODECTYPE]) && (strlen(valarray[SG_CODECTYPE])==4) && - daap_wantsmeta(pinfo->meta,metaSongCodecType)) - /* ascd */ - size += 12; - if(daap_wantsmeta(pinfo->meta,metaSongContentRating)) - /* ascr */ - size += 9; - if(daap_wantsmeta(pinfo->meta,metaItunesHasVideo)) - /* aeHV */ - size += 9; - - return size; - break; - - default: - pi_log(E_LOG,"Unknown query type: %d\n",(int)pinfo->dq.query_type); - return 0; - } - return 0; -} - -int daap_build_dmap(PRIVINFO *pinfo, char **valarray, unsigned char *presult, int len) { - unsigned char *current = presult; - int transcode; - int samplerate=0; - - switch(pinfo->dq.query_type) { - case QUERY_TYPE_DISTINCT: - return dmap_add_string(current,"mlit",valarray[0]); - case QUERY_TYPE_PLAYLISTS: - /* do I want to include the mlit? */ - current += dmap_add_container(current,"mlit",len - 8); - if(daap_wantsmeta(pinfo->meta,metaItemId)) - current += dmap_add_int(current,"miid",atoi(valarray[PL_ID])); - current += dmap_add_int(current,"mimc",atoi(valarray[PL_ITEMS])); - if(daap_wantsmeta(pinfo->meta,metaItunesSmartPlaylist)) { - if(valarray[PL_TYPE] && (atoi(valarray[PL_TYPE]) == 1) && - (atoi(valarray[PL_ID]) != 1)) - current += dmap_add_char(current,"aeSP",1); - } - if(atoi(valarray[PL_ID]) == 1) { - current += dmap_add_char(current,"abpl",1); - } - - if(daap_wantsmeta(pinfo->meta,metaItemName)) - current += dmap_add_string(current,"minm",valarray[PL_TITLE]); - if((valarray[PL_TYPE]) && (atoi(valarray[PL_TYPE])==1) && - daap_wantsmeta(pinfo->meta, metaMPlaylistSpec)) - current += dmap_add_string(current,"MSPS",valarray[PL_QUERY]); - if(daap_wantsmeta(pinfo->meta, metaMPlaylistType)) - current += dmap_add_char(current,"MPTY",atoi(valarray[PL_TYPE])); - break; - case QUERY_TYPE_ITEMS: - /* see if this is going to be transcoded */ - transcode = pi_should_transcode(pinfo->pwsc,valarray[SG_CODECTYPE]); - - /* Items that get changed by transcode: - * - * type: item 8: changes to 'wav' - * description: item 29: changes to 'wav audio file' - * bitrate: item 15: guestimated, but doesn't change file size - * - * probably file size should change as well, but currently doesn't - */ - - current += dmap_add_container(current,"mlit",len-8); - if(daap_wantsmeta(pinfo->meta, metaItemKind)) - current += dmap_add_char(current,"mikd", - (char)atoi(valarray[SG_ITEM_KIND])); - if(daap_wantsmeta(pinfo->meta, metaSongDataKind)) - current += dmap_add_char(current,"asdk", - (char)atoi(valarray[SG_DATA_KIND])); - if(EMIT(valarray[13]) && daap_wantsmeta(pinfo->meta, metaSongDataURL)) - current += dmap_add_string(current,"asul",valarray[SG_URL]); - if(EMIT(valarray[5]) && daap_wantsmeta(pinfo->meta, metaSongAlbum)) - current += dmap_add_string(current,"asal",valarray[SG_ALBUM]); - if(EMIT(valarray[4]) && daap_wantsmeta(pinfo->meta, metaSongArtist)) - current += dmap_add_string(current,"asar",valarray[SG_ARTIST]); - if(daap_wantsmeta(pinfo->meta, metaSongBPM)) - current += dmap_add_short(current,"asbt", - (short)atoi(valarray[SG_BPM])); - if(valarray[SG_BITRATE] && atoi(valarray[SG_BITRATE]) && - daap_wantsmeta(pinfo->meta, metaSongBitRate)) { - if(transcode) { - if(valarray[SG_SAMPLERATE]) - samplerate=atoi(valarray[SG_SAMPLERATE]); - if(samplerate) { - current += dmap_add_short(current,"asbr", - (short)(samplerate / 250 * 8)); - } - } else { - current += dmap_add_short(current,"asbr", - (short)atoi(valarray[SG_BITRATE])); - } - } - if(EMIT(valarray[SG_COMMENT]) && - daap_wantsmeta(pinfo->meta, metaSongComment)) - current += dmap_add_string(current,"ascm",valarray[SG_COMMENT]); - - if(valarray[SG_COMPILATION] && atoi(valarray[SG_COMPILATION]) && - daap_wantsmeta(pinfo->meta,metaSongCompilation)) - current += dmap_add_char(current,"asco", - (char)atoi(valarray[SG_COMPILATION])); - - if(EMIT(valarray[SG_COMPOSER]) && - daap_wantsmeta(pinfo->meta, metaSongComposer)) - current += dmap_add_string(current,"ascp", - valarray[SG_COMPOSER]); - - if(EMIT(valarray[SG_GROUPING]) && - daap_wantsmeta(pinfo->meta, metaSongGrouping)) - current += dmap_add_string(current,"agrp", - valarray[SG_GROUPING]); - - if(valarray[SG_TIME_ADDED] && atoi(valarray[SG_TIME_ADDED]) && - daap_wantsmeta(pinfo->meta, metaSongDateAdded)) - current += dmap_add_int(current,"asda", - (int)atoi(valarray[SG_TIME_ADDED])); - - if(valarray[SG_TIME_MODIFIED] && atoi(valarray[SG_TIME_MODIFIED]) && - daap_wantsmeta(pinfo->meta,metaSongDateModified)) - current += dmap_add_int(current,"asdm", - (int)atoi(valarray[SG_TIME_MODIFIED])); - - if(daap_wantsmeta(pinfo->meta, metaSongDiscCount)) - current += dmap_add_short(current,"asdc", - (short)atoi(valarray[SG_TOTAL_DISCS])); - if(daap_wantsmeta(pinfo->meta, metaSongDiscNumber)) - current += dmap_add_short(current,"asdn", - (short)atoi(valarray[SG_DISC])); - - if(EMIT(valarray[SG_GENRE]) && - daap_wantsmeta(pinfo->meta, metaSongGenre)) - current += dmap_add_string(current,"asgn",valarray[SG_GENRE]); - - if(daap_wantsmeta(pinfo->meta,metaItemId)) - current += dmap_add_int(current,"miid", - (int)atoi(valarray[SG_ID])); - - if(EMIT(valarray[SG_TYPE]) && - daap_wantsmeta(pinfo->meta,metaSongFormat)) { - if(transcode) { - current += dmap_add_string(current,"asfm","wav"); - } else { - current += dmap_add_string(current,"asfm", - valarray[SG_TYPE]); - } - } - - if(EMIT(valarray[SG_DESCRIPTION]) && - daap_wantsmeta(pinfo->meta,metaSongDescription)) { - if(transcode) { - current += dmap_add_string(current,"asdt","wav audio file"); - } else { - current += dmap_add_string(current,"asdt", - valarray[SG_DESCRIPTION]); - } - } - if(EMIT(valarray[SG_TITLE]) && - daap_wantsmeta(pinfo->meta,metaItemName)) - current += dmap_add_string(current,"minm",valarray[SG_TITLE]); - - if(valarray[SG_DISABLED] && atoi(valarray[SG_DISABLED]) && - daap_wantsmeta(pinfo->meta,metaSongDisabled)) - current += dmap_add_char(current,"asdb", - (char)atoi(valarray[SG_DISABLED])); - - if(valarray[SG_SAMPLERATE] && atoi(valarray[SG_SAMPLERATE]) && - daap_wantsmeta(pinfo->meta,metaSongSampleRate)) - current += dmap_add_int(current,"assr", - atoi(valarray[SG_SAMPLERATE])); - - if(valarray[SG_FILE_SIZE] && atoi(valarray[SG_FILE_SIZE]) && - daap_wantsmeta(pinfo->meta,metaSongSize)) - current += dmap_add_int(current,"assz", - atoi(valarray[SG_FILE_SIZE])); - - if(valarray[SG_SONG_LENGTH] && atoi(valarray[SG_SONG_LENGTH]) && - daap_wantsmeta(pinfo->meta, metaSongTime)) - current += dmap_add_int(current,"astm", - atoi(valarray[SG_SONG_LENGTH])); - - if(valarray[SG_TOTAL_TRACKS] && atoi(valarray[SG_TOTAL_TRACKS]) && - daap_wantsmeta(pinfo->meta, metaSongTrackCount)) - current += dmap_add_short(current,"astc", - (short)atoi(valarray[SG_TOTAL_TRACKS])); - - if(valarray[SG_TRACK] && atoi(valarray[SG_TRACK]) && - daap_wantsmeta(pinfo->meta, metaSongTrackNumber)) - current += dmap_add_short(current,"astn", - (short)atoi(valarray[SG_TRACK])); - - if(daap_wantsmeta(pinfo->meta, metaSongUserRating)) - current += dmap_add_char(current,"asur", - (char)atoi(valarray[SG_RATING])); - - if(valarray[SG_YEAR] && atoi(valarray[SG_YEAR]) && - daap_wantsmeta(pinfo->meta, metaSongYear)) - current += dmap_add_short(current,"asyr", - (short)atoi(valarray[SG_YEAR])); - - if((valarray[SG_CODECTYPE]) && (strlen(valarray[SG_CODECTYPE]) == 4) && - daap_wantsmeta(pinfo->meta,metaSongCodecType)) - current += dmap_add_literal(current,"ascd", - valarray[SG_CODECTYPE],4); - if(daap_wantsmeta(pinfo->meta, metaContainerItemId)) - current += dmap_add_int(current,"mcti",atoi(valarray[SG_ID])); - - if(daap_wantsmeta(pinfo->meta, metaItunesHasVideo)) - current += dmap_add_char(current,"aeHV", - atoi(valarray[SG_HAS_VIDEO])); - - if(daap_wantsmeta(pinfo->meta, metaSongContentRating)) - current += dmap_add_char(current,"ascr", - atoi(valarray[SG_CONTENTRATING])); - return 0; - break; - - default: - pi_log(E_LOG,"Unknown query type: %d\n",(int)pinfo->dq.query_type); - return 0; - } - return 0; -} - diff --git a/src/plugins/out-daap-proto.h b/src/plugins/out-daap-proto.h deleted file mode 100644 index 976475f0..00000000 --- a/src/plugins/out-daap-proto.h +++ /dev/null @@ -1,34 +0,0 @@ - -#ifndef _OUT_DAAP_PROTO_H_ -#define _OUT_DAAP_PROTO_H_ - -#include "out-daap.h" - -typedef struct tag_daap_items { - int type; - char *tag; - char *description; -} DAAP_ITEMS; - -extern DAAP_ITEMS taglist[]; - -/* metatag parsing */ -extern MetaField_t daap_encode_meta(char *meta); -extern int daap_wantsmeta(MetaField_t meta, MetaFieldName_t fieldNo); - -/* dmap helper functions */ -extern int dmap_add_char(unsigned char *where, char *tag, char value); -extern int dmap_add_short(unsigned char *where, char *tag, short value); -extern int dmap_add_int(unsigned char *where, char *tag, int value); -extern int dmap_add_long(unsigned char *where, char *tag, uint64_t value); -extern int dmap_add_string(unsigned char *where, char *tag, char *value); -extern int dmap_add_literal(unsigned char *where, char *tag, char *value, int size); -extern int dmap_add_container(unsigned char *where, char *tag, int size); - -extern int daap_get_next_session(void); - - -extern int daap_enum_size(char **pe, PRIVINFO *pinfo, int *count, int *total_size); -extern int daap_enum_fetch(char **pe, PRIVINFO *pinfo, int *size, unsigned char **pdmap); - -#endif /* _OUT_DAAP_PROTO_H_ */ diff --git a/src/plugins/out-daap.c b/src/plugins/out-daap.c deleted file mode 100644 index cef58a90..00000000 --- a/src/plugins/out-daap.c +++ /dev/null @@ -1,1472 +0,0 @@ -/* - * daap plugin handler and dispatch code - * - * Copyright (C) 2003-2006 Ron Pedde (ron@pedde.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#include - -#include - -#include "ff-dbstruct.h" -#include "ff-plugins.h" -#include "out-daap.h" -#include "out-daap-proto.h" - -//#undef strsep /* FIXME */ - -/** - * Hold the inf for the output serializer - */ -typedef struct tag_xml_stack { - char tag[5]; - int bytes_left; -} XML_STACK; - -typedef struct tag_output_info { - int xml_output; - int readable; - int browse_response; - int dmap_response_length; - int stack_height; - XML_STACK stack[10]; -} OUTPUT_INFO; - -/* Forwards */ -static void out_daap_server_info(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_login(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_content_codes(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_update(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_dbinfo(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_playlistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_playlists(WS_CONNINFO *pqsc, PRIVINFO *ppi); -static void out_daap_addplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_addplaylistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_editplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_deleteplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_deleteplaylistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_items(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_logout(WS_CONNINFO *pwsc, PRIVINFO *ppi); -static void out_daap_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, char *container, char *error); -static int out_daap_output_start(WS_CONNINFO *pwsc, PRIVINFO *ppi, int content_length); -static int out_daap_output_write(WS_CONNINFO *pwsc, PRIVINFO *ppi, unsigned char *block, int len); -static int out_daap_output_end(WS_CONNINFO *pwsc, PRIVINFO *ppi); - -static DAAP_ITEMS *out_daap_xml_lookup_tag(char *tag); -static char *out_daap_xml_encode(char *original, int len); -static int out_daap_output_xml_write(WS_CONNINFO *pwsc, PRIVINFO *ppi, unsigned char *block, int len); - -static void out_daap_cleanup(PRIVINFO *ppi); - -void plugin_handler(WS_CONNINFO *pwsc); -int plugin_can_handle(WS_CONNINFO *pwsc); -int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password); - -PLUGIN_INFO *plugin_info(void); -PLUGIN_OUTPUT_FN _pofn = { plugin_can_handle, plugin_handler, plugin_auth }; -PLUGIN_REND_INFO _pri[] = { - { "_daap._tcp", NULL }, - { NULL, NULL } -}; - -PLUGIN_INFO _pi = { - PLUGIN_VERSION, /* version */ - PLUGIN_OUTPUT, /* type */ - "daap/" VERSION, /* server */ - &_pofn, /* output fns */ - NULL, /* event fns */ - NULL, /* transcode fns */ - _pri, /* rend info */ - NULL /* transcode info */ -}; - - -typedef struct tag_response { - char *uri[10]; - void (*dispatch)(WS_CONNINFO *, PRIVINFO *); -} PLUGIN_RESPONSE; - -PLUGIN_RESPONSE daap_uri_map[] = { - {{"server-info", NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_server_info }, - {{"content-codes", NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_content_codes }, - {{"login", NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_login }, - {{"update", NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_update }, - {{"logout", NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_logout }, - {{"databases", NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_dbinfo }, - {{"databases","*","items", NULL,NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_items }, - {{"databases","*","containers",NULL,NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_playlists }, - {{"databases","*","browse","*",NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_browse }, - {{"databases","*","items","*",NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_stream }, - {{"databases","*","containers","add",NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_addplaylist }, - {{"databases","*","containers","del",NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_deleteplaylist }, - {{"databases","*","containers","edit",NULL,NULL,NULL,NULL,NULL,NULL }, - out_daap_editplaylist }, - {{"databases","*","containers","*","items",NULL,NULL,NULL,NULL,NULL }, - out_daap_playlistitems }, - {{"databases","*","containers","*","del",NULL,NULL,NULL,NULL,NULL }, - out_daap_deleteplaylistitems }, - {{"databases","*","containers","*","items","add",NULL,NULL,NULL,NULL }, - out_daap_addplaylistitems }, - {{"databases","*","containers","*","browse","*",NULL,NULL,NULL,NULL }, - out_daap_browse } -}; - - - -/** - * return info about this plugin module - */ -PLUGIN_INFO *plugin_info(void) { - return &_pi; -} - -/** - * see if the plugin should handle this request - */ -int plugin_can_handle(WS_CONNINFO *pwsc) { - char *uri = pi_ws_uri(pwsc); - - pi_log(E_DBG,"Checking url %s\n",uri); - if(strncasecmp(uri,"/databases",10) == 0) - return TRUE; - if(strncasecmp(uri,"/server-info",12) == 0) - return TRUE; - if(strncasecmp(uri,"/content-codes",14) == 0) - return TRUE; - if(strncasecmp(uri,"/login",6) == 0) - return TRUE; - if(strncasecmp(uri,"/update",7) == 0) - return TRUE; - if(strncasecmp(uri,"/logout",7) == 0) - return TRUE; - if(strncasecmp(uri,"/activity",9) == 0) - return TRUE; - - return FALSE; -} - -/** - * check for auth. Kind of a ham-handed implementation, but - * works. - */ -int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password) { - char *uri = pi_ws_uri(pwsc); - - /* don't auth for stuff we shouldn't */ - if(strncasecmp(uri,"/server-info",12) == 0) - return TRUE; - if(strncasecmp(uri,"/logout",7) == 0) - return TRUE; - if(strncasecmp(uri,"/databases/1/items/",19) == 0) - return TRUE; - if(strncasecmp(uri,"/activity",9) == 0) - return TRUE; - - return pi_ws_matchesrole(pwsc,username,password,"user"); -} - - -/** - * do cleanup on the ppi structure... free any allocated memory, etc - */ -void out_daap_cleanup(PRIVINFO *ppi) { - if(!ppi) - return; - - if(ppi->output_info) - free(ppi->output_info); - - free(ppi); -} - -char *_strsep(char **stringp, const char *delim) { - char *ret = *stringp; - if (ret == NULL) return(NULL); /* grrr */ - if ((*stringp = strpbrk(*stringp, delim)) != NULL) { - *((*stringp)++) = '\0'; - } - return(ret); -} - -/** - * Handles authentication for the daap server. This isn't the - * authenticator for the web admin page, but rather the iTunes - * authentication when trying to connect to the server. Note that most - * of this is actually handled in the web server registration, which - * decides when to apply the authentication or not. If you mess with - * when and where the webserver applies auth or not, you'll likely - * break something. It seems that some requests must be authed, and others - * not. If you apply authentication somewhere that iTunes doesn't expect - * it, it happily disconnects. - * - * @param username The username passed by iTunes - * @param password The password passed by iTunes - * @returns 1 if auth successful, 0 otherwise - */ -int daap_auth(WS_CONNINFO *pwsc, char *username, char *password) { - char *readpassword; - int result; - - readpassword = pi_conf_alloc_string("general","password",NULL); - - if(password == NULL) { - if((readpassword == NULL)||(strlen(readpassword) == 0)) { - result = TRUE; - } else { - result = FALSE; - } - } else { - if(strcasecmp(password,readpassword)) { - result = FALSE; - } else { - result = TRUE; - } - } - - if(readpassword) pi_conf_dispose_string(readpassword); - return result; -} - -/** - * dispatch handler for web stuff - */ -void plugin_handler(WS_CONNINFO *pwsc) { - char *string, *save, *token; - PRIVINFO *ppi; - int elements; - int index, part; - int found; - char *index_req = NULL; - long l,h; - char *ptr; - - pi_log(E_DBG,"Getting uri...\n"); - - string = pi_ws_uri(pwsc); - string++; - - pi_log(E_DBG,"Mallocing privinfo...\n"); - ppi = (PRIVINFO *)malloc(sizeof(PRIVINFO)); - if(ppi) { - memset(ppi,0,sizeof(PRIVINFO)); - } - - if(!ppi) { - pi_ws_returnerror(pwsc,500,"Malloc error in plugin_handler"); - return; - } - - memset((void*)&ppi->dq,0,sizeof(DB_QUERY)); - - ppi->empty_strings = pi_conf_get_int("daap","empty_strings",0); - ppi->pwsc = pwsc; - - pi_ws_addresponseheader(pwsc,"Accept-Ranges","bytes"); - pi_ws_addresponseheader(pwsc,"DAAP-Server","firefly/" VERSION); - pi_ws_addresponseheader(pwsc,"Content-Type","application/x-dmap-tagged"); - pi_ws_addresponseheader(pwsc,"Cache-Control","no-cache"); - pi_ws_addresponseheader(pwsc,"Expires","-1"); - - if(pi_ws_getvar(pwsc,"session-id")) - ppi->session_id = atoi(pi_ws_getvar(pwsc,"session-id")); - - ppi->dq.offset = 0; - ppi->dq.limit = 999999; - - l=h=0; - if(pi_ws_getvar(pwsc,"index")) { - index_req = pi_ws_getvar(pwsc,"index"); - l = strtol(index_req,&ptr,10); - - if(l<0) { /* "-h"... tail range, last "h" entries */ - pi_log(E_LOG,"Unsupported index range: %s\n",index_req); - } else if(*ptr == 0) { - /* single item */ - ppi->dq.offset = l; - ppi->dq.limit = 1; - } else if(*ptr == '-') { - ppi->dq.offset = l; - if(*++ptr != '\0') { /* l- */ - h = strtol(ptr, &ptr, 10); - ppi->dq.limit = (h - l) + 1; - } - } - - pi_log(E_DBG,"Index %s: offset %d, limit %d\n",index_req, - ppi->dq.offset,ppi->dq.limit); - } - - - if(pi_ws_getvar(pwsc,"query")) { - ppi->dq.filter_type = FILTER_TYPE_APPLE; - ppi->dq.filter = pi_ws_getvar(pwsc,"query"); - } - - pi_log(E_DBG,"Tokenizing url\n"); - save = NULL; - while((ppi->uri_count < 10) && (token=strtok_r(string,"/",&save))) { - string=NULL; - ppi->uri_sections[ppi->uri_count++] = token; - } - - elements = sizeof(daap_uri_map) / sizeof(PLUGIN_RESPONSE); - pi_log(E_DBG,"Found %d elements\n",elements); - - index = 0; - found = 0; - - while((!found) && (index < elements)) { - /* test this set */ - pi_log(E_DBG,"Checking reponse %d\n",index); - part=0; - while(part < 10) { - if((daap_uri_map[index].uri[part]) && (!ppi->uri_sections[part])) - break; - if((ppi->uri_sections[part]) && (!daap_uri_map[index].uri[part])) - break; - - if((daap_uri_map[index].uri[part]) && - (strcmp(daap_uri_map[index].uri[part],"*") != 0)) { - if(strcmp(daap_uri_map[index].uri[part], - ppi->uri_sections[part])!= 0) - break; - } - part++; - } - - if(part == 10) { - found = 1; - pi_log(E_DBG,"Found it! Index: %d\n",index); - } else { - index++; - } - } - - if(found) { - daap_uri_map[index].dispatch(pwsc, ppi); - out_daap_cleanup(ppi); - return; - } - - pi_ws_returnerror(pwsc,400,"Bad request"); - pi_ws_will_close(pwsc); - out_daap_cleanup(ppi); - return; -} - -/** - * set up whatever necessary to begin streaming the output - * to the client. - * - * @param pwsc pointer to the current conninfo struct - * @param ppi pointer to the current dbquery struct - * @param content_length content_length (assuming dmap) of the output - */ -int out_daap_output_start(WS_CONNINFO *pwsc, PRIVINFO *ppi, int content_length) { - OUTPUT_INFO *poi; - - poi=(OUTPUT_INFO*)calloc(1,sizeof(OUTPUT_INFO)); - if(!poi) { - pi_log(E_LOG,"Malloc error in out_daap_ouput_start\n"); - return -1; - } - - ppi->output_info = (void*) poi; - poi->dmap_response_length = content_length; - - if(pi_ws_getvar(pwsc,"output")) { - if(strcasecmp(pi_ws_getvar(pwsc,"output"),"readable") == 0) - poi->readable=1; - - poi->xml_output=1; - pi_ws_addresponseheader(pwsc,"Content-Type","text/xml"); - pi_ws_addresponseheader(pwsc,"Connection","Close"); - pi_ws_will_close(pwsc); - pi_ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n"); - pi_ws_emitheaders(pwsc); - pi_ws_writefd(pwsc,""); - if(poi->readable) - pi_ws_writefd(pwsc,"\n"); - return 0; - } - - pi_ws_addresponseheader(pwsc,"Content-Length","%d", - poi->dmap_response_length); - pi_ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n"); - pi_ws_emitheaders(pwsc); - - /* I guess now we would start writing the output */ - return 0; -} - -/** - * write the output to wherever it goes. This expects to be fed - * full dmap blocks. In the simplest case, it just streams those - * dmap blocks out to the client. In more complex cases, it convert - * them to xml, or compresses them. - * - * @param ppi pointer to the current dbquery info struct - * @param pwsc pointer to the current conninfo struct - * @param pblock block of data to write - * @param len length of block to write - */ -int out_daap_output_write(WS_CONNINFO *pwsc, PRIVINFO *ppi, unsigned char *block, int len) { - OUTPUT_INFO *poi=(ppi->output_info); - int result; - - if(poi->xml_output) - return out_daap_output_xml_write(pwsc, ppi, block, len); - - result=pi_ws_writebinary(pwsc,(char*)block,len); - - if(result != len) - return -1; - - return 0; -} - -/** - * this is the serializer for xml. This assumes that (with the exception of - * containers) blocks are complete dmap blocks - * - * @param ppi pointer to the current dbquery info struct - * @param pwsc pointer to the current conninfo struct - * @param pblock block of data to write - * @param len length of block to write - */ -int out_daap_output_xml_write(WS_CONNINFO *pwsc, PRIVINFO *ppi, unsigned char *block, int len) { - OUTPUT_INFO *poi = ppi->output_info; - unsigned char *current=block; - char block_tag[5]; - int block_len; - int len_left; - DAAP_ITEMS *pitem; - unsigned char *data; - int ivalue; - long long lvalue; - int block_done=1; - int stack_ptr; - char *encoded_string; - - while(current < (block + len)) { - block_done=1; - len_left=(int)((block+len) - current); - if(len_left < 8) { - pi_log(E_FATAL,"Badly formatted dmap block - frag size: %d",len_left); - } - - /* set up block */ - memcpy(block_tag,current,4); - block_tag[4] = '\0'; - block_len = current[4] << 24 | current[5] << 16 | - current[6] << 8 | current[7]; - data = ¤t[8]; - - if(strncmp(block_tag,"abro",4) ==0 ) { - /* browse queries treat mlit as a string, not container */ - poi->browse_response=1; - } - - /* lookup and serialize */ - pi_log(E_SPAM,"%*s %s: %d\n",poi->stack_height,"",block_tag,block_len); - pitem=out_daap_xml_lookup_tag(block_tag); - if(poi->readable) - pi_ws_writefd(pwsc,"%*s",poi->stack_height,""); - pi_ws_writefd(pwsc,"<%s>",pitem->description); - switch(pitem->type) { - case 0x01: /* byte */ - if(block_len != 1) { - pi_log(E_FATAL,"tag %s, size %d, wanted 1\n",block_tag, block_len); - } - pi_ws_writefd(pwsc,"%d",*((char *)data)); - break; - - case 0x02: /* unsigned byte */ - if(block_len != 1) { - pi_log(E_FATAL,"tag %s, size %d, wanted 1\n",block_tag, block_len); - } - pi_ws_writefd(pwsc,"%ud",*((char *)data)); - break; - - case 0x03: /* short */ - if(block_len != 2) { - pi_log(E_FATAL,"tag %s, size %d, wanted 2\n",block_tag, block_len); - } - - ivalue = data[0] << 8 | data[1]; - pi_ws_writefd(pwsc,"%d",ivalue); - break; - - case 0x05: /* int */ - case 0x0A: /* epoch */ - if(block_len != 4) { - pi_log(E_FATAL,"tag %s, size %d, wanted 4\n",block_tag, block_len); - } - ivalue = data[0] << 24 | - data[1] << 16 | - data[2] << 8 | - data[3]; - pi_ws_writefd(pwsc,"%d",ivalue); - break; - case 0x07: /* long long */ - if(block_len != 8) { - pi_log(E_FATAL,"tag %s, size %d, wanted 8\n",block_tag, block_len); - } - - ivalue = data[0] << 24 | - data[1] << 16 | - data[2] << 8 | - data[3]; - lvalue=ivalue; - ivalue = data[4] << 24 | - data[5] << 16 | - data[6] << 8 | - data[7]; - lvalue = (lvalue << 32) | ivalue; - pi_ws_writefd(pwsc,"%ll",ivalue); - break; - case 0x09: /* string */ - if(block_len) { - encoded_string=out_daap_xml_encode((char*)data,block_len); - pi_ws_writefd(pwsc,"%s",encoded_string); - free(encoded_string); - } - break; - case 0x0B: /* version? */ - if(block_len != 4) { - pi_log(E_FATAL,"tag %s, size %d, wanted 4\n",block_tag, block_len); - } - - ivalue=data[0] << 8 | data[1]; - pi_ws_writefd(pwsc,"%d.%d.%d",ivalue,data[2],data[3]); - break; - - case 0x0C: - if((poi->browse_response)&&(strcmp(block_tag,"mlit") ==0)) { - if(block_len) { - encoded_string=out_daap_xml_encode((char*)data,block_len); - pi_ws_writefd(pwsc,"%s",encoded_string); - free(encoded_string); - } - } else { - /* we'll need to stack this up and try and remember where we - * came from. Make it an extra 8 so that it gets fixed to - * the *right* amount when the stacks are juggled below - */ - - poi->stack[poi->stack_height].bytes_left=block_len + 8; - memcpy(poi->stack[poi->stack_height].tag,block_tag,5); - poi->stack_height++; - if(poi->stack_height == 10) { - pi_log(E_FATAL,"Stack overflow\n"); - } - block_done=0; - } - break; - - default: - pi_log(E_FATAL,"Bad dmap type: %d, %s\n", - pitem->type, pitem->description); - break; - } - - if(block_done) { - pi_ws_writefd(pwsc,"",pitem->description); - if(poi->readable) - pi_ws_writefd(pwsc,"\n"); - - block_len += 8; - } else { - /* must be a container */ - block_len = 8; - if(poi->readable) - pi_ws_writefd(pwsc,"\n"); - } - - current += block_len; - - if(poi->stack_height) { - stack_ptr=poi->stack_height; - while(stack_ptr--) { - poi->stack[stack_ptr].bytes_left -= block_len; - if(poi->stack[stack_ptr].bytes_left < 0) { - pi_log(E_FATAL,"negative container\n"); - } - - if(!poi->stack[stack_ptr].bytes_left) { - poi->stack_height--; - pitem=out_daap_xml_lookup_tag(poi->stack[stack_ptr].tag); - if(poi->readable) - pi_ws_writefd(pwsc,"%*s",poi->stack_height,""); - pi_ws_writefd(pwsc,"",pitem->description); - if(poi->readable) - pi_ws_writefd(pwsc,"\n"); - } - } - } - } - - return 0; -} - - -/** - * finish streaming output to the client, freeing any allocated - * memory, and cleaning up - * - * @param pwsc current conninfo struct - * @param ppi current dbquery struct - */ -int out_daap_output_end(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - OUTPUT_INFO *poi = ppi->output_info; - - if((poi) && (poi->xml_output) && (poi->stack_height)) { - pi_log(E_LOG,"Badly formed xml -- still stack\n"); - } - - pi_config_set_status(pwsc,ppi->session_id,NULL); - - return 0; -} - - -DAAP_ITEMS *out_daap_xml_lookup_tag(char *tag) { - DAAP_ITEMS *pitem; - - pitem=taglist; - while((pitem->tag) && (strncmp(tag,pitem->tag,4))) { - pitem++; - } - - if(!pitem->tag) - pi_log(E_FATAL,"Unknown daap tag: %c%c%c%c\n",tag[0],tag[1],tag[2],tag[3]); - - return pitem; -} - -/** - * xml entity encoding, stupid style - */ -char *out_daap_xml_encode(char *original, int len) { - char *new; - char *s, *d; - int destsize; - int truelen; - - /* this is about stupid */ - if(len) { - truelen=len; - } else { - truelen=(int) strlen(original); - } - - destsize = 6*truelen+1; - new=(char *)malloc(destsize); - if(!new) return NULL; - - memset(new,0x00,destsize); - - s=original; - d=new; - - while(s < (original+truelen)) { - switch(*s) { - case '>': - strcat(d,">"); - d += 4; - s++; - break; - case '<': - strcat(d,"<"); - d += 4; - s++; - break; - case '"': - strcat(d,"""); - d += 6; - s++; - break; - case '\'': - strcat(d,"'"); - d += 6; - s++; - break; - case '&': - strcat(d,"&"); - d += 5; - s++; - break; - default: - *d++ = *s++; - } - } - - return new; -} - -void out_daap_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - /* should show sesson id */ - pi_stream(pwsc, ppi->uri_sections[3]); -} - -/** - * add songs to an existing playlist - */ -void out_daap_addplaylistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char playlist_response[20]; - unsigned char *current; - char *tempstring; - char *token; - int playlist_id; - - playlist_id = atoi(ppi->uri_sections[3]); - - if(!pi_ws_getvar(pwsc,"dmap.itemid")) { - pi_log(E_LOG,"Attempt to add playlist item w/o dmap.itemid\n"); - out_daap_error(pwsc,ppi,"MAPI","No item id specified (dmap.itemid)"); - return; - } - - tempstring=strdup(pi_ws_getvar(pwsc,"dmap.itemid")); - current=(unsigned char*)tempstring; - - while((token=_strsep((char**)(char*)¤t,","))) { - if(token) { - /* FIXME: error handling */ - pi_db_add_playlist_item(NULL,playlist_id,atoi(token)); - } - } - - free(tempstring); - - /* success(ish)... spool out a dmap block */ - current = playlist_response; - current += dmap_add_container(current,"MAPI",12); - current += dmap_add_int(current,"mstt",200); /* 12 */ - - out_daap_output_start(pwsc,ppi,20); - out_daap_output_write(pwsc,ppi,playlist_response,20); - out_daap_output_end(pwsc,ppi); - - pi_ws_will_close(pwsc); - - return; -} - -/** - * delete a playlist - */ -void out_daap_deleteplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char playlist_response[20]; - unsigned char *current; - - if(!pi_ws_getvar(pwsc,"dmap.itemid")) { - pi_log(E_LOG,"Attempt to delete playlist w/o dmap.itemid\n"); - out_daap_error(pwsc,ppi,"MDPR","No playlist id specified"); - return; - } - - /* FIXME: error handling */ - pi_db_delete_playlist(NULL,atoi(pi_ws_getvar(pwsc,"dmap.itemid"))); - - /* success(ish)... spool out a dmap block */ - current = playlist_response; - current += dmap_add_container(current,"MDPR",12); - current += dmap_add_int(current,"mstt",200); /* 12 */ - - out_daap_output_start(pwsc,ppi,20); - out_daap_output_write(pwsc,ppi,playlist_response,20); - out_daap_output_end(pwsc,ppi); - - pi_ws_will_close(pwsc); - - return; -} - -/** - * delete a playlist item - */ -void out_daap_deleteplaylistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char playlist_response[20]; - unsigned char *current; - char *tempstring; - char *token; - int playlist_id; - - if(!pi_ws_getvar(pwsc,"dmap.itemid")) { - pi_log(E_LOG,"Delete playlist item w/o dmap.itemid\n"); - out_daap_error(pwsc,ppi,"MDPI","No playlist item specified"); - return; - } - - playlist_id = atoi(ppi->uri_sections[3]); - - tempstring=strdup(pi_ws_getvar(pwsc,"dmap.itemid")); - current=(unsigned char *)tempstring; - - /* this looks strange, but gets rid of gcc 4 warnings */ - while((token=_strsep((char**)(char*)¤t,","))) { - if(token) { - /* FIXME: Error handling */ - pi_db_delete_playlist_item(NULL,playlist_id,atoi(token)); - } - } - - free(tempstring); - - /* success(ish)... spool out a dmap block */ - current = playlist_response; - current += dmap_add_container(current,"MDPI",12); - current += dmap_add_int(current,"mstt",200); /* 12 */ - - out_daap_output_start(pwsc,ppi,20); - out_daap_output_write(pwsc,ppi,playlist_response,20); - out_daap_output_end(pwsc,ppi); - - pi_ws_will_close(pwsc); - - return; -} - -/** - * add a playlist - */ -void out_daap_addplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char playlist_response[32]; - unsigned char *current=playlist_response; - char *name, *query; - int type; - int retval, playlistid; - char *estring = NULL; - - if((!pi_ws_getvar(pwsc,"org.mt-daapd.playlist-type")) || - (!pi_ws_getvar(pwsc,"dmap.itemname"))) { - pi_log(E_LOG,"attempt to add playlist with invalid type\n"); - out_daap_error(pwsc,ppi,"MAPR","bad playlist info specified"); - return; - } - - type=atoi(pi_ws_getvar(pwsc,"org.mt-daapd.playlist-type")); - name=pi_ws_getvar(pwsc,"dmap.itemname"); - query=pi_ws_getvar(pwsc,"org.mt-daapd.smart-playlist-spec"); - - retval=pi_db_add_playlist(&estring,name,type,query,NULL,0,&playlistid); - if(retval) { - out_daap_error(pwsc,ppi,"MAPR",estring); - pi_log(E_LOG,"error adding playlist %s: %s\n",name,estring); - free(estring); - return; - } - - /* success... spool out a dmap block */ - current += dmap_add_container(current,"MAPR",24); - current += dmap_add_int(current,"mstt",200); /* 12 */ - current += dmap_add_int(current,"miid",playlistid); /* 12 */ - - out_daap_output_start(pwsc,ppi,32); - out_daap_output_write(pwsc,ppi,playlist_response,32); - out_daap_output_end(pwsc,ppi); - - pi_ws_will_close(pwsc); - return; -} - -/** - * edit an existing playlist (by id) - */ -void out_daap_editplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char edit_response[20]; - unsigned char *current = edit_response; - char *pe = NULL; - char *name, *query; - int id; - - int retval; - - if(!pi_ws_getvar(pwsc,"dmap.itemid")) { - pi_log(E_LOG,"Missing itemid on playlist edit"); - out_daap_error(pwsc,ppi,"MEPR","No itemid specified"); - return; - } - - name=pi_ws_getvar(pwsc,"dmap.itemname"); - query=pi_ws_getvar(pwsc,"org.mt-daapd.smart-playlist-spec"); - id=atoi(pi_ws_getvar(pwsc,"dmap.itemid")); - - /* FIXME: Error handling */ - retval=pi_db_edit_playlist(&pe,id,name,query); - if(retval) { - pi_log(E_LOG,"error editing playlist.\n"); - out_daap_error(pwsc,ppi,"MEPR",pe); - if(pe) free(pe); - return; - } - - current += dmap_add_container(current,"MEPR",12); - current += dmap_add_int(current,"mstt",200); /* 12 */ - - out_daap_output_start(pwsc,ppi,20); - out_daap_output_write(pwsc,ppi,edit_response,20); - out_daap_output_end(pwsc,ppi); - - pi_ws_will_close(pwsc); - return; -} - - -/** - * enumerate and return playlistitems - */ -void out_daap_playlistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char items_response[61]; - unsigned char *current=items_response; - int song_count; - int list_length; - unsigned char *block; - char *pe = NULL; - int mtco; - - if(pi_ws_getvar(pwsc,"meta")) { - ppi->meta = daap_encode_meta(pi_ws_getvar(pwsc,"meta")); - } else { - ppi->meta = ((1ll << metaItemId) | - (1ll << metaItemName) | - (1ll << metaItemKind) | - (1ll << metaContainerItemId) | - (1ll << metaParentContainerId)); - } - - ppi->dq.query_type = QUERY_TYPE_ITEMS; - ppi->dq.playlist_id = atoi(ppi->uri_sections[3]); - - if(pi_db_enum_start(&pe,&ppi->dq)) { - pi_log(E_LOG,"Could not start enum: %s\n",pe); - out_daap_error(pwsc,ppi,"apso",pe); - if(pe) free(pe); - return; - } - - if(daap_enum_size(&pe,ppi,&song_count,&list_length)) { - pi_log(E_LOG,"Could not enum size: %s\n",pe); - out_daap_error(pwsc,ppi,"apso",pe); - if(pe) free(pe); - return; - } - - pi_log(E_DBG,"Item enum: got %d songs, dmap size: %d\n",song_count,list_length); - - mtco = song_count; - if(ppi->dq.offset || ppi->dq.limit) - mtco = ppi->dq.totalcount; - - current += dmap_add_container(current,"apso",list_length + 53); - current += dmap_add_int(current,"mstt",200); /* 12 */ - current += dmap_add_char(current,"muty",0); /* 9 */ - current += dmap_add_int(current,"mtco",mtco); /* 12 */ - current += dmap_add_int(current,"mrco",song_count); /* 12 */ - current += dmap_add_container(current,"mlcl",list_length); - - out_daap_output_start(pwsc,ppi,61+list_length); - out_daap_output_write(pwsc,ppi,items_response,61); - - /* FIXME: Error checking */ - while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) && - (list_length)) { - pi_log(E_SPAM,"Got block of size %d\n",list_length); - out_daap_output_write(pwsc,ppi,block,list_length); - free(block); - } - - pi_log(E_DBG,"Done enumerating.\n"); - - pi_db_enum_end(NULL); - pi_db_enum_dispose(NULL,&ppi->dq); - - out_daap_output_end(pwsc,ppi); - return; -} - -void out_daap_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char browse_response[52]; - unsigned char *current=browse_response; - int item_count; - int list_length; - unsigned char *block; - char *response_type; - int which_field=5; - char *pe = NULL; - int mtco; - - if(strcasecmp(ppi->uri_sections[2],"browse") == 0) { - which_field = 3; - } - - pi_log(E_DBG,"Browsing by %s (field %d)\n", - ppi->uri_sections[which_field],which_field); - - ppi->dq.query_type = QUERY_TYPE_DISTINCT; - ppi->dq.distinct_field = ppi->uri_sections[which_field]; - // which_field = 3; - - if(!strcmp(ppi->uri_sections[which_field],"artists")) { - response_type = "abar"; - ppi->dq.distinct_field = "artist"; - } else if(!strcmp(ppi->uri_sections[which_field],"genres")) { - response_type = "abgn"; - ppi->dq.distinct_field = "genre"; - } else if(!strcmp(ppi->uri_sections[which_field],"albums")) { - response_type = "abal"; - ppi->dq.distinct_field = "album"; - } else if(!strcmp(ppi->uri_sections[which_field],"composers")) { - response_type = "abcp"; - ppi->dq.distinct_field = "composer"; - } else { - pi_log(E_WARN,"Invalid browse request type %s\n",ppi->uri_sections[3]); - out_daap_error(pwsc,ppi,"abro","Invalid browse type"); - pi_config_set_status(pwsc,ppi->session_id,NULL); - return; - } - - if(pi_db_enum_start(&pe,&ppi->dq)) { - pi_log(E_LOG,"Could not start enum: %s\n",pe); - out_daap_error(pwsc,ppi,"abro",pe); - if(pe) free(pe); - return; - } - - pi_log(E_DBG,"Getting enum size.\n"); - - /* FIXME: Error handling */ - daap_enum_size(NULL,ppi,&item_count,&list_length); - - pi_log(E_DBG,"Item enum: got %d items, dmap size: %d\n", - item_count,list_length); - - mtco = item_count; - if((ppi->dq.offset) || (ppi->dq.limit)) - mtco = ppi->dq.totalcount; - - current += dmap_add_container(current,"abro",list_length + 44); - current += dmap_add_int(current,"mstt",200); /* 12 */ - current += dmap_add_int(current,"mtco",mtco); /* 12 */ - current += dmap_add_int(current,"mrco",item_count); /* 12 */ - current += dmap_add_container(current,response_type,list_length); /* 8+ */ - - out_daap_output_start(pwsc,ppi,52+list_length); - out_daap_output_write(pwsc,ppi,browse_response,52); - - while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) && - (list_length)) - { - pi_log(E_SPAM,"Got block of size %d\n",list_length); - out_daap_output_write(pwsc,ppi,block,list_length); - free(block); - } - - pi_log(E_DBG,"Done enumerating\n"); - - pi_db_enum_end(NULL); - pi_db_enum_dispose(NULL,&ppi->dq); - - out_daap_output_end(pwsc,ppi); - return; -} - -void out_daap_playlists(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char playlist_response[61]; - unsigned char *current=playlist_response; - int pl_count; - int list_length; - unsigned char *block; - char *pe = NULL; - int mtco; - - /* currently, this is ignored for playlist queries */ - if(pi_ws_getvar(pwsc,"meta")) { - ppi->meta = daap_encode_meta(pi_ws_getvar(pwsc,"meta")); - } else { - ppi->meta = ((1ll << metaItemId) | - (1ll << metaItemName) | - (1ll << metaPersistentId) | - (1ll << metaItunesSmartPlaylist)); - } - - - ppi->dq.query_type = QUERY_TYPE_PLAYLISTS; - - if(pi_db_enum_start(&pe,&ppi->dq)) { - pi_log(E_LOG,"Could not start enum: %s\n",pe); - out_daap_error(pwsc,ppi,"aply",pe); - if(pe) free(pe); - return; - } - - if(daap_enum_size(NULL,ppi,&pl_count,&list_length)) { - pi_log(E_LOG,"error in enumerating size: %s\n",pe); - out_daap_error(pwsc,ppi,"aply",pe); - if(pe) free(pe); - return; - } - - pi_log(E_DBG,"Item enum: got %d playlists, dmap size: %d\n",pl_count,list_length); - - mtco = pl_count; - if((ppi->dq.offset) || (ppi->dq.limit)) - mtco = ppi->dq.totalcount; - - current += dmap_add_container(current,"aply",list_length + 53); - current += dmap_add_int(current,"mstt",200); /* 12 */ - current += dmap_add_char(current,"muty",0); /* 9 */ - current += dmap_add_int(current,"mtco",mtco); /* 12 */ - current += dmap_add_int(current,"mrco",pl_count); /* 12 */ - current += dmap_add_container(current,"mlcl",list_length); - - out_daap_output_start(pwsc,ppi,61+list_length); - out_daap_output_write(pwsc,ppi,playlist_response,61); - - /* FIXME: error checking */ - while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) && - (list_length)) - { - pi_log(E_SPAM,"Got block of size %d\n",list_length); - out_daap_output_write(pwsc,ppi,block,list_length); - free(block); - } - - pi_log(E_DBG,"Done enumerating.\n"); - - pi_db_enum_end(NULL); - pi_db_enum_dispose(NULL,&ppi->dq); - - out_daap_output_end(pwsc,ppi); - return; -} - -void out_daap_items(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char items_response[61]; - unsigned char *current=items_response; - int song_count; - int list_length; - unsigned char *block; - char *pe = NULL; - int mtco; - - if(pi_ws_getvar(pwsc,"meta")) { - ppi->meta = daap_encode_meta(pi_ws_getvar(pwsc,"meta")); - } else { - ppi->meta = (MetaField_t) -1ll; - } - - ppi->dq.query_type = QUERY_TYPE_ITEMS; - - if(pi_db_enum_start(&pe,&ppi->dq)) { - pi_log(E_LOG,"Could not start enum: %s\n",pe); - out_daap_error(pwsc,ppi,"adbs",pe); - if(pe) free(pe); - return; - } - - /* FIXME: Error handling */ - if(daap_enum_size(&pe,ppi,&song_count,&list_length)) { - pi_log(E_LOG,"Error getting dmap size: %s\n",pe); - out_daap_error(pwsc,ppi,"adbs",pe); - if(pe) free(pe); - return; - } - - pi_log(E_DBG,"Item enum: got %d songs, dmap size: %d\n",song_count, - list_length); - - mtco = song_count; - if((ppi->dq.offset) || (ppi->dq.limit)) - mtco = ppi->dq.totalcount; - - current += dmap_add_container(current,"adbs",list_length + 53); - current += dmap_add_int(current,"mstt",200); /* 12 */ - current += dmap_add_char(current,"muty",0); /* 9 */ - current += dmap_add_int(current,"mtco",mtco); /* 12 */ - current += dmap_add_int(current,"mrco",song_count); /* 12 */ - current += dmap_add_container(current,"mlcl",list_length); - - out_daap_output_start(pwsc,ppi,61+list_length); - out_daap_output_write(pwsc,ppi,items_response,61); - - /* FIXME: check errors */ - while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) && - (list_length)) { - pi_log(E_SPAM,"Got block of size %d\n",list_length); - out_daap_output_write(pwsc,ppi,block,list_length); - free(block); - } - pi_log(E_DBG,"Done enumerating.\n"); - pi_db_enum_end(NULL); - pi_db_enum_dispose(NULL,&ppi->dq); - out_daap_output_end(pwsc,ppi); - return; -} - -void out_daap_update(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char update_response[32]; - unsigned char *current=update_response; - - pi_log(E_DBG,"Preparing to send update response\n"); - pi_config_set_status(pwsc,ppi->session_id,"Waiting for DB update"); - - if(!pi_db_wait_update(pwsc)) { - pi_log(E_DBG,"Update session stopped\n"); - return; - } - - /* otherwise, send the info about this version */ - current += dmap_add_container(current,"mupd",24); - current += dmap_add_int(current,"mstt",200); /* 12 */ - current += dmap_add_int(current,"musr",pi_db_revision()); /* 12 */ - - out_daap_output_start(pwsc,ppi,32); - out_daap_output_write(pwsc,ppi,update_response,32); - out_daap_output_end(pwsc,ppi); - - return; -} - -void out_daap_dbinfo(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char dbinfo_response[255]; /* FIXME: servername limit 255-113 */ - unsigned char *current = dbinfo_response; - int namelen; - int count; - char servername[256]; - int servername_size; - - servername_size = sizeof(servername); - pi_server_name(servername,&servername_size); - - namelen=(int) strlen(servername); - - current += dmap_add_container(current,"avdb",121 + namelen); - current += dmap_add_int(current,"mstt",200); /* 12 */ - current += dmap_add_char(current,"muty",0); /* 9 */ - current += dmap_add_int(current,"mtco",1); /* 12 */ - current += dmap_add_int(current,"mrco",1); /* 12 */ - current += dmap_add_container(current,"mlcl",68 + namelen); - current += dmap_add_container(current,"mlit",60 + namelen); - current += dmap_add_int(current,"miid",1); /* 12 */ - current += dmap_add_long(current,"mper",1); /* 16 */ - current += dmap_add_string(current,"minm",servername); /* 8 + namelen */ - count = pi_db_count_items(COUNT_SONGS); - current += dmap_add_int(current,"mimc",count); /* 12 */ - count = pi_db_count_items(COUNT_PLAYLISTS); - current += dmap_add_int(current,"mctc",count); /* 12 */ - - out_daap_output_start(pwsc,ppi,129+namelen); - out_daap_output_write(pwsc,ppi,dbinfo_response,129+namelen); - out_daap_output_end(pwsc,ppi); - - return; -} - -void out_daap_logout(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - pi_config_set_status(pwsc,ppi->session_id,NULL); - pi_ws_returnerror(pwsc,204,"Logout Successful"); -} - - -void out_daap_login(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char login_response[32]; - unsigned char *current = login_response; - int session; - - session = daap_get_next_session(); - - current += dmap_add_container(current,"mlog",24); - current += dmap_add_int(current,"mstt",200); /* 12 */ - current += dmap_add_int(current,"mlid",session); /* 12 */ - - out_daap_output_start(pwsc,ppi,32); - out_daap_output_write(pwsc,ppi,login_response,32); - out_daap_output_end(pwsc,ppi); - return; -} - -void out_daap_content_codes(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char content_codes[20]; - unsigned char *current=content_codes; - unsigned char mdcl[256]; /* FIXME: Don't make this static */ - int len; - DAAP_ITEMS *dicurrent; - - dicurrent=taglist; - len=0; - while(dicurrent->type) { - len += (8 + 12 + 10 + 8 + (int) strlen(dicurrent->description)); - dicurrent++; - } - - current += dmap_add_container(current,"mccr",len + 12); - current += dmap_add_int(current,"mstt",200); - - out_daap_output_start(pwsc,ppi,len+20); - out_daap_output_write(pwsc,ppi,content_codes,20); - - dicurrent=taglist; - while(dicurrent->type) { - current=mdcl; - len = 12 + 10 + 8 + (int) strlen(dicurrent->description); - current += dmap_add_container(current,"mdcl",len); - current += dmap_add_string(current,"mcnm",dicurrent->tag); /* 12 */ - current += dmap_add_string(current,"mcna",dicurrent->description); /* 8 + descr */ - current += dmap_add_short(current,"mcty",dicurrent->type); /* 10 */ - out_daap_output_write(pwsc,ppi,mdcl,len+8); - dicurrent++; - } - - out_daap_output_end(pwsc,ppi); - return; -} - - -int out_daap_conf_isset(char *section, char *key) { - char *value; - - value = pi_conf_alloc_string(section,key,NULL); - if(value) { - pi_conf_dispose_string(value); - return TRUE; - } - - return FALSE; -} - -void out_daap_server_info(WS_CONNINFO *pwsc, PRIVINFO *ppi) { - unsigned char server_info[256]; - char servername[256]; - int size; - unsigned char *current = server_info; - char *client_version; - int mpro = 2 << 16; - int apro = 3 << 16; - int actual_length; - int supports_update=0; - - size = sizeof(servername); - pi_server_name(servername,&size); - // supports_update = conf_get_int("daap","supports_update",1); - - actual_length=139 + (int) strlen(servername); - if(!supports_update) - actual_length -= 9; - - if(actual_length > sizeof(server_info)) { - pi_log(E_FATAL,"Server name too long.\n"); - } - - client_version=pi_ws_getrequestheader(pwsc,"Client-DAAP-Version"); - - current += dmap_add_container(current,"msrv",actual_length - 8); - current += dmap_add_int(current,"mstt",200); /* 12 */ - - if((client_version) && (!strcmp(client_version,"1.0"))) { - mpro = 1 << 16; - apro = 1 << 16; - } - - if((client_version) && (!strcmp(client_version,"2.0"))) { - mpro = 1 << 16; - apro = 2 << 16; - } - - current += dmap_add_int(current,"mpro",mpro); /* 12 */ - current += dmap_add_int(current,"apro",apro); /* 12 */ - current += dmap_add_int(current,"mstm",1800); /* 12 */ - current += dmap_add_string(current,"minm",servername); /* 8 + strlen(name) */ - - - current += dmap_add_char(current,"msau", /* 9 */ - out_daap_conf_isset("general","password") ? 2 : 0); - current += dmap_add_char(current,"msex",0); /* 9 */ - current += dmap_add_char(current,"msix",0); /* 9 */ - current += dmap_add_char(current,"msbr",0); /* 9 */ - current += dmap_add_char(current,"msqy",0); /* 9 */ - - current += dmap_add_char(current,"mspi",0); - current += dmap_add_int(current,"msdc",1); /* 12 */ - - if(supports_update) - current += dmap_add_char(current,"msup",0); /* 9 */ - - out_daap_output_start(pwsc,ppi,actual_length); - out_daap_output_write(pwsc,ppi,server_info,actual_length); - out_daap_output_end(pwsc,ppi); - - return; -} - -/** - * throw out an error, xml style. This throws out a dmap block, but with a - * mstt of 500, and a msts as specified - */ -void out_daap_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, char *container, char *error) { - unsigned char *block, *current; - int len; - - len = 12 + 8 + 8 + (int) strlen(error); - block = (unsigned char *)malloc(len); - - if(!block) - pi_log(E_FATAL,"Malloc error\n"); - - current = block; - current += dmap_add_container(current,container,len - 8); - current += dmap_add_int(current,"mstt",500); - current += dmap_add_string(current,"msts",error); - - out_daap_output_start(pwsc,ppi,len); - out_daap_output_write(pwsc,ppi,block,len); - out_daap_output_end(pwsc,ppi); - - free(block); - - pi_ws_will_close(pwsc); -} - - - diff --git a/src/plugins/out-daap.h b/src/plugins/out-daap.h deleted file mode 100644 index 4d86c417..00000000 --- a/src/plugins/out-daap.h +++ /dev/null @@ -1,93 +0,0 @@ - -#ifndef _OUT_DAAP_H_ -#define _OUT_DAAP_H_ - -#ifndef TRUE -# define TRUE 1 -# define FALSE 0 -#endif - -#include "ff-plugins.h" - -typedef enum { - // generic meta data - metaItemId, - metaItemName, - metaItemKind, - metaPersistentId, - metaContainerItemId, - metaParentContainerId, - - firstTypeSpecificMetaId, - - // song meta data - metaSongAlbum = firstTypeSpecificMetaId, - metaSongArtist, - metaSongBPM, - 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, - - /* iTunes 4.5 + */ - metaSongCodecType, - metaSongCodecSubType, - metaItunesNormVolume, - metaItmsSongId, - metaItmsArtistId, - metaItmsPlaylistId, - metaItmsComposerId, - metaItmsGenreId, - metaItmsStorefrontId, - metaItunesSmartPlaylist, - - /* iTunes 5.0 + */ - metaSongContentRating, - metaHasChildContainers, - - /* iTunes 6.0.2+ */ - metaItunesHasVideo, - - /* mt-daapd specific */ - metaMPlaylistSpec, - metaMPlaylistType -} MetaFieldName_t; - -typedef unsigned long long MetaField_t; -typedef struct tag_ws_conninfo WS_CONNINFO; - -typedef struct tag_daap_privinfo { - DB_QUERY dq; - int uri_count; - MetaField_t meta; - int empty_strings; - struct tag_output_info *output_info; - int session_id; - char *uri_sections[10]; - WS_CONNINFO *pwsc; -} PRIVINFO; - -#endif /* _OUT_DAAP_H_ */ -