/** * This handles requests that are daap-related. For example, * /server-info, /login, etc. This should really be split up * into multiple functions, and perhaps moved into daap.c * * \param pwsc Webserver connection info, passed from the webserver * * \todo Decomplexify this! */ void daap_handler(WS_CONNINFO *pwsc) { int close; DAAP_BLOCK *root; int clientrev; /* for the /databases URI */ char *uri; unsigned long int db_index; unsigned long int playlist_index; unsigned long int item=0; char *first, *last; char* index = 0; int streaming=0; int compress =0; int start_time; int end_time; int bytes_written; MP3FILE *pmp3; int file_fd; int session_id=0; int img_fd; struct stat sb; long img_size; off_t offset=0; off_t real_len; off_t file_len; int bytes_copied=0; GZIP_STREAM *gz; close=pwsc->close; pwsc->close=1; /* in case we have any errors */ root=NULL; ws_addresponseheader(pwsc,"Accept-Ranges","bytes"); ws_addresponseheader(pwsc,"DAAP-Server","mt-daapd/%s",VERSION); ws_addresponseheader(pwsc,"Content-Type","application/x-dmap-tagged"); if(ws_getvar(pwsc,"session-id")) { session_id=atoi(ws_getvar(pwsc,"session-id")); } if(!strcasecmp(pwsc->uri,"/server-info")) { config_set_status(pwsc,session_id,"Sending server info"); root=daap_response_server_info(config.servername, ws_getrequestheader(pwsc,"Client-DAAP-Version")); } else if (!strcasecmp(pwsc->uri,"/content-codes")) { config_set_status(pwsc,session_id,"Sending content codes"); root=daap_response_content_codes(); } else if (!strcasecmp(pwsc->uri,"/login")) { config_set_status(pwsc,session_id,"Logging in"); root=daap_response_login(pwsc->hostname); } else if (!strcasecmp(pwsc->uri,"/update")) { if(!ws_getvar(pwsc,"delta")) { /* first check */ clientrev=db_version() - 1; config_set_status(pwsc,session_id,"Sending database"); } else { clientrev=atoi(ws_getvar(pwsc,"delta")); config_set_status(pwsc,session_id,"Waiting for DB updates"); } root=daap_response_update(pwsc->fd,clientrev); if((ws_getvar(pwsc,"delta")) && (root==NULL)) { DPRINTF(E_LOG,L_WS,"Client %s disconnected\n",pwsc->hostname); config_set_status(pwsc,session_id,NULL); pwsc->close=1; return; } } else if (!strcasecmp(pwsc->uri,"/logout")) { config_set_status(pwsc,session_id,NULL); ws_returnerror(pwsc,204,"Logout Successful"); return; } else if(strcmp(pwsc->uri,"/databases")==0) { config_set_status(pwsc,session_id,"Sending database info"); 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) { /* the /databases/ uri will either be: * * /databases/id/items, which returns items in a db * /databases/id/containers, which returns a container * /databases/id/containers/id/items, which returns playlist elements * /databases/id/items/id.mp3, to spool an mp3 * /databases/id/browse/category */ uri = strdup(pwsc->uri); first=(char*)&uri[11]; last=first; while((*last) && (*last != '/')) { last++; } if(*last) { *last='\0'; db_index=atoll(first); last++; if(strncasecmp(last,"items/",6)==0) { /* streaming */ first=last+6; while((*last) && (*last != '.')) last++; if(*last == '.') { *last='\0'; item=atoll(first); streaming=1; DPRINTF(E_DBG,L_DAAP|L_WS,"Streaming request for id %lu\n",item); } free(uri); } else if (strncasecmp(last,"items",5)==0) { /* songlist */ free(uri); // pass the meta field request for processing // pass the query request for processing root=daap_response_songlist(ws_getvar(pwsc,"meta"), ws_getvar(pwsc,"query")); config_set_status(pwsc,session_id,"Sending songlist"); } else if (strncasecmp(last,"containers/",11)==0) { /* playlist elements */ first=last + 11; last=first; while((*last) && (*last != '/')) { last++; } if(*last) { *last='\0'; playlist_index=atoll(first); // pass the meta list info for processing root=daap_response_playlist_items(playlist_index, ws_getvar(pwsc,"meta"), ws_getvar(pwsc,"query")); } free(uri); config_set_status(pwsc,session_id,"Sending playlist info"); } else if (strncasecmp(last,"containers",10)==0) { /* list of playlists */ free(uri); root=daap_response_playlists(config.servername); config_set_status(pwsc,session_id,"Sending playlist info"); } else if (strncasecmp(last,"browse/",7)==0) { config_set_status(pwsc,session_id,"Compiling browse info"); root = daap_response_browse(last + 7, ws_getvar(pwsc, "filter")); config_set_status(pwsc,session_id,"Sending browse info"); free(uri); } } // 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)) { DPRINTF(E_DBG,L_WS|L_DAAP,"Bad request -- root=%x, streaming=%d\n",root,streaming); ws_returnerror(pwsc,400,"Invalid Request"); config_set_status(pwsc,session_id,NULL); return; } pwsc->close=close; if(!streaming) { DPRINTF(E_DBG,L_WS,"Satisfying request\n"); if((config.compress) && ws_testrequestheader(pwsc,"Accept-Encoding","gzip") && root->reported_size >= 1000) { compress=1; } DPRINTF(E_DBG,L_WS|L_DAAP,"Serializing\n"); start_time = time(NULL); if (compress) { DPRINTF(E_DBG,L_WS|L_DAAP,"Using compression: %s\n", pwsc->uri); gz = gzip_alloc(); daap_serialize(root,pwsc->fd,gz); gzip_compress(gz); bytes_written = gz->bytes_out; ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n"); ws_addresponseheader(pwsc,"Content-Length","%d",bytes_written); ws_addresponseheader(pwsc,"Content-Encoding","gzip"); DPRINTF(E_DBG,L_WS,"Emitting headers\n"); ws_emitheaders(pwsc); if (gzip_close(gz,pwsc->fd) != bytes_written) { DPRINTF(E_LOG,L_WS|L_DAAP,"Error compressing data\n"); } DPRINTF(E_DBG,L_WS|L_DAAP,"Compression ratio: %f\n",((double) bytes_written)/(8.0 + root->reported_size)) } else {
int plugin_ssc_should_transcode(WS_CONNINFO *pwsc, char *codec) { int result; char *native_codecs=NULL; char *user_agent=NULL; char *never_transcode = NULL; char *always_transcode = NULL; ASSERT((pwsc) && (codec)); if(!pwsc) return FALSE; if(!codec) { DPRINTF(E_LOG,L_PLUG,"testing transcode on null codec?\n"); return FALSE; } never_transcode = conf_alloc_string("general","never_transcode",NULL); if(never_transcode) { if(strstr(never_transcode,codec)) { free(never_transcode); return FALSE; } free(never_transcode); } if(pwsc) { /* see if the headers give us any guidance */ native_codecs = ws_getrequestheader(pwsc,"accept-codecs"); if(!native_codecs) { user_agent = ws_getrequestheader(pwsc,"user-agent"); if(user_agent) { if(strncmp(user_agent,"iTunes",6)==0) { native_codecs = "mpeg,mp4a,wav,mp4v,alac"; } else if(strncmp(user_agent,"Roku",4)==0) { native_codecs = "mpeg,mp4a,wav,wma"; } else if(strncmp(user_agent,"Hifidelio",9)==0) { return FALSE; } } } } if(!native_codecs) { native_codecs = "mpeg,wav"; } /* can't transcode it if we can't transcode it */ if(!_plugin_ssc_codecs) return FALSE; always_transcode = conf_alloc_string("general","always_transcode",NULL); if(always_transcode) { if(strstr(always_transcode,codec)) { free(always_transcode); return TRUE; } free(always_transcode); } if(strstr(native_codecs,codec)) return FALSE; result = FALSE; if(strstr(_plugin_ssc_codecs,codec)) { result = TRUE; } return result; }