* Enhance error checking in some additional places as required by the latest UPnP CTT.
This commit is contained in:
parent
cfe7fa9b88
commit
08172a4ed2
12
NEWS
12
NEWS
@ -2,9 +2,21 @@
|
|||||||
--------------------------------
|
--------------------------------
|
||||||
- Add support for other operating systems.
|
- Add support for other operating systems.
|
||||||
- Switch to autoconf from our little genconfig.sh.
|
- Switch to autoconf from our little genconfig.sh.
|
||||||
|
|
||||||
|
1.0.23 - Released 00-Month-0000
|
||||||
|
--------------------------------
|
||||||
- Enable the subtitle menu on some Samsung TV's.
|
- Enable the subtitle menu on some Samsung TV's.
|
||||||
- Add subtitle support for Panasonic TV's.
|
- Add subtitle support for Panasonic TV's.
|
||||||
- Add workarounds for LifeTab tablets' bad behavior.
|
- Add workarounds for LifeTab tablets' bad behavior.
|
||||||
|
- Speed up playlist parsing.
|
||||||
|
- Make metadata-based virtual containers case insensitive.
|
||||||
|
- Add folder art support (very few clients support this though).
|
||||||
|
- Improve trimming of quotation marks.
|
||||||
|
- Fix SRT caption support with the latest Samsung Series D firmware.
|
||||||
|
- Fix subtitles on LG TV's for items whose titles don't have a dot in them.
|
||||||
|
- Add support for the av:mediaClass tag, so some Sony devices can filter items by media type.
|
||||||
|
- Fix inotify detection issues on first-level folders.
|
||||||
|
- Work around LifeTab's broken DLNA support.
|
||||||
|
|
||||||
1.0.22 - Released 24-Aug-2011
|
1.0.22 - Released 24-Aug-2011
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* $Id$ */
|
|
||||||
/* Project : miniupnp
|
/* Project : miniupnp
|
||||||
* Author : Thomas BERNARD
|
* Author : Thomas BERNARD
|
||||||
* copyright (c) 2005-2008 Thomas Bernard
|
* copyright (c) 2005-2008 Thomas Bernard
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* $Id$ */
|
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* $Id$ */
|
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
*
|
*
|
||||||
|
@ -156,7 +156,7 @@ inotify_create_watches(int fd)
|
|||||||
add_watch(fd, media_path->path);
|
add_watch(fd, media_path->path);
|
||||||
num_watches++;
|
num_watches++;
|
||||||
}
|
}
|
||||||
sql_get_table(db, "SELECT PATH from DETAILS where SIZE is NULL and PATH is not NULL", &result, &rows, NULL);
|
sql_get_table(db, "SELECT PATH from DETAILS where MIME is NULL and PATH is not NULL", &result, &rows, NULL);
|
||||||
for( i=1; i <= rows; i++ )
|
for( i=1; i <= rows; i++ )
|
||||||
{
|
{
|
||||||
DPRINTF(E_DEBUG, L_INOTIFY, "Add watch to %s\n", result[i]);
|
DPRINTF(E_DEBUG, L_INOTIFY, "Add watch to %s\n", result[i]);
|
||||||
@ -646,6 +646,7 @@ start_inotify()
|
|||||||
inotify_create_watches(pollfds[0].fd);
|
inotify_create_watches(pollfds[0].fd);
|
||||||
if (setpriority(PRIO_PROCESS, 0, 19) == -1)
|
if (setpriority(PRIO_PROCESS, 0, 19) == -1)
|
||||||
DPRINTF(E_WARN, L_INOTIFY, "Failed to reduce inotify thread priority\n");
|
DPRINTF(E_WARN, L_INOTIFY, "Failed to reduce inotify thread priority\n");
|
||||||
|
sqlite3_release_memory(1<<31);
|
||||||
|
|
||||||
while( !quitting )
|
while( !quitting )
|
||||||
{
|
{
|
||||||
|
@ -825,13 +825,8 @@ init(int argc, char * * argv)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef READYNAS
|
|
||||||
snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
|
|
||||||
"http://%s/admin/", lan_addr[0].str);
|
|
||||||
#else
|
|
||||||
snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
|
snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
|
||||||
"http://%s:%d/", lan_addr[0].str, runtime_vars.port);
|
"http://%s:%d/", lan_addr[0].str, runtime_vars.port);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set signal handler */
|
/* set signal handler */
|
||||||
|
75
minissdp.c
75
minissdp.c
@ -32,6 +32,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
@ -650,12 +651,12 @@ ProcessSSDPRequest(int s, unsigned short port)
|
|||||||
}
|
}
|
||||||
else if( !man || (strncmp(man, "\"ssdp:discover\"", 15) != 0) )
|
else if( !man || (strncmp(man, "\"ssdp:discover\"", 15) != 0) )
|
||||||
{
|
{
|
||||||
DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad MAN header %.*s]\n",
|
DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad %s header '%.*s']\n",
|
||||||
inet_ntoa(sendername.sin_addr), man_len, man);
|
inet_ntoa(sendername.sin_addr), "MAN", man_len, man);
|
||||||
}
|
}
|
||||||
else if( !mx || mx == mx_end || mx_val < 0 ) {
|
else if( !mx || mx == mx_end || mx_val < 0 ) {
|
||||||
DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad MX header %.*s]\n",
|
DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad %s header '%.*s']\n",
|
||||||
inet_ntoa(sendername.sin_addr), mx_len, mx);
|
inet_ntoa(sendername.sin_addr), "MX", mx_len, mx);
|
||||||
}
|
}
|
||||||
else if( st && (st_len > 0) )
|
else if( st && (st_len > 0) )
|
||||||
{
|
{
|
||||||
@ -685,11 +686,26 @@ ProcessSSDPRequest(int s, unsigned short port)
|
|||||||
for(i = 0; known_service_types[i]; i++)
|
for(i = 0; known_service_types[i]; i++)
|
||||||
{
|
{
|
||||||
l = strlen(known_service_types[i]);
|
l = strlen(known_service_types[i]);
|
||||||
if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
|
if( l <= st_len && (memcmp(st, known_service_types[i], l) == 0))
|
||||||
{
|
{
|
||||||
/* Check version number - must always be 1 currently. */
|
if( st_len != l )
|
||||||
if( (st[st_len-2] == ':') && (atoi(st+st_len-1) != 1) )
|
{
|
||||||
break;
|
/* Check version number - must always be 1 currently. */
|
||||||
|
if( (st[l-1] == ':') && (st[l] == '1') )
|
||||||
|
l++;
|
||||||
|
while( l < st_len )
|
||||||
|
{
|
||||||
|
if( !isspace(st[l]) )
|
||||||
|
{
|
||||||
|
DPRINTF(E_DEBUG, L_SSDP, "Ignoring SSDP M-SEARCH with bad extra data [%s]\n",
|
||||||
|
inet_ntoa(sendername.sin_addr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
l++;
|
||||||
|
}
|
||||||
|
if( l != st_len )
|
||||||
|
break;
|
||||||
|
}
|
||||||
_usleep(random()>>20);
|
_usleep(random()>>20);
|
||||||
SendSSDPAnnounce2(s, sendername,
|
SendSSDPAnnounce2(s, sendername,
|
||||||
i,
|
i,
|
||||||
@ -731,6 +747,7 @@ SendSSDPGoodbye(int * sockets, int n_sockets)
|
|||||||
struct sockaddr_in sockname;
|
struct sockaddr_in sockname;
|
||||||
int n, l;
|
int n, l;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
int dup, ret = 0;
|
||||||
char bufr[512];
|
char bufr[512];
|
||||||
|
|
||||||
memset(&sockname, 0, sizeof(struct sockaddr_in));
|
memset(&sockname, 0, sizeof(struct sockaddr_in));
|
||||||
@ -738,31 +755,35 @@ SendSSDPGoodbye(int * sockets, int n_sockets)
|
|||||||
sockname.sin_port = htons(SSDP_PORT);
|
sockname.sin_port = htons(SSDP_PORT);
|
||||||
sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
|
||||||
|
|
||||||
for(j=0; j<n_sockets; j++)
|
for (dup = 0; dup < 2; dup++)
|
||||||
{
|
{
|
||||||
for(i=0; known_service_types[i]; i++)
|
for(j=0; j<n_sockets; j++)
|
||||||
{
|
{
|
||||||
l = snprintf(bufr, sizeof(bufr),
|
for(i=0; known_service_types[i]; i++)
|
||||||
"NOTIFY * HTTP/1.1\r\n"
|
|
||||||
"HOST:%s:%d\r\n"
|
|
||||||
"NT:%s%s\r\n"
|
|
||||||
"USN:%s%s%s%s\r\n"
|
|
||||||
"NTS:ssdp:byebye\r\n"
|
|
||||||
"\r\n",
|
|
||||||
SSDP_MCAST_ADDR, SSDP_PORT,
|
|
||||||
known_service_types[i], (i>1?"1":""),
|
|
||||||
uuidvalue, (i>0?"::":""), (i>0?known_service_types[i]:""), (i>1?"1":"") );
|
|
||||||
//DEBUG DPRINTF(E_DEBUG, L_SSDP, "Sending NOTIFY:\n%s", bufr);
|
|
||||||
n = sendto(sockets[j], bufr, l, 0,
|
|
||||||
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
|
|
||||||
if(n < 0)
|
|
||||||
{
|
{
|
||||||
DPRINTF(E_ERROR, L_SSDP, "sendto(udp_shutdown=%d): %s\n", sockets[j], strerror(errno));
|
l = snprintf(bufr, sizeof(bufr),
|
||||||
return -1;
|
"NOTIFY * HTTP/1.1\r\n"
|
||||||
|
"HOST:%s:%d\r\n"
|
||||||
|
"NT:%s%s\r\n"
|
||||||
|
"USN:%s%s%s%s\r\n"
|
||||||
|
"NTS:ssdp:byebye\r\n"
|
||||||
|
"\r\n",
|
||||||
|
SSDP_MCAST_ADDR, SSDP_PORT,
|
||||||
|
known_service_types[i], (i>1?"1":""),
|
||||||
|
uuidvalue, (i>0?"::":""), (i>0?known_service_types[i]:""), (i>1?"1":"") );
|
||||||
|
//DEBUG DPRINTF(E_DEBUG, L_SSDP, "Sending NOTIFY:\n%s", bufr);
|
||||||
|
n = sendto(sockets[j], bufr, l, 0,
|
||||||
|
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
|
||||||
|
if(n < 0)
|
||||||
|
{
|
||||||
|
DPRINTF(E_ERROR, L_SSDP, "sendto(udp_shutdown=%d): %s\n", sockets[j], strerror(errno));
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SubmitServicesToMiniSSDPD() :
|
/* SubmitServicesToMiniSSDPD() :
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* $Id$ */
|
|
||||||
/* minixml.c : the minimum size a xml parser can be ! */
|
/* minixml.c : the minimum size a xml parser can be ! */
|
||||||
/* Project : miniupnp
|
/* Project : miniupnp
|
||||||
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* $Id$ */
|
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
*
|
*
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
/* $Id$ */
|
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
*
|
*
|
||||||
|
62
upnpevents.c
62
upnpevents.c
@ -54,6 +54,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/param.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -73,7 +74,6 @@ struct subscriber {
|
|||||||
struct upnp_event_notify * notify;
|
struct upnp_event_notify * notify;
|
||||||
time_t timeout;
|
time_t timeout;
|
||||||
uint32_t seq;
|
uint32_t seq;
|
||||||
/*enum { EWanCFG = 1, EWanIPC, EL3F } service;*/
|
|
||||||
enum subscriber_service_enum service;
|
enum subscriber_service_enum service;
|
||||||
char uuid[42];
|
char uuid[42];
|
||||||
char callback[];
|
char callback[];
|
||||||
@ -147,12 +147,8 @@ upnpevents_addSubscriber(const char * eventurl,
|
|||||||
int timeout)
|
int timeout)
|
||||||
{
|
{
|
||||||
struct subscriber * tmp;
|
struct subscriber * tmp;
|
||||||
/*static char uuid[42];*/
|
|
||||||
/* "uuid:00000000-0000-0000-0000-000000000000"; 5+36+1=42bytes */
|
|
||||||
DPRINTF(E_DEBUG, L_HTTP, "addSubscriber(%s, %.*s, %d)\n",
|
DPRINTF(E_DEBUG, L_HTTP, "addSubscriber(%s, %.*s, %d)\n",
|
||||||
eventurl, callbacklen, callback, timeout);
|
eventurl, callbacklen, callback, timeout);
|
||||||
/*strncpy(uuid, uuidvalue, sizeof(uuid));
|
|
||||||
uuid[sizeof(uuid)-1] = '\0';*/
|
|
||||||
tmp = newSubscriber(eventurl, callback, callbacklen);
|
tmp = newSubscriber(eventurl, callback, callbacklen);
|
||||||
if(!tmp)
|
if(!tmp)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -198,8 +194,7 @@ upnpevents_removeSubscriber(const char * sid, int sidlen)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* notifies all subscriber of a number of port mapping change
|
/* notifies all subscribers of a SystemUpdateID change */
|
||||||
* or external ip address change */
|
|
||||||
void
|
void
|
||||||
upnp_event_var_change_notify(enum subscriber_service_enum service)
|
upnp_event_var_change_notify(enum subscriber_service_enum service)
|
||||||
{
|
{
|
||||||
@ -265,7 +260,7 @@ upnp_event_notify_connect(struct upnp_event_notify * obj)
|
|||||||
}
|
}
|
||||||
p = obj->sub->callback;
|
p = obj->sub->callback;
|
||||||
p += 7; /* http:// */
|
p += 7; /* http:// */
|
||||||
while(*p != '/' && *p != ':')
|
while(*p != '/' && *p != ':' && i < (sizeof(obj->addrstr)-1))
|
||||||
obj->addrstr[i++] = *(p++);
|
obj->addrstr[i++] = *(p++);
|
||||||
obj->addrstr[i] = '\0';
|
obj->addrstr[i] = '\0';
|
||||||
if(*p == ':') {
|
if(*p == ':') {
|
||||||
@ -349,16 +344,15 @@ static void upnp_event_send(struct upnp_event_notify * obj)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
//DEBUG DPRINTF(E_DEBUG, L_HTTP, "Sending UPnP Event:\n%s", obj->buffer+obj->sent);
|
//DEBUG DPRINTF(E_DEBUG, L_HTTP, "Sending UPnP Event:\n%s", obj->buffer+obj->sent);
|
||||||
i = send(obj->s, obj->buffer + obj->sent, obj->tosend - obj->sent, 0);
|
while( obj->sent < obj->tosend ) {
|
||||||
if(i<0) {
|
i = send(obj->s, obj->buffer + obj->sent, obj->tosend - obj->sent, 0);
|
||||||
DPRINTF(E_WARN, L_HTTP, "%s: send(): %s\n", "upnp_event_send", strerror(errno));
|
if(i<0) {
|
||||||
obj->state = EError;
|
DPRINTF(E_WARN, L_HTTP, "%s: send(): %s\n", "upnp_event_send", strerror(errno));
|
||||||
return;
|
obj->state = EError;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
obj->sent += i;
|
||||||
}
|
}
|
||||||
else if(i != (obj->tosend - obj->sent))
|
|
||||||
DPRINTF(E_WARN, L_HTTP, "%s: %d bytes send out of %d\n",
|
|
||||||
"upnp_event_send", i, obj->tosend - obj->sent);
|
|
||||||
obj->sent += i;
|
|
||||||
if(obj->sent == obj->tosend)
|
if(obj->sent == obj->tosend)
|
||||||
obj->state = EWaitingForResponse;
|
obj->state = EWaitingForResponse;
|
||||||
}
|
}
|
||||||
@ -376,7 +370,11 @@ static void upnp_event_recv(struct upnp_event_notify * obj)
|
|||||||
n, n, obj->buffer);
|
n, n, obj->buffer);
|
||||||
obj->state = EFinished;
|
obj->state = EFinished;
|
||||||
if(obj->sub)
|
if(obj->sub)
|
||||||
|
{
|
||||||
obj->sub->seq++;
|
obj->sub->seq++;
|
||||||
|
if (!obj->sub->seq)
|
||||||
|
obj->sub->seq++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -421,13 +419,13 @@ void upnpevents_selectfds(fd_set *readset, fd_set *writeset, int * max_fd)
|
|||||||
if(obj->s > *max_fd)
|
if(obj->s > *max_fd)
|
||||||
*max_fd = obj->s;
|
*max_fd = obj->s;
|
||||||
break;
|
break;
|
||||||
case EFinished:
|
|
||||||
case EError:
|
|
||||||
case EWaitingForResponse:
|
case EWaitingForResponse:
|
||||||
FD_SET(obj->s, readset);
|
FD_SET(obj->s, readset);
|
||||||
if(obj->s > *max_fd)
|
if(obj->s > *max_fd)
|
||||||
*max_fd = obj->s;
|
*max_fd = obj->s;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -483,29 +481,3 @@ void upnpevents_processfds(fd_set *readset, fd_set *writeset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_MINIDLNACTL
|
|
||||||
void write_events_details(int s) {
|
|
||||||
int n;
|
|
||||||
char buff[80];
|
|
||||||
struct upnp_event_notify * obj;
|
|
||||||
struct subscriber * sub;
|
|
||||||
write(s, "Events details\n", 15);
|
|
||||||
for(obj = notifylist.lh_first; obj != NULL; obj = obj->entries.le_next) {
|
|
||||||
n = snprintf(buff, sizeof(buff), " %p sub=%p state=%d s=%d\n",
|
|
||||||
obj, obj->sub, obj->state, obj->s);
|
|
||||||
write(s, buff, n);
|
|
||||||
}
|
|
||||||
write(s, "Subscribers :\n", 14);
|
|
||||||
for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
|
|
||||||
n = snprintf(buff, sizeof(buff), " %p timeout=%d seq=%u service=%d\n",
|
|
||||||
sub, sub->timeout, sub->seq, sub->service);
|
|
||||||
write(s, buff, n);
|
|
||||||
n = snprintf(buff, sizeof(buff), " notify=%p %s\n",
|
|
||||||
sub->notify, sub->uuid);
|
|
||||||
write(s, buff, n);
|
|
||||||
n = snprintf(buff, sizeof(buff), " %s\n",
|
|
||||||
sub->callback);
|
|
||||||
write(s, buff, n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
121
upnphttp.c
121
upnphttp.c
@ -209,6 +209,9 @@ ParseHttpHeaders(struct upnphttp * h)
|
|||||||
n++;
|
n++;
|
||||||
h->req_Callback = p + 1;
|
h->req_Callback = p + 1;
|
||||||
h->req_CallbackLen = MAX(0, n - 1);
|
h->req_CallbackLen = MAX(0, n - 1);
|
||||||
|
/* Verify callback validity */
|
||||||
|
if(strncmp(h->req_Callback, "http://", 7) != 0)
|
||||||
|
h->req_Callback = NULL;
|
||||||
}
|
}
|
||||||
else if(strncasecmp(line, "SID", 3)==0)
|
else if(strncasecmp(line, "SID", 3)==0)
|
||||||
{
|
{
|
||||||
@ -233,6 +236,17 @@ ParseHttpHeaders(struct upnphttp * h)
|
|||||||
h->req_SIDLen = n;
|
h->req_SIDLen = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(strncasecmp(line, "NT", 2)==0)
|
||||||
|
{
|
||||||
|
p = colon + 1;
|
||||||
|
while(isspace(*p))
|
||||||
|
p++;
|
||||||
|
n = 0;
|
||||||
|
while(!isspace(p[n]))
|
||||||
|
n++;
|
||||||
|
h->req_NT = p;
|
||||||
|
h->req_NTLen = n;
|
||||||
|
}
|
||||||
/* Timeout: Seconds-nnnn */
|
/* Timeout: Seconds-nnnn */
|
||||||
/* TIMEOUT
|
/* TIMEOUT
|
||||||
Recommended. Requested duration until subscription expires,
|
Recommended. Requested duration until subscription expires,
|
||||||
@ -406,6 +420,10 @@ intervening space) by either an integer or the keyword "infinite". */
|
|||||||
h->reqflags |= FLAG_CHUNKED;
|
h->reqflags |= FLAG_CHUNKED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(strncasecmp(line, "Accept-Language", 15)==0)
|
||||||
|
{
|
||||||
|
h->reqflags |= FLAG_LANGUAGE;
|
||||||
|
}
|
||||||
else if(strncasecmp(line, "getcontentFeatures.dlna.org", 27)==0)
|
else if(strncasecmp(line, "getcontentFeatures.dlna.org", 27)==0)
|
||||||
{
|
{
|
||||||
p = colon + 1;
|
p = colon + 1;
|
||||||
@ -651,6 +669,34 @@ sendXMLdesc(struct upnphttp * h, char * (f)(int *))
|
|||||||
free(desc);
|
free(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
SendResp_presentation(struct upnphttp * h)
|
||||||
|
{
|
||||||
|
char body[1024];
|
||||||
|
int l;
|
||||||
|
h->respflags = FLAG_HTML;
|
||||||
|
|
||||||
|
#ifdef READYNAS
|
||||||
|
l = snprintf(body, sizeof(body), "<meta http-equiv=\"refresh\" content=\"0; url=https://%s/admin/\">",
|
||||||
|
lan_addr[h->iface].str);
|
||||||
|
#else
|
||||||
|
int a, v, p;
|
||||||
|
a = sql_get_int_field(db, "SELECT count(*) from DETAILS where MIME glob 'a*'");
|
||||||
|
v = sql_get_int_field(db, "SELECT count(*) from DETAILS where MIME glob 'v*'");
|
||||||
|
p = sql_get_int_field(db, "SELECT count(*) from DETAILS where MIME glob 'i*'");
|
||||||
|
l = snprintf(body, sizeof(body),
|
||||||
|
"<HTML><HEAD><TITLE>" SERVER_NAME "</TITLE></HEAD>"
|
||||||
|
"<BODY><div style=\"text-align: center\">"
|
||||||
|
"<h3>" SERVER_NAME " status</h3>"
|
||||||
|
"Audio files: %d<br>"
|
||||||
|
"Video files: %d<br>"
|
||||||
|
"Image files: %d</div>"
|
||||||
|
"</BODY></HTML>\r\n", a, v, p);
|
||||||
|
#endif
|
||||||
|
BuildResp_upnphttp(h, body, l);
|
||||||
|
SendResp_upnphttp(h);
|
||||||
|
}
|
||||||
|
|
||||||
/* ProcessHTTPPOST_upnphttp()
|
/* ProcessHTTPPOST_upnphttp()
|
||||||
* executes the SOAP query if it is possible */
|
* executes the SOAP query if it is possible */
|
||||||
static void
|
static void
|
||||||
@ -693,7 +739,15 @@ ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path)
|
|||||||
DPRINTF(E_DEBUG, L_HTTP, "Callback '%.*s' Timeout=%d\n",
|
DPRINTF(E_DEBUG, L_HTTP, "Callback '%.*s' Timeout=%d\n",
|
||||||
h->req_CallbackLen, h->req_Callback, h->req_Timeout);
|
h->req_CallbackLen, h->req_Callback, h->req_Timeout);
|
||||||
DPRINTF(E_DEBUG, L_HTTP, "SID '%.*s'\n", h->req_SIDLen, h->req_SID);
|
DPRINTF(E_DEBUG, L_HTTP, "SID '%.*s'\n", h->req_SIDLen, h->req_SID);
|
||||||
if(!h->req_Callback && !h->req_SID) {
|
if(!h->req_NT) {
|
||||||
|
static const char err400str[] =
|
||||||
|
"<html><body>Bad request</body></html>";
|
||||||
|
BuildResp2_upnphttp(h, 400, "Bad Request",
|
||||||
|
err400str, sizeof(err400str) - 1);
|
||||||
|
SendResp_upnphttp(h);
|
||||||
|
CloseSocket_upnphttp(h);
|
||||||
|
} else if((!h->req_Callback && !h->req_SID) ||
|
||||||
|
strncmp(h->req_NT, "upnp:event", h->req_NTLen) != 0) {
|
||||||
/* Missing or invalid CALLBACK : 412 Precondition Failed.
|
/* Missing or invalid CALLBACK : 412 Precondition Failed.
|
||||||
* If CALLBACK header is missing or does not contain a valid HTTP URL,
|
* If CALLBACK header is missing or does not contain a valid HTTP URL,
|
||||||
* the publisher must respond with HTTP error 412 Precondition Failed*/
|
* the publisher must respond with HTTP error 412 Precondition Failed*/
|
||||||
@ -944,6 +998,11 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
|
|||||||
SendResp_caption(h, HttpUrl+10);
|
SendResp_caption(h, HttpUrl+10);
|
||||||
CloseSocket_upnphttp(h);
|
CloseSocket_upnphttp(h);
|
||||||
}
|
}
|
||||||
|
else if(strcmp(HttpUrl, "/") == 0)
|
||||||
|
{
|
||||||
|
SendResp_presentation(h);
|
||||||
|
CloseSocket_upnphttp(h);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DPRINTF(E_WARN, L_HTTP, "%s not found, responding ERROR 404\n", HttpUrl);
|
DPRINTF(E_WARN, L_HTTP, "%s not found, responding ERROR 404\n", HttpUrl);
|
||||||
@ -1047,23 +1106,6 @@ Process_upnphttp(struct upnphttp * h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char httpresphead[] =
|
|
||||||
"%s %d %s\r\n"
|
|
||||||
"Content-Type: %s\r\n"
|
|
||||||
"Connection: close\r\n"
|
|
||||||
"Content-Length: %d\r\n"
|
|
||||||
"Server: " MINIDLNA_SERVER_STRING "\r\n"
|
|
||||||
// "Accept-Ranges: bytes\r\n"
|
|
||||||
; /*"\r\n";*/
|
|
||||||
/*
|
|
||||||
"<?xml version=\"1.0\"?>\n"
|
|
||||||
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
|
|
||||||
"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
|
||||||
"<s:Body>"
|
|
||||||
|
|
||||||
"</s:Body>"
|
|
||||||
"</s:Envelope>";
|
|
||||||
*/
|
|
||||||
/* with response code and response message
|
/* with response code and response message
|
||||||
* also allocate enough memory */
|
* also allocate enough memory */
|
||||||
|
|
||||||
@ -1072,15 +1114,22 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode,
|
|||||||
const char * respmsg,
|
const char * respmsg,
|
||||||
int bodylen)
|
int bodylen)
|
||||||
{
|
{
|
||||||
|
static const char httpresphead[] =
|
||||||
|
"%s %d %s\r\n"
|
||||||
|
"Content-Type: %s\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"Server: " MINIDLNA_SERVER_STRING "\r\n";
|
||||||
|
time_t curtime = time(NULL);
|
||||||
|
char date[30];
|
||||||
int templen;
|
int templen;
|
||||||
if(!h->res_buf)
|
if(!h->res_buf)
|
||||||
{
|
{
|
||||||
templen = sizeof(httpresphead) + 192 + bodylen;
|
templen = sizeof(httpresphead) + 256 + bodylen;
|
||||||
h->res_buf = (char *)malloc(templen);
|
h->res_buf = (char *)malloc(templen);
|
||||||
h->res_buf_alloclen = templen;
|
h->res_buf_alloclen = templen;
|
||||||
}
|
}
|
||||||
h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
|
h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
|
||||||
//httpresphead, h->HttpVer,
|
|
||||||
httpresphead, "HTTP/1.1",
|
httpresphead, "HTTP/1.1",
|
||||||
respcode, respmsg,
|
respcode, respmsg,
|
||||||
(h->respflags&FLAG_HTML)?"text/html":"text/xml; charset=\"utf-8\"",
|
(h->respflags&FLAG_HTML)?"text/html":"text/xml; charset=\"utf-8\"",
|
||||||
@ -1098,7 +1147,6 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode,
|
|||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
h->res_buf_alloclen - h->res_buflen,
|
||||||
"300\r\n");
|
"300\r\n");
|
||||||
//JM DLNA must force to 300 - "infinite\r\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(h->respflags & FLAG_SID) {
|
if(h->respflags & FLAG_SID) {
|
||||||
@ -1106,19 +1154,22 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode,
|
|||||||
h->res_buf_alloclen - h->res_buflen,
|
h->res_buf_alloclen - h->res_buflen,
|
||||||
"SID: %.*s\r\n", h->req_SIDLen, h->req_SID);
|
"SID: %.*s\r\n", h->req_SIDLen, h->req_SID);
|
||||||
}
|
}
|
||||||
#if 0 // DLNA
|
if(h->reqflags & FLAG_LANGUAGE) {
|
||||||
char szTime[30];
|
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||||
time_t curtime = time(NULL);
|
h->res_buf_alloclen - h->res_buflen,
|
||||||
strftime(szTime, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
"Content-Language: en\r\n");
|
||||||
|
}
|
||||||
|
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
h->res_buf_alloclen - h->res_buflen,
|
||||||
"Date: %s\r\n", szTime);
|
"Date: %s\r\n", date);
|
||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
|
||||||
"contentFeatures.dlna.org: \r\n");
|
|
||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
h->res_buf_alloclen - h->res_buflen,
|
||||||
"EXT:\r\n");
|
"EXT:\r\n");
|
||||||
|
#if 0 // DLNA
|
||||||
|
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||||
|
h->res_buf_alloclen - h->res_buflen,
|
||||||
|
"contentFeatures.dlna.org: \r\n");
|
||||||
#endif
|
#endif
|
||||||
h->res_buf[h->res_buflen++] = '\r';
|
h->res_buf[h->res_buflen++] = '\r';
|
||||||
h->res_buf[h->res_buflen++] = '\n';
|
h->res_buf[h->res_buflen++] = '\n';
|
||||||
@ -1339,8 +1390,6 @@ SendResp_albumArt(struct upnphttp * h, char * object)
|
|||||||
}
|
}
|
||||||
DPRINTF(E_INFO, L_HTTP, "Serving album art ID: %s [%s]\n", object, path);
|
DPRINTF(E_INFO, L_HTTP, "Serving album art ID: %s [%s]\n", object, path);
|
||||||
|
|
||||||
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
|
||||||
|
|
||||||
fd = open(path, O_RDONLY);
|
fd = open(path, O_RDONLY);
|
||||||
if( fd < 0 ) {
|
if( fd < 0 ) {
|
||||||
DPRINTF(E_ERROR, L_HTTP, "Error opening %s\n", path);
|
DPRINTF(E_ERROR, L_HTTP, "Error opening %s\n", path);
|
||||||
@ -1352,6 +1401,7 @@ SendResp_albumArt(struct upnphttp * h, char * object)
|
|||||||
size = lseek(fd, 0, SEEK_END);
|
size = lseek(fd, 0, SEEK_END);
|
||||||
lseek(fd, 0, SEEK_SET);
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
|
||||||
|
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
||||||
ret = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n"
|
ret = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Type: image/jpeg\r\n"
|
"Content-Type: image/jpeg\r\n"
|
||||||
"Content-Length: %jd\r\n"
|
"Content-Length: %jd\r\n"
|
||||||
@ -1403,8 +1453,8 @@ SendResp_caption(struct upnphttp * h, char * object)
|
|||||||
sqlite3_free(path);
|
sqlite3_free(path);
|
||||||
size = lseek(fd, 0, SEEK_END);
|
size = lseek(fd, 0, SEEK_END);
|
||||||
lseek(fd, 0, SEEK_SET);
|
lseek(fd, 0, SEEK_SET);
|
||||||
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
|
||||||
|
|
||||||
|
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
||||||
ret = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n"
|
ret = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Type: smi/caption\r\n"
|
"Content-Type: smi/caption\r\n"
|
||||||
"Content-Length: %jd\r\n"
|
"Content-Length: %jd\r\n"
|
||||||
@ -1456,7 +1506,6 @@ SendResp_thumbnail(struct upnphttp * h, char * object)
|
|||||||
sqlite3_free(path);
|
sqlite3_free(path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
|
||||||
|
|
||||||
l = exif_loader_new();
|
l = exif_loader_new();
|
||||||
exif_loader_write_file(l, path);
|
exif_loader_write_file(l, path);
|
||||||
@ -1471,6 +1520,7 @@ SendResp_thumbnail(struct upnphttp * h, char * object)
|
|||||||
exif_data_unref(ed);
|
exif_data_unref(ed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
||||||
ret = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n"
|
ret = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Type: image/jpeg\r\n"
|
"Content-Type: image/jpeg\r\n"
|
||||||
"Content-Length: %d\r\n"
|
"Content-Length: %d\r\n"
|
||||||
@ -1611,12 +1661,11 @@ SendResp_resizedimg(struct upnphttp * h, char * object)
|
|||||||
else if( srcw>>1 >= dstw && srch>>1 >= dsth )
|
else if( srcw>>1 >= dstw && srch>>1 >= dsth )
|
||||||
scale = 2;
|
scale = 2;
|
||||||
|
|
||||||
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
|
||||||
|
|
||||||
str.data = header;
|
str.data = header;
|
||||||
str.size = sizeof(header);
|
str.size = sizeof(header);
|
||||||
str.off = 0;
|
str.off = 0;
|
||||||
|
|
||||||
|
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
||||||
strcatf(&str, "HTTP/1.1 200 OK\r\n"
|
strcatf(&str, "HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Type: image/jpeg\r\n"
|
"Content-Type: image/jpeg\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
@ -1816,7 +1865,6 @@ SendResp_dlnafile(struct upnphttp * h, char * object)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
|
||||||
offset = h->req_RangeStart;
|
offset = h->req_RangeStart;
|
||||||
sendfh = open(last_file.path, O_RDONLY);
|
sendfh = open(last_file.path, O_RDONLY);
|
||||||
if( sendfh < 0 ) {
|
if( sendfh < 0 ) {
|
||||||
@ -1900,6 +1948,7 @@ SendResp_dlnafile(struct upnphttp * h, char * object)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
||||||
strcatf(&str, "Accept-Ranges: bytes\r\n"
|
strcatf(&str, "Accept-Ranges: bytes\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
"Date: %s\r\n"
|
"Date: %s\r\n"
|
||||||
|
@ -71,6 +71,8 @@ struct upnphttp {
|
|||||||
int req_soapActionLen;
|
int req_soapActionLen;
|
||||||
const char * req_Callback; /* For SUBSCRIBE */
|
const char * req_Callback; /* For SUBSCRIBE */
|
||||||
int req_CallbackLen;
|
int req_CallbackLen;
|
||||||
|
const char * req_NT;
|
||||||
|
int req_NTLen;
|
||||||
int req_Timeout;
|
int req_Timeout;
|
||||||
const char * req_SID; /* For UNSUBSCRIBE */
|
const char * req_SID; /* For UNSUBSCRIBE */
|
||||||
int req_SIDLen;
|
int req_SIDLen;
|
||||||
@ -92,9 +94,10 @@ struct upnphttp {
|
|||||||
#define FLAG_SID 0x00000002
|
#define FLAG_SID 0x00000002
|
||||||
#define FLAG_RANGE 0x00000004
|
#define FLAG_RANGE 0x00000004
|
||||||
#define FLAG_HOST 0x00000008
|
#define FLAG_HOST 0x00000008
|
||||||
|
#define FLAG_LANGUAGE 0x00000010
|
||||||
|
|
||||||
|
#define FLAG_INVALID_REQ 0x00000040
|
||||||
#define FLAG_HTML 0x00000080
|
#define FLAG_HTML 0x00000080
|
||||||
#define FLAG_INVALID_REQ 0x00000010
|
|
||||||
|
|
||||||
#define FLAG_CHUNKED 0x00000100
|
#define FLAG_CHUNKED 0x00000100
|
||||||
#define FLAG_TIMESEEK 0x00000200
|
#define FLAG_TIMESEEK 0x00000200
|
||||||
|
74
upnpsoap.c
74
upnpsoap.c
@ -129,11 +129,22 @@ IsAuthorizedValidated(struct upnphttp * h, const char * action)
|
|||||||
|
|
||||||
char body[512];
|
char body[512];
|
||||||
int bodylen;
|
int bodylen;
|
||||||
|
struct NameValueParserData data;
|
||||||
|
const char * id;
|
||||||
|
|
||||||
bodylen = snprintf(body, sizeof(body), resp,
|
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
|
||||||
action, "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1",
|
id = GetValueFromNameValueList(&data, "DeviceID");
|
||||||
1, action);
|
if(id)
|
||||||
BuildSendAndCloseSoapResp(h, body, bodylen);
|
{
|
||||||
|
bodylen = snprintf(body, sizeof(body), resp,
|
||||||
|
action, "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1",
|
||||||
|
1, action);
|
||||||
|
BuildSendAndCloseSoapResp(h, body, bodylen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SoapError(h, 402, "Invalid Args");
|
||||||
|
|
||||||
|
ClearNameValueList(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -246,11 +257,32 @@ GetCurrentConnectionInfo(struct upnphttp * h, const char * action)
|
|||||||
|
|
||||||
char body[sizeof(resp)+128];
|
char body[sizeof(resp)+128];
|
||||||
int bodylen;
|
int bodylen;
|
||||||
|
struct NameValueParserData data;
|
||||||
|
const char * id_str;
|
||||||
|
int id;
|
||||||
|
char *endptr;
|
||||||
|
|
||||||
bodylen = snprintf(body, sizeof(body), resp,
|
ParseNameValue(h->req_buf + h->req_contentoff, h->req_contentlen, &data);
|
||||||
action, "urn:schemas-upnp-org:service:ConnectionManager:1",
|
id_str = GetValueFromNameValueList(&data, "ConnectionID");
|
||||||
action);
|
DPRINTF(E_INFO, L_HTTP, "GetCurrentConnectionInfo(%s)\n", id_str);
|
||||||
BuildSendAndCloseSoapResp(h, body, bodylen);
|
if(id_str)
|
||||||
|
id = strtol(id_str, &endptr, 10);
|
||||||
|
if(!id_str || !id_str[0] || endptr[0] || id != 0)
|
||||||
|
{
|
||||||
|
SoapError(h, 402, "Invalid Args");
|
||||||
|
}
|
||||||
|
else if(id != 0)
|
||||||
|
{
|
||||||
|
SoapError(h, 701, "No such object error");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bodylen = snprintf(body, sizeof(body), resp,
|
||||||
|
action, "urn:schemas-upnp-org:service:ConnectionManager:1",
|
||||||
|
action);
|
||||||
|
BuildSendAndCloseSoapResp(h, body, bodylen);
|
||||||
|
}
|
||||||
|
ClearNameValueList(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -533,6 +565,12 @@ parse_sort_criteria(char *sortCriteria, int *error)
|
|||||||
reverse = 1;
|
reverse = 1;
|
||||||
item++;
|
item++;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPRINTF(E_DEBUG, L_HTTP, "No order specified [%s]\n", item);
|
||||||
|
*error = 1;
|
||||||
|
goto unhandled_order;
|
||||||
|
}
|
||||||
if( strcasecmp(item, "upnp:class") == 0 )
|
if( strcasecmp(item, "upnp:class") == 0 )
|
||||||
{
|
{
|
||||||
strcat(order, "o.CLASS");
|
strcat(order, "o.CLASS");
|
||||||
@ -556,7 +594,7 @@ parse_sort_criteria(char *sortCriteria, int *error)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Unhandled SortCriteria [%s]\n", item);
|
DPRINTF(E_DEBUG, L_HTTP, "Unhandled SortCriteria [%s]\n", item);
|
||||||
*error = 1;
|
*error = 1;
|
||||||
if( i )
|
if( i )
|
||||||
{
|
{
|
||||||
@ -1017,6 +1055,10 @@ callback(void *args, int argc, char **argv, char **azColName)
|
|||||||
"<dc:title>%s</dc:title>"
|
"<dc:title>%s</dc:title>"
|
||||||
"<upnp:class>object.%s</upnp:class>",
|
"<upnp:class>object.%s</upnp:class>",
|
||||||
title, class);
|
title, class);
|
||||||
|
if( strcmp(class+10, "storageFolder") == 0 ) {
|
||||||
|
/* TODO: Implement real folder size tracking */
|
||||||
|
ret = strcatf(str, "<upnp:storageUsed>%s</upnp:storageUsed>", (size ? size : "-1"));
|
||||||
|
}
|
||||||
if( creator && (passed_args->filter & FILTER_DC_CREATOR) ) {
|
if( creator && (passed_args->filter & FILTER_DC_CREATOR) ) {
|
||||||
ret = strcatf(str, "<dc:creator>%s</dc:creator>", creator);
|
ret = strcatf(str, "<dc:creator>%s</dc:creator>", creator);
|
||||||
}
|
}
|
||||||
@ -1087,10 +1129,20 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
|
|
||||||
if( (ptr = GetValueFromNameValueList(&data, "RequestedCount")) )
|
if( (ptr = GetValueFromNameValueList(&data, "RequestedCount")) )
|
||||||
RequestedCount = atoi(ptr);
|
RequestedCount = atoi(ptr);
|
||||||
|
if( RequestedCount < 0 )
|
||||||
|
{
|
||||||
|
SoapError(h, 402, "Invalid Args");
|
||||||
|
goto browse_error;
|
||||||
|
}
|
||||||
if( !RequestedCount )
|
if( !RequestedCount )
|
||||||
RequestedCount = -1;
|
RequestedCount = -1;
|
||||||
if( (ptr = GetValueFromNameValueList(&data, "StartingIndex")) )
|
if( (ptr = GetValueFromNameValueList(&data, "StartingIndex")) )
|
||||||
StartingIndex = atoi(ptr);
|
StartingIndex = atoi(ptr);
|
||||||
|
if( StartingIndex < 0 )
|
||||||
|
{
|
||||||
|
SoapError(h, 402, "Invalid Args");
|
||||||
|
goto browse_error;
|
||||||
|
}
|
||||||
if( !BrowseFlag || (strcmp(BrowseFlag, "BrowseDirectChildren") && strcmp(BrowseFlag, "BrowseMetadata")) )
|
if( !BrowseFlag || (strcmp(BrowseFlag, "BrowseDirectChildren") && strcmp(BrowseFlag, "BrowseMetadata")) )
|
||||||
{
|
{
|
||||||
SoapError(h, 402, "Invalid Args");
|
SoapError(h, 402, "Invalid Args");
|
||||||
@ -1098,7 +1150,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
}
|
}
|
||||||
if( !ObjectID && !(ObjectID = GetValueFromNameValueList(&data, "ContainerID")) )
|
if( !ObjectID && !(ObjectID = GetValueFromNameValueList(&data, "ContainerID")) )
|
||||||
{
|
{
|
||||||
SoapError(h, 701, "No such object error");
|
SoapError(h, 402, "Invalid Args");
|
||||||
goto browse_error;
|
goto browse_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1293,7 +1345,7 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
|||||||
{
|
{
|
||||||
if( !(ContainerID = GetValueFromNameValueList(&data, "ObjectID")) )
|
if( !(ContainerID = GetValueFromNameValueList(&data, "ObjectID")) )
|
||||||
{
|
{
|
||||||
SoapError(h, 701, "No such object error");
|
SoapError(h, 402, "Invalid Args");
|
||||||
goto search_error;
|
goto search_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user