diff --git a/minidlnatypes.h b/minidlnatypes.h index 39cee82..fb8ed1c 100644 --- a/minidlnatypes.h +++ b/minidlnatypes.h @@ -77,6 +77,7 @@ enum client_types { ERokuSoundBridge, EToshibaTV, ELGDevice, + ENetgearEVA2000, EStandardDLNA150 = 100 }; diff --git a/upnphttp.c b/upnphttp.c index 5b9655f..cef17c7 100644 --- a/upnphttp.c +++ b/upnphttp.c @@ -334,6 +334,11 @@ intervening space) by either an integer or the keyword "infinite". */ h->req_client = ELGDevice; h->reqflags |= FLAG_DLNA; } + else if(strncmp(p, "Verismo,", 8)==0) + { + h->req_client = ENetgearEVA2000; + h->reqflags |= FLAG_MS_PFS; + } else if(strstrc(p, "UPnP/1.0 DLNADOC/1.50 Intel_SDK_for_UPnP_devices/1.2", '\r')) { h->req_client = EToshibaTV; @@ -1364,12 +1369,12 @@ SendResp_caption(struct upnphttp * h, char * object) "Date: %s\r\n" "EXT:\r\n" "Server: " MINIDLNA_SERVER_STRING "\r\n\r\n", - size, date); + (intmax_t)size, date); if( send_data(h, header, ret, MSG_MORE) == 0 ) { if( h->req_command != EHead ) - send_file(h, fd, 0, size); + send_file(h, fd, 0, size-1); } close(fd); } diff --git a/upnpsoap.c b/upnpsoap.c index 5af8746..e371f12 100644 --- a/upnpsoap.c +++ b/upnpsoap.c @@ -767,11 +767,12 @@ callback(void *args, int argc, char **argv, char **azColName) lan_addr[passed_args->iface].str, runtime_vars.port, album_art, detailID); } } -#ifdef PFS_HACK if( (passed_args->flags & FLAG_MS_PFS) && *mime == 'i' ) { - ret = strcatf(str, "<upnp:album>%s</upnp:album>", "[No Keywords]"); + if( passed_args->client == EMediaRoom && !album ) + ret = strcatf(str, "<upnp:album>%s</upnp:album>", "[No Keywords]"); - if( tn && atoi(tn) ) { + /* EVA2000 doesn't seem to handle embedded thumbnails */ + if( passed_args->client != ENetgearEVA2000 && tn && atoi(tn) ) { ret = strcatf(str, "<upnp:albumArtURI>" "http://%s:%d/Thumbnails/%s.jpg" "</upnp:albumArtURI>", @@ -783,7 +784,6 @@ callback(void *args, int argc, char **argv, char **azColName) lan_addr[passed_args->iface].str, runtime_vars.port, detailID); } } -#endif if( passed_args->filter & FILTER_RES ) { mime_to_ext(mime, ext); if( (passed_args->client == EFreeBox) && tn && atoi(tn) ) { @@ -796,7 +796,6 @@ callback(void *args, int argc, char **argv, char **azColName) add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels, resolution, dlna_buf, mime, detailID, ext, passed_args); if( (*mime == 'i') && (passed_args->client != EFreeBox) ) { -#if 1 //JPEG_RESIZE int srcw = atoi(strsep(&resolution, "x")); int srch = atoi(resolution); if( !dlna_pn ) { @@ -805,7 +804,6 @@ callback(void *args, int argc, char **argv, char **azColName) if( !dlna_pn || !strncmp(dlna_pn, "JPEG_L", 6) || !strncmp(dlna_pn, "JPEG_M", 6) ) { add_resized_res(srcw, srch, 640, 480, "JPEG_SM", detailID, passed_args); } -#endif if( tn && atoi(tn) ) { ret = strcatf(str, "<res protocolInfo=\"http-get:*:%s:%s\">" "http://%s:%d/Thumbnails/%s.jpg" @@ -963,7 +961,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) struct NameValueParserData data; ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data); - char * ObjectId = GetValueFromNameValueList(&data, "ObjectID"); + char * ObjectID = GetValueFromNameValueList(&data, "ObjectID"); char * Filter = GetValueFromNameValueList(&data, "Filter"); char * BrowseFlag = GetValueFromNameValueList(&data, "BrowseFlag"); char * SortCriteria = GetValueFromNameValueList(&data, "SortCriteria"); @@ -979,15 +977,11 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) if( !BrowseFlag || (strcmp(BrowseFlag, "BrowseDirectChildren") && strcmp(BrowseFlag, "BrowseMetadata")) ) { SoapError(h, 402, "Invalid Args"); - if( h->reqflags & FLAG_MS_PFS ) - ObjectId = sqlite3_malloc(1); goto browse_error; } - if( !ObjectId && !(ObjectId = GetValueFromNameValueList(&data, "ContainerID")) ) + if( !ObjectID && !(ObjectID = GetValueFromNameValueList(&data, "ContainerID")) ) { SoapError(h, 701, "No such object error"); - if( h->reqflags & FLAG_MS_PFS ) - ObjectId = sqlite3_malloc(1); goto browse_error; } memset(&args, 0, sizeof(args)); @@ -996,7 +990,6 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) str.data = malloc(DEFAULT_RESP_SIZE); str.size = DEFAULT_RESP_SIZE; str.off = sprintf(str.data, "%s", resp0); - args.str = &str; /* See if we need to include DLNA namespace reference */ args.iface = h->iface; args.filter = set_filter_flags(Filter, h->req_client); @@ -1010,17 +1003,18 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) args.requested = RequestedCount; args.client = h->req_client; args.flags = h->reqflags; + args.str = &str; if( args.flags & FLAG_MS_PFS ) { - if( !strchr(ObjectId, '$') && (strcmp(ObjectId, "0") != 0) ) + if( !strchr(ObjectID, '$') && (strcmp(ObjectID, "0") != 0) ) { ptr = sql_get_text_field(db, "SELECT OBJECT_ID from OBJECTS" " where OBJECT_ID in " "('"MUSIC_ID"$%s', '"VIDEO_ID"$%s', '"IMAGE_ID"$%s')", - ObjectId, ObjectId, ObjectId); + ObjectID, ObjectID, ObjectID); if( ptr ) { - ObjectId = ptr; + ObjectID = ptr; args.flags |= FLAG_FREE_OBJECT_ID; } } @@ -1032,12 +1026,12 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) " * BrowseFlag: %s\n" " * Filter: %s\n" " * SortCriteria: %s\n", - ObjectId, RequestedCount, StartingIndex, + ObjectID, RequestedCount, StartingIndex, BrowseFlag, Filter, SortCriteria); - if( (args.flags & FLAG_AUDIO_ONLY) && (strcmp(ObjectId, "0") == 0) ) + if( (args.flags & FLAG_AUDIO_ONLY) && (strcmp(ObjectID, "0") == 0) ) { - ObjectId = sqlite3_mprintf("%s", MUSIC_ID); + ObjectID = sqlite3_mprintf("%s", MUSIC_ID); args.flags |= FLAG_FREE_OBJECT_ID; } @@ -1047,13 +1041,13 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) sql = sqlite3_mprintf( SELECT_COLUMNS "from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)" " where OBJECT_ID = '%s';" - , ObjectId); + , ObjectID); ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg); totalMatches = args.returned; } else { - ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", ObjectId); + ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", ObjectID); totalMatches = (ret > 0) ? ret : 0; ret = 0; if( SortCriteria ) @@ -1065,9 +1059,9 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) } else { - if( strncmp(ObjectId, MUSIC_PLIST_ID, strlen(MUSIC_PLIST_ID)) == 0 ) + if( strncmp(ObjectID, MUSIC_PLIST_ID, strlen(MUSIC_PLIST_ID)) == 0 ) { - if( strcmp(ObjectId, MUSIC_PLIST_ID) == 0 ) + if( strcmp(ObjectID, MUSIC_PLIST_ID) == 0 ) asprintf(&orderBy, "order by d.TITLE"); else asprintf(&orderBy, "order by length(OBJECT_ID), OBJECT_ID"); @@ -1090,7 +1084,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) sql = sqlite3_mprintf( SELECT_COLUMNS "from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)" " where PARENT_ID = '%s' %s limit %d, %d;", - ObjectId, orderBy, StartingIndex, RequestedCount); + ObjectID, orderBy, StartingIndex, RequestedCount); DPRINTF(E_DEBUG, L_HTTP, "Browse SQL: %s\n", sql); ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg); } @@ -1103,7 +1097,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) /* Does the object even exist? */ if( !totalMatches ) { - ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", ObjectId); + ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", ObjectID); if( ret <= 0 ) { SoapError(h, 701, "No such object error"); @@ -1120,7 +1114,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) browse_error: ClearNameValueList(&data); if( args.flags & FLAG_FREE_OBJECT_ID ) - sqlite3_free(ObjectId); + sqlite3_free(ObjectID); free(orderBy); free(str.data); } @@ -1164,8 +1158,6 @@ SearchContentDirectory(struct upnphttp * h, const char * action) if( !(ContainerID = GetValueFromNameValueList(&data, "ObjectID")) ) { SoapError(h, 701, "No such object error"); - if( h->reqflags & FLAG_MS_PFS ) - ContainerID = sqlite3_malloc(1); goto search_error; } } @@ -1182,29 +1174,26 @@ SearchContentDirectory(struct upnphttp * h, const char * action) { ret = strcatf(&str, DLNA_NAMESPACE); } - ret = strcatf(&str, ">\n"); + strcatf(&str, ">\n"); args.returned = 0; args.requested = RequestedCount; args.client = h->req_client; args.flags = h->reqflags; args.str = &str; - if( h->reqflags & FLAG_MS_PFS ) + if( args.flags & FLAG_MS_PFS ) { - if( strchr(ContainerID, '$') || (strcmp(ContainerID, "0") == 0) ) - { - ContainerID = sqlite3_mprintf("%s", ContainerID); - } - else + if( !strchr(ContainerID, '$') && (strcmp(ContainerID, "0") != 0) ) { ptr = sql_get_text_field(db, "SELECT OBJECT_ID from OBJECTS" " where OBJECT_ID in " "('"MUSIC_ID"$%s', '"VIDEO_ID"$%s', '"IMAGE_ID"$%s')", ContainerID, ContainerID, ContainerID); if( ptr ) + { ContainerID = ptr; - else - ContainerID = sqlite3_mprintf("%s", ContainerID); + args.flags |= FLAG_FREE_OBJECT_ID; + } } #if 0 // Looks like the 360 already does this /* Sort by track number for some containers */ @@ -1354,7 +1343,7 @@ SearchContentDirectory(struct upnphttp * h, const char * action) BuildSendAndCloseSoapResp(h, str.data, str.off); search_error: ClearNameValueList(&data); - if( h->reqflags & FLAG_MS_PFS ) + if( args.flags & FLAG_FREE_OBJECT_ID ) sqlite3_free(ContainerID); free(orderBy); free(newSearchCriteria);