#include "config.h" #ifdef ENABLE_TIVO #include #include #include #include "tivo_utils.h" #include "upnpglobalvars.h" #include "upnphttp.h" #include "log.h" void SendRootContainer(struct upnphttp * h) { char * resp; int len; len = asprintf(&resp, "\n" "" "
" "x-container/tivo-server" "x-container/folder" "0" "2" "%s" "
" "0" "2" "" "
" "x-container/tivo-photos" "x-container/folder" "Pictures on %s" "
" "" "" "/TiVoConnect?Command=QueryContainer&Container=3/Pictures on %s" "" "" "
" "" "
" "x-container/tivo-music" "x-container/folder" "Music on %s" "
" "" "" "/TiVoConnect?Command=QueryContainer&Container=1" "" "" "
" "
", friendly_name, friendly_name, friendly_name, friendly_name); BuildResp_upnphttp(h, resp, len); SendResp_upnphttp(h); } #if 0 int callback(void *args, int argc, char **argv, char **azColName) { struct Response *passed_args = (struct Response *)args; char *id = argv[1], *parent = argv[2], *refID = argv[3], *class = argv[4], *detailID = argv[5], *size = argv[9], *title = argv[10], *duration = argv[11], *bitrate = argv[12], *sampleFrequency = argv[13], *artist = argv[14], *album = argv[15], *genre = argv[16], *comment = argv[17], *nrAudioChannels = argv[18], *track = argv[19], *date = argv[20], *resolution = argv[21], *tn = argv[22], *creator = argv[23], *dlna_pn = argv[24], *mime = argv[25], *album_art = argv[26], *art_dlna_pn = argv[27]; char dlna_buf[64]; char str_buf[4096]; char **result; int ret; passed_args->total++; if( passed_args->requested && (passed_args->returned >= passed_args->requested) ) return 0; passed_args->returned++; if( dlna_pn ) sprintf(dlna_buf, "DLNA.ORG_PN=%s", dlna_pn); else strcpy(dlna_buf, "*"); if( strncmp(class, "item", 4) == 0 ) { if( passed_args->client == EXbox ) { if( strcmp(mime, "video/divx") == 0 ) { mime[6] = 'a'; mime[7] = 'v'; mime[8] = 'i'; mime[9] = '\0'; } } sprintf(str_buf, "<item id=\"%s\" parentID=\"%s\" restricted=\"1\"", id, parent); strcat(passed_args->resp, str_buf); if( refID && (!passed_args->filter || strstr(passed_args->filter, "@refID")) ) { sprintf(str_buf, " refID=\"%s\"", refID); strcat(passed_args->resp, str_buf); } sprintf(str_buf, ">" "<dc:title>%s</dc:title>" "<upnp:class>object.%s</upnp:class>", title, class); strcat(passed_args->resp, str_buf); if( comment && (!passed_args->filter || strstr(passed_args->filter, "dc:description")) ) { sprintf(str_buf, "<dc:description>%s</dc:description>", comment); strcat(passed_args->resp, str_buf); } if( creator && (!passed_args->filter || strstr(passed_args->filter, "dc:creator")) ) { sprintf(str_buf, "<dc:creator>%s</dc:creator>", creator); strcat(passed_args->resp, str_buf); } if( date && (!passed_args->filter || strstr(passed_args->filter, "dc:date")) ) { sprintf(str_buf, "<dc:date>%s</dc:date>", date); strcat(passed_args->resp, str_buf); } if( artist && (!passed_args->filter || strstr(passed_args->filter, "upnp:artist")) ) { sprintf(str_buf, "<upnp:artist>%s</upnp:artist>", artist); strcat(passed_args->resp, str_buf); } if( album && (!passed_args->filter || strstr(passed_args->filter, "upnp:album")) ) { sprintf(str_buf, "<upnp:album>%s</upnp:album>", album); strcat(passed_args->resp, str_buf); } if( genre && (!passed_args->filter || strstr(passed_args->filter, "upnp:genre")) ) { sprintf(str_buf, "<upnp:genre>%s</upnp:genre>", genre); strcat(passed_args->resp, str_buf); } if( track && atoi(track) && (!passed_args->filter || strstr(passed_args->filter, "upnp:originalTrackNumber")) ) { sprintf(str_buf, "<upnp:originalTrackNumber>%s</upnp:originalTrackNumber>", track); strcat(passed_args->resp, str_buf); } if( album_art && atoi(album_art) && (!passed_args->filter || strstr(passed_args->filter, "upnp:albumArtURI")) ) { strcat(passed_args->resp, "<upnp:albumArtURI "); if( !passed_args->filter || strstr(passed_args->filter, "upnp:albumArtURI@dlna:profileID") ) { sprintf(str_buf, "dlna:profileID=\"%s\" xmlns:dlna=\"urn:schemas-dlnaorg:metadata-1-0/\"", art_dlna_pn); strcat(passed_args->resp, str_buf); } sprintf(str_buf, ">http://%s:%d/AlbumArt/%s.jpg</upnp:albumArtURI>", lan_addr[0].str, runtime_vars.port, album_art); strcat(passed_args->resp, str_buf); } if( !passed_args->filter || strstr(passed_args->filter, "res") ) { strcat(passed_args->resp, "<res "); if( size && (!passed_args->filter || strstr(passed_args->filter, "res@size")) ) { sprintf(str_buf, "size=\"%s\" ", size); strcat(passed_args->resp, str_buf); } if( duration && (!passed_args->filter || strstr(passed_args->filter, "res@duration")) ) { sprintf(str_buf, "duration=\"%s\" ", duration); strcat(passed_args->resp, str_buf); } if( bitrate && (!passed_args->filter || strstr(passed_args->filter, "res@bitrate")) ) { sprintf(str_buf, "bitrate=\"%s\" ", bitrate); strcat(passed_args->resp, str_buf); } if( sampleFrequency && (!passed_args->filter || strstr(passed_args->filter, "res@sampleFrequency")) ) { sprintf(str_buf, "sampleFrequency=\"%s\" ", sampleFrequency); strcat(passed_args->resp, str_buf); } if( nrAudioChannels && (!passed_args->filter || strstr(passed_args->filter, "res@nrAudioChannels")) ) { sprintf(str_buf, "nrAudioChannels=\"%s\" ", nrAudioChannels); strcat(passed_args->resp, str_buf); } if( resolution && (!passed_args->filter || strstr(passed_args->filter, "res@resolution")) ) { sprintf(str_buf, "resolution=\"%s\" ", resolution); strcat(passed_args->resp, str_buf); } sprintf(str_buf, "protocolInfo=\"http-get:*:%s:%s\">" "http://%s:%d/MediaItems/%s.dat" "</res>", mime, dlna_buf, lan_addr[0].str, runtime_vars.port, detailID); #if 0 //JPEG_RESIZE if( dlna_pn && (strncmp(dlna_pn, "JPEG_LRG", 8) == 0) ) { strcat(passed_args->resp, str_buf); sprintf(str_buf, "<res " "protocolInfo=\"http-get:*:%s:%s\">" "http://%s:%d/Resized/%s" "</res>", mime, "DLNA.ORG_PN=JPEG_SM", lan_addr[0].str, runtime_vars.port, id); } #endif if( tn && atoi(tn) && dlna_pn ) { strcat(passed_args->resp, str_buf); strcat(passed_args->resp, "<res "); sprintf(str_buf, "protocolInfo=\"http-get:*:%s:%s\">" "http://%s:%d/Thumbnails/%s.dat" "</res>", mime, "DLNA.ORG_PN=JPEG_TN", lan_addr[0].str, runtime_vars.port, detailID); } strcat(passed_args->resp, str_buf); } strcpy(str_buf, "</item>"); } else if( strncmp(class, "container", 9) == 0 ) { sprintf(str_buf, "SELECT count(ID) from OBJECTS where PARENT_ID = '%s';", id); ret = sql_get_table(db, str_buf, &result, NULL, NULL); sprintf(str_buf, "<container id=\"%s\" parentID=\"%s\" restricted=\"1\" ", id, parent); strcat(passed_args->resp, str_buf); if( !passed_args->filter || strstr(passed_args->filter, "@childCount")) { sprintf(str_buf, "childCount=\"%s\"", result[1]); strcat(passed_args->resp, str_buf); } /* If the client calls for BrowseMetadata on root, we have to include our "upnp:searchClass"'s, unless they're filtered out */ if( (passed_args->requested == 1) && (strcmp(id, "0") == 0) ) { if( !passed_args->filter || strstr(passed_args->filter, "upnp:searchClass") ) { strcat(passed_args->resp, ">" "<upnp:searchClass includeDerived=\"1\">object.item.audioItem</upnp:searchClass>" "<upnp:searchClass includeDerived=\"1\">object.item.imageItem</upnp:searchClass>" "<upnp:searchClass includeDerived=\"1\">object.item.videoItem</upnp:searchClass"); } } sprintf(str_buf, ">" "<dc:title>%s</dc:title>" "<upnp:class>object.%s</upnp:class>", title, class); strcat(passed_args->resp, str_buf); if( creator && (!passed_args->filter || strstr(passed_args->filter, "dc:creator")) ) { sprintf(str_buf, "<dc:creator>%s</dc:creator>", creator); strcat(passed_args->resp, str_buf); } if( genre && (!passed_args->filter || strstr(passed_args->filter, "upnp:genre")) ) { sprintf(str_buf, "<upnp:genre>%s</upnp:genre>", genre); strcat(passed_args->resp, str_buf); } if( artist && (!passed_args->filter || strstr(passed_args->filter, "upnp:artist")) ) { sprintf(str_buf, "<upnp:artist>%s</upnp:artist>", artist); strcat(passed_args->resp, str_buf); } if( album_art && atoi(album_art) && (!passed_args->filter || strstr(passed_args->filter, "upnp:albumArtURI")) ) { strcat(passed_args->resp, "<upnp:albumArtURI "); if( !passed_args->filter || strstr(passed_args->filter, "upnp:albumArtURI@dlna:profileID") ) { sprintf(str_buf, "dlna:profileID=\"%s\" xmlns:dlna=\"urn:schemas-dlnaorg:metadata-1-0/\"", art_dlna_pn); strcat(passed_args->resp, str_buf); } sprintf(str_buf, ">http://%s:%d/AlbumArt/%s.jpg</upnp:albumArtURI>", lan_addr[0].str, runtime_vars.port, album_art); strcat(passed_args->resp, str_buf); } sprintf(str_buf, "</container>"); sqlite3_free_table(result); } strcat(passed_args->resp, str_buf); return 0; } #endif void SendContainer(struct upnphttp * h, const char * objectID, const char * title, int itemStart, int itemCount) { char * resp; int len; len = asprintf(&resp, "\n" "" "
" "x-container/tivo-%s" "x-container/folder" "0" "2" "%s" "
" "%d" "%d" "" "
" "x-container/tivo-photos" "x-container/folder" "Pictures on %s" "
" "" "" "/TiVoConnect?Command=QueryContainer&Container=3" "" "" "
" "" "
" "x-container/tivo-music" "x-container/folder" "Music on %s" "
" "" "" "/TiVoConnect?Command=QueryContainer&Container=1" "" "" "
" "
", (objectID[0]=='1') ? "music":"photos", title, itemStart, itemCount, title, title); BuildResp_upnphttp(h, resp, len); SendResp_upnphttp(h); } void ProcessTiVoCommand(struct upnphttp * h, const char * orig_path) { char *path; char *key, *val; char *saveptr, *item; char *command = NULL, *container = NULL; int itemStart=0, itemCount=0; path = decodeString(orig_path); DPRINTF(E_DEBUG, L_GENERAL, "Processing TiVo command %s\n", path); item = strtok_r( path, "&", &saveptr ); while( item != NULL ) { if( strlen( item ) == 0 ) { item = strtok_r( NULL, "&", &saveptr ); continue; } val = item; key = strsep(&val, "="); DPRINTF(E_DEBUG, L_GENERAL, "%s: %s\n", key, val); if( strcasecmp(key, "command") == 0 ) { command = val; } else if( strcasecmp(key, "container") == 0 ) { container = val; } else if( strcasecmp(key, "itemstart") == 0 ) { itemStart = atoi(val); } else if( strcasecmp(key, "itemcount") == 0 ) { itemCount = atoi(val); } item = strtok_r( NULL, "&", &saveptr ); } if( strcmp(command, "QueryContainer") == 0 ) { if( !container || (strcmp(container, "/") == 0) ) { SendRootContainer(h); } else { val = container; key = strsep(&val, "/"); SendContainer(h, container, val, itemStart, itemCount); } } CloseSocket_upnphttp(h); } #endif // ENABLE_TIVO