Mark Ryan (mark.d.ryan@intel.com)
Ludovic Ferrandis (ludovic.ferrandis@intel.com)
Sébastien Bianti (sebastien.bianti@intel.com)
-Regis Merlino (regis.merlino@intel.com)
\ No newline at end of file
+Regis Merlino (regis.merlino@intel.com)
+Christophe Guiraud (christophe.guiraud@intel.com)
+version 0.3.0
+ - Implemented the Update method which allows server side object
+ meta data to be added, updated and deleted.
+
+ https://github.com/01org/media-service-upnp/pull/98
+
+ - Unsubscribe to service notifications when a context is lost. This is
+ necessary to fix a bug reported by the UPnP test tool.
+
+ - Fixed a few problems with the API.txt file.
+
+
+version 0.2.1
+ - Added missing soup dependencies to the main Makefile.am.
+
+version 0.2.0
+ - Completed implementation of Upload. It is now possible to
+ upload files to remote DMSs, both to specific directories and to
+ the AnyContainer ( if it is supported by your DMS ) . Methods
+ have also been added to allow clients to cancel uploads and to
+ monitor their progress.
+ https://github.com/01org/media-service-upnp/issues/34
+ - DMS objects and containers can now be deleted.
+ https://github.com/01org/media-service-upnp/issues/35
+ - Containers can now be created on remote DMSs.
+ https://github.com/01org/media-service-upnp/issues/43
+ - New properties have been added to provide more information about
+ media objects exposed by DMSs.
+ - DLNAManaged indicates which actions can be performed on an object,
+ e.g., upload, delete, etc.
+ https://github.com/01org/media-service-upnp/issues/36
+ - Creator which indicates the creator of the content.
+ - CreateClass which identifies the type of objects that can be
+ created in a given container.
+ https://github.com/01org/media-service-upnp/issues/45
+ - The Artists property has been added to org.gnome.UPnP.MediaItem2.
+ Artists is an array of all the artists who worked on the object.
+ - The com.intel.UPnP.MediaDevice interface exposes some additional
+ properties that inform clients about the optional features supported
+ by DMSs. These include:
+ - DLNACaps indicating the DLNA OCM operations supported by the server.
+ - FeatureList containing the list of features, e.g., BOOKMARK, EPG,
+ supported by the server.
+ - SortCaps and SortExt Caps indicating the sorting capabilities of the
+ server.
+ - SearchCaps indicating the searching capabilities of the server.
+ - See https://github.com/01org/media-service-upnp/issues/24 for more
+ details
+ - Some new methods and properties have been added to
+ com.intel.UPnP.MediaDevice for ContentSync:
+ - The System ID property
+ https://github.com/01org/media-service-upnp/issues/38
+ - GetSystemResetToken
+ https://github.com/01org/media-service-upnp/issues/46
+ - The method com.intel.MediaServiceUPnP.PreferLocalAddresses has been
+ added. This is useful for writing DMCs. It allows DMCs to instruct
+ media-service-upnp to favour remote addresses.
+ https://github.com/01org/media-service-upnp/issues/21
+
+
version 0.1.0
- Implemented Upload
https://github.com/01org/media-service-upnp/issues/34
AM_CFLAGS = $(GLIB_CFLAGS) \
$(GIO_CFLAGS) \
+ $(GSSDP_CFLAGS) \
$(GUPNP_CFLAGS) \
$(GUPNPAV_CFLAGS) \
+ $(SOUP_CFLAGS) \
-DSYS_CONFIG_DIR="\"$(sysconfdir)\"" \
-include config.h
sysconf_DATA = media-service-upnp.conf
media_service_upnp_sources = src/async.c \
+ src/chain-task.c \
src/device.c \
src/error.c \
src/media-service-upnp.c \
src/task.c \
src/upnp.c
-media_service_upnp_headers = src/async.h \
- src/device.h \
- src/error.h \
- src/interface.h \
- src/log.h \
- src/path.h \
- src/props.h \
- src/search.h \
- src/settings.h \
- src/sort.h \
- src/task.h \
+media_service_upnp_headers = src/async.h \
+ src/chain-task.h \
+ src/client.h \
+ src/device.h \
+ src/error.h \
+ src/interface.h \
+ src/log.h \
+ src/path.h \
+ src/props.h \
+ src/search.h \
+ src/settings.h \
+ src/sort.h \
+ src/task.h \
src/upnp.h
media_service_upnp_LDADD = $(GLIB_LIBS) \
$(GIO_LIBS) \
+ $(GSSDP_LIBS) \
$(GUPNP_LIBS) \
- $(GUPNPAV_LIBS)
+ $(GUPNPAV_LIBS) \
+ $(SOUP_LIBS)
dms_info_sources = test/dms-info.c
-# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
VPATH = @srcdir@
+am__make_dryrun = \
+ { \
+ am__dry=no; \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
+ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+ *) \
+ for am__flg in $$MAKEFLAGS; do \
+ case $$am__flg in \
+ *=*|--*) ;; \
+ *n*) am__dry=yes; break;; \
+ esac; \
+ done;; \
+ esac; \
+ test $$am__dry = yes; \
+ }
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
dms_info_LINK = $(CCLD) $(dms_info_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
am__objects_2 =
-am__objects_3 = src/async.$(OBJEXT) src/device.$(OBJEXT) \
- src/error.$(OBJEXT) src/media-service-upnp.$(OBJEXT) \
- src/log.$(OBJEXT) src/path.$(OBJEXT) src/props.$(OBJEXT) \
- src/search.$(OBJEXT) src/settings.$(OBJEXT) src/sort.$(OBJEXT) \
- src/task.$(OBJEXT) src/upnp.$(OBJEXT)
+am__objects_3 = src/async.$(OBJEXT) src/chain-task.$(OBJEXT) \
+ src/device.$(OBJEXT) src/error.$(OBJEXT) \
+ src/media-service-upnp.$(OBJEXT) src/log.$(OBJEXT) \
+ src/path.$(OBJEXT) src/props.$(OBJEXT) src/search.$(OBJEXT) \
+ src/settings.$(OBJEXT) src/sort.$(OBJEXT) src/task.$(OBJEXT) \
+ src/upnp.$(OBJEXT)
am_media_service_upnp_OBJECTS = $(am__objects_2) $(am__objects_3)
media_service_upnp_OBJECTS = $(am_media_service_upnp_OBJECTS)
media_service_upnp_DEPENDENCIES = $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1)
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
am__v_GEN_0 = @echo " GEN " $@;
SOURCES = $(dms_info_SOURCES) $(media_service_upnp_SOURCES)
DIST_SOURCES = $(dms_info_SOURCES) $(media_service_upnp_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_LIBS = @GLIB_LIBS@
GREP = @GREP@
+GSSDP_CFLAGS = @GSSDP_CFLAGS@
+GSSDP_LIBS = @GSSDP_LIBS@
GUPNPAV_CFLAGS = @GUPNPAV_CFLAGS@
GUPNPAV_LIBS = @GUPNPAV_LIBS@
GUPNP_CFLAGS = @GUPNP_CFLAGS@
INCLUDES = -DG_LOG_DOMAIN=\"MSU\"
AM_CFLAGS = $(GLIB_CFLAGS) \
$(GIO_CFLAGS) \
+ $(GSSDP_CFLAGS) \
$(GUPNP_CFLAGS) \
$(GUPNPAV_CFLAGS) \
+ $(SOUP_CFLAGS) \
-DSYS_CONFIG_DIR="\"$(sysconfdir)\"" \
-include config.h
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
sysconf_DATA = media-service-upnp.conf
media_service_upnp_sources = src/async.c \
+ src/chain-task.c \
src/device.c \
src/error.c \
src/media-service-upnp.c \
src/task.c \
src/upnp.c
-media_service_upnp_headers = src/async.h \
- src/device.h \
- src/error.h \
- src/interface.h \
- src/log.h \
- src/path.h \
- src/props.h \
- src/search.h \
- src/settings.h \
- src/sort.h \
- src/task.h \
+media_service_upnp_headers = src/async.h \
+ src/chain-task.h \
+ src/client.h \
+ src/device.h \
+ src/error.h \
+ src/interface.h \
+ src/log.h \
+ src/path.h \
+ src/props.h \
+ src/search.h \
+ src/settings.h \
+ src/sort.h \
+ src/task.h \
src/upnp.h
media_service_upnp_SOURCES = $(media_service_upnp_headers) \
media_service_upnp_LDADD = $(GLIB_LIBS) \
$(GIO_LIBS) \
+ $(GSSDP_LIBS) \
$(GUPNP_LIBS) \
- $(GUPNPAV_LIBS)
+ $(GUPNPAV_LIBS) \
+ $(SOUP_LIBS)
dms_info_sources = test/dms-info.c
dms_info_SOURCES = $(dms_info_sources)
cd $(top_builddir) && $(SHELL) ./config.status $@
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
- test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p; \
@$(MKDIR_P) src/$(DEPDIR)
@: > src/$(DEPDIR)/$(am__dirstamp)
src/async.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/chain-task.$(OBJEXT): src/$(am__dirstamp) \
+ src/$(DEPDIR)/$(am__dirstamp)
src/device.$(OBJEXT): src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/error.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
-rm -f src/async.$(OBJEXT)
+ -rm -f src/chain-task.$(OBJEXT)
-rm -f src/device.$(OBJEXT)
-rm -f src/error.$(OBJEXT)
-rm -f src/log.$(OBJEXT)
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/async.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/chain-task.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/device.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/error.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/log.Po@am__quote@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(dms_info_CFLAGS) $(CFLAGS) -c -o test/dms_info-dms-info.obj `if test -f 'test/dms-info.c'; then $(CYGPATH_W) 'test/dms-info.c'; else $(CYGPATH_W) '$(srcdir)/test/dms-info.c'; fi`
install-dbussessionDATA: $(dbussession_DATA)
@$(NORMAL_INSTALL)
- test -z "$(dbussessiondir)" || $(MKDIR_P) "$(DESTDIR)$(dbussessiondir)"
@list='$(dbussession_DATA)'; test -n "$(dbussessiondir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(dbussessiondir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(dbussessiondir)" || exit 1; \
+ fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
dir='$(DESTDIR)$(dbussessiondir)'; $(am__uninstall_files_from_dir)
install-pkgconfigDATA: $(pkgconfig_DATA)
@$(NORMAL_INSTALL)
- test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)"
@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+ fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
install-sysconfDATA: $(sysconf_DATA)
@$(NORMAL_INSTALL)
- test -z "$(sysconfdir)" || $(MKDIR_P) "$(DESTDIR)$(sysconfdir)"
@list='$(sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sysconfdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" || exit 1; \
+ fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
*.zip*) \
unzip $(distdir).zip ;;\
esac
- chmod -R a-w $(distdir); chmod a+w $(distdir)
+ chmod -R a-w $(distdir); chmod u+w $(distdir)
mkdir $(distdir)/_build
mkdir $(distdir)/_inst
chmod a-w $(distdir)
-# generated automatically by aclocal 1.11.3 -*- Autoconf -*-
+# generated automatically by aclocal 1.11.6 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
-[m4_warning([this file was generated for autoconf 2.68.
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically `autoreconf'.])])
[am__api_version='1.11'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
-m4_if([$1], [1.11.3], [],
+m4_if([$1], [1.11.6], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.11.3])dnl
+[AM_AUTOMAKE_VERSION([1.11.6])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
-scriptversion=2012-01-04.17; # UTC
+scriptversion=2012-03-05.13; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009, 2010, 2012 Free
# Software Foundation, Inc.
esac
}
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+ func_file_conv "$1"
+ if test -z "$lib_path"; then
+ lib_path=$file
+ else
+ lib_path="$lib_path;$file"
+ fi
+ linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+ lib=$1
+ found=no
+ save_IFS=$IFS
+ IFS=';'
+ for dir in $lib_path $LIB
+ do
+ IFS=$save_IFS
+ if $shared && test -f "$dir/$lib.dll.lib"; then
+ found=yes
+ lib=$dir/$lib.dll.lib
+ break
+ fi
+ if test -f "$dir/$lib.lib"; then
+ found=yes
+ lib=$dir/$lib.lib
+ break
+ fi
+ done
+ IFS=$save_IFS
+
+ if test "$found" != yes; then
+ lib=$lib.lib
+ fi
+}
+
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
;;
esac
;;
+ -I)
+ eat=1
+ func_file_conv "$2" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
+ -l)
+ eat=1
+ func_cl_dashl "$2"
+ set x "$@" "$lib"
+ shift
+ ;;
-l*)
- lib=${1#-l}
- found=no
- save_IFS=$IFS
- IFS=';'
- for dir in $lib_path $LIB
- do
- IFS=$save_IFS
- if $shared && test -f "$dir/$lib.dll.lib"; then
- found=yes
- set x "$@" "$dir/$lib.dll.lib"
- break
- fi
- if test -f "$dir/$lib.lib"; then
- found=yes
- set x "$@" "$dir/$lib.lib"
- break
- fi
- done
- IFS=$save_IFS
-
- test "$found" != yes && set x "$@" "$lib.lib"
+ func_cl_dashl "${1#-l}"
+ set x "$@" "$lib"
shift
;;
+ -L)
+ eat=1
+ func_cl_dashL "$2"
+ ;;
-L*)
- func_file_conv "${1#-L}"
- if test -z "$lib_path"; then
- lib_path=$file
- else
- lib_path="$lib_path;$file"
- fi
- linker_opts="$linker_opts -LIBPATH:$file"
+ func_cl_dashL "${1#-L}"
;;
-static)
shared=false
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
-scriptversion=2011-12-04.11; # UTC
+scriptversion=2012-03-27.16; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
-# 2011 Free Software Foundation, Inc.
+# 2011, 2012 Free Software Foundation, Inc.
# 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
case $1 in
'')
- echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
Environment variables:
depmode Dependency tracking mode.
- source Source file read by `PROGRAMS ARGS'.
- object Object file output by `PROGRAMS ARGS'.
+ source Source file read by 'PROGRAMS ARGS'.
+ object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
;;
esac
+# A tabulation character.
+tab=' '
+# A newline character.
+nl='
+'
+
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
depmode=msvc7
fi
+if test "$depmode" = xlc; then
+ # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations.
+ gccflag=-qmakedep=gcc,-MF
+ depmode=gcc
+fi
+
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
-## This next piece of magic avoids the `deleted header file' problem.
+## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
- tr ' ' '
-' < "$tmpdepfile" |
-## Some versions of gcc put a space before the `:'. On the theory
+ tr ' ' "$nl" < "$tmpdepfile" |
+## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
- # the IRIX cc adds comments like `#:fec' to the end of the
+ # the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
- tr ' ' '
-' < "$tmpdepfile" \
+ tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
- tr '
-' ' ' >> "$depfile"
+ tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
- tr ' ' '
-' < "$tmpdepfile" \
+ tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
rm -f "$tmpdepfile"
;;
+xlc)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
- # current directory. Also, the AIX compiler puts `$object:' at the
+ # current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
- # Each line is of the form `foo.o: dependent.h'.
+ # Each line is of the form 'foo.o: dependent.h'.
# Do two passes, one to just change these to
- # `$object: dependent.h' and one to simply `dependent.h:'.
+ # '$object: dependent.h' and one to simply 'dependent.h:'.
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
- # That's a tab and a space in the [].
- sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
;;
icc)
- # Intel's C compiler understands `-MD -MF file'. However on
- # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'.
+ # However on
+ # $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# ICC 7.0 will fill foo.d with something like
# foo.o: sub/foo.c
# foo.o: sub/foo.h
- # which is wrong. We want:
+ # which is wrong. We want
# sub/foo.o: sub/foo.c
# sub/foo.o: sub/foo.h
# sub/foo.c:
# sub/foo.h:
# ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h
- # and will wrap long lines using \ :
+ # and will wrap long lines using '\':
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
-
+ # tcc 0.9.26 (FIXME still under development at the moment of writing)
+ # will emit a similar output, but also prepend the continuation lines
+ # with horizontal tabulation characters.
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
exit $stat
fi
rm -f "$depfile"
- # Each line is of the form `foo.o: dependent.h',
- # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Each line is of the form 'foo.o: dependent.h',
+ # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'.
# Do two passes, one to just change these to
- # `$object: dependent.h' and one to simply `dependent.h:'.
- sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
- # Some versions of the HPUX 10.20 sed can't process this invocation
- # correctly. Breaking it into two sed invocations is a workaround.
- sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
- sed -e 's/$/ :/' >> "$depfile"
+ # '$object: dependent.h' and one to simply 'dependent.h:'.
+ sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \
+ < "$tmpdepfile" > "$depfile"
+ sed '
+ s/[ '"$tab"'][ '"$tab"']*/ /g
+ s/^ *//
+ s/ *\\*$//
+ s/^[^:]*: *//
+ /^$/d
+ /:$/d
+ s/$/ :/
+ ' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
- # Add `dependent.h:' lines.
+ # Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
- # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
- # dependencies in `foo.d' instead, so we check for that too.
+ # dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
- # That's a tab and a space in the [].
- sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
-s/\(.*\)/ \1 \\/p
+s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
- s/.*/ /
+ s/.*/'"$tab"'/
G
p
}' >> "$depfile"
shift
fi
- # Remove `-o $object'.
+ # Remove '-o $object'.
IFS=" "
for arg
do
done
test -z "$dashmflag" && dashmflag=-M
- # Require at least two characters before searching for `:'
+ # Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
- # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
- sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
- tr ' ' '
-' < "$tmpdepfile" | \
+ tr ' ' "$nl" < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
- sed '1,2d' "$tmpdepfile" | tr ' ' '
-' | \
+ sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
shift
fi
- # Remove `-o $object'.
+ # Remove '-o $object'.
IFS=" "
for arg
do
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
- sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
- echo " " >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+ echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for media-service-upnp 0.1.0.
+# Generated by GNU Autoconf 2.69 for media-service-upnp 0.3.0.
#
# Report bugs to <https://github.com/01org/media-service-upnp/issues/new>.
#
#
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
-# Foundation, Inc.
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
# CDPATH.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
else
exitcode=1; echo positional parameters were not saved.
fi
-test x\$exitcode = x0 || exit 1"
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
if test "x$CONFIG_SHELL" != x; then :
- # We cannot yet assume a decent shell, so we have to provide a
- # neutralization value for shells without unset; and this also
- # works around shells that cannot unset nonexistent variables.
- # Preserve -v and -x to the replacement shell.
- BASH_ENV=/dev/null
- ENV=/dev/null
- (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
- export CONFIG_SHELL
- case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
- esac
- exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
fi
if test x$as_have_required = xno; then :
} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
chmod +x "$as_me.lineno" ||
{ $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
# Don't try to exec as it changes $[0], causing all sort of problems
# (the dirname of $[0] is not the place where we might find the
# original and so on. Autoconf is especially sensitive to this).
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -p'.
+ # In both cases, we have to default to `cp -pR'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -p'
+ as_ln_s='cp -pR'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
- as_ln_s='cp -p'
+ as_ln_s='cp -pR'
fi
else
- as_ln_s='cp -p'
+ as_ln_s='cp -pR'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
as_mkdir_p=false
fi
-if test -x / >/dev/null 2>&1; then
- as_test_x='test -x'
-else
- if ls -dL / >/dev/null 2>&1; then
- as_ls_L_option=L
- else
- as_ls_L_option=
- fi
- as_test_x='
- eval sh -c '\''
- if test -d "$1"; then
- test -d "$1/.";
- else
- case $1 in #(
- -*)set "./$1";;
- esac;
- case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
- ???[sx]*):;;*)false;;esac;fi
- '\'' sh
- '
-fi
-as_executable_p=$as_test_x
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
# Identity of this package.
PACKAGE_NAME='media-service-upnp'
PACKAGE_TARNAME='media-service-upnp'
-PACKAGE_VERSION='0.1.0'
-PACKAGE_STRING='media-service-upnp 0.1.0'
+PACKAGE_VERSION='0.3.0'
+PACKAGE_STRING='media-service-upnp 0.3.0'
PACKAGE_BUGREPORT='https://github.com/01org/media-service-upnp/issues/new'
PACKAGE_URL='https://01.org/dleyna/'
GUPNPAV_CFLAGS
GUPNP_LIBS
GUPNP_CFLAGS
+GSSDP_LIBS
+GSSDP_CFLAGS
GIO_LIBS
GIO_CFLAGS
GLIB_LIBS
GLIB_LIBS
GIO_CFLAGS
GIO_LIBS
+GSSDP_CFLAGS
+GSSDP_LIBS
GUPNP_CFLAGS
GUPNP_LIBS
GUPNPAV_CFLAGS
if test "x$host_alias" != x; then
if test "x$build_alias" = x; then
cross_compiling=maybe
- $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
- If a cross compiler is detected then cross compile mode will be used" >&2
elif test "x$build_alias" != "x$host_alias"; then
cross_compiling=yes
fi
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures media-service-upnp 0.1.0 to adapt to many kinds of systems.
+\`configure' configures media-service-upnp 0.3.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of media-service-upnp 0.1.0:";;
+ short | recursive ) echo "Configuration of media-service-upnp 0.3.0:";;
esac
cat <<\_ACEOF
GLIB_LIBS linker flags for GLIB, overriding pkg-config
GIO_CFLAGS C compiler flags for GIO, overriding pkg-config
GIO_LIBS linker flags for GIO, overriding pkg-config
+ GSSDP_CFLAGS
+ C compiler flags for GSSDP, overriding pkg-config
+ GSSDP_LIBS linker flags for GSSDP, overriding pkg-config
GUPNP_CFLAGS
C compiler flags for GUPNP, overriding pkg-config
GUPNP_LIBS linker flags for GUPNP, overriding pkg-config
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-media-service-upnp configure 0.1.0
-generated by GNU Autoconf 2.68
+media-service-upnp configure 0.3.0
+generated by GNU Autoconf 2.69
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
main ()
{
static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)];
-test_array [0] = 0
+test_array [0] = 0;
+return test_array [0];
;
return 0;
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
- $as_test_x conftest$ac_exeext
+ test -x conftest$ac_exeext
}; then :
ac_retval=0
else
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by media-service-upnp $as_me 0.1.0, which was
-generated by GNU Autoconf 2.68. Invocation command line was
+It was created by media-service-upnp $as_me 0.3.0, which was
+generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
# by default.
for ac_prog in ginstall scoinst install; do
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
if test $ac_prog = install &&
grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
# AIX install. It has an incompatible calling convention.
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_STRIP="${ac_tool_prefix}strip"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_STRIP="strip"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
test -z "$as_dir" && as_dir=.
for ac_prog in mkdir gmkdir; do
for ac_exec_ext in '' $ac_executable_extensions; do
- { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+ as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
'mkdir (GNU coreutils) '* | \
'mkdir (coreutils) '* | \
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_AWK="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
# Define the identity of the package.
PACKAGE='media-service-upnp'
- VERSION='0.1.0'
+ VERSION='0.3.0'
cat >>confdefs.h <<_ACEOF
CFLAGS+=" -Wno-overlength-strings"
CFLAGS+=" -DG_DISABLE_DEPRECATED"
+ CFLAGS+=" -DGLIB_DISABLE_DEPRECATION_WARNINGS"
fi
CFLAGS+=" -Wno-format-extra-args"
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}cc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
ac_prog_rejected=yes
continue
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
/* end confdefs.h. */
#include <stdarg.h>
#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+struct stat;
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
struct buf { int x; };
FILE * (*rcsopen) (struct buf *, struct stat *, int);
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GSSDP" >&5
+$as_echo_n "checking for GSSDP... " >&6; }
+
+if test -n "$GSSDP_CFLAGS"; then
+ pkg_cv_GSSDP_CFLAGS="$GSSDP_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gssdp-1.0 >= 0.13.0\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "gssdp-1.0 >= 0.13.0") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_GSSDP_CFLAGS=`$PKG_CONFIG --cflags "gssdp-1.0 >= 0.13.0" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$GSSDP_LIBS"; then
+ pkg_cv_GSSDP_LIBS="$GSSDP_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gssdp-1.0 >= 0.13.0\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "gssdp-1.0 >= 0.13.0") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_GSSDP_LIBS=`$PKG_CONFIG --libs "gssdp-1.0 >= 0.13.0" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ GSSDP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gssdp-1.0 >= 0.13.0" 2>&1`
+ else
+ GSSDP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gssdp-1.0 >= 0.13.0" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$GSSDP_PKG_ERRORS" >&5
+
+ as_fn_error $? "Package requirements (gssdp-1.0 >= 0.13.0) were not met:
+
+$GSSDP_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables GSSDP_CFLAGS
+and GSSDP_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables GSSDP_CFLAGS
+and GSSDP_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ GSSDP_CFLAGS=$pkg_cv_GSSDP_CFLAGS
+ GSSDP_LIBS=$pkg_cv_GSSDP_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+
+pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GUPNP" >&5
$as_echo_n "checking for GUPNP... " >&6; }
pkg_cv_GUPNP_CFLAGS="$GUPNP_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gupnp-1.0 >= 0.17.2\""; } >&5
- ($PKG_CONFIG --exists --print-errors "gupnp-1.0 >= 0.17.2") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gupnp-1.0 >= 0.19.1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "gupnp-1.0 >= 0.19.1") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_GUPNP_CFLAGS=`$PKG_CONFIG --cflags "gupnp-1.0 >= 0.17.2" 2>/dev/null`
+ pkg_cv_GUPNP_CFLAGS=`$PKG_CONFIG --cflags "gupnp-1.0 >= 0.19.1" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
pkg_cv_GUPNP_LIBS="$GUPNP_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gupnp-1.0 >= 0.17.2\""; } >&5
- ($PKG_CONFIG --exists --print-errors "gupnp-1.0 >= 0.17.2") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gupnp-1.0 >= 0.19.1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "gupnp-1.0 >= 0.19.1") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_GUPNP_LIBS=`$PKG_CONFIG --libs "gupnp-1.0 >= 0.17.2" 2>/dev/null`
+ pkg_cv_GUPNP_LIBS=`$PKG_CONFIG --libs "gupnp-1.0 >= 0.19.1" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- GUPNP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gupnp-1.0 >= 0.17.2" 2>&1`
+ GUPNP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gupnp-1.0 >= 0.19.1" 2>&1`
else
- GUPNP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gupnp-1.0 >= 0.17.2" 2>&1`
+ GUPNP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gupnp-1.0 >= 0.19.1" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$GUPNP_PKG_ERRORS" >&5
- as_fn_error $? "Package requirements (gupnp-1.0 >= 0.17.2) were not met:
+ as_fn_error $? "Package requirements (gupnp-1.0 >= 0.19.1) were not met:
$GUPNP_PKG_ERRORS
pkg_cv_GUPNPAV_CFLAGS="$GUPNPAV_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gupnp-av-1.0\""; } >&5
- ($PKG_CONFIG --exists --print-errors "gupnp-av-1.0") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gupnp-av-1.0 >= 0.11.1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "gupnp-av-1.0 >= 0.11.1") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_GUPNPAV_CFLAGS=`$PKG_CONFIG --cflags "gupnp-av-1.0" 2>/dev/null`
+ pkg_cv_GUPNPAV_CFLAGS=`$PKG_CONFIG --cflags "gupnp-av-1.0 >= 0.11.1" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
pkg_cv_GUPNPAV_LIBS="$GUPNPAV_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gupnp-av-1.0\""; } >&5
- ($PKG_CONFIG --exists --print-errors "gupnp-av-1.0") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gupnp-av-1.0 >= 0.11.1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "gupnp-av-1.0 >= 0.11.1") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_GUPNPAV_LIBS=`$PKG_CONFIG --libs "gupnp-av-1.0" 2>/dev/null`
+ pkg_cv_GUPNPAV_LIBS=`$PKG_CONFIG --libs "gupnp-av-1.0 >= 0.11.1" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- GUPNPAV_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gupnp-av-1.0" 2>&1`
+ GUPNPAV_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gupnp-av-1.0 >= 0.11.1" 2>&1`
else
- GUPNPAV_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gupnp-av-1.0" 2>&1`
+ GUPNPAV_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gupnp-av-1.0 >= 0.11.1" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$GUPNPAV_PKG_ERRORS" >&5
- as_fn_error $? "Package requirements (gupnp-av-1.0) were not met:
+ as_fn_error $? "Package requirements (gupnp-av-1.0 >= 0.11.1) were not met:
$GUPNPAV_PKG_ERRORS
pkg_cv_SOUP_CFLAGS="$SOUP_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsoup-2.4\""; } >&5
- ($PKG_CONFIG --exists --print-errors "libsoup-2.4") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsoup-2.4 >= 2.28.2\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libsoup-2.4 >= 2.28.2") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_SOUP_CFLAGS=`$PKG_CONFIG --cflags "libsoup-2.4" 2>/dev/null`
+ pkg_cv_SOUP_CFLAGS=`$PKG_CONFIG --cflags "libsoup-2.4 >= 2.28.2" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
pkg_cv_SOUP_LIBS="$SOUP_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsoup-2.4\""; } >&5
- ($PKG_CONFIG --exists --print-errors "libsoup-2.4") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsoup-2.4 >= 2.28.2\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libsoup-2.4 >= 2.28.2") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_SOUP_LIBS=`$PKG_CONFIG --libs "libsoup-2.4" 2>/dev/null`
+ pkg_cv_SOUP_LIBS=`$PKG_CONFIG --libs "libsoup-2.4 >= 2.28.2" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- SOUP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsoup-2.4" 2>&1`
+ SOUP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsoup-2.4 >= 2.28.2" 2>&1`
else
- SOUP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsoup-2.4" 2>&1`
+ SOUP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsoup-2.4 >= 2.28.2" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$SOUP_PKG_ERRORS" >&5
- as_fn_error $? "Package requirements (libsoup-2.4) were not met:
+ as_fn_error $? "Package requirements (libsoup-2.4 >= 2.28.2) were not met:
$SOUP_PKG_ERRORS
for ac_prog in grep ggrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
- { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+ as_fn_executable_p "$ac_path_GREP" || continue
# Check for GNU ac_path_GREP and select it if it is found.
# Check for GNU $ac_path_GREP
case `"$ac_path_GREP" --version 2>&1` in
for ac_prog in egrep; do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
- { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+ as_fn_executable_p "$ac_path_EGREP" || continue
# Check for GNU ac_path_EGREP and select it if it is found.
# Check for GNU $ac_path_EGREP
case `"$ac_path_EGREP" --version 2>&1` in
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#include <stdbool.h>
-#ifndef bool
- "error: bool is not defined"
-#endif
-#ifndef false
- "error: false is not defined"
-#endif
-#if false
- "error: false is not 0"
-#endif
-#ifndef true
- "error: true is not defined"
-#endif
-#if true != 1
- "error: true is not 1"
-#endif
-#ifndef __bool_true_false_are_defined
- "error: __bool_true_false_are_defined is not defined"
-#endif
-
- struct s { _Bool s: 1; _Bool t; } s;
-
- char a[true == 1 ? 1 : -1];
- char b[false == 0 ? 1 : -1];
- char c[__bool_true_false_are_defined == 1 ? 1 : -1];
- char d[(bool) 0.5 == true ? 1 : -1];
- /* See body of main program for 'e'. */
- char f[(_Bool) 0.0 == false ? 1 : -1];
- char g[true];
- char h[sizeof (_Bool)];
- char i[sizeof s.t];
- enum { j = false, k = true, l = false * true, m = true * 256 };
- /* The following fails for
- HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */
- _Bool n[m];
- char o[sizeof n == m * sizeof n[0] ? 1 : -1];
- char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1];
- /* Catch a bug in an HP-UX C compiler. See
- http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html
- http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html
- */
- _Bool q = true;
- _Bool *pq = &q;
+ #include <stdbool.h>
+ #ifndef bool
+ "error: bool is not defined"
+ #endif
+ #ifndef false
+ "error: false is not defined"
+ #endif
+ #if false
+ "error: false is not 0"
+ #endif
+ #ifndef true
+ "error: true is not defined"
+ #endif
+ #if true != 1
+ "error: true is not 1"
+ #endif
+ #ifndef __bool_true_false_are_defined
+ "error: __bool_true_false_are_defined is not defined"
+ #endif
+
+ struct s { _Bool s: 1; _Bool t; } s;
+
+ char a[true == 1 ? 1 : -1];
+ char b[false == 0 ? 1 : -1];
+ char c[__bool_true_false_are_defined == 1 ? 1 : -1];
+ char d[(bool) 0.5 == true ? 1 : -1];
+ /* See body of main program for 'e'. */
+ char f[(_Bool) 0.0 == false ? 1 : -1];
+ char g[true];
+ char h[sizeof (_Bool)];
+ char i[sizeof s.t];
+ enum { j = false, k = true, l = false * true, m = true * 256 };
+ /* The following fails for
+ HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */
+ _Bool n[m];
+ char o[sizeof n == m * sizeof n[0] ? 1 : -1];
+ char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1];
+ /* Catch a bug in an HP-UX C compiler. See
+ http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html
+ http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html
+ */
+ _Bool q = true;
+ _Bool *pq = &q;
int
main ()
{
- bool e = &s;
- *pq |= q;
- *pq |= ! q;
- /* Refer to every declared value, to avoid compiler optimizations. */
- return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l
- + !m + !n + !o + !p + !q + !pq);
+ bool e = &s;
+ *pq |= q;
+ *pq |= ! q;
+ /* Refer to every declared value, to avoid compiler optimizations. */
+ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l
+ + !m + !n + !o + !p + !q + !pq);
;
return 0;
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5
$as_echo "$ac_cv_header_stdbool_h" >&6; }
-ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default"
+ ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default"
if test "x$ac_cv_type__Bool" = xyes; then :
cat >>confdefs.h <<_ACEOF
fi
+
if test $ac_cv_header_stdbool_h = yes; then
$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h
# ... but there are two gotchas:
# 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
# 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -p'.
+ # In both cases, we have to default to `cp -pR'.
ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -p'
+ as_ln_s='cp -pR'
elif ln conf$$.file conf$$ 2>/dev/null; then
as_ln_s=ln
else
- as_ln_s='cp -p'
+ as_ln_s='cp -pR'
fi
else
- as_ln_s='cp -p'
+ as_ln_s='cp -pR'
fi
rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
rmdir conf$$.dir 2>/dev/null
as_mkdir_p=false
fi
-if test -x / >/dev/null 2>&1; then
- as_test_x='test -x'
-else
- if ls -dL / >/dev/null 2>&1; then
- as_ls_L_option=L
- else
- as_ls_L_option=
- fi
- as_test_x='
- eval sh -c '\''
- if test -d "$1"; then
- test -d "$1/.";
- else
- case $1 in #(
- -*)set "./$1";;
- esac;
- case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
- ???[sx]*):;;*)false;;esac;fi
- '\'' sh
- '
-fi
-as_executable_p=$as_test_x
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
# Sed expression to map a string onto a valid CPP name.
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by media-service-upnp $as_me 0.1.0, which was
-generated by GNU Autoconf 2.68. Invocation command line was
+This file was extended by media-service-upnp $as_me 0.3.0, which was
+generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-media-service-upnp config.status 0.1.0
-configured by $0, generated by GNU Autoconf 2.68,
+media-service-upnp config.status 0.3.0
+configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then
- set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
shift
\$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
CONFIG_SHELL='$SHELL'
AC_PREREQ([2.66])
AC_INIT([media-service-upnp],
- [0.1.0],
+ [0.3.0],
[https://github.com/01org/media-service-upnp/issues/new],
,
[https://01.org/dleyna/])
PKG_CHECK_MODULES([DBUS], [dbus-1])
PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.26.1])
PKG_CHECK_MODULES([GIO], [gio-2.0 >= 2.26.1])
-PKG_CHECK_MODULES([GUPNP], [gupnp-1.0 >= 0.17.2])
-PKG_CHECK_MODULES([GUPNPAV], [gupnp-av-1.0])
-PKG_CHECK_MODULES([SOUP], [libsoup-2.4])
+PKG_CHECK_MODULES([GSSDP], [gssdp-1.0 >= 0.13.0])
+PKG_CHECK_MODULES([GUPNP], [gupnp-1.0 >= 0.19.1])
+PKG_CHECK_MODULES([GUPNPAV], [gupnp-av-1.0 >= 0.11.1])
+PKG_CHECK_MODULES([SOUP], [libsoup-2.4 >= 2.28.2])
# Checks for header files.
AC_CHECK_HEADERS([stdlib.h string.h syslog.h])
CFLAGS+=" -Wno-overlength-strings"
CFLAGS+=" -DG_DISABLE_DEPRECATED"
+ CFLAGS+=" -DGLIB_DISABLE_DEPRECATION_WARNINGS"
fi
CFLAGS+=" -Wno-format-extra-args"
+* Wed Nov 14 11:19:45 CET 2012 - Mark Ryan <mark.d.ryan@intel.com>
+- Submit version 0.3.0 ( ca17a69 ) of media-service-upnp
+
* Mon Sep 24 14:46:57 CEST 2012 - Mark Ryan <mark.d.ryan@intel.com>
-- Submit version 0.10.0 ( d56381a) of media-service-upnp
+- Submit version 0.1.0 ( d56381a ) of media-service-upnp
Name: media-service-upnp
Summary: A high level API for discovering, browsing and searching digital media servers.
-Version: 0.1.0
+Version: 0.3.0
Release: 0
Group: System/Libraries
License: LGPLv2+
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(gio-2.0)
BuildRequires: pkgconfig(gupnp-1.0)
+BuildRequires: pkgconfig(gssdp-1.0)
BuildRequires: pkgconfig(gupnp-av-1.0)
+BuildRequires: pkgconfig(libsoup-2.4)
%description
#include "log.h"
msu_async_cb_data_t *msu_async_cb_data_new(msu_task_t *task,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
msu_async_cb_data_t *cb_data = g_new0(msu_async_cb_data_t, 1);
cb_data->type = task->type;
cb_data->task = task;
cb_data->cb = cb;
- cb_data->user_data = user_data;
return cb_data;
}
g_free(cb_data->ut.upload.root_path);
g_free(cb_data->ut.upload.mime_type);
break;
+ case MSU_TASK_CREATE_CONTAINER:
+ g_free(cb_data->ut.create_container.root_path);
+ break;
+ case MSU_TASK_UPDATE_OBJECT:
+ g_free(cb_data->ut.update.current_tag_value);
+ g_free(cb_data->ut.update.new_tag_value);
+ break;
default:
break;
}
MSU_LOG_DEBUG("Enter. Error %p", (void *) cb_data->error);
MSU_LOG_DEBUG_NL();
- cb_data->cb(cb_data->task, cb_data->result, cb_data->error,
- cb_data->user_data);
+ cb_data->cb(cb_data->task, cb_data->result, cb_data->error);
msu_async_cb_data_delete(cb_data);
return FALSE;
guint32 filter_mask;
const gchar *protocol_info;
gboolean need_child_count;
+ gboolean device_object;
+ msu_device_t *device;
};
typedef struct msu_async_upload_t_ msu_async_upload_t;
msu_device_t *device;
};
+typedef struct msu_async_create_container_t_ msu_async_create_container_t;
+struct msu_async_create_container_t_ {
+ gchar *root_path;
+};
+
+typedef struct msu_async_update_t_ msu_async_update_t;
+struct msu_async_update_t_ {
+ gchar *current_tag_value;
+ gchar *new_tag_value;
+ GHashTable *map;
+};
+
struct msu_async_cb_data_t_ {
msu_task_type_t type;
msu_task_t *task;
msu_upnp_task_complete_t cb;
- void *user_data;
GVariant *result;
GError *error;
GUPnPServiceProxyAction *action;
msu_async_get_prop_t get_prop;
msu_async_get_all_t get_all;
msu_async_upload_t upload;
+ msu_async_create_container_t create_container;
+ msu_async_update_t update;
} ut;
};
msu_async_cb_data_t *msu_async_cb_data_new(msu_task_t *task,
- msu_upnp_task_complete_t cb,
- void *user_data);
+ msu_upnp_task_complete_t cb);
void msu_async_cb_data_delete(msu_async_cb_data_t *cb_data);
gboolean msu_async_complete_task(gpointer user_data);
void msu_async_task_cancelled(GCancellable *cancellable, gpointer user_data);
--- /dev/null
+/*
+ * media-service-upnp
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Ludovic Ferrandis <ludovic.ferrandis@intel.com>
+ *
+ */
+
+#include <glib.h>
+
+#include "chain-task.h"
+#include "device.h"
+#include "log.h"
+
+typedef struct msu_chain_task_atom_t_ msu_chain_task_atom_t;
+struct msu_chain_task_atom_t_ {
+ GUPnPServiceProxyActionCallback callback;
+ GUPnPServiceProxyAction *p_action;
+ GDestroyNotify free_func;
+ gpointer user_data;
+ msu_chain_task_action t_action;
+ msu_device_t *device;
+};
+
+struct msu_chain_task_t_ {
+ msu_chain_task_end end_func;
+ gpointer end_data;
+ GList *task_list;
+ msu_chain_task_atom_t *current;
+ gboolean canceled;
+ guint idle_id;
+};
+
+static void prv_free_atom(msu_chain_task_atom_t *atom)
+{
+ if (atom->free_func != NULL)
+ atom->free_func(atom->user_data);
+
+ g_free(atom);
+}
+
+static gboolean prv_idle_end_func(gpointer user_data)
+{
+ msu_chain_task_t *chain = (msu_chain_task_t *)user_data;
+
+ chain->end_func(chain, chain->end_data);
+ return FALSE;
+}
+
+static gboolean prv_idle_next_task(gpointer user_data)
+{
+ msu_chain_task_t *chain = (msu_chain_task_t *) user_data;
+ GList *head = chain->task_list;
+
+ chain->task_list = g_list_remove_link(chain->task_list, head);
+ g_list_free_1(head);
+
+ chain->idle_id = 0;
+ msu_chain_task_start(chain);
+
+ return FALSE;
+}
+
+static void prv_next_task(msu_chain_task_t *chain)
+{
+ chain->idle_id = g_idle_add(prv_idle_next_task, chain);
+}
+
+gboolean msu_chain_task_is_canceled(msu_chain_task_t *chain)
+{
+ return chain->canceled;
+}
+
+msu_device_t *msu_chain_task_get_device(msu_chain_task_t *chain)
+{
+ if ((chain != NULL) && (chain->current != NULL))
+ return chain->current->device;
+
+ return NULL;
+}
+
+gpointer *msu_chain_task_get_user_data(msu_chain_task_t *chain)
+{
+ if ((chain != NULL) && (chain->current != NULL))
+ return chain->current->user_data;
+
+ return NULL;
+}
+
+void msu_chain_task_cancel(msu_chain_task_t *chain)
+{
+ msu_device_t *device;
+ msu_device_context_t *context;
+
+ if (chain->idle_id) {
+ g_source_remove(chain->idle_id);
+ chain->idle_id = 0;
+ }
+
+ device = msu_chain_task_get_device(chain);
+ context = msu_device_get_context(device, NULL);
+
+ if (chain->current->p_action) {
+ gupnp_service_proxy_cancel_action(context->service_proxy,
+ chain->current->p_action);
+ chain->current->p_action = 0;
+ }
+
+ chain->canceled = TRUE;
+}
+
+void msu_chain_task_begin_action_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ msu_chain_task_t *chain = (msu_chain_task_t *) user_data;
+ msu_chain_task_atom_t *current;
+
+ if (chain != NULL) {
+ current = chain->current;
+
+ if (chain->current != NULL) {
+ current->callback(proxy, action, current->user_data);
+ chain->current->p_action = NULL;
+ }
+
+ prv_next_task(chain);
+ }
+}
+
+void msu_chain_task_start(msu_chain_task_t *chain)
+{
+ gboolean failed;
+
+ if ((chain->task_list != NULL) && (!chain->canceled)) {
+ chain->current = chain->task_list->data;
+ chain->current->p_action = chain->current->t_action(chain,
+ &failed);
+
+ if (failed)
+ chain->canceled = TRUE;
+
+ if (chain->current->p_action == NULL &&
+ chain->current->callback == NULL)
+ prv_next_task(chain);
+
+ } else {
+ if (chain->end_func)
+ chain->idle_id = g_idle_add(prv_idle_end_func, chain);
+ }
+}
+
+void msu_chain_task_add(msu_chain_task_t *chain,
+ msu_chain_task_action action,
+ msu_device_t *device,
+ GUPnPServiceProxyActionCallback action_cb,
+ GDestroyNotify free_func,
+ gpointer cb_user_data)
+{
+ msu_chain_task_atom_t *atom;
+
+ atom = g_new0(msu_chain_task_atom_t, 1);
+
+ atom->t_action = action;
+ atom->callback = action_cb;
+ atom->free_func = free_func;
+ atom->user_data = cb_user_data;
+ atom->device = device;
+
+ chain->task_list = g_list_append(chain->task_list, atom);
+}
+
+void msu_chain_task_delete(msu_chain_task_t *chain)
+{
+ g_list_free_full(chain->task_list, (GDestroyNotify)prv_free_atom);
+ chain->task_list = NULL;
+ g_free(chain);
+}
+
+msu_chain_task_t *msu_chain_task_new(msu_chain_task_end end_func,
+ gpointer end_data)
+{
+ msu_chain_task_t *chain;
+
+ chain = g_new0(msu_chain_task_t, 1);
+ chain->end_func = end_func;
+ chain->end_data = end_data;
+
+ return chain;
+}
--- /dev/null
+/*
+ * media-service-upnp
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Ludovic Ferrandis <ludovic.ferrandis@intel.com>
+ *
+ */
+
+#ifndef MSU_CHAIN_TASK_H__
+#define MSU_CHAIN_TASK_H__
+
+#include <libgupnp/gupnp-service-proxy.h>
+#include "async.h"
+
+typedef struct msu_chain_task_t_ msu_chain_task_t;
+
+typedef GUPnPServiceProxyAction * (*msu_chain_task_action)
+ (msu_chain_task_t *chain, gboolean *failed);
+
+typedef void (*msu_chain_task_end)(msu_chain_task_t *chain, gpointer data);
+
+msu_chain_task_t *msu_chain_task_new(msu_chain_task_end end_func,
+ gpointer end_data);
+
+void msu_chain_task_delete(msu_chain_task_t *chain);
+
+void msu_chain_task_add(msu_chain_task_t *chain,
+ msu_chain_task_action action,
+ msu_device_t *device,
+ GUPnPServiceProxyActionCallback action_cb,
+ GDestroyNotify free_func,
+ gpointer cb_user_data);
+
+void msu_chain_task_start(msu_chain_task_t *chain);
+
+void msu_chain_task_begin_action_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data);
+
+void msu_chain_task_cancel(msu_chain_task_t *chain);
+gboolean msu_chain_task_is_canceled(msu_chain_task_t *chain);
+
+msu_device_t *msu_chain_task_get_device(msu_chain_task_t *chain);
+gpointer *msu_chain_task_get_user_data(msu_chain_task_t *chain);
+
+#endif /* MSU_CHAIN_TASK_H__ */
--- /dev/null
+/*
+ * media-service-upnp
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Regis Merlino <regis.merlino@intel.com>
+ *
+ */
+
+#ifndef MSU_CLIENT_H__
+#define MSU_CLIENT_H__
+
+#include <glib.h>
+
+typedef struct msu_client_t_ msu_client_t;
+struct msu_client_t_ {
+ guint id;
+ gchar *protocol_info;
+ gboolean prefer_local_addresses;
+};
+
+
+#endif /* MSU_CLIENT_H__ */
#include <libgupnp/gupnp-error.h>
#include <libsoup/soup.h>
+#include "chain-task.h"
#include "device.h"
#include "error.h"
#include "interface.h"
#define MSU_SYSTEM_UPDATE_VAR "SystemUpdateID"
#define MSU_CONTAINER_UPDATE_VAR "ContainerUpdateIDs"
+#define MEDIA_SERVER_DEVICE_TYPE "urn:schemas-upnp-org:device:MediaServer:"
+
+#define MSU_UPLOAD_STATUS_IN_PROGRESS "IN_PROGRESS"
+#define MSU_UPLOAD_STATUS_CANCELLED "CANCELLED"
+#define MSU_UPLOAD_STATUS_ERROR "ERROR"
+#define MSU_UPLOAD_STATUS_COMPLETED "COMPLETED"
typedef gboolean (*msu_device_count_cb_t)(msu_async_cb_data_t *cb_data,
gint count);
gboolean needs_child_count;
};
+typedef struct msu_device_upload_job_t_ msu_device_upload_job_t;
+
typedef struct msu_device_upload_t_ msu_device_upload_t;
struct msu_device_upload_t_ {
SoupSession *soup_session;
SoupMessage *msg;
GMappedFile *mapped_file;
+ const gchar *status;
+ guint64 bytes_uploaded;
+ guint64 bytes_to_upload;
};
-typedef struct msu_device_upload_job_t_ msu_device_upload_job_t;
struct msu_device_upload_job_t_ {
gint upload_id;
msu_device_t *device;
+ guint remove_idle;
+};
+
+/* Private structure used in chain task */
+typedef struct prv_new_device_ct_t_ prv_new_device_ct_t;
+struct prv_new_device_ct_t_ {
+ msu_device_t *dev;
+ GDBusConnection *connection;
+ const GDBusSubtreeVTable *vtable;
+ void *user_data;
+ GHashTable *property_map;
};
static void prv_get_child_count(msu_async_cb_data_t *cb_data,
GValue *value,
gpointer user_data);
static void prv_msu_device_upload_delete(gpointer up);
+static void prv_msu_upload_job_delete(gpointer up);
+static void prv_get_sr_token_for_props(GUPnPServiceProxy *proxy,
+ msu_device_t *device,
+ GCancellable *cancellable,
+ msu_async_cb_data_t *cb_data);
static void prv_msu_device_object_builder_delete(void *dob)
{
MSU_CONTAINER_UPDATE_VAR,
prv_container_update_cb,
ctx->device);
+ gupnp_service_proxy_set_subscribed(ctx->service_proxy,
+ FALSE);
}
if (ctx->device_proxy)
msu_device_t *dev = device;
if (dev) {
+ dev->shutting_down = TRUE;
+ g_hash_table_unref(dev->upload_jobs);
g_hash_table_unref(dev->uploads);
if (dev->timeout_id)
g_ptr_array_unref(dev->contexts);
g_free(dev->path);
+ g_variant_unref(dev->search_caps);
+ g_variant_unref(dev->sort_caps);
+ g_variant_unref(dev->sort_ext_caps);
+ g_variant_unref(dev->feature_list);
g_free(dev);
}
}
GValue *value,
gpointer user_data)
{
+ GVariantBuilder *array;
+ GVariant *val;
msu_device_t *device = user_data;
+ guint suid = g_value_get_uint(value);
+
+ MSU_LOG_DEBUG("System Update %u", suid);
+
+ device->system_update_id = suid;
- MSU_LOG_DEBUG("System Update %u", g_value_get_uint(value));
+ array = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ g_variant_builder_add(array, "{sv}", MSU_INTERFACE_SYSTEM_UPDATE_ID,
+ g_variant_new_uint32(suid));
+ val = g_variant_new("(s@a{sv}as)", MSU_INTERFACE_MEDIA_DEVICE,
+ g_variant_builder_end(array),
+ NULL);
(void) g_dbus_connection_emit_signal(device->connection,
- NULL,
- device->path,
- MSU_INTERFACE_MEDIA_DEVICE,
- MSU_INTERFACE_SYSTEM_UPDATE,
- g_variant_new("(u)", g_value_get_uint(value)),
- NULL);
+ NULL,
+ device->path,
+ MSU_INTERFACE_PROPERTIES,
+ MSU_INTERFACE_PROPERTIES_CHANGED,
+ val,
+ NULL);
+
+ g_variant_builder_unref(array);
}
static gboolean prv_re_enable_subscription(gpointer user_data)
{
msu_device_context_t *context;
- context = msu_device_get_context(device);
+ context = msu_device_get_context(device, NULL);
MSU_LOG_DEBUG("Subscribe for events on context: %s",
context->ip_address);
G_TYPE_UINT,
prv_system_update_cb,
device);
+
gupnp_service_proxy_add_notify(context->service_proxy,
MSU_CONTAINER_UPDATE_VAR,
G_TYPE_STRING,
context);
}
-gboolean msu_device_new(GDBusConnection *connection,
- GUPnPDeviceProxy *proxy,
- const gchar *ip_address,
- const GDBusSubtreeVTable *vtable,
- void *user_data,
- guint counter,
- msu_device_t **device)
+static void prv_feature_list_add_feature(gchar* root_path,
+ GUPnPFeature *feature,
+ GVariantBuilder *vb)
{
- msu_device_t *dev = g_new0(msu_device_t, 1);
- guint flags;
- guint id;
- GString *new_path = NULL;
+ GVariantBuilder vbo;
+ GVariant *var_obj;
+ const char *name;
+ const char *version;
+ const char *obj_id;
+ gchar **obj;
+ gchar **saved;
+ gchar *path;
- MSU_LOG_DEBUG("Enter");
+ name = gupnp_feature_get_name(feature);
+ version = gupnp_feature_get_version(feature);
+ obj_id = gupnp_feature_get_object_ids(feature);
- dev->connection = connection;
- dev->contexts = g_ptr_array_new_with_free_func(prv_msu_context_delete);
- msu_device_append_new_context(dev, ip_address, proxy);
+ g_variant_builder_init(&vbo, G_VARIANT_TYPE("ao"));
- msu_device_subscribe_to_contents_change(dev);
+ if (obj_id != NULL && *obj_id) {
+ obj = g_strsplit(obj_id, ",", 0);
+ saved = obj;
- new_path = g_string_new("");
- g_string_printf(new_path, "%s/%u", MSU_SERVER_PATH, counter);
+ while (obj && *obj) {
+ path = msu_path_from_id(root_path, *obj);
+ g_variant_builder_add(&vbo, "o", path);
+ g_free(path);
+ obj++;
+ }
- MSU_LOG_DEBUG("Server Path %s", new_path->str);
+ g_strfreev(saved);
+ }
- flags = G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES;
- id = g_dbus_connection_register_subtree(connection, new_path->str,
- vtable, flags, user_data, NULL,
- NULL);
- if (!id)
+ var_obj = g_variant_builder_end(&vbo);
+ g_variant_builder_add(vb, "(ss@ao)", name, version, var_obj);
+}
+
+static void prv_get_feature_list_analyze(msu_device_t *device, gchar *result)
+{
+ GUPnPFeatureListParser *parser;
+ GUPnPFeature *feature;
+ GList *list;
+ GList *item;
+ GError *error = NULL;
+ GVariantBuilder vb;
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ char *str;
+#endif
+ parser = gupnp_feature_list_parser_new();
+ list = gupnp_feature_list_parser_parse_text(parser, result, &error);
+
+ if (error != NULL) {
+ MSU_LOG_WARNING("GetFeatureList parsing failed: %s",
+ error->message);
+ goto on_exit;
+ }
+
+ g_variant_builder_init(&vb, G_VARIANT_TYPE("a(ssao)"));
+ item = list;
+
+ while (item != NULL) {
+ feature = (GUPnPFeature *) item->data;
+ prv_feature_list_add_feature(device->path, feature, &vb);
+ g_object_unref(feature);
+ item = g_list_next(item);
+ }
+
+ device->feature_list = g_variant_ref_sink(g_variant_builder_end(&vb));
+
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ str = g_variant_print(device->feature_list, FALSE);
+ MSU_LOG_DEBUG("%s = %s", MSU_INTERFACE_PROP_SV_FEATURE_LIST, str);
+ g_free(str);
+#endif
+
+on_exit:
+ g_list_free(list);
+ g_object_unref(parser);
+
+ if (error != NULL)
+ g_error_free(error);
+}
+
+static void prv_get_feature_list_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ gchar *result = NULL;
+ GError *error = NULL;
+ prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *) user_data;
+
+ if (!gupnp_service_proxy_end_action(proxy, action, &error,
+ "FeatureList", G_TYPE_STRING,
+ &result, NULL)) {
+ MSU_LOG_WARNING("GetFeatureList operation failed: %s",
+ error->message);
goto on_error;
+ }
- dev->path = g_string_free(new_path, FALSE);
- dev->id = id;
+ MSU_LOG_DEBUG("GetFeatureList result: %s", result);
- dev->uploads = g_hash_table_new_full(g_int_hash, g_int_equal, g_free,
- prv_msu_device_upload_delete);
+ prv_get_feature_list_analyze(priv_t->dev, result);
- *device = dev;
+on_error:
+ if (error != NULL)
+ g_error_free(error);
- MSU_LOG_DEBUG("Exit with SUCCESS");
+ g_free(result);
+}
- return TRUE;
+static GUPnPServiceProxyAction *prv_get_feature_list(msu_chain_task_t *chain,
+ gboolean *failed)
+{
+ msu_device_t *device;
+ msu_device_context_t *context;
+
+ device = msu_chain_task_get_device(chain);
+ context = msu_device_get_context(device, NULL);
+ *failed = FALSE;
+
+ return gupnp_service_proxy_begin_action(context->service_proxy,
+ "GetFeatureList",
+ msu_chain_task_begin_action_cb,
+ chain, NULL);
+}
+
+static void prv_get_sort_ext_capabilities_analyze(msu_device_t *device,
+ gchar *result)
+{
+ gchar **caps;
+ gchar **saved;
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ gchar *props;
+#endif
+ GVariantBuilder sort_ext_caps_vb;
+
+ g_variant_builder_init(&sort_ext_caps_vb, G_VARIANT_TYPE("as"));
+
+ caps = g_strsplit(result, ",", 0);
+ saved = caps;
+
+ while (caps && *caps) {
+ g_variant_builder_add(&sort_ext_caps_vb, "s", *caps);
+ caps++;
+ }
+
+ g_strfreev(saved);
+
+ device->sort_ext_caps = g_variant_ref_sink(g_variant_builder_end(
+ &sort_ext_caps_vb));
+
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ props = g_variant_print(device->sort_ext_caps, FALSE);
+ MSU_LOG_DEBUG("%s = %s", MSU_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES,
+ props);
+ g_free(props);
+#endif
+}
+
+static void prv_get_sort_ext_capabilities_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ gchar *result = NULL;
+ GError *error = NULL;
+ prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *) user_data;
+
+ if (!gupnp_service_proxy_end_action(proxy, action, &error,
+ "SortExtensionCaps",
+ G_TYPE_STRING, &result, NULL)) {
+ MSU_LOG_WARNING(
+ "GetSortExtensionCapabilities operation failed: %s",
+ error->message);
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("GetSortExtensionCapabilities result: %s", result);
+
+ prv_get_sort_ext_capabilities_analyze(priv_t->dev, result);
on_error:
- if (new_path)
- g_string_free(new_path, TRUE);
- msu_device_delete(dev);
+ if (error)
+ g_error_free(error);
- MSU_LOG_DEBUG("Exit with FAIL");
+ g_free(result);
+}
- return FALSE;
+static GUPnPServiceProxyAction *prv_get_sort_ext_capabilities(
+ msu_chain_task_t *chain,
+ gboolean *failed)
+{
+ msu_device_t *device;
+ msu_device_context_t *context;
+
+ device = msu_chain_task_get_device(chain);
+ context = msu_device_get_context(device, NULL);
+ *failed = FALSE;
+
+ return gupnp_service_proxy_begin_action(context->service_proxy,
+ "GetSortExtensionCapabilities",
+ msu_chain_task_begin_action_cb,
+ chain, NULL);
+}
+
+static void prv_get_capabilities_analyze(GHashTable *property_map,
+ gchar *result,
+ GVariant **variant)
+{
+ gchar **caps;
+ gchar **saved;
+ gchar *prop_name;
+ GVariantBuilder caps_vb;
+
+ g_variant_builder_init(&caps_vb, G_VARIANT_TYPE("as"));
+
+ caps = g_strsplit(result, ",", 0);
+ saved = caps;
+
+ while (caps && *caps) {
+ prop_name = g_hash_table_lookup(property_map, *caps);
+
+ if (prop_name)
+ g_variant_builder_add(&caps_vb, "s", prop_name);
+
+ caps++;
+ }
+
+ g_strfreev(saved);
+
+ *variant = g_variant_ref_sink(g_variant_builder_end(&caps_vb));
+
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ prop_name = g_variant_print(*variant, FALSE);
+ MSU_LOG_DEBUG("%s = %s", " Variant", prop_name);
+ g_free(prop_name);
+#endif
+}
+
+static void prv_get_sort_capabilities_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ gchar *result = NULL;
+ GError *error = NULL;
+ prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *) user_data;
+
+ if (!gupnp_service_proxy_end_action(proxy, action, &error, "SortCaps",
+ G_TYPE_STRING, &result, NULL)) {
+ MSU_LOG_WARNING("GetSortCapabilities operation failed: %s",
+ error->message);
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("GetSortCapabilities result: %s", result);
+
+ prv_get_capabilities_analyze(priv_t->property_map, result,
+ &priv_t->dev->sort_caps);
+
+on_error:
+
+ if (error)
+ g_error_free(error);
+
+ g_free(result);
+}
+
+static GUPnPServiceProxyAction *prv_get_sort_capabilities(
+ msu_chain_task_t *chain,
+ gboolean *failed)
+{
+ msu_device_t *device;
+ msu_device_context_t *context;
+
+ device = msu_chain_task_get_device(chain);
+ context = msu_device_get_context(device, NULL);
+ *failed = FALSE;
+
+ return gupnp_service_proxy_begin_action(context->service_proxy,
+ "GetSortCapabilities",
+ msu_chain_task_begin_action_cb,
+ chain, NULL);
+}
+
+static void prv_get_search_capabilities_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ gchar *result = NULL;
+ GError *error = NULL;
+ prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *) user_data;
+
+ if (!gupnp_service_proxy_end_action(proxy, action, &error, "SearchCaps",
+ G_TYPE_STRING, &result, NULL)) {
+ MSU_LOG_WARNING("GetSearchCapabilities operation failed: %s",
+ error->message);
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("GetSearchCapabilities result: %s", result);
+
+ prv_get_capabilities_analyze(priv_t->property_map, result,
+ &priv_t->dev->search_caps);
+
+on_error:
+
+ if (error)
+ g_error_free(error);
+
+ g_free(result);
+}
+
+static GUPnPServiceProxyAction *prv_get_search_capabilities(
+ msu_chain_task_t *chain,
+ gboolean *failed)
+{
+ msu_device_t *device;
+ msu_device_context_t *context;
+
+ device = msu_chain_task_get_device(chain);
+ context = msu_device_get_context(device, NULL);
+ *failed = FALSE;
+
+ return gupnp_service_proxy_begin_action(context->service_proxy,
+ "GetSearchCapabilities",
+ msu_chain_task_begin_action_cb,
+ chain, NULL);
+}
+
+static GUPnPServiceProxyAction *prv_subscribe(msu_chain_task_t *chain,
+ gboolean *failed)
+{
+ msu_device_t *device;
+
+ device = msu_chain_task_get_device(chain);
+ msu_device_subscribe_to_contents_change(device);
+
+ *failed = FALSE;
+
+ return NULL;
+}
+
+static GUPnPServiceProxyAction *prv_declare(msu_chain_task_t *chain,
+ gboolean *failed)
+{
+ guint flags;
+ guint id;
+ msu_device_t *device;
+ prv_new_device_ct_t *priv_t;
+
+ device = msu_chain_task_get_device(chain);
+
+ priv_t = (prv_new_device_ct_t *) msu_chain_task_get_user_data(chain);
+
+ flags = G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES;
+ id = g_dbus_connection_register_subtree(priv_t->connection,
+ device->path,
+ priv_t->vtable,
+ flags,
+ priv_t->user_data,
+ NULL, NULL);
+ if (id) {
+ device->id = id;
+
+ device->uploads = g_hash_table_new_full(g_int_hash, g_int_equal,
+ g_free,
+ prv_msu_device_upload_delete);
+ device->upload_jobs =
+ g_hash_table_new_full(g_int_hash, g_int_equal,
+ g_free,
+ prv_msu_upload_job_delete);
+
+ } else
+ MSU_LOG_ERROR("g_dbus_connection_register_subtree FAILED");
+
+ *failed = (!id);
+
+ return NULL;
+}
+
+msu_device_t *msu_device_new(GDBusConnection *connection,
+ GUPnPDeviceProxy *proxy,
+ const gchar *ip_address,
+ const GDBusSubtreeVTable *vtable,
+ void *user_data,
+ GHashTable *property_map,
+ guint counter,
+ msu_chain_task_t *chain)
+{
+ msu_device_t *dev;
+ prv_new_device_ct_t *priv_t;
+ gchar *new_path;
+
+ MSU_LOG_DEBUG("New Device on %s", ip_address);
+
+ new_path = g_strdup_printf("%s/%u", MSU_SERVER_PATH, counter);
+ MSU_LOG_DEBUG("Server Path %s", new_path);
+
+ dev = g_new0(msu_device_t, 1);
+ priv_t = g_new0(prv_new_device_ct_t, 1);
+
+ dev->connection = connection;
+ dev->contexts = g_ptr_array_new_with_free_func(prv_msu_context_delete);
+ dev->path = new_path;
+
+ priv_t->dev = dev;
+ priv_t->connection = connection;
+ priv_t->vtable = vtable;
+ priv_t->user_data = user_data;
+ priv_t->property_map = property_map;
+
+ msu_device_append_new_context(dev, ip_address, proxy);
+
+ msu_chain_task_add(chain, prv_get_search_capabilities, dev,
+ prv_get_search_capabilities_cb, NULL, priv_t);
+
+ msu_chain_task_add(chain, prv_get_sort_capabilities, dev,
+ prv_get_sort_capabilities_cb, NULL, priv_t);
+
+ msu_chain_task_add(chain, prv_get_sort_ext_capabilities, dev,
+ prv_get_sort_ext_capabilities_cb, NULL, priv_t);
+
+ msu_chain_task_add(chain, prv_get_feature_list, dev,
+ prv_get_feature_list_cb, NULL, priv_t);
+MSU_LOG_DEBUG("AFTER");
+ msu_chain_task_add(chain, prv_subscribe, dev, NULL, NULL, NULL);
+ msu_chain_task_add(chain, prv_declare, dev, NULL, g_free, priv_t);
+
+ msu_chain_task_start(chain);
+
+ return dev;
}
void msu_device_append_new_context(msu_device_t *device,
return retval;
}
-msu_device_context_t *msu_device_get_context(msu_device_t *device)
+msu_device_context_t *msu_device_get_context(msu_device_t *device,
+ msu_client_t *client)
{
msu_device_context_t *context;
unsigned int i;
const char ip4_local_prefix[] = "127.0.0.";
+ gboolean prefer_local;
+ gboolean is_local;
+
+ prefer_local = (client && client->prefer_local_addresses);
for (i = 0; i < device->contexts->len; ++i) {
context = g_ptr_array_index(device->contexts, i);
- if (!strncmp(context->ip_address, ip4_local_prefix,
- sizeof(ip4_local_prefix) - 1) ||
- !strcmp(context->ip_address, "::1") ||
- !strcmp(context->ip_address, "0:0:0:0:0:0:0:1"))
+ is_local = (!strncmp(context->ip_address, ip4_local_prefix,
+ sizeof(ip4_local_prefix) - 1) ||
+ !strcmp(context->ip_address, "::1") ||
+ !strcmp(context->ip_address, "0:0:0:0:0:0:0:1"));
+
+ if (prefer_local == is_local)
break;
}
MSU_LOG_DEBUG("Exit");
}
-void msu_device_get_children(msu_device_t *device, msu_task_t *task,
- msu_async_cb_data_t *cb_data,
+void msu_device_get_children(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task, msu_async_cb_data_t *cb_data,
const gchar *upnp_filter, const gchar *sort_by,
GCancellable *cancellable)
{
MSU_LOG_DEBUG("Enter");
- context = msu_device_get_context(device);
+ context = msu_device_get_context(device, client);
cb_data->action =
gupnp_service_proxy_begin_action(context->service_proxy,
}
}
-static gboolean prv_get_all_child_count_cb(msu_async_cb_data_t *cb_data,
- gint count)
+static gboolean prv_device_subscribed(msu_device_t *device)
{
- msu_async_get_all_t *cb_task_data = &cb_data->ut.get_all;
+ msu_device_context_t *context;
+ unsigned int i;
+ gboolean subscribed = FALSE;
- msu_props_add_child_count(cb_task_data->vb, count);
- cb_data->result = g_variant_ref_sink(g_variant_builder_end(
- cb_task_data->vb));
- return TRUE;
+ for (i = 0; i < device->contexts->len; ++i) {
+ context = g_ptr_array_index(device->contexts, i);
+ if (context->subscribed) {
+ subscribed = TRUE;
+ break;
+ }
+ }
+
+ return subscribed;
}
-static void prv_get_all_ms2spec_props_cb(GUPnPServiceProxy *proxy,
- GUPnPServiceProxyAction *action,
- gpointer user_data)
+static void prv_system_update_id_for_prop_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
{
GError *upnp_error = NULL;
- gchar *result = NULL;
- GUPnPDIDLLiteParser *parser = NULL;
+ guint id;
msu_async_cb_data_t *cb_data = user_data;
- msu_async_get_all_t *cb_task_data = &cb_data->ut.get_all;
MSU_LOG_DEBUG("Enter");
- if (!gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
- &upnp_error,
- "Result", G_TYPE_STRING,
- &result, NULL)) {
- MSU_LOG_WARNING("Browse operation failed: %s",
- upnp_error->message);
+ if (!gupnp_service_proxy_end_action(proxy, action, &upnp_error,
+ "Id", G_TYPE_UINT,
+ &id,
+ NULL)) {
+ MSU_LOG_ERROR("Unable to retrieve ServiceUpdateID: %s %s",
+ g_quark_to_string(upnp_error->domain),
+ upnp_error->message);
cb_data->error = g_error_new(MSU_ERROR,
- MSU_ERROR_OPERATION_FAILED,
- "Browse operation failed: %s",
- upnp_error->message);
- goto on_error;
+ MSU_ERROR_OPERATION_FAILED,
+ "Unable to retrieve ServiceUpdateID: %s",
+ upnp_error->message);
+
+ goto on_complete;
}
- MSU_LOG_DEBUG("GetMS2SpecProps result: %s", result);
+ cb_data->result = g_variant_ref_sink(g_variant_new_uint32(id));
- parser = gupnp_didl_lite_parser_new();
+on_complete:
- g_signal_connect(parser, "object-available" , cb_task_data->prop_func,
- cb_data);
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
- if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error)) {
- if (upnp_error->code == GUPNP_XML_ERROR_EMPTY_NODE) {
- MSU_LOG_WARNING("Property not defined for object");
+ if (upnp_error)
+ g_error_free(upnp_error);
- cb_data->error =
- g_error_new(MSU_ERROR,
- MSU_ERROR_UNKNOWN_PROPERTY,
- "Property not defined for object");
- } else {
- MSU_LOG_WARNING("Unable to parse results of browse: %s",
- upnp_error->message);
+ MSU_LOG_DEBUG("Exit");
+}
- cb_data->error =
- g_error_new(MSU_ERROR,
- MSU_ERROR_OPERATION_FAILED,
- "Unable to parse results of "
- "browse: %s",
- upnp_error->message);
- }
- goto on_error;
- }
+static void prv_get_system_update_id_for_prop(GUPnPServiceProxy *proxy,
+ msu_device_t *device,
+ GCancellable *cancellable,
+ msu_async_cb_data_t *cb_data)
+{
+ guint suid;
- if (cb_data->error)
- goto on_error;
+ MSU_LOG_DEBUG("Enter");
- if (cb_task_data->need_child_count) {
- MSU_LOG_DEBUG("Need Child Count");
+ if (prv_device_subscribed(device)) {
+ suid = device->system_update_id;
- prv_get_child_count(cb_data, prv_get_all_child_count_cb,
- cb_data->id);
+ cb_data->result = g_variant_ref_sink(
+ g_variant_new_uint32(suid));
- goto no_complete;
- } else {
- cb_data->result = g_variant_ref_sink(g_variant_builder_end(
- cb_task_data->vb));
- }
-
-on_error:
+ (void) g_idle_add(msu_async_complete_task, cb_data);
- (void) g_idle_add(msu_async_complete_task, cb_data);
- g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
+ goto on_complete;
+ }
-no_complete:
+ gupnp_service_proxy_begin_action(proxy, "GetSystemUpdateID",
+ prv_system_update_id_for_prop_cb,
+ cb_data,
+ NULL);
- if (upnp_error)
- g_error_free(upnp_error);
+ cb_data->proxy = proxy;
- if (parser)
- g_object_unref(parser);
+ cb_data->cancel_id =
+ g_cancellable_connect(cancellable,
+ G_CALLBACK(msu_async_task_cancelled),
+ cb_data, NULL);
+ cb_data->cancellable = cancellable;
- g_free(result);
+on_complete:
MSU_LOG_DEBUG("Exit");
}
-static void prv_get_all_ms2spec_props(msu_device_context_t *context,
- GCancellable *cancellable,
- msu_async_cb_data_t *cb_data)
+static void prv_system_update_id_for_props_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
{
+ GError *upnp_error = NULL;
+ guint id;
+ msu_async_cb_data_t *cb_data = user_data;
msu_async_get_all_t *cb_task_data = &cb_data->ut.get_all;
- msu_task_t *task = cb_data->task;
- msu_task_get_props_t *task_data = &task->ut.get_props;
-
- MSU_LOG_DEBUG("Enter called");
-
- if (!strcmp(MSU_INTERFACE_MEDIA_CONTAINER, task_data->interface_name))
- cb_task_data->prop_func = G_CALLBACK(prv_get_container);
- else if (!strcmp(MSU_INTERFACE_MEDIA_ITEM, task_data->interface_name))
- cb_task_data->prop_func = G_CALLBACK(prv_get_item);
- else if (!strcmp(MSU_INTERFACE_MEDIA_OBJECT, task_data->interface_name))
- cb_task_data->prop_func = G_CALLBACK(prv_get_object);
- else if (!strcmp("", task_data->interface_name))
- cb_task_data->prop_func = G_CALLBACK(prv_get_all);
- else {
- MSU_LOG_WARNING("Interface is unknown.");
- cb_data->error =
- g_error_new(MSU_ERROR, MSU_ERROR_UNKNOWN_INTERFACE,
- "Interface is unknown.");
- goto on_error;
- }
+ MSU_LOG_DEBUG("Enter");
- cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "Browse",
- prv_get_all_ms2spec_props_cb, cb_data,
- "ObjectID", G_TYPE_STRING, cb_data->id,
- "BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
- "Filter", G_TYPE_STRING, "*",
- "StartingIndex", G_TYPE_INT, 0,
- "RequestedCount", G_TYPE_INT, 0,
- "SortCriteria", G_TYPE_STRING,
- "", NULL);
+ if (!gupnp_service_proxy_end_action(proxy, action, &upnp_error,
+ "Id", G_TYPE_UINT,
+ &id,
+ NULL)) {
+ MSU_LOG_ERROR("Unable to retrieve ServiceUpdateID: %s %s",
+ g_quark_to_string(upnp_error->domain),
+ upnp_error->message);
- cb_data->proxy = context->service_proxy;
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Unable to retrieve ServiceUpdateID: %s",
+ upnp_error->message);
- cb_data->cancel_id =
- g_cancellable_connect(cancellable,
- G_CALLBACK(msu_async_task_cancelled),
- cb_data, NULL);
- cb_data->cancellable = cancellable;
+ goto on_complete;
+ }
- MSU_LOG_DEBUG("Exit with SUCCESS");
+ g_variant_builder_add(cb_task_data->vb, "{sv}",
+ MSU_SYSTEM_UPDATE_VAR,
+ g_variant_new_uint32(id));
- return;
+ cb_data->result = g_variant_ref_sink(g_variant_builder_end(
+ cb_task_data->vb));
-on_error:
+on_complete:
- (void) g_idle_add(msu_async_complete_task, cb_data);
+ if (!cb_data->error)
+ prv_get_sr_token_for_props(proxy, cb_task_data->device,
+ cb_data->cancellable, cb_data);
+ else {
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable,
+ cb_data->cancel_id);
+ }
- MSU_LOG_DEBUG("Exit with FAIL");
+ if (upnp_error)
+ g_error_free(upnp_error);
- return;
+ MSU_LOG_DEBUG("Exit");
}
-void msu_device_get_all_props(msu_device_t *device, msu_task_t *task,
- msu_async_cb_data_t *cb_data,
- gboolean root_object,
- GCancellable *cancellable)
+static void prv_get_system_update_id_for_props(GUPnPServiceProxy *proxy,
+ msu_device_t *device,
+ GCancellable *cancellable,
+ msu_async_cb_data_t *cb_data)
{
msu_async_get_all_t *cb_task_data;
- msu_task_get_props_t *task_data = &task->ut.get_props;
- msu_device_context_t *context;
+ guint suid;
MSU_LOG_DEBUG("Enter");
- context = msu_device_get_context(device);
- cb_task_data = &cb_data->ut.get_all;
+ if (prv_device_subscribed(device)) {
+ suid = device->system_update_id;
- cb_task_data->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ cb_task_data = &cb_data->ut.get_all;
- if (!strcmp(task_data->interface_name, MSU_INTERFACE_MEDIA_DEVICE)) {
- if (root_object) {
- msu_props_add_device(
- (GUPnPDeviceInfo *) context->device_proxy,
- cb_task_data->vb);
+ g_variant_builder_add(cb_task_data->vb, "{sv}",
+ MSU_SYSTEM_UPDATE_VAR,
+ g_variant_new_uint32(suid));
- cb_data->result =
- g_variant_ref_sink(g_variant_builder_end(
- cb_task_data->vb));
- } else {
- cb_data->error =
- g_error_new(MSU_ERROR,
- MSU_ERROR_UNKNOWN_INTERFACE,
- "Interface is only valid on "
- "root objects.");
- }
+ prv_get_sr_token_for_props(proxy, device, cancellable, cb_data);
- (void) g_idle_add(msu_async_complete_task, cb_data);
+ goto on_complete;
+ }
- } else if (strcmp(task_data->interface_name, "")) {
- prv_get_all_ms2spec_props(context, cancellable, cb_data);
- } else {
- if (root_object)
- msu_props_add_device(
- (GUPnPDeviceInfo *) context->device_proxy,
- cb_task_data->vb);
+ gupnp_service_proxy_begin_action(proxy, "GetSystemUpdateID",
+ prv_system_update_id_for_props_cb,
+ cb_data,
+ NULL);
- prv_get_all_ms2spec_props(context, cancellable, cb_data);
- }
+ cb_data->proxy = proxy;
+
+ cb_data->cancel_id =
+ g_cancellable_connect(cancellable,
+ G_CALLBACK(msu_async_task_cancelled),
+ cb_data, NULL);
+ cb_data->cancellable = cancellable;
+
+on_complete:
MSU_LOG_DEBUG("Exit");
}
-static void prv_get_object_property(GUPnPDIDLLiteParser *parser,
- GUPnPDIDLLiteObject *object,
- gpointer user_data)
+static int prv_get_media_server_version(msu_device_t *device)
{
- msu_async_cb_data_t *cb_data = user_data;
- msu_task_t *task = cb_data->task;
- msu_task_get_prop_t *task_data = &task->ut.get_prop;
- msu_async_get_prop_t *cb_task_data = &cb_data->ut.get_prop;
+ msu_device_context_t *context;
+ const char *device_type;
+ const char *version;
- if (cb_data->result)
+ context = msu_device_get_context(device, NULL);
+ device_type = gupnp_device_info_get_device_type((GUPnPDeviceInfo *)
+ context->device_proxy);
+
+ if (strncmp(device_type, MEDIA_SERVER_DEVICE_TYPE,
+ sizeof(MEDIA_SERVER_DEVICE_TYPE) - 1))
goto on_error;
- cb_data->result = msu_props_get_object_prop(task_data->prop_name,
- cb_task_data->root_path,
- object);
+ version = device_type + sizeof(MEDIA_SERVER_DEVICE_TYPE) - 1;
+
+ return atoi(version);
on_error:
- return;
+ return -1;
}
-static void prv_get_item_property(GUPnPDIDLLiteParser *parser,
- GUPnPDIDLLiteObject *object,
- gpointer user_data)
+static void prv_service_reset_for_prop_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
{
+ GError *upnp_error = NULL;
+ gchar *token = NULL;
msu_async_cb_data_t *cb_data = user_data;
- msu_task_t *task = cb_data->task;
- msu_task_get_prop_t *task_data = &task->ut.get_prop;
- msu_async_get_prop_t *cb_task_data = &cb_data->ut.get_prop;
- if (cb_data->result)
- goto on_error;
+ MSU_LOG_DEBUG("Enter");
- cb_data->result = msu_props_get_item_prop(task_data->prop_name,
- cb_task_data->root_path,
- object,
- cb_task_data->protocol_info);
+ if (!gupnp_service_proxy_end_action(proxy, action, &upnp_error,
+ "ResetToken", G_TYPE_STRING,
+ &token,
+ NULL)) {
+ MSU_LOG_ERROR("Unable to retrieve ServiceResetToken: %s %s",
+ g_quark_to_string(upnp_error->domain),
+ upnp_error->message);
-on_error:
- return;
-}
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "GetServiceResetToken failed: %s",
+ upnp_error->message);
-static void prv_get_container_property(GUPnPDIDLLiteParser *parser,
- GUPnPDIDLLiteObject *object,
- gpointer user_data)
-{
- msu_async_cb_data_t *cb_data = user_data;
- msu_task_t *task = cb_data->task;
- msu_task_get_prop_t *task_data = &task->ut.get_prop;
+ goto on_complete;
+ }
- if (cb_data->result)
- goto on_error;
+ cb_data->result = g_variant_ref_sink(g_variant_new_string(token));
- cb_data->result = msu_props_get_container_prop(task_data->prop_name,
- object);
+ g_free(token);
-on_error:
+ MSU_LOG_DEBUG("Service Reset %s", token);
- return;
+on_complete:
+
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
+
+ if (upnp_error)
+ g_error_free(upnp_error);
+
+ MSU_LOG_DEBUG("Exit");
}
-static void prv_get_all_property(GUPnPDIDLLiteParser *parser,
- GUPnPDIDLLiteObject *object,
- gpointer user_data)
+static void prv_get_sr_token_for_prop(GUPnPServiceProxy *proxy,
+ msu_device_t *device,
+ GCancellable *cancellable,
+ msu_async_cb_data_t *cb_data)
{
- msu_async_cb_data_t *cb_data = user_data;
-
- prv_get_object_property(parser, object, user_data);
+ MSU_LOG_DEBUG("Enter");
- if (cb_data->result)
- goto on_error;
+ if (prv_get_media_server_version(device) < 3) {
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_UNKNOWN_PROPERTY,
+ "Unknown property");
- if (GUPNP_IS_DIDL_LITE_CONTAINER(object))
- prv_get_container_property(parser, object, user_data);
- else
- prv_get_item_property(parser, object, user_data);
+ (void) g_idle_add(msu_async_complete_task, cb_data);
-on_error:
+ goto on_error;
+ }
- return;
-}
+ gupnp_service_proxy_begin_action(proxy, "GetServiceResetToken",
+ prv_service_reset_for_prop_cb,
+ cb_data,
+ NULL);
-static gboolean prv_get_child_count_cb(msu_async_cb_data_t *cb_data,
- gint count)
-{
- MSU_LOG_DEBUG("Enter");
+ cb_data->proxy = proxy;
- MSU_LOG_DEBUG("Count %d", count);
+ cb_data->cancel_id = g_cancellable_connect(cancellable,
+ G_CALLBACK(msu_async_task_cancelled),
+ cb_data, NULL);
+ cb_data->cancellable = cancellable;
- cb_data->result = g_variant_ref_sink(
- g_variant_new_uint32((guint) count));
+on_error:
MSU_LOG_DEBUG("Exit");
-
- return TRUE;
}
-static void prv_count_children_cb(GUPnPServiceProxy *proxy,
- GUPnPServiceProxyAction *action,
- gpointer user_data)
+static void prv_service_reset_for_props_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
{
- msu_device_count_data_t *count_data = user_data;
- msu_async_cb_data_t *cb_data = count_data->cb_data;
GError *upnp_error = NULL;
- gint count;
- gboolean complete = FALSE;
+ gchar *token = NULL;
+ msu_async_cb_data_t *cb_data = user_data;
+ msu_async_get_all_t *cb_task_data;
MSU_LOG_DEBUG("Enter");
- if (!gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
- &upnp_error,
- "TotalMatches", G_TYPE_INT,
- &count,
+ if (!gupnp_service_proxy_end_action(proxy, action, &upnp_error,
+ "ResetToken", G_TYPE_STRING,
+ &token,
NULL)) {
- MSU_LOG_WARNING("Browse operation failed: %s",
+ MSU_LOG_ERROR("Unable to retrieve ServiceResetToken: %s %s",
+ g_quark_to_string(upnp_error->domain),
upnp_error->message);
cb_data->error = g_error_new(MSU_ERROR,
MSU_ERROR_OPERATION_FAILED,
- "Browse operation failed: %s",
+ "GetServiceResetToken failed: %s",
upnp_error->message);
- goto on_error;
+
+ goto on_complete;
}
- complete = count_data->cb(cb_data, count);
+ cb_task_data = &cb_data->ut.get_all;
+ g_variant_builder_add(cb_task_data->vb, "{sv}",
+ MSU_INTERFACE_PROP_ESV_SERVICE_RESET_TOKEN,
+ g_variant_new_string(token));
-on_error:
+ cb_data->result = g_variant_ref_sink(g_variant_builder_end(
+ cb_task_data->vb));
- g_free(user_data);
+ g_free(token);
- if (cb_data->error || complete) {
- (void) g_idle_add(msu_async_complete_task, cb_data);
- g_cancellable_disconnect(cb_data->cancellable,
- cb_data->cancel_id);
- }
+ MSU_LOG_DEBUG("Service Reset %s", token);
+
+on_complete:
+
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
if (upnp_error)
g_error_free(upnp_error);
MSU_LOG_DEBUG("Exit");
}
-static void prv_get_child_count(msu_async_cb_data_t *cb_data,
- msu_device_count_cb_t cb, const gchar *id)
+static void prv_get_sr_token_for_props(GUPnPServiceProxy *proxy,
+ msu_device_t *device,
+ GCancellable *cancellable,
+ msu_async_cb_data_t *cb_data)
{
- msu_device_count_data_t *count_data;
+ msu_async_get_all_t *cb_task_data;
MSU_LOG_DEBUG("Enter");
- prv_msu_device_count_data_new(cb_data, cb, &count_data);
- cb_data->action =
- gupnp_service_proxy_begin_action(cb_data->proxy,
- "Browse",
- prv_count_children_cb,
- count_data,
- "ObjectID", G_TYPE_STRING, id,
+ if (prv_get_media_server_version(device) < 3) {
+ cb_task_data = &cb_data->ut.get_all;
- "BrowseFlag", G_TYPE_STRING,
- "BrowseDirectChildren",
+ cb_data->result = g_variant_ref_sink(g_variant_builder_end(
+ cb_task_data->vb));
- "Filter", G_TYPE_STRING, "",
+ goto on_complete; /* No error here, just skip the property */
+ }
- "StartingIndex", G_TYPE_INT,
- 0,
+ gupnp_service_proxy_begin_action(proxy, "GetServiceResetToken",
+ prv_service_reset_for_props_cb,
+ cb_data,
+ NULL);
- "RequestedCount", G_TYPE_INT,
- 1,
+ cb_data->proxy = proxy;
- "SortCriteria", G_TYPE_STRING,
- "",
+ cb_data->cancel_id = g_cancellable_connect(cancellable,
+ G_CALLBACK(msu_async_task_cancelled),
+ cb_data, NULL);
+ cb_data->cancellable = cancellable;
- NULL);
+on_complete:
- MSU_LOG_DEBUG("Exit with SUCCESS");
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+
+ MSU_LOG_DEBUG("Exit");
}
-static void prv_get_ms2spec_prop_cb(GUPnPServiceProxy *proxy,
- GUPnPServiceProxyAction *action,
- gpointer user_data)
+static gboolean prv_get_all_child_count_cb(msu_async_cb_data_t *cb_data,
+ gint count)
+{
+ msu_async_get_all_t *cb_task_data = &cb_data->ut.get_all;
+
+ msu_props_add_child_count(cb_task_data->vb, count);
+ if (cb_task_data->device_object)
+ prv_get_system_update_id_for_props(cb_data->proxy,
+ cb_task_data->device,
+ cb_data->cancellable,
+ cb_data);
+ else
+ cb_data->result = g_variant_ref_sink(g_variant_builder_end(
+ cb_task_data->vb));
+
+ return !cb_task_data->device_object;
+}
+
+static void prv_get_all_ms2spec_props_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
{
GError *upnp_error = NULL;
gchar *result = NULL;
GUPnPDIDLLiteParser *parser = NULL;
msu_async_cb_data_t *cb_data = user_data;
- msu_async_get_prop_t *cb_task_data = &cb_data->ut.get_prop;
- msu_task_get_prop_t *task_data = &cb_data->task->ut.get_prop;
+ msu_async_get_all_t *cb_task_data = &cb_data->ut.get_all;
MSU_LOG_DEBUG("Enter");
goto on_error;
}
- MSU_LOG_DEBUG("GetMS2SpecProp result: %s", result);
+ MSU_LOG_DEBUG("GetMS2SpecProps result: %s", result);
parser = gupnp_didl_lite_parser_new();
goto on_error;
}
- if (!cb_data->result) {
- MSU_LOG_WARNING("Property not defined for object");
+ if (cb_data->error)
+ goto on_error;
- cb_data->error = g_error_new(MSU_ERROR,
- MSU_ERROR_UNKNOWN_PROPERTY,
- "Property not defined for object");
- }
+ if (cb_task_data->need_child_count) {
+ MSU_LOG_DEBUG("Need Child Count");
-on_error:
+ prv_get_child_count(cb_data, prv_get_all_child_count_cb,
+ cb_data->id);
- if (cb_data->error && !strcmp(task_data->prop_name,
- MSU_INTERFACE_PROP_CHILD_COUNT)) {
- MSU_LOG_DEBUG("ChildCount not supported by server");
+ goto no_complete;
+ } else if (cb_data->task->type == MSU_TASK_GET_ALL_PROPS &&
+ cb_task_data->device_object) {
+ prv_get_system_update_id_for_props(proxy, cb_task_data->device,
+ cb_data->cancellable, cb_data);
- g_error_free(cb_data->error);
- cb_data->error = NULL;
- prv_get_child_count(cb_data, prv_get_child_count_cb,
- cb_data->id);
+ goto no_complete;
} else {
- (void) g_idle_add(msu_async_complete_task, cb_data);
- g_cancellable_disconnect(cb_data->cancellable,
- cb_data->cancel_id);
+ cb_data->result = g_variant_ref_sink(g_variant_builder_end(
+ cb_task_data->vb));
}
+on_error:
+
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
+
+no_complete:
+
if (upnp_error)
g_error_free(upnp_error);
MSU_LOG_DEBUG("Exit");
}
-static void prv_get_ms2spec_prop(msu_device_context_t *context,
- msu_prop_map_t *prop_map,
- msu_task_get_prop_t *task_data,
- GCancellable *cancellable,
- msu_async_cb_data_t *cb_data)
+static void prv_get_all_ms2spec_props(msu_device_context_t *context,
+ GCancellable *cancellable,
+ msu_async_cb_data_t *cb_data)
{
- msu_async_get_prop_t *cb_task_data;
- const gchar *filter;
-
- MSU_LOG_DEBUG("Enter");
-
- cb_task_data = &cb_data->ut.get_prop;
-
- if (!prop_map) {
- cb_data->error = g_error_new(MSU_ERROR,
- MSU_ERROR_UNKNOWN_PROPERTY,
- "Unknown property");
- goto on_error;
- }
+ msu_async_get_all_t *cb_task_data = &cb_data->ut.get_all;
+ msu_task_t *task = cb_data->task;
+ msu_task_get_props_t *task_data = &task->ut.get_props;
- filter = prop_map->filter ? prop_map->upnp_prop_name : "";
+ MSU_LOG_DEBUG("Enter called");
- if (!strcmp(MSU_INTERFACE_MEDIA_CONTAINER, task_data->interface_name)) {
- cb_task_data->prop_func =
- G_CALLBACK(prv_get_container_property);
- } else if (!strcmp(MSU_INTERFACE_MEDIA_ITEM,
- task_data->interface_name)) {
- cb_task_data->prop_func = G_CALLBACK(prv_get_item_property);
- } else if (!strcmp(MSU_INTERFACE_MEDIA_OBJECT,
- task_data->interface_name)) {
- cb_task_data->prop_func = G_CALLBACK(prv_get_object_property);
- } else if (!strcmp("", task_data->interface_name)) {
- cb_task_data->prop_func = G_CALLBACK(prv_get_all_property);
- } else {
- MSU_LOG_WARNING("Interface is unknown.%s",
- task_data->interface_name);
+ if (!strcmp(MSU_INTERFACE_MEDIA_CONTAINER, task_data->interface_name))
+ cb_task_data->prop_func = G_CALLBACK(prv_get_container);
+ else if (!strcmp(MSU_INTERFACE_MEDIA_ITEM, task_data->interface_name))
+ cb_task_data->prop_func = G_CALLBACK(prv_get_item);
+ else if (!strcmp(MSU_INTERFACE_MEDIA_OBJECT, task_data->interface_name))
+ cb_task_data->prop_func = G_CALLBACK(prv_get_object);
+ else if (!strcmp("", task_data->interface_name))
+ cb_task_data->prop_func = G_CALLBACK(prv_get_all);
+ else {
+ MSU_LOG_WARNING("Interface is unknown.");
- cb_data->error = g_error_new(MSU_ERROR,
- MSU_ERROR_UNKNOWN_INTERFACE,
- "Interface is unknown.");
+ cb_data->error =
+ g_error_new(MSU_ERROR, MSU_ERROR_UNKNOWN_INTERFACE,
+ "Interface is unknown.");
goto on_error;
}
cb_data->action = gupnp_service_proxy_begin_action(
context->service_proxy, "Browse",
- prv_get_ms2spec_prop_cb,
- cb_data,
+ prv_get_all_ms2spec_props_cb, cb_data,
"ObjectID", G_TYPE_STRING, cb_data->id,
- "BrowseFlag", G_TYPE_STRING,
- "BrowseMetadata",
- "Filter", G_TYPE_STRING, filter,
+ "BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
+ "Filter", G_TYPE_STRING, "*",
"StartingIndex", G_TYPE_INT, 0,
"RequestedCount", G_TYPE_INT, 0,
"SortCriteria", G_TYPE_STRING,
- "",
- NULL);
+ "", NULL);
cb_data->proxy = context->service_proxy;
return;
}
-void msu_device_get_prop(msu_device_t *device, msu_task_t *task,
- msu_async_cb_data_t *cb_data,
- msu_prop_map_t *prop_map, gboolean root_object,
- GCancellable *cancellable)
+void msu_device_get_all_props(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task, msu_async_cb_data_t *cb_data,
+ gboolean root_object,
+ GCancellable *cancellable)
{
- msu_task_get_prop_t *task_data = &task->ut.get_prop;
+ msu_async_get_all_t *cb_task_data;
+ msu_task_get_props_t *task_data = &task->ut.get_props;
msu_device_context_t *context;
MSU_LOG_DEBUG("Enter");
- context = msu_device_get_context(device);
+ context = msu_device_get_context(device, client);
+ cb_task_data = &cb_data->ut.get_all;
+
+ cb_task_data->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ cb_task_data->device_object = root_object;
+ cb_task_data->device = device;
if (!strcmp(task_data->interface_name, MSU_INTERFACE_MEDIA_DEVICE)) {
if (root_object) {
- cb_data->result =
- msu_props_get_device_prop(
- (GUPnPDeviceInfo *)
- context->device_proxy,
- task_data->prop_name);
- if (!cb_data->result)
- cb_data->error = g_error_new(
- MSU_ERROR,
- MSU_ERROR_UNKNOWN_PROPERTY,
- "Unknown property");
+ msu_props_add_device(
+ (GUPnPDeviceInfo *) context->device_proxy,
+ device,
+ cb_task_data->vb);
+
+ prv_get_system_update_id_for_props(
+ context->service_proxy,
+ device,
+ cancellable,
+ cb_data);
} else {
cb_data->error =
g_error_new(MSU_ERROR,
MSU_ERROR_UNKNOWN_INTERFACE,
- "Interface is unknown.");
- }
+ "Interface is only valid on "
+ "root objects.");
- (void) g_idle_add(msu_async_complete_task, cb_data);
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ }
} else if (strcmp(task_data->interface_name, "")) {
- prv_get_ms2spec_prop(context, prop_map, &task->ut.get_prop,
- cancellable, cb_data);
+ cb_task_data->device_object = FALSE;
+ prv_get_all_ms2spec_props(context, cancellable, cb_data);
} else {
if (root_object)
- cb_data->result = msu_props_get_device_prop(
- (GUPnPDeviceInfo *)
- context->device_proxy,
- task_data->prop_name);
+ msu_props_add_device(
+ (GUPnPDeviceInfo *) context->device_proxy,
+ device,
+ cb_task_data->vb);
- if (cb_data->result)
- (void) g_idle_add(msu_async_complete_task, cb_data);
- else
- prv_get_ms2spec_prop(context, prop_map,
- &task->ut.get_prop, cancellable,
- cb_data);
+ prv_get_all_ms2spec_props(context, cancellable, cb_data);
}
MSU_LOG_DEBUG("Exit");
}
-static void prv_found_target(GUPnPDIDLLiteParser *parser,
- GUPnPDIDLLiteObject *object,
- gpointer user_data)
+static void prv_get_object_property(GUPnPDIDLLiteParser *parser,
+ GUPnPDIDLLiteObject *object,
+ gpointer user_data)
{
msu_async_cb_data_t *cb_data = user_data;
- msu_async_bas_t *cb_task_data = &cb_data->ut.bas;
- const char *id;
- const char *parent_path;
- gchar *path = NULL;
- gboolean have_child_count;
- msu_device_object_builder_t *builder;
+ msu_task_t *task = cb_data->task;
+ msu_task_get_prop_t *task_data = &task->ut.get_prop;
+ msu_async_get_prop_t *cb_task_data = &cb_data->ut.get_prop;
- MSU_LOG_DEBUG("Enter");
+ if (cb_data->result)
+ goto on_error;
- builder = g_new0(msu_device_object_builder_t, 1);
+ cb_data->result = msu_props_get_object_prop(task_data->prop_name,
+ cb_task_data->root_path,
+ object);
- id = gupnp_didl_lite_object_get_parent_id(object);
+on_error:
- if (!id || !strcmp(id, "-1") || !strcmp(id, "")) {
- parent_path = cb_task_data->root_path;
- } else {
- path = msu_path_from_id(cb_task_data->root_path, id);
- parent_path = path;
- }
+ return;
+}
- builder->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+static void prv_get_item_property(GUPnPDIDLLiteParser *parser,
+ GUPnPDIDLLiteObject *object,
+ gpointer user_data)
+{
+ msu_async_cb_data_t *cb_data = user_data;
+ msu_task_t *task = cb_data->task;
+ msu_task_get_prop_t *task_data = &task->ut.get_prop;
+ msu_async_get_prop_t *cb_task_data = &cb_data->ut.get_prop;
- if (!msu_props_add_object(builder->vb, object, cb_task_data->root_path,
- parent_path, cb_task_data->filter_mask))
+ if (cb_data->result)
goto on_error;
- if (GUPNP_IS_DIDL_LITE_CONTAINER(object)) {
- msu_props_add_container(builder->vb,
- (GUPnPDIDLLiteContainer *) object,
- cb_task_data->filter_mask,
- &have_child_count);
-
- if (!have_child_count && (cb_task_data->filter_mask &
- MSU_UPNP_MASK_PROP_CHILD_COUNT)) {
- builder->needs_child_count = TRUE;
- builder->id = g_strdup(
- gupnp_didl_lite_object_get_id(object));
- cb_task_data->need_child_count = TRUE;
- }
- } else {
- msu_props_add_item(builder->vb,
- object,
- cb_task_data->root_path,
- cb_task_data->filter_mask,
- cb_task_data->protocol_info);
- }
-
- g_ptr_array_add(cb_task_data->vbs, builder);
- g_free(path);
-
- MSU_LOG_DEBUG("Exit with SUCCESS");
-
- return;
+ cb_data->result = msu_props_get_item_prop(task_data->prop_name,
+ cb_task_data->root_path,
+ object,
+ cb_task_data->protocol_info);
on_error:
- g_free(path);
- prv_msu_device_object_builder_delete(builder);
-
- MSU_LOG_DEBUG("Exit with FAIL");
+ return;
}
-static void prv_search_cb(GUPnPServiceProxy *proxy,
- GUPnPServiceProxyAction *action,
- gpointer user_data)
-{
- gchar *result = NULL;
+static void prv_get_container_property(GUPnPDIDLLiteParser *parser,
+ GUPnPDIDLLiteObject *object,
+ gpointer user_data)
+{
+ msu_async_cb_data_t *cb_data = user_data;
+ msu_task_t *task = cb_data->task;
+ msu_task_get_prop_t *task_data = &task->ut.get_prop;
+
+ if (cb_data->result)
+ goto on_error;
+
+ cb_data->result = msu_props_get_container_prop(task_data->prop_name,
+ object);
+
+on_error:
+
+ return;
+}
+
+static void prv_get_all_property(GUPnPDIDLLiteParser *parser,
+ GUPnPDIDLLiteObject *object,
+ gpointer user_data)
+{
+ msu_async_cb_data_t *cb_data = user_data;
+
+ prv_get_object_property(parser, object, user_data);
+
+ if (cb_data->result)
+ goto on_error;
+
+ if (GUPNP_IS_DIDL_LITE_CONTAINER(object))
+ prv_get_container_property(parser, object, user_data);
+ else
+ prv_get_item_property(parser, object, user_data);
+
+on_error:
+
+ return;
+}
+
+static gboolean prv_get_child_count_cb(msu_async_cb_data_t *cb_data,
+ gint count)
+{
+ MSU_LOG_DEBUG("Enter");
+
+ MSU_LOG_DEBUG("Count %d", count);
+
+ cb_data->result = g_variant_ref_sink(
+ g_variant_new_uint32((guint) count));
+
+ MSU_LOG_DEBUG("Exit");
+
+ return TRUE;
+}
+
+static void prv_count_children_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ msu_device_count_data_t *count_data = user_data;
+ msu_async_cb_data_t *cb_data = count_data->cb_data;
+ GError *upnp_error = NULL;
+ gint count;
+ gboolean complete = FALSE;
+
+ MSU_LOG_DEBUG("Enter");
+
+ if (!gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
+ &upnp_error,
+ "TotalMatches", G_TYPE_INT,
+ &count,
+ NULL)) {
+ MSU_LOG_WARNING("Browse operation failed: %s",
+ upnp_error->message);
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Browse operation failed: %s",
+ upnp_error->message);
+ goto on_error;
+ }
+
+ complete = count_data->cb(cb_data, count);
+
+on_error:
+
+ g_free(user_data);
+
+ if (cb_data->error || complete) {
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable,
+ cb_data->cancel_id);
+ }
+
+ if (upnp_error)
+ g_error_free(upnp_error);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+static void prv_get_child_count(msu_async_cb_data_t *cb_data,
+ msu_device_count_cb_t cb, const gchar *id)
+{
+ msu_device_count_data_t *count_data;
+
+ MSU_LOG_DEBUG("Enter");
+
+ prv_msu_device_count_data_new(cb_data, cb, &count_data);
+ cb_data->action =
+ gupnp_service_proxy_begin_action(cb_data->proxy,
+ "Browse",
+ prv_count_children_cb,
+ count_data,
+ "ObjectID", G_TYPE_STRING, id,
+
+ "BrowseFlag", G_TYPE_STRING,
+ "BrowseDirectChildren",
+
+ "Filter", G_TYPE_STRING, "",
+
+ "StartingIndex", G_TYPE_INT,
+ 0,
+
+ "RequestedCount", G_TYPE_INT,
+ 1,
+
+ "SortCriteria", G_TYPE_STRING,
+ "",
+
+ NULL);
+
+ MSU_LOG_DEBUG("Exit with SUCCESS");
+}
+
+static void prv_get_ms2spec_prop_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ GError *upnp_error = NULL;
+ gchar *result = NULL;
+ GUPnPDIDLLiteParser *parser = NULL;
+ msu_async_cb_data_t *cb_data = user_data;
+ msu_async_get_prop_t *cb_task_data = &cb_data->ut.get_prop;
+ msu_task_get_prop_t *task_data = &cb_data->task->ut.get_prop;
+
+ MSU_LOG_DEBUG("Enter");
+
+ if (!gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
+ &upnp_error,
+ "Result", G_TYPE_STRING,
+ &result, NULL)) {
+ MSU_LOG_WARNING("Browse operation failed: %s",
+ upnp_error->message);
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Browse operation failed: %s",
+ upnp_error->message);
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("GetMS2SpecProp result: %s", result);
+
+ parser = gupnp_didl_lite_parser_new();
+
+ g_signal_connect(parser, "object-available" , cb_task_data->prop_func,
+ cb_data);
+
+ if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error)) {
+ if (upnp_error->code == GUPNP_XML_ERROR_EMPTY_NODE) {
+ MSU_LOG_WARNING("Property not defined for object");
+
+ cb_data->error =
+ g_error_new(MSU_ERROR,
+ MSU_ERROR_UNKNOWN_PROPERTY,
+ "Property not defined for object");
+ } else {
+ MSU_LOG_WARNING("Unable to parse results of browse: %s",
+ upnp_error->message);
+
+ cb_data->error =
+ g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Unable to parse results of "
+ "browse: %s",
+ upnp_error->message);
+ }
+ goto on_error;
+ }
+
+ if (!cb_data->result) {
+ MSU_LOG_WARNING("Property not defined for object");
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_UNKNOWN_PROPERTY,
+ "Property not defined for object");
+ }
+
+on_error:
+
+ if (cb_data->error && !strcmp(task_data->prop_name,
+ MSU_INTERFACE_PROP_CHILD_COUNT)) {
+ MSU_LOG_DEBUG("ChildCount not supported by server");
+
+ g_error_free(cb_data->error);
+ cb_data->error = NULL;
+ prv_get_child_count(cb_data, prv_get_child_count_cb,
+ cb_data->id);
+ } else {
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable,
+ cb_data->cancel_id);
+ }
+
+ if (upnp_error)
+ g_error_free(upnp_error);
+
+ if (parser)
+ g_object_unref(parser);
+
+ g_free(result);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+static void prv_get_ms2spec_prop(msu_device_context_t *context,
+ msu_prop_map_t *prop_map,
+ msu_task_get_prop_t *task_data,
+ GCancellable *cancellable,
+ msu_async_cb_data_t *cb_data)
+{
+ msu_async_get_prop_t *cb_task_data;
+ const gchar *filter;
+
+ MSU_LOG_DEBUG("Enter");
+
+ cb_task_data = &cb_data->ut.get_prop;
+
+ if (!prop_map) {
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_UNKNOWN_PROPERTY,
+ "Unknown property");
+ goto on_error;
+ }
+
+ filter = prop_map->filter ? prop_map->upnp_prop_name : "";
+
+ if (!strcmp(MSU_INTERFACE_MEDIA_CONTAINER, task_data->interface_name)) {
+ cb_task_data->prop_func =
+ G_CALLBACK(prv_get_container_property);
+ } else if (!strcmp(MSU_INTERFACE_MEDIA_ITEM,
+ task_data->interface_name)) {
+ cb_task_data->prop_func = G_CALLBACK(prv_get_item_property);
+ } else if (!strcmp(MSU_INTERFACE_MEDIA_OBJECT,
+ task_data->interface_name)) {
+ cb_task_data->prop_func = G_CALLBACK(prv_get_object_property);
+ } else if (!strcmp("", task_data->interface_name)) {
+ cb_task_data->prop_func = G_CALLBACK(prv_get_all_property);
+ } else {
+ MSU_LOG_WARNING("Interface is unknown.%s",
+ task_data->interface_name);
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_UNKNOWN_INTERFACE,
+ "Interface is unknown.");
+ goto on_error;
+ }
+
+ cb_data->action = gupnp_service_proxy_begin_action(
+ context->service_proxy, "Browse",
+ prv_get_ms2spec_prop_cb,
+ cb_data,
+ "ObjectID", G_TYPE_STRING, cb_data->id,
+ "BrowseFlag", G_TYPE_STRING,
+ "BrowseMetadata",
+ "Filter", G_TYPE_STRING, filter,
+ "StartingIndex", G_TYPE_INT, 0,
+ "RequestedCount", G_TYPE_INT, 0,
+ "SortCriteria", G_TYPE_STRING,
+ "",
+ NULL);
+
+ cb_data->proxy = context->service_proxy;
+
+ cb_data->cancel_id =
+ g_cancellable_connect(cancellable,
+ G_CALLBACK(msu_async_task_cancelled),
+ cb_data, NULL);
+ cb_data->cancellable = cancellable;
+
+ MSU_LOG_DEBUG("Exit with SUCCESS");
+
+ return;
+
+on_error:
+
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+
+ MSU_LOG_DEBUG("Exit with FAIL");
+
+ return;
+}
+
+void msu_device_get_prop(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task, msu_async_cb_data_t *cb_data,
+ msu_prop_map_t *prop_map, gboolean root_object,
+ GCancellable *cancellable)
+{
+ msu_task_get_prop_t *task_data = &task->ut.get_prop;
+ msu_device_context_t *context;
+ gboolean complete = FALSE;
+
+ MSU_LOG_DEBUG("Enter");
+
+ context = msu_device_get_context(device, client);
+
+ if (!strcmp(task_data->interface_name, MSU_INTERFACE_MEDIA_DEVICE)) {
+ if (root_object) {
+ if (!strcmp(task_data->prop_name,
+ MSU_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID)) {
+ prv_get_system_update_id_for_prop(
+ context->service_proxy,
+ device,
+ cancellable,
+ cb_data);
+ } else if (!strcmp(task_data->prop_name,
+ MSU_INTERFACE_PROP_ESV_SERVICE_RESET_TOKEN)) {
+ prv_get_sr_token_for_prop(
+ context->service_proxy,
+ device,
+ cancellable,
+ cb_data);
+ } else {
+ cb_data->result =
+ msu_props_get_device_prop(
+ (GUPnPDeviceInfo *)
+ context->device_proxy,
+ device,
+ task_data->prop_name);
+
+ if (!cb_data->result)
+ cb_data->error = g_error_new(
+ MSU_ERROR,
+ MSU_ERROR_UNKNOWN_PROPERTY,
+ "Unknown property");
+
+ (void) g_idle_add(msu_async_complete_task,
+ cb_data);
+ }
+
+ } else {
+ cb_data->error =
+ g_error_new(MSU_ERROR,
+ MSU_ERROR_UNKNOWN_INTERFACE,
+ "Interface is unknown.");
+
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ }
+
+ } else if (strcmp(task_data->interface_name, "")) {
+ prv_get_ms2spec_prop(context, prop_map, &task->ut.get_prop,
+ cancellable, cb_data);
+ } else {
+ if (root_object) {
+ if (!strcmp(task_data->prop_name,
+ MSU_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID)) {
+ prv_get_system_update_id_for_prop(
+ context->service_proxy,
+ device,
+ cancellable,
+ cb_data);
+ complete = TRUE;
+ } else if (!strcmp(task_data->prop_name,
+ MSU_INTERFACE_PROP_ESV_SERVICE_RESET_TOKEN)) {
+ prv_get_sr_token_for_prop(
+ context->service_proxy,
+ device,
+ cancellable,
+ cb_data);
+ complete = TRUE;
+ } else {
+ cb_data->result = msu_props_get_device_prop(
+ (GUPnPDeviceInfo *)
+ context->device_proxy,
+ device,
+ task_data->prop_name);
+ if (cb_data->result) {
+ (void) g_idle_add(
+ msu_async_complete_task,
+ cb_data);
+ complete = TRUE;
+ }
+ }
+ }
+
+ if (!complete)
+ prv_get_ms2spec_prop(context, prop_map,
+ &task->ut.get_prop, cancellable,
+ cb_data);
+ }
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+static void prv_found_target(GUPnPDIDLLiteParser *parser,
+ GUPnPDIDLLiteObject *object,
+ gpointer user_data)
+{
+ msu_async_cb_data_t *cb_data = user_data;
+ msu_async_bas_t *cb_task_data = &cb_data->ut.bas;
+ const char *id;
+ const char *parent_path;
+ gchar *path = NULL;
+ gboolean have_child_count;
+ msu_device_object_builder_t *builder;
+
+ MSU_LOG_DEBUG("Enter");
+
+ builder = g_new0(msu_device_object_builder_t, 1);
+
+ id = gupnp_didl_lite_object_get_parent_id(object);
+
+ if (!id || !strcmp(id, "-1") || !strcmp(id, "")) {
+ parent_path = cb_task_data->root_path;
+ } else {
+ path = msu_path_from_id(cb_task_data->root_path, id);
+ parent_path = path;
+ }
+
+ builder->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ if (!msu_props_add_object(builder->vb, object, cb_task_data->root_path,
+ parent_path, cb_task_data->filter_mask))
+ goto on_error;
+
+ if (GUPNP_IS_DIDL_LITE_CONTAINER(object)) {
+ msu_props_add_container(builder->vb,
+ (GUPnPDIDLLiteContainer *) object,
+ cb_task_data->filter_mask,
+ &have_child_count);
+
+ if (!have_child_count && (cb_task_data->filter_mask &
+ MSU_UPNP_MASK_PROP_CHILD_COUNT)) {
+ builder->needs_child_count = TRUE;
+ builder->id = g_strdup(
+ gupnp_didl_lite_object_get_id(object));
+ cb_task_data->need_child_count = TRUE;
+ }
+ } else {
+ msu_props_add_item(builder->vb,
+ object,
+ cb_task_data->root_path,
+ cb_task_data->filter_mask,
+ cb_task_data->protocol_info);
+ }
+
+ g_ptr_array_add(cb_task_data->vbs, builder);
+ g_free(path);
+
+ MSU_LOG_DEBUG("Exit with SUCCESS");
+
+ return;
+
+on_error:
+
+ g_free(path);
+ prv_msu_device_object_builder_delete(builder);
+
+ MSU_LOG_DEBUG("Exit with FAIL");
+}
+
+static void prv_search_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ gchar *result = NULL;
+ GUPnPDIDLLiteParser *parser = NULL;
+ GError *upnp_error = NULL;
+ msu_async_cb_data_t *cb_data = user_data;
+ msu_async_bas_t *cb_task_data = &cb_data->ut.bas;
+
+ MSU_LOG_DEBUG("Enter");
+
+ if (!gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
+ &upnp_error,
+ "Result", G_TYPE_STRING,
+ &result,
+ "TotalMatches", G_TYPE_INT,
+ &cb_task_data->max_count,
+ NULL)) {
+
+ MSU_LOG_WARNING("Search operation failed %s",
+ upnp_error->message);
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Search operation failed: %s",
+ upnp_error->message);
+ goto on_error;
+ }
+
+ parser = gupnp_didl_lite_parser_new();
+
+ cb_task_data->vbs = g_ptr_array_new_with_free_func(
+ prv_msu_device_object_builder_delete);
+
+ g_signal_connect(parser, "object-available" ,
+ G_CALLBACK(prv_found_target), cb_data);
+
+ MSU_LOG_DEBUG("Server Search result: %s", result);
+
+ if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error)
+ && upnp_error->code != GUPNP_XML_ERROR_EMPTY_NODE) {
+ MSU_LOG_WARNING("Unable to parse results of search: %s",
+ upnp_error->message);
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Unable to parse results of "
+ "search: %s", upnp_error->message);
+ goto on_error;
+ }
+
+ if (cb_task_data->need_child_count) {
+ MSU_LOG_DEBUG("Need to retrieve child count");
+
+ if (cb_data->task->multiple_retvals)
+ cb_task_data->get_children_cb =
+ prv_get_search_ex_result;
+ else
+ cb_task_data->get_children_cb = prv_get_children_result;
+ prv_retrieve_child_count_for_list(cb_data);
+ goto no_complete;
+ } else {
+ if (cb_data->task->multiple_retvals)
+ prv_get_search_ex_result(cb_data);
+ else
+ prv_get_children_result(cb_data);
+ }
+
+on_error:
+
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
+
+no_complete:
+
+ if (parser)
+ g_object_unref(parser);
+
+ g_free(result);
+
+ if (upnp_error)
+ g_error_free(upnp_error);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_device_search(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task, msu_async_cb_data_t *cb_data,
+ const gchar *upnp_filter, const gchar *upnp_query,
+ const gchar *sort_by, GCancellable *cancellable)
+{
+ msu_device_context_t *context;
+
+ MSU_LOG_DEBUG("Enter");
+
+ context = msu_device_get_context(device, client);
+
+ cb_data->action = gupnp_service_proxy_begin_action(
+ context->service_proxy, "Search",
+ prv_search_cb,
+ cb_data,
+ "ContainerID", G_TYPE_STRING, cb_data->id,
+ "SearchCriteria", G_TYPE_STRING, upnp_query,
+ "Filter", G_TYPE_STRING, upnp_filter,
+ "StartingIndex", G_TYPE_INT, task->ut.search.start,
+ "RequestedCount", G_TYPE_INT, task->ut.search.count,
+ "SortCriteria", G_TYPE_STRING, sort_by,
+ NULL);
+
+ cb_data->proxy = context->service_proxy;
+
+ cb_data->cancel_id =
+ g_cancellable_connect(cancellable,
+ G_CALLBACK(msu_async_task_cancelled),
+ cb_data, NULL);
+ cb_data->cancellable = cancellable;
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+static void prv_get_resource(GUPnPDIDLLiteParser *parser,
+ GUPnPDIDLLiteObject *object,
+ gpointer user_data)
+{
+ msu_async_cb_data_t *cb_data = user_data;
+ msu_task_t *task = cb_data->task;
+ msu_task_get_resource_t *task_data = &task->ut.resource;
+ msu_async_get_all_t *cb_task_data = &cb_data->ut.get_all;
+
+ MSU_LOG_DEBUG("Enter");
+
+ msu_props_add_resource(cb_task_data->vb, object,
+ cb_task_data->filter_mask,
+ task_data->protocol_info);
+}
+
+void msu_device_get_resource(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task, msu_async_cb_data_t *cb_data,
+ const gchar *upnp_filter,
+ GCancellable *cancellable)
+{
+ msu_async_get_all_t *cb_task_data;
+ msu_device_context_t *context;
+
+ context = msu_device_get_context(device, client);
+ cb_task_data = &cb_data->ut.get_all;
+
+ cb_task_data->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ cb_task_data->prop_func = G_CALLBACK(prv_get_resource);
+ cb_task_data->device_object = FALSE;
+
+ cb_data->action = gupnp_service_proxy_begin_action(
+ context->service_proxy, "Browse",
+ prv_get_all_ms2spec_props_cb, cb_data,
+ "ObjectID", G_TYPE_STRING, cb_data->id,
+ "BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
+ "Filter", G_TYPE_STRING, upnp_filter,
+ "StartingIndex", G_TYPE_INT, 0,
+ "RequestedCount", G_TYPE_INT, 0,
+ "SortCriteria", G_TYPE_STRING,
+ "", NULL);
+
+ cb_data->proxy = context->service_proxy;
+
+ cb_data->cancel_id =
+ g_cancellable_connect(cancellable,
+ G_CALLBACK(msu_async_task_cancelled),
+ cb_data, NULL);
+ cb_data->cancellable = cancellable;
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+static gchar *prv_create_new_container_didl(const gchar *parent_id,
+ msu_task_t *task)
+{
+ GUPnPDIDLLiteWriter *writer;
+ GUPnPDIDLLiteObject *item;
+ GUPnPDIDLLiteContainer *container;
+ gchar *retval;
+ GVariantIter iter;
+ GVariant *child_type;
+ const gchar *actual_type;
+
+ writer = gupnp_didl_lite_writer_new(NULL);
+ item = GUPNP_DIDL_LITE_OBJECT(
+ gupnp_didl_lite_writer_add_container(writer));
+ container = GUPNP_DIDL_LITE_CONTAINER(item);
+
+ gupnp_didl_lite_object_set_id(item, "");
+ gupnp_didl_lite_object_set_title(item,
+ task->ut.create_container.display_name);
+ gupnp_didl_lite_object_set_parent_id(item, parent_id);
+ actual_type = msu_props_media_spec_to_upnp_class(
+ task->ut.create_container.type);
+ gupnp_didl_lite_object_set_upnp_class(item, actual_type);
+ gupnp_didl_lite_object_set_restricted(item, FALSE);
+ gupnp_didl_lite_object_set_dlna_managed(item, GUPNP_OCM_FLAGS_UPLOAD);
+
+ g_variant_iter_init(&iter, task->ut.create_container.child_types);
+ while ((child_type = g_variant_iter_next_value(&iter))) {
+ actual_type = msu_props_media_spec_to_upnp_class(
+ g_variant_get_string(child_type, NULL));
+ if (actual_type != NULL)
+ gupnp_didl_lite_container_add_create_class(container,
+ actual_type);
+ g_variant_unref(child_type);
+ }
+
+ retval = gupnp_didl_lite_writer_get_string(writer);
+
+ g_object_unref(item);
+ g_object_unref(writer);
+
+ return retval;
+}
+
+static gchar *prv_create_upload_didl(const gchar *parent_id, msu_task_t *task,
+ const gchar *object_class,
+ const gchar *mime_type)
+{
+ GUPnPDIDLLiteWriter *writer;
+ GUPnPDIDLLiteObject *item;
+ gchar *retval;
+ GUPnPProtocolInfo *protocol_info;
+ GUPnPDIDLLiteResource *res;
+
+ writer = gupnp_didl_lite_writer_new(NULL);
+ item = GUPNP_DIDL_LITE_OBJECT(gupnp_didl_lite_writer_add_item(writer));
+
+ gupnp_didl_lite_object_set_id(item, "");
+ gupnp_didl_lite_object_set_title(item, task->ut.upload.display_name);
+ gupnp_didl_lite_object_set_parent_id(item, parent_id);
+ gupnp_didl_lite_object_set_upnp_class(item, object_class);
+ gupnp_didl_lite_object_set_restricted(item, FALSE);
+
+ protocol_info = gupnp_protocol_info_new();
+ gupnp_protocol_info_set_mime_type(protocol_info, mime_type);
+ gupnp_protocol_info_set_protocol(protocol_info, "*");
+ gupnp_protocol_info_set_network(protocol_info, "*");
+
+ res = gupnp_didl_lite_object_add_resource(item);
+ gupnp_didl_lite_resource_set_protocol_info(res, protocol_info);
+
+ /* TODO: Need to compute DLNA Profile */
+
+ retval = gupnp_didl_lite_writer_get_string(writer);
+
+ g_object_unref(res);
+ g_object_unref(protocol_info);
+ g_object_unref(item);
+ g_object_unref(writer);
+
+ return retval;
+}
+
+static void prv_extract_import_uri(GUPnPDIDLLiteParser *parser,
+ GUPnPDIDLLiteObject *object,
+ gpointer user_data)
+{
+ gchar **import_uri = user_data;
+ GList *resources;
+ GList *ptr;
+ GUPnPDIDLLiteResource *res;
+ const gchar *uri;
+
+ if (!*import_uri) {
+ resources = gupnp_didl_lite_object_get_resources(object);
+ ptr = resources;
+ while (ptr) {
+ res = ptr->data;
+ if (!*import_uri) {
+ uri = gupnp_didl_lite_resource_get_import_uri(
+ res);
+ if (uri)
+ *import_uri = g_strdup(uri);
+ }
+ g_object_unref(res);
+ ptr = ptr->next;
+ }
+
+ g_list_free(resources);
+ }
+}
+
+static void prv_upload_delete_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ msu_async_cb_data_t *cb_data = user_data;
+
+ MSU_LOG_DEBUG("Enter");
+
+ (void) gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
+ NULL, NULL);
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+static void prv_msu_upload_job_delete(gpointer up_job)
+{
+ msu_device_upload_job_t *upload_job = up_job;
+
+ if (up_job) {
+ if (upload_job->remove_idle)
+ (void) g_source_remove(upload_job->remove_idle);
+
+ g_free(upload_job);
+ }
+}
+
+static gboolean prv_remove_update_job(gpointer user_data)
+{
+ msu_device_upload_job_t *upload_job = user_data;
+ msu_device_upload_t *upload;
+
+ upload = g_hash_table_lookup(upload_job->device->uploads,
+ &upload_job->upload_id);
+ if (upload) {
+ g_hash_table_remove(upload_job->device->uploads,
+ &upload_job->upload_id);
+
+ MSU_LOG_DEBUG("Removing Upload Object: %d",
+ upload_job->upload_id);
+ }
+
+ upload_job->remove_idle = 0;
+ g_hash_table_remove(upload_job->device->upload_jobs,
+ &upload_job->upload_id);
+
+ return FALSE;
+}
+
+static void prv_generate_upload_update(msu_device_upload_job_t *upload_job,
+ msu_device_upload_t *upload)
+{
+ GVariant *args;
+
+ args = g_variant_new("(ustt)", upload_job->upload_id, upload->status,
+ upload->bytes_uploaded, upload->bytes_to_upload);
+
+ MSU_LOG_DEBUG(
+ "Emitting: %s (%u %s %"G_GUINT64_FORMAT" %"G_GUINT64_FORMAT")"
+ " on %s",
+ MSU_INTERFACE_UPLOAD_UPDATE, upload_job->upload_id,
+ upload->status, upload->bytes_uploaded,
+ upload->bytes_to_upload, upload_job->device->path);
+
+ (void) g_dbus_connection_emit_signal(upload_job->device->connection,
+ NULL,
+ upload_job->device->path,
+ MSU_INTERFACE_MEDIA_DEVICE,
+ MSU_INTERFACE_UPLOAD_UPDATE,
+ args,
+ NULL);
+}
+
+static void prv_post_finished(SoupSession *session, SoupMessage *msg,
+ gpointer user_data)
+{
+ msu_device_upload_job_t *upload_job = user_data;
+ msu_device_upload_t *upload;
+ gint *upload_id;
+
+ MSU_LOG_DEBUG("Enter");
+
+ MSU_LOG_DEBUG("Upload %u finished. Code %u Message %s",
+ upload_job->upload_id, msg->status_code,
+ msg->reason_phrase);
+
+ /* This is clumsy but we need to distinguish between two cases:
+ 1. We cancel because the process is exitting.
+ 2. We cancel because a client has called CancelUpload.
+
+ We could use custom SOUP error messages to distinguish the cases
+ but device->shutting_down seemed less hacky.
+
+ We need this check as if we are shutting down it is
+ dangerous to manipulate uploads as we are being called from its
+ destructor.
+ */
+
+ if (upload_job->device->shutting_down) {
+ MSU_LOG_DEBUG("Device shutting down. Cancelling Upload");
+ goto on_error;
+ }
+
+ upload = g_hash_table_lookup(upload_job->device->uploads,
+ &upload_job->upload_id);
+ if (upload) {
+ upload_job->remove_idle =
+ g_timeout_add(30000, prv_remove_update_job, user_data);
+
+ if (SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) {
+ upload->status = MSU_UPLOAD_STATUS_COMPLETED;
+ upload->bytes_uploaded = upload->bytes_to_upload;
+ } else if (msg->status_code == SOUP_STATUS_CANCELLED) {
+ upload->status = MSU_UPLOAD_STATUS_CANCELLED;
+ } else {
+ upload->status = MSU_UPLOAD_STATUS_ERROR;
+ }
+
+ MSU_LOG_DEBUG("Upload Status: %s", upload->status);
+
+ prv_generate_upload_update(upload_job, upload);
+
+ g_object_unref(upload->msg);
+ upload->msg = NULL;
+
+ g_object_unref(upload->soup_session);
+ upload->soup_session = NULL;
+
+ g_mapped_file_unref(upload->mapped_file);
+ upload->mapped_file = NULL;
+
+ upload_id = g_new(gint, 1);
+ *upload_id = upload_job->upload_id;
+
+ g_hash_table_insert(upload_job->device->upload_jobs, upload_id,
+ upload_job);
+
+ upload_job = NULL;
+ }
+
+on_error:
+
+ prv_msu_upload_job_delete(upload_job);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+static void prv_msu_device_upload_delete(gpointer up)
+{
+ msu_device_upload_t *upload = up;
+
+ MSU_LOG_DEBUG("Enter");
+
+ if (upload) {
+ if (upload->msg) {
+ soup_session_cancel_message(upload->soup_session,
+ upload->msg,
+ SOUP_STATUS_CANCELLED);
+ g_object_unref(upload->msg);
+ }
+
+ if (upload->soup_session)
+ g_object_unref(upload->soup_session);
+
+ if (upload->mapped_file)
+ g_mapped_file_unref(upload->mapped_file);
+
+ g_free(upload);
+ }
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+static void prv_post_bytes_written(SoupMessage *msg, SoupBuffer *chunk,
+ gpointer user_data)
+{
+ msu_device_upload_t *upload = user_data;
+
+ upload->bytes_uploaded += chunk->length;
+ if (upload->bytes_uploaded > upload->bytes_to_upload)
+ upload->bytes_uploaded = upload->bytes_to_upload;
+}
+
+static msu_device_upload_t *prv_msu_device_upload_new(const gchar *file_path,
+ const gchar *import_uri,
+ const gchar *mime_type,
+ GError **error)
+{
+ const char *body;
+ gsize body_length;
+ msu_device_upload_t *upload;
+
+ MSU_LOG_DEBUG("Enter");
+
+ upload = g_new0(msu_device_upload_t, 1);
+
+ upload->mapped_file = g_mapped_file_new(file_path, FALSE, NULL);
+ if (!upload->mapped_file) {
+ MSU_LOG_WARNING("Unable to map %s into memory", file_path);
+
+ *error = g_error_new(MSU_ERROR, MSU_ERROR_IO,
+ "Unable to map %s into memory",
+ file_path);
+ goto on_error;
+ }
+
+ body = g_mapped_file_get_contents(upload->mapped_file);
+ body_length = g_mapped_file_get_length(upload->mapped_file);
+
+ upload->soup_session = soup_session_async_new();
+ upload->msg = soup_message_new("POST", import_uri);
+
+ if (!upload->msg) {
+ MSU_LOG_WARNING("Invalid URI %s", import_uri);
+
+ *error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_RESULT,
+ "Invalid URI %s", import_uri);
+ goto on_error;
+ }
+ upload->status = MSU_UPLOAD_STATUS_IN_PROGRESS;
+ upload->bytes_to_upload = body_length;
+
+ soup_message_headers_set_expectations(upload->msg->request_headers,
+ SOUP_EXPECTATION_CONTINUE);
+
+ soup_message_set_request(upload->msg, mime_type, SOUP_MEMORY_STATIC,
+ body, body_length);
+ g_signal_connect(upload->msg, "wrote-body-data",
+ G_CALLBACK(prv_post_bytes_written), upload);
+
+ MSU_LOG_DEBUG("Exit with Success");
+
+ return upload;
+
+on_error:
+
+ prv_msu_device_upload_delete(upload);
+
+ MSU_LOG_WARNING("Exit with Fail");
+
+ return NULL;
+}
+
+static void prv_create_container_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ msu_async_cb_data_t *cb_data = user_data;
+ msu_async_create_container_t *cb_task_data;
+ GError *upnp_error = NULL;
+ gchar *result = NULL;
+ gchar *object_id = NULL;
+ gchar *object_path;
+
+ MSU_LOG_DEBUG("Enter");
+
+ cb_task_data = &cb_data->ut.create_container;
+
+ if (!gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
+ &upnp_error,
+ "ObjectID", G_TYPE_STRING,
+ &object_id,
+ "Result", G_TYPE_STRING,
+ &result,
+ NULL)) {
+ MSU_LOG_ERROR("Create Object operation failed: %s",
+ upnp_error->message);
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Create Object operation "
+ " failed: %s",
+ upnp_error->message);
+ goto on_error;
+ }
+
+ object_path = msu_path_from_id(cb_task_data->root_path, object_id);
+ cb_data->result = g_variant_ref_sink(g_variant_new_object_path(
+ object_path));
+ g_free(object_path);
+
+on_error:
+
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
+
+ if (object_id)
+ g_free(object_id);
+
+ if (result)
+ g_free(result);
+
+ if (upnp_error)
+ g_error_free(upnp_error);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+static void prv_create_object_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
+{
+ gchar *result = NULL;
GUPnPDIDLLiteParser *parser = NULL;
GError *upnp_error = NULL;
msu_async_cb_data_t *cb_data = user_data;
- msu_async_bas_t *cb_task_data = &cb_data->ut.bas;
+ msu_async_upload_t *cb_task_data = &cb_data->ut.upload;
+ gchar *import_uri = NULL;
+ gchar *object_id = NULL;
+ gboolean delete_needed = FALSE;
+ GVariant *out_params[2];
+ gchar *object_path;
+ msu_device_upload_t *upload;
+ gint *upload_id;
+ msu_device_upload_job_t *upload_job;
MSU_LOG_DEBUG("Enter");
if (!gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
&upnp_error,
+ "ObjectID", G_TYPE_STRING,
+ &object_id,
"Result", G_TYPE_STRING,
&result,
- "TotalMatches", G_TYPE_INT,
- &cb_task_data->max_count,
NULL)) {
+ MSU_LOG_WARNING("Create Object operation failed: %s",
+ upnp_error->message);
- MSU_LOG_WARNING("Search operation failed %s",
- upnp_error->message);
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Create Object operation "
+ " failed: %s",
+ upnp_error->message);
+ goto on_error;
+ }
+
+ delete_needed = TRUE;
+ parser = gupnp_didl_lite_parser_new();
+
+ g_signal_connect(parser, "object-available" ,
+ G_CALLBACK(prv_extract_import_uri), &import_uri);
+
+ MSU_LOG_DEBUG("Create Object Result: %s", result);
+
+ if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error)
+ && upnp_error->code != GUPNP_XML_ERROR_EMPTY_NODE) {
+
+ MSU_LOG_WARNING("Unable to parse results of CreateObject: %s",
+ upnp_error->message);
cb_data->error = g_error_new(MSU_ERROR,
MSU_ERROR_OPERATION_FAILED,
- "Search operation failed: %s",
+ "Unable to parse results of "
+ "CreateObject: %s",
upnp_error->message);
goto on_error;
}
- parser = gupnp_didl_lite_parser_new();
+ if (!import_uri) {
+ MSU_LOG_WARNING("Missing Import URI");
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Missing Import URI");
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Import URI %s", import_uri);
+
+ upload = prv_msu_device_upload_new(cb_data->task->ut.upload.file_path,
+ import_uri, cb_task_data->mime_type,
+ &cb_data->error);
+ if (!upload)
+ goto on_error;
+
+ upload_job = g_new0(msu_device_upload_job_t, 1);
+ upload_job->device = cb_task_data->device;
+ upload_job->upload_id = (gint) cb_task_data->device->upload_id;
+
+ soup_session_queue_message(upload->soup_session, upload->msg,
+ prv_post_finished, upload_job);
+ g_object_ref(upload->msg);
+
+ upload_id = g_new(gint, 1);
+ *upload_id = upload_job->upload_id;
+ g_hash_table_insert(cb_task_data->device->uploads, upload_id, upload);
+
+ object_path = msu_path_from_id(cb_task_data->root_path, object_id);
- cb_task_data->vbs = g_ptr_array_new_with_free_func(
- prv_msu_device_object_builder_delete);
+ MSU_LOG_DEBUG("Upload ID %u", *upload_id);
+ MSU_LOG_DEBUG("Object ID %s", object_id);
+ MSU_LOG_DEBUG("Object Path %s", object_path);
- g_signal_connect(parser, "object-available" ,
- G_CALLBACK(prv_found_target), cb_data);
+ out_params[0] = g_variant_new_uint32(*upload_id);
+ out_params[1] = g_variant_new_object_path(object_path);
+ cb_data->result = g_variant_ref_sink(g_variant_new_tuple(out_params,
+ 2));
- MSU_LOG_DEBUG("Server Search result: %s", result);
+ ++cb_task_data->device->upload_id;
+ if (cb_task_data->device->upload_id > G_MAXINT)
+ cb_task_data->device->upload_id = 0;
- if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error)
- && upnp_error->code != GUPNP_XML_ERROR_EMPTY_NODE) {
- MSU_LOG_WARNING("Unable to parse results of search: %s",
- upnp_error->message);
+ g_free(object_path);
- cb_data->error = g_error_new(MSU_ERROR,
- MSU_ERROR_OPERATION_FAILED,
- "Unable to parse results of "
- "search: %s", upnp_error->message);
- goto on_error;
- }
+on_error:
- if (cb_task_data->need_child_count) {
- MSU_LOG_DEBUG("Need to retrieve child count");
+ if (cb_data->error && delete_needed) {
+ MSU_LOG_WARNING("Upload failed deleting created object "
+ "with id %s", object_id);
- if (cb_data->task->multiple_retvals)
- cb_task_data->get_children_cb =
- prv_get_search_ex_result;
- else
- cb_task_data->get_children_cb = prv_get_children_result;
- prv_retrieve_child_count_for_list(cb_data);
- goto no_complete;
+ cb_data->action = gupnp_service_proxy_begin_action(
+ cb_data->proxy, "DestroyObject", prv_upload_delete_cb,
+ cb_data, "ObjectID", G_TYPE_STRING,
+ object_id, NULL);
} else {
- if (cb_data->task->multiple_retvals)
- prv_get_search_ex_result(cb_data);
- else
- prv_get_children_result(cb_data);
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable,
+ cb_data->cancel_id);
}
-on_error:
-
- (void) g_idle_add(msu_async_complete_task, cb_data);
- g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
-
-no_complete:
+ g_free(object_id);
+ g_free(import_uri);
if (parser)
g_object_unref(parser);
MSU_LOG_DEBUG("Exit");
}
-void msu_device_search(msu_device_t *device, msu_task_t *task,
- msu_async_cb_data_t *cb_data,
- const gchar *upnp_filter, const gchar *upnp_query,
- const gchar *sort_by, GCancellable *cancellable)
+void msu_device_upload(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task, const gchar *parent_id,
+ msu_async_cb_data_t *cb_data, GCancellable *cancellable)
{
msu_device_context_t *context;
+ gchar *didl;
+ msu_async_upload_t *cb_task_data;
MSU_LOG_DEBUG("Enter");
+ MSU_LOG_DEBUG("Uploading file to %s", parent_id);
+
+ context = msu_device_get_context(device, client);
+ cb_task_data = &cb_data->ut.upload;
+
+ didl = prv_create_upload_didl(parent_id, task,
+ cb_task_data->object_class,
+ cb_task_data->mime_type);
- context = msu_device_get_context(device);
+ MSU_LOG_DEBUG("DIDL: %s", didl);
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "Search",
- prv_search_cb,
- cb_data,
- "ContainerID", G_TYPE_STRING, cb_data->id,
- "SearchCriteria", G_TYPE_STRING, upnp_query,
- "Filter", G_TYPE_STRING, upnp_filter,
- "StartingIndex", G_TYPE_INT, task->ut.search.start,
- "RequestedCount", G_TYPE_INT, task->ut.search.count,
- "SortCriteria", G_TYPE_STRING, sort_by,
+ context->service_proxy, "CreateObject",
+ prv_create_object_cb, cb_data,
+ "ContainerID", G_TYPE_STRING, parent_id,
+ "Elements", G_TYPE_STRING, didl,
NULL);
cb_data->proxy = context->service_proxy;
+ cb_task_data->device = device;
cb_data->cancel_id =
g_cancellable_connect(cancellable,
cb_data, NULL);
cb_data->cancellable = cancellable;
+ g_free(didl);
+
MSU_LOG_DEBUG("Exit");
}
-static void prv_get_resource(GUPnPDIDLLiteParser *parser,
- GUPnPDIDLLiteObject *object,
- gpointer user_data)
+gboolean msu_device_get_upload_status(msu_device_t *device,
+ msu_task_t *task, GError **error)
{
- msu_async_cb_data_t *cb_data = user_data;
- msu_task_t *task = cb_data->task;
- msu_task_get_resource_t *task_data = &task->ut.resource;
- msu_async_get_all_t *cb_task_data = &cb_data->ut.get_all;
+ msu_device_upload_t *upload;
+ gboolean retval = FALSE;
+ GVariant *out_params[3];
+ guint upload_id;
MSU_LOG_DEBUG("Enter");
- msu_props_add_resource(cb_task_data->vb, object,
- cb_task_data->filter_mask,
- task_data->protocol_info);
+ upload_id = task->ut.upload_action.upload_id;
+
+ upload = g_hash_table_lookup(device->uploads, &upload_id);
+ if (!upload) {
+ *error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Unknown Upload ID %u ", upload_id);
+ goto on_error;
+ }
+
+ out_params[0] = g_variant_new_string(upload->status);
+ out_params[1] = g_variant_new_uint64(upload->bytes_uploaded);
+ out_params[2] = g_variant_new_uint64(upload->bytes_to_upload);
+
+ MSU_LOG_DEBUG("Upload ( %s %"G_GUINT64_FORMAT" %"G_GUINT64_FORMAT" )",
+ upload->status, upload->bytes_uploaded,
+ upload->bytes_to_upload);
+
+ task->result = g_variant_ref_sink(g_variant_new_tuple(out_params, 3));
+
+ retval = TRUE;
+
+on_error:
+
+ MSU_LOG_DEBUG("Exit");
+
+ return retval;
}
-void msu_device_get_resource(msu_device_t *device, msu_task_t *task,
- msu_async_cb_data_t *cb_data,
- const gchar *upnp_filter,
- GCancellable *cancellable)
+void msu_device_get_upload_ids(msu_device_t *device, msu_task_t *task)
{
- msu_async_get_all_t *cb_task_data;
- msu_device_context_t *context;
-
- context = msu_device_get_context(device);
- cb_task_data = &cb_data->ut.get_all;
+ GVariantBuilder vb;
+ GHashTableIter iter;
+ gpointer key;
- cb_task_data->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
- cb_task_data->prop_func = G_CALLBACK(prv_get_resource);
+ MSU_LOG_DEBUG("Enter");
- cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "Browse",
- prv_get_all_ms2spec_props_cb, cb_data,
- "ObjectID", G_TYPE_STRING, cb_data->id,
- "BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
- "Filter", G_TYPE_STRING, upnp_filter,
- "StartingIndex", G_TYPE_INT, 0,
- "RequestedCount", G_TYPE_INT, 0,
- "SortCriteria", G_TYPE_STRING,
- "", NULL);
+ g_variant_builder_init(&vb, G_VARIANT_TYPE("au"));
- cb_data->proxy = context->service_proxy;
+ g_hash_table_iter_init(&iter, device->uploads);
+ while (g_hash_table_iter_next(&iter, &key, NULL))
+ g_variant_builder_add(&vb, "u", (guint32) (*((gint *) key)));
- cb_data->cancel_id =
- g_cancellable_connect(cancellable,
- G_CALLBACK(msu_async_task_cancelled),
- cb_data, NULL);
- cb_data->cancellable = cancellable;
+ task->result = g_variant_ref_sink(g_variant_builder_end(&vb));
MSU_LOG_DEBUG("Exit");
}
-static gchar *prv_create_upload_didl(const gchar *parent_id, msu_task_t *task,
- const gchar *object_class,
- const gchar *mime_type)
+gboolean msu_device_cancel_upload(msu_device_t *device, msu_task_t *task,
+ GError **error)
{
- GUPnPDIDLLiteWriter *writer;
- GUPnPDIDLLiteObject *item;
- gchar *retval;
- GUPnPProtocolInfo *protocol_info;
- GUPnPDIDLLiteResource *res;
+ msu_device_upload_t *upload;
+ gboolean retval = FALSE;
+ guint upload_id;
- writer = gupnp_didl_lite_writer_new(NULL);
- item = GUPNP_DIDL_LITE_OBJECT(gupnp_didl_lite_writer_add_item(writer));
+ MSU_LOG_DEBUG("Enter");
- gupnp_didl_lite_object_set_id(item, "");
- gupnp_didl_lite_object_set_title(item, task->ut.upload.display_name);
- gupnp_didl_lite_object_set_parent_id(item, parent_id);
- gupnp_didl_lite_object_set_upnp_class(item, object_class);
- gupnp_didl_lite_object_set_restricted(item, FALSE);
+ upload_id = task->ut.upload_action.upload_id;
- protocol_info = gupnp_protocol_info_new();
- gupnp_protocol_info_set_mime_type(protocol_info, mime_type);
- gupnp_protocol_info_set_protocol(protocol_info, "*");
- gupnp_protocol_info_set_network(protocol_info, "*");
+ upload = g_hash_table_lookup(device->uploads, &upload_id);
+ if (!upload) {
+ *error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Unknown Upload ID %u ", upload_id);
+ goto on_error;
+ }
- res = gupnp_didl_lite_object_add_resource(item);
- gupnp_didl_lite_resource_set_protocol_info(res, protocol_info);
+ if (upload->msg) {
+ soup_session_cancel_message(upload->soup_session, upload->msg,
+ SOUP_STATUS_CANCELLED);
+ MSU_LOG_DEBUG("Cancelling Upload %u ", upload_id);
+ }
- /* TODO: Need to compute DLNA Profile */
+ retval = TRUE;
- retval = gupnp_didl_lite_writer_get_string(writer);
+on_error:
- g_object_unref(res);
- g_object_unref(protocol_info);
- g_object_unref(item);
- g_object_unref(writer);
+ MSU_LOG_DEBUG("Exit");
return retval;
}
-static void prv_extract_import_uri(GUPnPDIDLLiteParser *parser,
- GUPnPDIDLLiteObject *object,
- gpointer user_data)
+static void prv_destroy_object_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
{
- gchar **import_uri = user_data;
- GList *resources;
- GList *ptr;
- GUPnPDIDLLiteResource *res;
- const gchar *uri;
+ GError *upnp_error = NULL;
+ msu_async_cb_data_t *cb_data = user_data;
- if (!*import_uri) {
- ptr = resources = gupnp_didl_lite_object_get_resources(object);
- while (ptr) {
- res = ptr->data;
- if (!*import_uri) {
- uri = gupnp_didl_lite_resource_get_import_uri(
- res);
- if (uri)
- *import_uri = g_strdup(uri);
- }
- g_object_unref(res);
- ptr = ptr->next;
- }
+ MSU_LOG_DEBUG("Enter");
- g_list_free(resources);
+ if (!gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
+ &upnp_error,
+ NULL)) {
+ MSU_LOG_WARNING("Destroy Object operation failed: %s",
+ upnp_error->message);
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Destroy Object operation "
+ " failed: %s",
+ upnp_error->message);
}
+
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
+
+ if (upnp_error)
+ g_error_free(upnp_error);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_device_delete_object(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task,
+ msu_async_cb_data_t *cb_data,
+ GCancellable *cancellable)
+{
+ msu_device_context_t *context;
+
+ MSU_LOG_DEBUG("Enter");
+
+ context = msu_device_get_context(device, client);
+
+ cb_data->action = gupnp_service_proxy_begin_action(
+ context->service_proxy, "DestroyObject",
+ prv_destroy_object_cb, cb_data,
+ "ObjectID", G_TYPE_STRING, cb_data->id,
+ NULL);
+
+ cb_data->proxy = context->service_proxy;
+
+ cb_data->cancel_id = g_cancellable_connect(cancellable,
+ G_CALLBACK(msu_async_task_cancelled),
+ cb_data, NULL);
+ cb_data->cancellable = cancellable;
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_device_create_container(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task,
+ const gchar *parent_id,
+ msu_async_cb_data_t *cb_data,
+ GCancellable *cancellable)
+{
+ msu_device_context_t *context;
+ gchar *didl;
+
+ MSU_LOG_DEBUG("Enter");
+
+ context = msu_device_get_context(device, client);
+
+ didl = prv_create_new_container_didl(parent_id, task);
+
+ MSU_LOG_DEBUG("DIDL: %s", didl);
+
+ cb_data->action = gupnp_service_proxy_begin_action(
+ context->service_proxy, "CreateObject",
+ prv_create_container_cb, cb_data,
+ "ContainerID", G_TYPE_STRING, parent_id,
+ "Elements", G_TYPE_STRING, didl,
+ NULL);
+
+ cb_data->proxy = context->service_proxy;
+
+ cb_data->cancel_id =
+ g_cancellable_connect(cancellable,
+ G_CALLBACK(msu_async_task_cancelled),
+ cb_data, NULL);
+ cb_data->cancellable = cancellable;
+
+ g_free(didl);
+
+ MSU_LOG_DEBUG("Exit");
}
-static void prv_upload_delete_cb(GUPnPServiceProxy *proxy,
- GUPnPServiceProxyAction *action,
- gpointer user_data)
+static void prv_update_object_update_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
{
+ GError *upnp_error = NULL;
msu_async_cb_data_t *cb_data = user_data;
MSU_LOG_DEBUG("Enter");
- (void) gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
- NULL, NULL);
+ if (!gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
+ &upnp_error,
+ NULL)) {
+ MSU_LOG_WARNING("Update Object operation failed: %s",
+ upnp_error->message);
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Update Object operation "
+ " failed: %s",
+ upnp_error->message);
+ }
+
(void) g_idle_add(msu_async_complete_task, cb_data);
g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
+ if (upnp_error)
+ g_error_free(upnp_error);
+
MSU_LOG_DEBUG("Exit");
}
-static void prv_post_finished(SoupSession *session, SoupMessage *msg,
- gpointer user_data)
+static gchar *prv_get_current_xml_fragment(GUPnPDIDLLiteObject *object,
+ guint32 mask)
{
- msu_device_upload_job_t *upload_job = user_data;
+ gchar *retval = NULL;
+
+ if (mask & MSU_UPNP_MASK_PROP_DISPLAY_NAME)
+ retval = gupnp_didl_lite_object_get_title_xml_string(object);
+ else if (mask & MSU_UPNP_MASK_PROP_ALBUM)
+ retval = gupnp_didl_lite_object_get_album_xml_string(object);
+ else if (mask & MSU_UPNP_MASK_PROP_DATE)
+ retval = gupnp_didl_lite_object_get_date_xml_string(object);
+ else if (mask & MSU_UPNP_MASK_PROP_TYPE)
+ retval = gupnp_didl_lite_object_get_upnp_class_xml_string(
+ object);
+ else if (mask & MSU_UPNP_MASK_PROP_TRACK_NUMBER)
+ retval = gupnp_didl_lite_object_get_track_number_xml_string(
+ object);
+ else if (mask & MSU_UPNP_MASK_PROP_ARTISTS)
+ retval = gupnp_didl_lite_object_get_artists_xml_string(object);
- MSU_LOG_DEBUG("Enter");
+ return retval;
+}
- MSU_LOG_DEBUG("Upload %u finished. Code %u Message %s",
- upload_job->upload_id, msg->status_code,
- msg->reason_phrase);
+static gchar *prv_get_new_xml_fragment(GUPnPDIDLLiteObject *object,
+ guint32 mask,
+ GVariant *value)
+{
+ GUPnPDIDLLiteContributor *artist;
+ const gchar *artist_name;
+ const gchar *upnp_class;
+ GVariantIter viter;
+ gchar *retval = NULL;
+
+ if (mask & MSU_UPNP_MASK_PROP_DISPLAY_NAME) {
+ gupnp_didl_lite_object_set_title(object,
+ g_variant_get_string(value, NULL));
+
+ retval = gupnp_didl_lite_object_get_title_xml_string(object);
+ } else if (mask & MSU_UPNP_MASK_PROP_ALBUM) {
+ gupnp_didl_lite_object_set_album(object,
+ g_variant_get_string(value, NULL));
+
+ retval = gupnp_didl_lite_object_get_album_xml_string(object);
+ } else if (mask & MSU_UPNP_MASK_PROP_DATE) {
+ gupnp_didl_lite_object_set_date(object,
+ g_variant_get_string(value, NULL));
+
+ retval = gupnp_didl_lite_object_get_date_xml_string(object);
+ } else if (mask & MSU_UPNP_MASK_PROP_TYPE) {
+ upnp_class = msu_props_media_spec_to_upnp_class(
+ g_variant_get_string(value, NULL));
+
+ gupnp_didl_lite_object_set_upnp_class(object, upnp_class);
+
+ retval = gupnp_didl_lite_object_get_upnp_class_xml_string(
+ object);
+ } else if (mask & MSU_UPNP_MASK_PROP_TRACK_NUMBER) {
+ gupnp_didl_lite_object_set_track_number(object,
+ g_variant_get_int32(value));
+
+ retval = gupnp_didl_lite_object_get_track_number_xml_string(
+ object);
+ } else if (mask & MSU_UPNP_MASK_PROP_ARTISTS) {
+ gupnp_didl_lite_object_unset_artists(object);
+
+ (void) g_variant_iter_init(&viter, value);
+
+ while (g_variant_iter_next(&viter, "&s", &artist_name)) {
+ artist = gupnp_didl_lite_object_add_artist(object);
+
+ gupnp_didl_lite_contributor_set_name(artist,
+ artist_name);
+ }
- if (msg->status_code != SOUP_STATUS_CANCELLED)
- g_hash_table_remove(upload_job->device->uploads,
- &upload_job->upload_id);
- g_free(upload_job);
+ retval = gupnp_didl_lite_object_get_artists_xml_string(object);
+ }
- MSU_LOG_DEBUG("Exit");
+ return retval;
}
-static void prv_msu_device_upload_delete(gpointer up)
+static void prv_get_xml_fragments(GUPnPDIDLLiteParser *parser,
+ GUPnPDIDLLiteObject *object,
+ gpointer user_data)
{
- msu_device_upload_t *upload = up;
+ GString *current_str;
+ GString *new_str;
+ gchar *frag1;
+ gchar *frag2;
+ GVariantIter viter;
+ const gchar *prop;
+ GVariant *value;
+ msu_prop_map_t *prop_map;
+ GUPnPDIDLLiteWriter *writer;
+ GUPnPDIDLLiteObject *scratch_object;
+ gboolean first = TRUE;
+ msu_async_cb_data_t *cb_data = user_data;
+ msu_async_update_t *cb_task_data = &cb_data->ut.update;
+ msu_task_t *task = cb_data->task;
+ msu_task_update_t *task_data = &task->ut.update;
MSU_LOG_DEBUG("Enter");
- if (upload) {
- if (upload->msg) {
- soup_session_cancel_message(upload->soup_session,
- upload->msg,
- SOUP_STATUS_CANCELLED);
- g_object_unref(upload->msg);
- }
+ current_str = g_string_new("");
+ new_str = g_string_new("");
- if (upload->soup_session)
- g_object_unref(upload->soup_session);
+ writer = gupnp_didl_lite_writer_new(NULL);
+ if (GUPNP_IS_DIDL_LITE_CONTAINER(object))
+ scratch_object = GUPNP_DIDL_LITE_OBJECT(
+ gupnp_didl_lite_writer_add_container(writer));
+ else
+ scratch_object = GUPNP_DIDL_LITE_OBJECT(
+ gupnp_didl_lite_writer_add_item(writer));
- if (upload->mapped_file)
- g_mapped_file_unref(upload->mapped_file);
+ (void) g_variant_iter_init(&viter, task_data->to_add_update);
- g_free(upload);
- }
+ while (g_variant_iter_next(&viter, "{&sv}", &prop, &value)) {
- MSU_LOG_DEBUG("Exit");
-}
+ MSU_LOG_DEBUG("to_add_update = %s", prop);
-static msu_device_upload_t *prv_msu_device_upload_new(const gchar *file_path,
- const gchar *import_uri,
- const gchar *mime_type,
- GError **error)
-{
- const char *body;
- gsize body_length;
- msu_device_upload_t *upload;
+ prop_map = g_hash_table_lookup(cb_task_data->map, prop);
- MSU_LOG_DEBUG("Enter");
+ frag1 = prv_get_current_xml_fragment(object, prop_map->type);
+ frag2 = prv_get_new_xml_fragment(scratch_object, prop_map->type,
+ value);
- upload = g_new0(msu_device_upload_t, 1);
+ if (!frag2) {
+ MSU_LOG_DEBUG("Unable to set %s. Skipping", prop);
- upload->mapped_file = g_mapped_file_new(file_path, FALSE, NULL);
- if (!upload->mapped_file) {
- MSU_LOG_WARNING("Unable to map %s into memory", file_path);
+ g_free(frag1);
+ continue;
+ }
- *error = g_error_new(MSU_ERROR, MSU_ERROR_IO,
- "Unable to map %s into memory",
- file_path);
- goto on_error;
- }
+ if (!first) {
+ g_string_append(current_str, ",");
+ g_string_append(new_str, ",");
+ } else {
+ first = FALSE;
+ }
- body = g_mapped_file_get_contents(upload->mapped_file);
- body_length = g_mapped_file_get_length(upload->mapped_file);
+ if (frag1) {
+ g_string_append(current_str, (const gchar *) frag1);
+ g_free(frag1);
+ }
- upload->soup_session = soup_session_async_new();
- upload->msg = soup_message_new("POST", import_uri);
+ g_string_append(new_str, (const gchar *) frag2);
+ g_free(frag2);
+ }
- if (!upload->msg) {
- MSU_LOG_WARNING("Invalid URI %s", import_uri);
+ (void) g_variant_iter_init(&viter, task_data->to_delete);
- *error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_RESULT,
- "Invalid URI %s", import_uri);
- goto on_error;
- }
+ while (g_variant_iter_next(&viter, "&s", &prop)) {
+ MSU_LOG_DEBUG("to_delete = %s", prop);
- soup_message_headers_set_expectations(upload->msg->request_headers,
- SOUP_EXPECTATION_CONTINUE);
+ prop_map = g_hash_table_lookup(cb_task_data->map, prop);
- soup_message_set_request(upload->msg, mime_type, SOUP_MEMORY_STATIC,
- body, body_length);
+ frag1 = prv_get_current_xml_fragment(object, prop_map->type);
+ if (!frag1)
+ continue;
- MSU_LOG_DEBUG("Exit with Success");
+ if (!first)
+ g_string_append(current_str, ",");
+ else
+ first = FALSE;
- return upload;
+ g_string_append(current_str, (const gchar *) frag1);
+ g_free(frag1);
+ }
-on_error:
+ cb_task_data->current_tag_value = g_string_free(current_str, FALSE);
+ MSU_LOG_DEBUG("current_tag_value = %s",
+ cb_task_data->current_tag_value);
- prv_msu_device_upload_delete(upload);
+ cb_task_data->new_tag_value = g_string_free(new_str, FALSE);
+ MSU_LOG_DEBUG("new_tag_value = %s", cb_task_data->new_tag_value);
- MSU_LOG_WARNING("Exit with Fail");
+ g_object_unref(scratch_object);
+ g_object_unref(writer);
- return NULL;
+ MSU_LOG_DEBUG("Exit");
}
-static void prv_create_object_cb(GUPnPServiceProxy *proxy,
- GUPnPServiceProxyAction *action,
- gpointer user_data)
+static void prv_update_object_browse_cb(GUPnPServiceProxy *proxy,
+ GUPnPServiceProxyAction *action,
+ gpointer user_data)
{
- gchar *result = NULL;
- GUPnPDIDLLiteParser *parser = NULL;
GError *upnp_error = NULL;
msu_async_cb_data_t *cb_data = user_data;
- msu_async_upload_t *cb_task_data = &cb_data->ut.upload;
- gchar *import_uri = NULL;
- gchar *object_id = NULL;
- gboolean delete_needed = FALSE;
- GVariant *out_params[2];
- gchar *object_path;
- msu_device_upload_t *upload;
- gint *upload_id;
- msu_device_upload_job_t *upload_job;
+ msu_async_update_t *cb_task_data = &cb_data->ut.update;
+ GUPnPDIDLLiteParser *parser = NULL;
+ gchar *result = NULL;
MSU_LOG_DEBUG("Enter");
if (!gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
&upnp_error,
- "ObjectID", G_TYPE_STRING,
- &object_id,
"Result", G_TYPE_STRING,
- &result,
- NULL)) {
- MSU_LOG_WARNING("Create Object operation failed: %s",
+ &result, NULL)) {
+ MSU_LOG_WARNING("Browse Object operation failed: %s",
upnp_error->message);
cb_data->error = g_error_new(MSU_ERROR,
MSU_ERROR_OPERATION_FAILED,
- "Create Object operation "
- " failed: %s",
+ "Browse operation failed: %s",
upnp_error->message);
goto on_error;
}
- delete_needed = TRUE;
- parser = gupnp_didl_lite_parser_new();
-
- g_signal_connect(parser, "object-available" ,
- G_CALLBACK(prv_extract_import_uri), &import_uri);
+ MSU_LOG_DEBUG("msu_device_update_ex_object result: %s", result);
- MSU_LOG_DEBUG("Create Object Result: %s", result);
+ parser = gupnp_didl_lite_parser_new();
- if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error)
- && upnp_error->code != GUPNP_XML_ERROR_EMPTY_NODE) {
+ g_signal_connect(parser, "object-available",
+ G_CALLBACK(prv_get_xml_fragments),
+ cb_data);
- MSU_LOG_WARNING("Unable to parse results of CreateObject: %s",
- upnp_error->message);
+ if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error)) {
+ if (upnp_error->code == GUPNP_XML_ERROR_EMPTY_NODE) {
+ MSU_LOG_WARNING("Property not defined for object");
- cb_data->error = g_error_new(MSU_ERROR,
- MSU_ERROR_OPERATION_FAILED,
- "Unable to parse results of "
- "CreateObject: %s",
- upnp_error->message);
- goto on_error;
- }
+ cb_data->error =
+ g_error_new(MSU_ERROR,
+ MSU_ERROR_UNKNOWN_PROPERTY,
+ "Property not defined for object");
+ } else {
+ MSU_LOG_WARNING("Unable to parse results of browse: %s",
+ upnp_error->message);
- if (!import_uri) {
- MSU_LOG_WARNING("Missing Import URI");
+ cb_data->error =
+ g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Unable to parse results of "
+ "browse: %s",
+ upnp_error->message);
+ }
- cb_data->error = g_error_new(MSU_ERROR,
- MSU_ERROR_OPERATION_FAILED,
- "Missing Import URI");
goto on_error;
}
- MSU_LOG_DEBUG("Import URI %s", import_uri);
-
- upload = prv_msu_device_upload_new(cb_data->task->ut.upload.file_path,
- import_uri, cb_task_data->mime_type,
- &cb_data->error);
- if (!upload)
- goto on_error;
-
- upload_job = g_new(msu_device_upload_job_t, 1);
- upload_job->device = cb_task_data->device;
- upload_job->upload_id = (gint) cb_task_data->device->upload_id;
-
- soup_session_queue_message(upload->soup_session, upload->msg,
- prv_post_finished, upload_job);
- g_object_ref(upload->msg);
-
- upload_id = g_new(gint, 1);
- *upload_id = upload_job->upload_id;
- g_hash_table_insert(cb_task_data->device->uploads, upload_id, upload);
-
- object_path = msu_path_from_id(cb_task_data->root_path, object_id);
-
- MSU_LOG_DEBUG("Upload ID %u", *upload_id);
- MSU_LOG_DEBUG("Object ID %s", object_id);
- MSU_LOG_DEBUG("Object Path %s", object_path);
-
- out_params[0] = g_variant_new_uint32(*upload_id);
- out_params[1] = g_variant_new_object_path(object_path);
- cb_data->result = g_variant_ref_sink(g_variant_new_tuple(out_params,
- 2));
-
- ++cb_task_data->device->upload_id;
- if (cb_task_data->device->upload_id > G_MAXINT)
- cb_task_data->device->upload_id = 0;
+ cb_data->action = gupnp_service_proxy_begin_action(
+ cb_data->proxy, "UpdateObject",
+ prv_update_object_update_cb, cb_data,
+ "ObjectID", G_TYPE_STRING, cb_data->id,
+ "CurrentTagValue", G_TYPE_STRING,
+ cb_task_data->current_tag_value,
+ "NewTagValue", G_TYPE_STRING, cb_task_data->new_tag_value,
+ NULL);
- g_free(object_path);
+ goto no_complete;
on_error:
- if (cb_data->error && delete_needed) {
- MSU_LOG_WARNING("Upload failed deleting created object "
- "with id %s", object_id);
-
- cb_data->action = gupnp_service_proxy_begin_action(
- cb_data->proxy, "DestroyObject", prv_upload_delete_cb,
- cb_data, "ObjectID", G_TYPE_STRING,
- object_id, NULL);
- } else {
- (void) g_idle_add(msu_async_complete_task, cb_data);
- g_cancellable_disconnect(cb_data->cancellable,
- cb_data->cancel_id);
- }
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+ g_cancellable_disconnect(cb_data->cancellable, cb_data->cancel_id);
- g_free(object_id);
- g_free(import_uri);
+no_complete:
if (parser)
g_object_unref(parser);
MSU_LOG_DEBUG("Exit");
}
-void msu_device_upload(msu_device_t *device, msu_task_t *task,
- const gchar *parent_id, msu_async_cb_data_t *cb_data,
- GCancellable *cancellable)
+void msu_device_update_object(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task,
+ msu_async_cb_data_t *cb_data,
+ const gchar *upnp_filter,
+ GCancellable *cancellable)
{
msu_device_context_t *context;
- gchar *didl;
- msu_async_upload_t *cb_task_data;
MSU_LOG_DEBUG("Enter");
- MSU_LOG_DEBUG("Uploading file to %s", parent_id);
-
- context = msu_device_get_context(device);
- cb_task_data = &cb_data->ut.upload;
-
- didl = prv_create_upload_didl(parent_id, task,
- cb_task_data->object_class,
- cb_task_data->mime_type);
- MSU_LOG_DEBUG("DIDL: %s", didl);
+ context = msu_device_get_context(device, client);
cb_data->action = gupnp_service_proxy_begin_action(
- context->service_proxy, "CreateObject",
- prv_create_object_cb, cb_data,
- "ContainerID", G_TYPE_STRING, parent_id,
- "Elements", G_TYPE_STRING, didl,
- NULL);
+ context->service_proxy, "Browse",
+ prv_update_object_browse_cb, cb_data,
+ "ObjectID", G_TYPE_STRING, cb_data->id,
+ "BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
+ "Filter", G_TYPE_STRING, upnp_filter,
+ "StartingIndex", G_TYPE_INT, 0,
+ "RequestedCount", G_TYPE_INT, 0,
+ "SortCriteria", G_TYPE_STRING,
+ "", NULL);
cb_data->proxy = context->service_proxy;
- cb_task_data->device = device;
- cb_data->cancel_id =
- g_cancellable_connect(cancellable,
- G_CALLBACK(msu_async_task_cancelled),
- cb_data, NULL);
- cb_data->cancellable = cancellable;
+ cb_data->cancel_id = g_cancellable_connect(cancellable,
+ G_CALLBACK(msu_async_task_cancelled),
+ cb_data, NULL);
- g_free(didl);
+ cb_data->cancellable = cancellable;
MSU_LOG_DEBUG("Exit");
}
#include <libgupnp/gupnp-control-point.h>
#include "async.h"
+#include "chain-task.h"
+#include "client.h"
#include "props.h"
typedef struct msu_device_context_t_ msu_device_context_t;
GPtrArray *contexts;
guint timeout_id;
GHashTable *uploads;
+ GHashTable *upload_jobs;
guint upload_id;
+ guint system_update_id;
+ GVariant *search_caps;
+ GVariant *sort_caps;
+ GVariant *sort_ext_caps;
+ GVariant *feature_list;
+ gboolean shutting_down;
};
void msu_device_append_new_context(msu_device_t *device,
const gchar *ip_address,
GUPnPDeviceProxy *proxy);
void msu_device_delete(void *device);
-gboolean msu_device_new(GDBusConnection *connection,
- GUPnPDeviceProxy *proxy,
- const gchar *ip_address,
- const GDBusSubtreeVTable *vtable,
- void *user_data,
- guint counter,
- msu_device_t **device);
+msu_device_t *msu_device_new(GDBusConnection *connection,
+ GUPnPDeviceProxy *proxy,
+ const gchar *ip_address,
+ const GDBusSubtreeVTable *vtable,
+ void *user_data,
+ GHashTable *filter_map,
+ guint counter,
+ msu_chain_task_t *chain);
+
msu_device_t *msu_device_from_path(const gchar *path, GHashTable *device_list);
-msu_device_context_t *msu_device_get_context(msu_device_t *device);
-void msu_device_get_children(msu_device_t *device, msu_task_t *task,
- msu_async_cb_data_t *cb_data,
+msu_device_context_t *msu_device_get_context(msu_device_t *device,
+ msu_client_t *client);
+void msu_device_get_children(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task, msu_async_cb_data_t *cb_data,
const gchar *upnp_filter, const gchar *sort_by,
GCancellable *cancellable);
-void msu_device_get_all_props(msu_device_t *device, msu_task_t *task,
+void msu_device_get_all_props(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task,
msu_async_cb_data_t *cb_data,
gboolean root_object,
GCancellable *cancellable);
-void msu_device_get_prop(msu_device_t *device, msu_task_t *task,
- msu_async_cb_data_t *cb_data,
+void msu_device_get_prop(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task, msu_async_cb_data_t *cb_data,
msu_prop_map_t *prop_map, gboolean root_object,
GCancellable *cancellable);
-void msu_device_search(msu_device_t *device, msu_task_t *task,
- msu_async_cb_data_t *cb_data, const gchar *upnp_filter,
- const gchar *upnp_query, const gchar *sort_by,
- GCancellable *cancellable);
-void msu_device_get_resource(msu_device_t *device, msu_task_t *task,
+void msu_device_search(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task, msu_async_cb_data_t *cb_data,
+ const gchar *upnp_filter, const gchar *upnp_query,
+ const gchar *sort_by, GCancellable *cancellable);
+void msu_device_get_resource(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task,
msu_async_cb_data_t *cb_data,
const gchar *upnp_filter,
GCancellable *cancellable);
void msu_device_subscribe_to_contents_change(msu_device_t *device);
-void msu_device_upload(msu_device_t *device, msu_task_t *task,
- const gchar *parent_id, msu_async_cb_data_t *cb_data,
- GCancellable *cancellable);
-
+void msu_device_upload(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task, const gchar *parent_id,
+ msu_async_cb_data_t *cb_data, GCancellable *cancellable);
+gboolean msu_device_get_upload_status(msu_device_t *device,
+ msu_task_t *task, GError **error);
+gboolean msu_device_cancel_upload(msu_device_t *device, msu_task_t *task,
+ GError **error);
+void msu_device_get_upload_ids(msu_device_t *device, msu_task_t *task);
+void msu_device_delete_object(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task,
+ msu_async_cb_data_t *cb_data,
+ GCancellable *cancellable);
+void msu_device_create_container(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task,
+ const gchar *parent_id,
+ msu_async_cb_data_t *cb_data,
+ GCancellable *cancellable);
+void msu_device_update_object(msu_device_t *device, msu_client_t *client,
+ msu_task_t *task,
+ msu_async_cb_data_t *cb_data,
+ const gchar *upnp_filter,
+ GCancellable *cancellable);
#endif
#define MSU_INTERFACE_MEDIA_OBJECT "org.gnome.UPnP.MediaObject2"
#define MSU_INTERFACE_MEDIA_ITEM "org.gnome.UPnP.MediaItem2"
-#define MSU_INTERFACE_PROP_PARENT "Parent"
-#define MSU_INTERFACE_PROP_TYPE "Type"
+/* Object Properties */
#define MSU_INTERFACE_PROP_PATH "Path"
+#define MSU_INTERFACE_PROP_PARENT "Parent"
+#define MSU_INTERFACE_PROP_RESTRICTED "Restricted"
#define MSU_INTERFACE_PROP_DISPLAY_NAME "DisplayName"
+#define MSU_INTERFACE_PROP_TYPE "Type"
+#define MSU_INTERFACE_PROP_CREATOR "Creator"
+#define MSU_INTERFACE_PROP_DLNA_MANAGED "DLNAManaged"
-#define MSU_INTERFACE_PROP_CHILD_COUNT "ChildCount"
-#define MSU_INTERFACE_PROP_SEARCHABLE "Searchable"
-
-#define MSU_INTERFACE_PROP_URLS "URLs"
-#define MSU_INTERFACE_PROP_URL "URL"
-#define MSU_INTERFACE_PROP_RESOURCES "Resources"
-#define MSU_INTERFACE_PROP_MIME_TYPE "MIMEType"
+/* Item Properties */
+#define MSU_INTERFACE_PROP_REFPATH "RefPath"
#define MSU_INTERFACE_PROP_ARTIST "Artist"
+#define MSU_INTERFACE_PROP_ARTISTS "Artists"
#define MSU_INTERFACE_PROP_ALBUM "Album"
#define MSU_INTERFACE_PROP_DATE "Date"
#define MSU_INTERFACE_PROP_GENRE "Genre"
-#define MSU_INTERFACE_PROP_DLNA_PROFILE "DLNAProfile"
#define MSU_INTERFACE_PROP_TRACK_NUMBER "TrackNumber"
#define MSU_INTERFACE_PROP_ALBUM_ART_URL "AlbumArtURL"
-#define MSU_INTERFACE_PROP_ICON_URL "IconURL"
-#define MSU_INTERFACE_PROP_REFPATH "RefPath"
-#define MSU_INTERFACE_PROP_RESTRICTED "Restricted"
+#define MSU_INTERFACE_PROP_RESOURCES "Resources"
-#define MSU_INTERFACE_PROP_SIZE "Size"
-#define MSU_INTERFACE_PROP_DURATION "Duration"
-#define MSU_INTERFACE_PROP_BITRATE "Bitrate"
-#define MSU_INTERFACE_PROP_SAMPLE_RATE "SampleRate"
-#define MSU_INTERFACE_PROP_BITS_PER_SAMPLE "BitsPerSample"
-#define MSU_INTERFACE_PROP_WIDTH "Width"
-#define MSU_INTERFACE_PROP_HEIGHT "Height"
-#define MSU_INTERFACE_PROP_COLOR_DEPTH "ColorDepth"
+/* Container Properties */
+#define MSU_INTERFACE_PROP_SEARCHABLE "Searchable"
+#define MSU_INTERFACE_PROP_CHILD_COUNT "ChildCount"
+#define MSU_INTERFACE_PROP_CREATE_CLASSES "CreateClasses"
+/* Device Properties */
#define MSU_INTERFACE_PROP_LOCATION "Location"
#define MSU_INTERFACE_PROP_UDN "UDN"
#define MSU_INTERFACE_PROP_DEVICE_TYPE "DeviceType"
#define MSU_INTERFACE_PROP_MODEL_URL "ModelURL"
#define MSU_INTERFACE_PROP_SERIAL_NUMBER "SerialNumber"
#define MSU_INTERFACE_PROP_PRESENTATION_URL "PresentationURL"
+#define MSU_INTERFACE_PROP_ICON_URL "IconURL"
+#define MSU_INTERFACE_PROP_SV_DLNA_CAPABILITIES "DLNACaps"
+#define MSU_INTERFACE_PROP_SV_SEARCH_CAPABILITIES "SearchCaps"
+#define MSU_INTERFACE_PROP_SV_SORT_CAPABILITIES "SortCaps"
+#define MSU_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES "SortExtCaps"
+#define MSU_INTERFACE_PROP_SV_FEATURE_LIST "FeatureList"
+
+/* Resources Properties */
+#define MSU_INTERFACE_PROP_MIME_TYPE "MIMEType"
+#define MSU_INTERFACE_PROP_DLNA_PROFILE "DLNAProfile"
+#define MSU_INTERFACE_PROP_SIZE "Size"
+#define MSU_INTERFACE_PROP_DURATION "Duration"
+#define MSU_INTERFACE_PROP_BITRATE "Bitrate"
+#define MSU_INTERFACE_PROP_SAMPLE_RATE "SampleRate"
+#define MSU_INTERFACE_PROP_BITS_PER_SAMPLE "BitsPerSample"
+#define MSU_INTERFACE_PROP_WIDTH "Width"
+#define MSU_INTERFACE_PROP_HEIGHT "Height"
+#define MSU_INTERFACE_PROP_COLOR_DEPTH "ColorDepth"
+#define MSU_INTERFACE_PROP_URLS "URLs"
+#define MSU_INTERFACE_PROP_URL "URL"
+
+/* Evented State Variable Properties */
+#define MSU_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID "SystemUpdateID"
+#define MSU_INTERFACE_PROP_ESV_SERVICE_RESET_TOKEN "ServiceResetToken"
#define MSU_INTERFACE_GET_VERSION "GetVersion"
#define MSU_INTERFACE_GET_SERVERS "GetServers"
#define MSU_INTERFACE_RELEASE "Release"
#define MSU_INTERFACE_SET_PROTOCOL_INFO "SetProtocolInfo"
+#define MSU_INTERFACE_PREFER_LOCAL_ADDRESSES "PreferLocalAddresses"
#define MSU_INTERFACE_FOUND_SERVER "FoundServer"
#define MSU_INTERFACE_LOST_SERVER "LostServer"
#define MSU_INTERFACE_LIST_CONTAINERS_EX "ListContainersEx"
#define MSU_INTERFACE_SEARCH_OBJECTS "SearchObjects"
#define MSU_INTERFACE_SEARCH_OBJECTS_EX "SearchObjectsEx"
-#define MSU_INTERFACE_UPLOAD "Upload"
+#define MSU_INTERFACE_UPDATE "Update"
#define MSU_INTERFACE_GET_COMPATIBLE_RESOURCE "GetCompatibleResource"
#define MSU_INTERFACE_PROPERTY_NAME "PropertyName"
#define MSU_INTERFACE_PROPERTIES_VALUE "Properties"
#define MSU_INTERFACE_VALUE "value"
+#define MSU_INTERFACE_CHILD_TYPES "ChildTypes"
#define MSU_INTERFACE_VERSION "Version"
#define MSU_INTERFACE_SERVERS "Servers"
#define MSU_INTERFACE_PATH "Path"
#define MSU_INTERFACE_QUERY "Query"
#define MSU_INTERFACE_PROTOCOL_INFO "ProtocolInfo"
+#define MSU_INTERFACE_PREFER "Prefer"
#define MSU_INTERFACE_OFFSET "Offset"
#define MSU_INTERFACE_MAX "Max"
#define MSU_INTERFACE_SORT_BY "SortBy"
#define MSU_INTERFACE_TOTAL_ITEMS "TotalItems"
-#define MSU_INTERFACE_SYSTEM_UPDATE "SystemUpdate"
+#define MSU_INTERFACE_PROPERTIES_CHANGED "PropertiesChanged"
+#define MSU_INTERFACE_CHANGED_PROPERTIES "ChangedProperties"
+#define MSU_INTERFACE_INVALIDATED_PROPERTIES "InvalidatedProperties"
#define MSU_INTERFACE_SYSTEM_UPDATE_ID "SystemUpdateId"
#define MSU_INTERFACE_CONTAINER_UPDATE "ContainerUpdate"
#define MSU_INTERFACE_CONTAINER_PATHS "ContainerPaths"
+#define MSU_INTERFACE_DELETE "Delete"
+
+#define MSU_INTERFACE_CREATE_CONTAINER "CreateContainer"
+#define MSU_INTERFACE_CREATE_CONTAINER_IN_ANY "CreateContainerInAnyContainer"
+
+#define MSU_INTERFACE_UPLOAD "Upload"
#define MSU_INTERFACE_UPLOAD_TO_ANY "UploadToAnyContainer"
+#define MSU_INTERFACE_GET_UPLOAD_STATUS "GetUploadStatus"
+#define MSU_INTERFACE_GET_UPLOAD_IDS "GetUploadIDs"
+#define MSU_INTERFACE_CANCEL_UPLOAD "CancelUpload"
+#define MSU_INTERFACE_TOTAL "Total"
+#define MSU_INTERFACE_LENGTH "Length"
#define MSU_INTERFACE_FILE_PATH "FilePath"
#define MSU_INTERFACE_UPLOAD_ID "UploadId"
-
+#define MSU_INTERFACE_UPLOAD_IDS "UploadIDs"
+#define MSU_INTERFACE_UPLOAD_STATUS "UploadStatus"
+#define MSU_INTERFACE_UPLOAD_UPDATE "UploadUpdate"
+#define MSU_INTERFACE_TO_ADD_UPDATE "ToAddUpdate"
+#define MSU_INTERFACE_TO_DELETE "ToDelete"
#endif
+
#include <syslog.h>
#include <sys/signalfd.h>
+#include "client.h"
#include "interface.h"
#include "log.h"
#include "settings.h"
#include "task.h"
#include "upnp.h"
-typedef struct msu_client_t_ msu_client_t;
-struct msu_client_t_ {
- guint id;
- gchar *protocol_info;
-};
-
typedef struct msu_context_t_ msu_context_t;
struct msu_context_t_ {
bool error;
msu_settings_context_t *settings;
};
+static msu_context_t g_context;
+
static const gchar g_msu_root_introspection[] =
"<node>"
" <interface name='"MSU_INTERFACE_MANAGER"'>"
" <arg type='s' name='"MSU_INTERFACE_PROTOCOL_INFO"'"
" direction='in'/>"
" </method>"
+ " <method name='"MSU_INTERFACE_PREFER_LOCAL_ADDRESSES"'>"
+ " <arg type='b' name='"MSU_INTERFACE_PREFER"'"
+ " direction='in'/>"
+ " </method>"
" <signal name='"MSU_INTERFACE_FOUND_SERVER"'>"
" <arg type='o' name='"MSU_INTERFACE_PATH"'/>"
" </signal>"
" <arg type='a{sv}' name='"MSU_INTERFACE_PROPERTIES_VALUE"'"
" direction='out'/>"
" </method>"
+ " <signal name='"MSU_INTERFACE_PROPERTIES_CHANGED"'>"
+ " <arg type='s' name='"MSU_INTERFACE_INTERFACE_NAME"'/>"
+ " <arg type='a{sv}' name='"MSU_INTERFACE_CHANGED_PROPERTIES"'/>"
+ " <arg type='as' name='"MSU_INTERFACE_INVALIDATED_PROPERTIES"'/>"
+ " </signal>"
" </interface>"
" <interface name='"MSU_INTERFACE_MEDIA_OBJECT"'>"
" <property type='o' name='"MSU_INTERFACE_PROP_PARENT"'"
" access='read'/>"
" <property type='s' name='"MSU_INTERFACE_PROP_DISPLAY_NAME"'"
" access='read'/>"
+ " <property type='s' name='"MSU_INTERFACE_PROP_CREATOR"'"
+ " access='read'/>"
" <property type='b' name='"MSU_INTERFACE_PROP_RESTRICTED"'"
" access='read'/>"
+ " <property type='a{sb}' name='"MSU_INTERFACE_PROP_DLNA_MANAGED"'"
+ " access='read'/>"
+ " <method name='"MSU_INTERFACE_DELETE"'>"
+ " </method>"
+ " <method name='"MSU_INTERFACE_UPDATE"'>"
+ " <arg type='a{sv}' name='"MSU_INTERFACE_TO_ADD_UPDATE"'"
+ " direction='in'/>"
+ " <arg type='as' name='"MSU_INTERFACE_TO_DELETE"'"
+ " direction='in'/>"
+ " </method>"
" </interface>"
" <interface name='"MSU_INTERFACE_MEDIA_CONTAINER"'>"
" <method name='"MSU_INTERFACE_LIST_CHILDREN"'>"
" <arg type='o' name='"MSU_INTERFACE_PATH"'"
" direction='out'/>"
" </method>"
+ " <method name='"MSU_INTERFACE_CREATE_CONTAINER"'>"
+ " <arg type='s' name='"MSU_INTERFACE_PROP_DISPLAY_NAME"'"
+ " direction='in'/>"
+ " <arg type='s' name='"MSU_INTERFACE_PROP_TYPE"'"
+ " direction='in'/>"
+ " <arg type='as' name='"MSU_INTERFACE_CHILD_TYPES"'"
+ " direction='in'/>"
+ " <arg type='o' name='"MSU_INTERFACE_PATH"'"
+ " direction='out'/>"
+ " </method>"
" <property type='u' name='"MSU_INTERFACE_PROP_CHILD_COUNT"'"
" access='read'/>"
" <property type='b' name='"MSU_INTERFACE_PROP_SEARCHABLE"'"
" access='read'/>"
+ " <property type='a(sb)' name='"MSU_INTERFACE_PROP_CREATE_CLASSES"'"
+ " access='read'/>"
" </interface>"
" <interface name='"MSU_INTERFACE_MEDIA_ITEM"'>"
" <method name='"MSU_INTERFACE_GET_COMPATIBLE_RESOURCE"'>"
" access='read'/>"
" <property type='s' name='"MSU_INTERFACE_PROP_ARTIST"'"
" access='read'/>"
+ " <property type='as' name='"MSU_INTERFACE_PROP_ARTISTS"'"
+ " access='read'/>"
" <property type='s' name='"MSU_INTERFACE_PROP_ALBUM"'"
" access='read'/>"
" <property type='s' name='"MSU_INTERFACE_PROP_DATE"'"
" <arg type='o' name='"MSU_INTERFACE_PATH"'"
" direction='out'/>"
" </method>"
+ " <method name='"MSU_INTERFACE_GET_UPLOAD_STATUS"'>"
+ " <arg type='u' name='"MSU_INTERFACE_UPLOAD_ID"'"
+ " direction='in'/>"
+ " <arg type='s' name='"MSU_INTERFACE_UPLOAD_STATUS"'"
+ " direction='out'/>"
+ " <arg type='t' name='"MSU_INTERFACE_LENGTH"'"
+ " direction='out'/>"
+ " <arg type='t' name='"MSU_INTERFACE_TOTAL"'"
+ " direction='out'/>"
+ " </method>"
+ " <method name='"MSU_INTERFACE_GET_UPLOAD_IDS"'>"
+ " <arg type='au' name='"MSU_INTERFACE_TOTAL"'"
+ " direction='out'/>"
+ " </method>"
+ " <method name='"MSU_INTERFACE_CANCEL_UPLOAD"'>"
+ " <arg type='u' name='"MSU_INTERFACE_UPLOAD_ID"'"
+ " direction='in'/>"
+ " </method>"
+ " <method name='"MSU_INTERFACE_CREATE_CONTAINER_IN_ANY"'>"
+ " <arg type='s' name='"MSU_INTERFACE_PROP_DISPLAY_NAME"'"
+ " direction='in'/>"
+ " <arg type='s' name='"MSU_INTERFACE_PROP_TYPE"'"
+ " direction='in'/>"
+ " <arg type='as' name='"MSU_INTERFACE_CHILD_TYPES"'"
+ " direction='in'/>"
+ " <arg type='o' name='"MSU_INTERFACE_PATH"'"
+ " direction='out'/>"
+ " </method>"
" <property type='s' name='"MSU_INTERFACE_PROP_LOCATION"'"
" access='read'/>"
" <property type='s' name='"MSU_INTERFACE_PROP_UDN"'"
" access='read'/>"
" <property type='s' name='"MSU_INTERFACE_PROP_ICON_URL"'"
" access='read'/>"
- " <signal name='"MSU_INTERFACE_SYSTEM_UPDATE"'>"
- " <arg type='u' name='"MSU_INTERFACE_SYSTEM_UPDATE_ID"'/>"
- " </signal>"
+ " <property type='a{sv}'name='"
+ MSU_INTERFACE_PROP_SV_DLNA_CAPABILITIES"'"
+ " access='read'/>"
+ " <property type='as' name='"
+ MSU_INTERFACE_PROP_SV_SEARCH_CAPABILITIES"'"
+ " access='read'/>"
+ " <property type='as' name='"
+ MSU_INTERFACE_PROP_SV_SORT_CAPABILITIES"'"
+ " access='read'/>"
+ " <property type='as' name='"
+ MSU_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES"'"
+ " access='read'/>"
+ " <property type='a(ssao)' name='"
+ MSU_INTERFACE_PROP_SV_FEATURE_LIST"'"
+ " access='read'/>"
+ " <property type='u' name='"
+ MSU_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID"'"
+ " access='read'/>"
+ " <property type='s' name='"
+ MSU_INTERFACE_PROP_ESV_SERVICE_RESET_TOKEN"'"
+ " access='read'/>"
" <signal name='"MSU_INTERFACE_CONTAINER_UPDATE"'>"
" <arg type='ao' name='"MSU_INTERFACE_CONTAINER_PATHS"'/>"
" </signal>"
+ " <signal name='"MSU_INTERFACE_UPLOAD_UPDATE"'>"
+ " <arg type='u' name='"MSU_INTERFACE_UPLOAD_ID"'/>"
+ " <arg type='s' name='"MSU_INTERFACE_UPLOAD_STATUS"'/>"
+ " <arg type='t' name='"MSU_INTERFACE_LENGTH"'/>"
+ " <arg type='t' name='"MSU_INTERFACE_TOTAL"'/>"
+ " </signal>"
" </interface>"
"</node>";
msu_task_delete(data);
}
-static void prv_process_sync_task(msu_context_t *context, msu_task_t *task)
+static void prv_process_sync_task(msu_task_t *task)
{
const gchar *client_name;
msu_client_t *client;
- context->current_task = task;
+ g_context.current_task = task;
switch (task->type) {
case MSU_TASK_GET_VERSION:
msu_task_complete_and_delete(task);
break;
case MSU_TASK_GET_SERVERS:
- task->result = msu_upnp_get_server_ids(context->upnp);
+ task->result = msu_upnp_get_server_ids(g_context.upnp);
msu_task_complete_and_delete(task);
break;
case MSU_TASK_SET_PROTOCOL_INFO:
client_name =
g_dbus_method_invocation_get_sender(task->invocation);
- client = g_hash_table_lookup(context->watchers, client_name);
+ client = g_hash_table_lookup(g_context.watchers, client_name);
if (client) {
g_free(client->protocol_info);
if (task->ut.protocol_info.protocol_info[0]) {
}
msu_task_complete_and_delete(task);
break;
-
+ case MSU_TASK_SET_PREFER_LOCAL_ADDRESSES:
+ client_name =
+ g_dbus_method_invocation_get_sender(task->invocation);
+ client = g_hash_table_lookup(g_context.watchers, client_name);
+ if (client) {
+ client->prefer_local_addresses =
+ task->ut.prefer_local_addresses.prefer;
+ }
+ msu_task_complete_and_delete(task);
+ break;
+ case MSU_TASK_GET_UPLOAD_STATUS:
+ msu_upnp_get_upload_status(g_context.upnp, task);
+ break;
+ case MSU_TASK_GET_UPLOAD_IDS:
+ msu_upnp_get_upload_ids(g_context.upnp, task);
+ break;
+ case MSU_TASK_CANCEL_UPLOAD:
+ msu_upnp_cancel_upload(g_context.upnp, task);
+ break;
default:
break;
}
- context->current_task = NULL;
+ g_context.current_task = NULL;
}
static void prv_async_task_complete(msu_task_t *task, GVariant *result,
- GError *error, void *user_data)
+ GError *error)
{
- msu_context_t *context = user_data;
-
MSU_LOG_DEBUG("Enter");
- g_object_unref(context->cancellable);
- context->cancellable = NULL;
- context->current_task = NULL;
+ g_object_unref(g_context.cancellable);
+ g_context.cancellable = NULL;
+ g_context.current_task = NULL;
if (error) {
msu_task_fail_and_delete(task, error);
msu_task_complete_and_delete(task);
}
- if (context->quitting)
- g_main_loop_quit(context->main_loop);
- else if (context->tasks->len > 0)
- context->idle_id = g_idle_add(prv_process_task, context);
+ if (g_context.quitting)
+ g_main_loop_quit(g_context.main_loop);
+ else if (g_context.tasks->len > 0)
+ g_context.idle_id = g_idle_add(prv_process_task, NULL);
MSU_LOG_DEBUG("Exit");
}
-static void prv_process_async_task(msu_context_t *context, msu_task_t *task)
+static void prv_process_async_task(msu_task_t *task)
{
const gchar *client_name;
msu_client_t *client;
- const gchar *protocol_info = NULL;
MSU_LOG_DEBUG("Enter");
- context->cancellable = g_cancellable_new();
- context->current_task = task;
+ g_context.cancellable = g_cancellable_new();
+ g_context.current_task = task;
client_name =
g_dbus_method_invocation_get_sender(task->invocation);
- client = g_hash_table_lookup(context->watchers, client_name);
- if (client)
- protocol_info = client->protocol_info;
+ client = g_hash_table_lookup(g_context.watchers, client_name);
switch (task->type) {
case MSU_TASK_GET_CHILDREN:
- msu_upnp_get_children(context->upnp, task, protocol_info,
- context->cancellable,
- prv_async_task_complete, context);
+ msu_upnp_get_children(g_context.upnp, client, task,
+ g_context.cancellable,
+ prv_async_task_complete);
break;
case MSU_TASK_GET_PROP:
- msu_upnp_get_prop(context->upnp, task, protocol_info,
- context->cancellable,
- prv_async_task_complete, context);
+ msu_upnp_get_prop(g_context.upnp, client, task,
+ g_context.cancellable,
+ prv_async_task_complete);
break;
case MSU_TASK_GET_ALL_PROPS:
- msu_upnp_get_all_props(context->upnp, task, protocol_info,
- context->cancellable,
- prv_async_task_complete, context);
+ msu_upnp_get_all_props(g_context.upnp, client, task,
+ g_context.cancellable,
+ prv_async_task_complete);
break;
case MSU_TASK_SEARCH:
- msu_upnp_search(context->upnp, task, protocol_info,
- context->cancellable,
- prv_async_task_complete, context);
+ msu_upnp_search(g_context.upnp, client, task,
+ g_context.cancellable,
+ prv_async_task_complete);
break;
case MSU_TASK_GET_RESOURCE:
- msu_upnp_get_resource(context->upnp, task,
- context->cancellable,
- prv_async_task_complete, context);
+ msu_upnp_get_resource(g_context.upnp, client, task,
+ g_context.cancellable,
+ prv_async_task_complete);
break;
case MSU_TASK_UPLOAD_TO_ANY:
- msu_upnp_upload_to_any(context->upnp, task,
- context->cancellable,
- prv_async_task_complete, context);
+ msu_upnp_upload_to_any(g_context.upnp, client, task,
+ g_context.cancellable,
+ prv_async_task_complete);
break;
case MSU_TASK_UPLOAD:
- msu_upnp_upload(context->upnp, task, context->cancellable,
- prv_async_task_complete, context);
+ msu_upnp_upload(g_context.upnp, client, task,
+ g_context.cancellable,
+ prv_async_task_complete);
+ break;
+ case MSU_TASK_DELETE_OBJECT:
+ msu_upnp_delete_object(g_context.upnp, client, task,
+ g_context.cancellable,
+ prv_async_task_complete);
+ break;
+ case MSU_TASK_CREATE_CONTAINER:
+ msu_upnp_create_container(g_context.upnp, client, task,
+ g_context.cancellable,
+ prv_async_task_complete);
+ break;
+ case MSU_TASK_CREATE_CONTAINER_IN_ANY:
+ msu_upnp_create_container_in_any(g_context.upnp, client, task,
+ g_context.cancellable,
+ prv_async_task_complete);
+ break;
+ case MSU_TASK_UPDATE_OBJECT:
+ msu_upnp_update_object(g_context.upnp, client, task,
+ g_context.cancellable,
+ prv_async_task_complete);
break;
default:
break;
static gboolean prv_process_task(gpointer user_data)
{
- msu_context_t *context = user_data;
msu_task_t *task;
gboolean retval = FALSE;
- if (context->tasks->len > 0) {
- task = g_ptr_array_index(context->tasks, 0);
+ if (g_context.tasks->len > 0) {
+ task = g_ptr_array_index(g_context.tasks, 0);
if (task->synchronous) {
- prv_process_sync_task(context, task);
+ prv_process_sync_task(task);
retval = TRUE;
} else {
- prv_process_async_task(context, task);
- context->idle_id = 0;
+ prv_process_async_task(task);
+ g_context.idle_id = 0;
}
- g_ptr_array_remove_index(context->tasks, 0);
+ g_ptr_array_remove_index(g_context.tasks, 0);
} else {
- context->idle_id = 0;
+ g_context.idle_id = 0;
}
return retval;
GDBusMethodInvocation *invocation,
gpointer user_data);
+static void prv_object_method_call(GDBusConnection *conn,
+ const gchar *sender,
+ const gchar *object,
+ const gchar *interface,
+ const gchar *method,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data);
+
static void prv_item_method_call(GDBusConnection *conn,
const gchar *sender,
const gchar *object,
NULL
};
+static const GDBusInterfaceVTable g_object_vtable = {
+ prv_object_method_call,
+ NULL,
+ NULL
+};
+
static const GDBusInterfaceVTable g_item_vtable = {
prv_item_method_call,
NULL,
static const GDBusInterfaceVTable *g_server_vtables[MSU_INTERFACE_INFO_MAX] = {
&g_props_vtable,
- NULL,
+ &g_object_vtable,
&g_ms_vtable,
&g_item_vtable,
&g_device_vtable
};
-static void prv_msu_context_init(msu_context_t *context)
+static void prv_msu_context_init(void)
{
- memset(context, 0, sizeof(*context));
+ memset(&g_context, 0, sizeof(g_context));
}
-static void prv_msu_context_free(msu_context_t *context)
+static void prv_msu_context_free(void)
{
- msu_upnp_delete(context->upnp);
+ msu_upnp_delete(g_context.upnp);
- if (context->watchers)
- g_hash_table_unref(context->watchers);
+ if (g_context.watchers)
+ g_hash_table_unref(g_context.watchers);
- if (context->tasks) {
- g_ptr_array_foreach(context->tasks, prv_free_msu_task_cb, NULL);
- g_ptr_array_unref(context->tasks);
+ if (g_context.tasks) {
+ g_ptr_array_foreach(g_context.tasks, prv_free_msu_task_cb,
+ NULL);
+ g_ptr_array_unref(g_context.tasks);
}
- if (context->idle_id)
- (void) g_source_remove(context->idle_id);
+ if (g_context.idle_id)
+ (void) g_source_remove(g_context.idle_id);
- if (context->sig_id)
- (void) g_source_remove(context->sig_id);
+ if (g_context.sig_id)
+ (void) g_source_remove(g_context.sig_id);
- if (context->connection) {
- if (context->msu_id)
+ if (g_context.connection) {
+ if (g_context.msu_id)
g_dbus_connection_unregister_object(
- context->connection,
- context->msu_id);
+ g_context.connection,
+ g_context.msu_id);
}
- if (context->owner_id)
- g_bus_unown_name(context->owner_id);
+ if (g_context.owner_id)
+ g_bus_unown_name(g_context.owner_id);
- if (context->connection)
- g_object_unref(context->connection);
+ if (g_context.connection)
+ g_object_unref(g_context.connection);
- if (context->main_loop)
- g_main_loop_unref(context->main_loop);
+ if (g_context.main_loop)
+ g_main_loop_unref(g_context.main_loop);
- if (context->server_node_info)
- g_dbus_node_info_unref(context->server_node_info);
+ if (g_context.server_node_info)
+ g_dbus_node_info_unref(g_context.server_node_info);
- if (context->root_node_info)
- g_dbus_node_info_unref(context->root_node_info);
+ if (g_context.root_node_info)
+ g_dbus_node_info_unref(g_context.root_node_info);
- if (context->settings)
- msu_settings_delete(context->settings);
+ if (g_context.settings)
+ msu_settings_delete(g_context.settings);
}
-static void prv_quit(msu_context_t *context)
+static void prv_quit(void)
{
- if (context->cancellable) {
- g_cancellable_cancel(context->cancellable);
- context->quitting = TRUE;
+ if (g_context.cancellable) {
+ g_cancellable_cancel(g_context.cancellable);
+ g_context.quitting = TRUE;
} else {
- g_main_loop_quit(context->main_loop);
+ g_main_loop_quit(g_context.main_loop);
}
}
-static void prv_remove_client(msu_context_t *context, const gchar *name)
+static void prv_remove_client(const gchar *name)
{
const gchar *client_name;
msu_task_t *task;
guint pos;
- if (context->cancellable) {
+ if (g_context.cancellable) {
client_name = g_dbus_method_invocation_get_sender(
- context->current_task->invocation);
+ g_context.current_task->invocation);
if (!strcmp(client_name, name)) {
MSU_LOG_DEBUG("Cancelling current task, type is %d",
- context->current_task->type);
+ g_context.current_task->type);
- g_cancellable_cancel(context->cancellable);
+ g_cancellable_cancel(g_context.cancellable);
}
}
pos = 0;
- while (pos < context->tasks->len) {
- task = (msu_task_t *) g_ptr_array_index(context->tasks, pos);
+ while (pos < g_context.tasks->len) {
+ task = (msu_task_t *) g_ptr_array_index(g_context.tasks, pos);
client_name = g_dbus_method_invocation_get_sender(
task->invocation);
MSU_LOG_DEBUG("Removing task type %d from array", task->type);
- (void) g_ptr_array_remove_index(context->tasks, pos);
+ (void) g_ptr_array_remove_index(g_context.tasks, pos);
msu_task_cancel_and_delete(task);
}
- (void) g_hash_table_remove(context->watchers, name);
+ (void) g_hash_table_remove(g_context.watchers, name);
- if (g_hash_table_size(context->watchers) == 0)
- if (!msu_settings_is_never_quit(context->settings))
- prv_quit(context);
+ if (g_hash_table_size(g_context.watchers) == 0)
+ if (!msu_settings_is_never_quit(g_context.settings))
+ prv_quit();
}
static void prv_lost_client(GDBusConnection *connection, const gchar *name,
{
MSU_LOG_DEBUG("Lost Client %s", name);
- prv_remove_client(user_data, name);
+ prv_remove_client(name);
}
-static void prv_add_task(msu_context_t *context, msu_task_t *task)
+static void prv_add_task(msu_task_t *task)
{
const gchar *client_name;
msu_client_t *client;
client_name = g_dbus_method_invocation_get_sender(task->invocation);
- if (!g_hash_table_lookup(context->watchers, client_name)) {
+ if (!g_hash_table_lookup(g_context.watchers, client_name)) {
client = g_new0(msu_client_t, 1);
+ client->prefer_local_addresses = TRUE;
client->id = g_bus_watch_name(G_BUS_TYPE_SESSION, client_name,
G_BUS_NAME_WATCHER_FLAGS_NONE,
- NULL, prv_lost_client, context,
+ NULL, prv_lost_client, NULL,
NULL);
- g_hash_table_insert(context->watchers, g_strdup(client_name),
+ g_hash_table_insert(g_context.watchers, g_strdup(client_name),
client);
}
- if (!context->cancellable && !context->idle_id)
- context->idle_id = g_idle_add(prv_process_task, context);
+ if (!g_context.cancellable && !g_context.idle_id)
+ g_context.idle_id = g_idle_add(prv_process_task, NULL);
- g_ptr_array_add(context->tasks, task);
+ g_ptr_array_add(g_context.tasks, task);
}
static void prv_msu_method_call(GDBusConnection *conn,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
- msu_context_t *context = user_data;
const gchar *client_name;
msu_task_t *task;
if (!strcmp(method, MSU_INTERFACE_RELEASE)) {
client_name = g_dbus_method_invocation_get_sender(invocation);
- prv_remove_client(context, client_name);
+ prv_remove_client(client_name);
g_dbus_method_invocation_return_value(invocation, NULL);
} else if (!strcmp(method, MSU_INTERFACE_GET_VERSION)) {
task = msu_task_get_version_new(invocation);
- prv_add_task(context, task);
+ prv_add_task(task);
} else if (!strcmp(method, MSU_INTERFACE_GET_SERVERS)) {
task = msu_task_get_servers_new(invocation);
- prv_add_task(context, task);
+ prv_add_task(task);
} else if (!strcmp(method, MSU_INTERFACE_SET_PROTOCOL_INFO)) {
task = msu_task_set_protocol_info_new(invocation, parameters);
- prv_add_task(context, task);
+ prv_add_task(task);
+ } else if (!strcmp(method, MSU_INTERFACE_PREFER_LOCAL_ADDRESSES)) {
+ task = msu_task_prefer_local_addresses_new(invocation,
+ parameters);
+ prv_add_task(task);
}
}
+static void prv_object_method_call(GDBusConnection *conn,
+ const gchar *sender, const gchar *object,
+ const gchar *interface,
+ const gchar *method, GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ msu_task_t *task;
+
+ if (!strcmp(method, MSU_INTERFACE_DELETE)) {
+ task = msu_task_delete_new(invocation, object);
+ } else if (!strcmp(method, MSU_INTERFACE_UPDATE))
+ task = msu_task_update_new(invocation, object, parameters);
+ else
+ goto finished;
+
+ prv_add_task(task);
+
+finished:
+
+ return;
+}
+
static void prv_item_method_call(GDBusConnection *conn,
const gchar *sender, const gchar *object,
const gchar *interface,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
- msu_context_t *context = user_data;
msu_task_t *task;
if (!strcmp(method, MSU_INTERFACE_GET_COMPATIBLE_RESOURCE)) {
task = msu_task_get_resource_new(invocation, object,
parameters);
- prv_add_task(context, task);
+ prv_add_task(task);
}
}
GDBusMethodInvocation *invocation,
gpointer user_data)
{
- msu_context_t *context = user_data;
msu_task_t *task;
if (!strcmp(method, MSU_INTERFACE_LIST_CHILDREN))
parameters);
else if (!strcmp(method, MSU_INTERFACE_UPLOAD))
task = msu_task_upload_new(invocation, object, parameters);
+ else if (!strcmp(method, MSU_INTERFACE_CREATE_CONTAINER))
+ task = msu_task_create_container_new_generic(invocation,
+ MSU_TASK_CREATE_CONTAINER,
+ object, parameters);
else
goto finished;
- prv_add_task(context, task);
+ prv_add_task(task);
finished:
GDBusMethodInvocation *invocation,
gpointer user_data)
{
- msu_context_t *context = user_data;
msu_task_t *task;
if (!strcmp(method, MSU_INTERFACE_GET_ALL))
else
goto finished;
- prv_add_task(context, task);
+ prv_add_task(task);
finished:
GDBusMethodInvocation *invocation,
gpointer user_data)
{
- msu_context_t *context = user_data;
msu_task_t *task;
if (!strcmp(method, MSU_INTERFACE_UPLOAD_TO_ANY)) {
task = msu_task_upload_to_any_new(invocation, object,
parameters);
- prv_add_task(context, task);
+ prv_add_task(task);
+ } else if (!strcmp(method, MSU_INTERFACE_CREATE_CONTAINER_IN_ANY)) {
+ task = msu_task_create_container_new_generic(invocation,
+ MSU_TASK_CREATE_CONTAINER_IN_ANY,
+ object, parameters);
+ prv_add_task(task);
+ } else if (!strcmp(method, MSU_INTERFACE_GET_UPLOAD_STATUS)) {
+ task = msu_task_get_upload_status_new(invocation, object,
+ parameters);
+ prv_add_task(task);
+ } else if (!strcmp(method, MSU_INTERFACE_GET_UPLOAD_IDS)) {
+ task = msu_task_get_upload_ids_new(invocation, object);
+ prv_add_task(task);
+ } else if (!strcmp(method, MSU_INTERFACE_CANCEL_UPLOAD)) {
+ task = msu_task_cancel_upload_new(invocation, object,
+ parameters);
+ prv_add_task(task);
}
}
static void prv_found_media_server(const gchar *path, void *user_data)
{
- msu_context_t *context = user_data;
-
- (void) g_dbus_connection_emit_signal(context->connection,
+ (void) g_dbus_connection_emit_signal(g_context.connection,
NULL,
MSU_OBJECT,
MSU_INTERFACE_MANAGER,
static void prv_lost_media_server(const gchar *path, void *user_data)
{
- msu_context_t *context = user_data;
-
- (void) g_dbus_connection_emit_signal(context->connection,
+ (void) g_dbus_connection_emit_signal(g_context.connection,
NULL,
MSU_OBJECT,
MSU_INTERFACE_MANAGER,
static void prv_bus_acquired(GDBusConnection *connection, const gchar *name,
gpointer user_data)
{
- msu_context_t *context = user_data;
msu_interface_info_t *info;
unsigned int i;
- context->connection = connection;
+ g_context.connection = connection;
- context->msu_id =
+ g_context.msu_id =
g_dbus_connection_register_object(connection, MSU_OBJECT,
- context->root_node_info->
+ g_context.root_node_info->
interfaces[0],
&g_msu_vtable,
user_data, NULL, NULL);
- if (!context->msu_id) {
- context->error = true;
- g_main_loop_quit(context->main_loop);
+ if (!g_context.msu_id) {
+ g_context.error = true;
+ g_main_loop_quit(g_context.main_loop);
} else {
info = g_new(msu_interface_info_t, MSU_INTERFACE_INFO_MAX);
for (i = 0; i < MSU_INTERFACE_INFO_MAX; ++i) {
info[i].interface =
- context->server_node_info->interfaces[i];
+ g_context.server_node_info->interfaces[i];
info[i].vtable = g_server_vtables[i];
}
- context->upnp = msu_upnp_new(connection, info,
+ g_context.upnp = msu_upnp_new(connection, info,
prv_found_media_server,
prv_lost_media_server,
user_data);
static void prv_name_lost(GDBusConnection *connection, const gchar *name,
gpointer user_data)
{
- msu_context_t *context = user_data;
-
- context->connection = NULL;
+ g_context.connection = NULL;
- prv_quit(context);
+ prv_quit();
}
static gboolean prv_quit_handler(GIOChannel *source, GIOCondition condition,
gpointer user_data)
{
- msu_context_t *context = user_data;
-
- prv_quit(context);
- context->sig_id = 0;
+ prv_quit();
+ g_context.sig_id = 0;
return FALSE;
}
-static bool prv_init_signal_handler(sigset_t mask, msu_context_t *context)
+static bool prv_init_signal_handler(sigset_t mask)
{
bool retval = false;
int fd = -1;
G_IO_STATUS_NORMAL)
goto on_error;
- context->sig_id = g_io_add_watch(channel, G_IO_IN | G_IO_PRI,
+ g_context.sig_id = g_io_add_watch(channel, G_IO_IN | G_IO_PRI,
prv_quit_handler,
- context);
+ NULL);
retval = true;
int main(int argc, char *argv[])
{
- msu_context_t context;
-
sigset_t mask;
int retval = 1;
- prv_msu_context_init(&context);
+ prv_msu_context_init();
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
g_type_init();
msu_log_init(argv[0]);
- msu_settings_new(&context.settings);
+ msu_settings_new(&g_context.settings);
- context.root_node_info =
+ g_context.root_node_info =
g_dbus_node_info_new_for_xml(g_msu_root_introspection, NULL);
- if (!context.root_node_info)
+ if (!g_context.root_node_info)
goto on_error;
- context.server_node_info =
+ g_context.server_node_info =
g_dbus_node_info_new_for_xml(g_msu_server_introspection, NULL);
- if (!context.server_node_info)
+ if (!g_context.server_node_info)
goto on_error;
- context.main_loop = g_main_loop_new(NULL, FALSE);
+ g_context.main_loop = g_main_loop_new(NULL, FALSE);
- context.owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
+ g_context.owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
MSU_SERVER_NAME,
G_BUS_NAME_OWNER_FLAGS_NONE,
prv_bus_acquired, NULL,
- prv_name_lost, &context, NULL);
+ prv_name_lost, NULL, NULL);
- context.tasks = g_ptr_array_new();
+ g_context.tasks = g_ptr_array_new();
- context.watchers = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_context.watchers = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, prv_unregister_client);
- if (!prv_init_signal_handler(mask, &context))
+ if (!prv_init_signal_handler(mask))
goto on_error;
- g_main_loop_run(context.main_loop);
- if (context.error)
+ g_main_loop_run(g_context.main_loop);
+ if (g_context.error)
goto on_error;
retval = 0;
on_error:
- prv_msu_context_free(&context);
+ prv_msu_context_free();
msu_log_finalize();
return retval;
}
+
*/
#include <string.h>
+#include <libgupnp-av/gupnp-didl-lite-contributor.h>
+#include "device.h"
#include "interface.h"
#include "log.h"
#include "path.h"
static msu_prop_map_t *prv_msu_prop_map_new(const gchar *prop_name,
msu_upnp_prop_mask type,
gboolean filter,
- gboolean searchable)
+ gboolean searchable,
+ gboolean updateable)
{
msu_prop_map_t *retval = g_new(msu_prop_map_t, 1);
retval->upnp_prop_name = prop_name;
retval->type = type;
retval->filter = filter;
retval->searchable = searchable;
+ retval->updateable = updateable;
return retval;
}
-GHashTable *msu_prop_maps_new()
+void msu_prop_maps_new(GHashTable **property_map, GHashTable **filter_map)
{
- msu_prop_map_t *prop_map;
- GHashTable *filter_map =
- g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
-
- prop_map = prv_msu_prop_map_new("@parentID", MSU_UPNP_MASK_PROP_PARENT,
- FALSE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_PARENT, prop_map);
+ msu_prop_map_t *prop_t;
+ GHashTable *p_map;
+ GHashTable *f_map;
- prop_map = prv_msu_prop_map_new("upnp:class", MSU_UPNP_MASK_PROP_TYPE,
- FALSE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_TYPE, prop_map);
+ p_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
+ f_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
- prop_map = prv_msu_prop_map_new("@id", MSU_UPNP_MASK_PROP_PATH,
- FALSE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_PATH, prop_map);
-
- prop_map = prv_msu_prop_map_new("dc:title",
- MSU_UPNP_MASK_PROP_DISPLAY_NAME,
- FALSE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_DISPLAY_NAME,
- prop_map);
-
- prop_map = prv_msu_prop_map_new("@childCount",
+ /* @childCount */
+ prop_t = prv_msu_prop_map_new("@childCount",
MSU_UPNP_MASK_PROP_CHILD_COUNT,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_CHILD_COUNT,
- prop_map);
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_CHILD_COUNT, prop_t);
+ g_hash_table_insert(p_map, "@childCount",
+ MSU_INTERFACE_PROP_CHILD_COUNT);
+
+ /* @id */
+ prop_t = prv_msu_prop_map_new("@id",
+ MSU_UPNP_MASK_PROP_PATH,
+ FALSE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_PATH, prop_t);
+ g_hash_table_insert(p_map, "@id", MSU_INTERFACE_PROP_PATH);
+
+ /* @parentID */
+ prop_t = prv_msu_prop_map_new("@parentID",
+ MSU_UPNP_MASK_PROP_PARENT,
+ FALSE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_PARENT, prop_t);
+ g_hash_table_insert(p_map, "@parentID", MSU_INTERFACE_PROP_PARENT);
+
+ /* @refID */
+ prop_t = prv_msu_prop_map_new("@refID",
+ MSU_UPNP_MASK_PROP_REFPATH,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_REFPATH, prop_t);
+ g_hash_table_insert(p_map, "@refID", MSU_INTERFACE_PROP_REFPATH);
+
+ /* @restricted */
+ prop_t = prv_msu_prop_map_new("@restricted",
+ MSU_UPNP_MASK_PROP_RESTRICTED,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_RESTRICTED, prop_t);
+ g_hash_table_insert(p_map, "@restricted",
+ MSU_INTERFACE_PROP_RESTRICTED);
- prop_map = prv_msu_prop_map_new("@searchable",
+ /* @searchable */
+ prop_t = prv_msu_prop_map_new("@searchable",
MSU_UPNP_MASK_PROP_SEARCHABLE,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_SEARCHABLE, prop_map);
-
- prop_map = prv_msu_prop_map_new("res", MSU_UPNP_MASK_PROP_URLS,
- TRUE, FALSE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_URLS, prop_map);
-
- prop_map = prv_msu_prop_map_new("res@protocolInfo",
- MSU_UPNP_MASK_PROP_MIME_TYPE,
- TRUE, FALSE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_MIME_TYPE, prop_map);
-
- prop_map = prv_msu_prop_map_new("upnp:artist",
- MSU_UPNP_MASK_PROP_ARTIST, TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_ARTIST, prop_map);
-
- prop_map = prv_msu_prop_map_new("upnp:album", MSU_UPNP_MASK_PROP_ALBUM,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_ALBUM, prop_map);
-
- prop_map = prv_msu_prop_map_new("dc:date", MSU_UPNP_MASK_PROP_DATE,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_DATE, prop_map);
-
- prop_map = prv_msu_prop_map_new("upnp:genre", MSU_UPNP_MASK_PROP_GENRE,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_GENRE, prop_map);
-
- prop_map = prv_msu_prop_map_new("res@protocolInfo",
- MSU_UPNP_MASK_PROP_DLNA_PROFILE,
- TRUE, FALSE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_DLNA_PROFILE,
- prop_map);
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_SEARCHABLE, prop_t);
+ g_hash_table_insert(p_map, "@searchable",
+ MSU_INTERFACE_PROP_SEARCHABLE);
+
+ /* dc:creator */
+ prop_t = prv_msu_prop_map_new("dc:creator",
+ MSU_UPNP_MASK_PROP_CREATOR,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_CREATOR, prop_t);
+ g_hash_table_insert(p_map, "dc:creator", MSU_INTERFACE_PROP_CREATOR);
+
+ /* dc:date */
+ prop_t = prv_msu_prop_map_new("dc:date",
+ MSU_UPNP_MASK_PROP_DATE,
+ TRUE, TRUE, TRUE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_DATE, prop_t);
+ g_hash_table_insert(p_map, "dc:date", MSU_INTERFACE_PROP_DATE);
+
+ /* dc:title */
+ prop_t = prv_msu_prop_map_new("dc:title",
+ MSU_UPNP_MASK_PROP_DISPLAY_NAME,
+ FALSE, TRUE, TRUE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_DISPLAY_NAME, prop_t);
+ g_hash_table_insert(p_map, "dc:title", MSU_INTERFACE_PROP_DISPLAY_NAME);
+
+ /* dlna:dlnaManaged */
+ prop_t = prv_msu_prop_map_new("dlna:dlnaManaged",
+ MSU_UPNP_MASK_PROP_DLNA_MANAGED,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_DLNA_MANAGED, prop_t);
+ g_hash_table_insert(p_map, "dlna:dlnaManaged",
+ MSU_INTERFACE_PROP_DLNA_MANAGED);
+
+ /* res */
+ /* res - RES */
+ prop_t = prv_msu_prop_map_new("res",
+ MSU_UPNP_MASK_PROP_RESOURCES,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_RESOURCES, prop_t);
+
+ /* res - URL */
+ prop_t = prv_msu_prop_map_new("res",
+ MSU_UPNP_MASK_PROP_URL,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_URL, prop_t);
+
+ /* res - URLS */
+ prop_t = prv_msu_prop_map_new("res",
+ MSU_UPNP_MASK_PROP_URLS,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_URLS, prop_t);
+
+ /* res@bitrate */
+ prop_t = prv_msu_prop_map_new("res@bitrate",
+ MSU_UPNP_MASK_PROP_BITRATE,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_BITRATE, prop_t);
+ g_hash_table_insert(p_map, "res@bitrate", MSU_INTERFACE_PROP_BITRATE);
- prop_map = prv_msu_prop_map_new("upnp:originalTrackNumber",
- MSU_UPNP_MASK_PROP_TRACK_NUMBER,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_TRACK_NUMBER,
- prop_map);
+ /* res@bitsPerSample */
+ prop_t = prv_msu_prop_map_new("res@bitsPerSample",
+ MSU_UPNP_MASK_PROP_BITS_PER_SAMPLE,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_BITS_PER_SAMPLE, prop_t);
+ g_hash_table_insert(p_map, "res@bitsPerSample",
+ MSU_INTERFACE_PROP_BITS_PER_SAMPLE);
- prop_map = prv_msu_prop_map_new("res@size", MSU_UPNP_MASK_PROP_SIZE,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_SIZE, prop_map);
+ /* res@colorDepth */
+ prop_t = prv_msu_prop_map_new("res@colorDepth",
+ MSU_UPNP_MASK_PROP_COLOR_DEPTH,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_COLOR_DEPTH, prop_t);
+ g_hash_table_insert(p_map, "res@colorDepth",
+ MSU_INTERFACE_PROP_COLOR_DEPTH);
- prop_map = prv_msu_prop_map_new("res@duration",
+ /* res@duration */
+ prop_t = prv_msu_prop_map_new("res@duration",
MSU_UPNP_MASK_PROP_DURATION,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_DURATION, prop_map);
-
- prop_map = prv_msu_prop_map_new("res@bitrate",
- MSU_UPNP_MASK_PROP_BITRATE,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_BITRATE, prop_map);
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_DURATION, prop_t);
+ g_hash_table_insert(p_map, "res@duration",
+ MSU_INTERFACE_PROP_DURATION);
+
+ /* res@protocolInfo */
+ /* res@protocolInfo - DLNA PROFILE*/
+ prop_t = prv_msu_prop_map_new("res@protocolInfo",
+ MSU_UPNP_MASK_PROP_DLNA_PROFILE,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_DLNA_PROFILE, prop_t);
- prop_map = prv_msu_prop_map_new("res@sampleFrequency",
+ /* res@protocolInfo - MIME TYPES*/
+ prop_t = prv_msu_prop_map_new("res@protocolInfo",
+ MSU_UPNP_MASK_PROP_MIME_TYPE,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_MIME_TYPE, prop_t);
+
+ /* res@resolution */
+ /* res@resolution - HEIGH */
+ prop_t = prv_msu_prop_map_new("res@resolution",
+ MSU_UPNP_MASK_PROP_HEIGHT,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_HEIGHT, prop_t);
+
+ /* res@resolution - WIDTH */
+ prop_t = prv_msu_prop_map_new("res@resolution",
+ MSU_UPNP_MASK_PROP_WIDTH,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_WIDTH, prop_t);
+
+ /* res@sampleFrequency */
+ prop_t = prv_msu_prop_map_new("res@sampleFrequency",
MSU_UPNP_MASK_PROP_SAMPLE_RATE,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_SAMPLE_RATE,
- prop_map);
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_SAMPLE_RATE, prop_t);
+ g_hash_table_insert(p_map, "res@sampleFrequency",
+ MSU_INTERFACE_PROP_SAMPLE_RATE);
+
+ /* res@size */
+ prop_t = prv_msu_prop_map_new("res@size",
+ MSU_UPNP_MASK_PROP_SIZE,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_SIZE, prop_t);
+ g_hash_table_insert(p_map, "res@size", MSU_INTERFACE_PROP_SIZE);
+
+ /* upnp:album */
+ prop_t = prv_msu_prop_map_new("upnp:album",
+ MSU_UPNP_MASK_PROP_ALBUM,
+ TRUE, TRUE, TRUE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_ALBUM, prop_t);
+ g_hash_table_insert(p_map, "upnp:album", MSU_INTERFACE_PROP_ALBUM);
+
+ /* upnp:albumArtURI */
+ prop_t = prv_msu_prop_map_new("upnp:albumArtURI",
+ MSU_UPNP_MASK_PROP_ALBUM_ART_URL,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_ALBUM_ART_URL, prop_t);
+ g_hash_table_insert(p_map, "upnp:albumArtURI",
+ MSU_INTERFACE_PROP_ALBUM_ART_URL);
+
+ /* upnp:artist */
+ /* upnp:artist - ARTIST*/
+ prop_t = prv_msu_prop_map_new("upnp:artist",
+ MSU_UPNP_MASK_PROP_ARTIST,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_ARTIST, prop_t);
+ g_hash_table_insert(p_map, "upnp:artist", MSU_INTERFACE_PROP_ARTIST);
+
+ /* upnp:artist - ARTISTS*/
+ prop_t = prv_msu_prop_map_new("upnp:artist",
+ MSU_UPNP_MASK_PROP_ARTISTS,
+ TRUE, FALSE, TRUE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_ARTISTS, prop_t);
+
+ /* upnp:class */
+ prop_t = prv_msu_prop_map_new("upnp:class",
+ MSU_UPNP_MASK_PROP_TYPE,
+ FALSE, TRUE, TRUE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_TYPE, prop_t);
+ g_hash_table_insert(p_map, "upnp:class", MSU_INTERFACE_PROP_TYPE);
+
+ /* upnp:createClass */
+ prop_t = prv_msu_prop_map_new("upnp:createClass",
+ MSU_UPNP_MASK_PROP_CREATE_CLASSES,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_CREATE_CLASSES, prop_t);
+
+ /* upnp:genre */
+ prop_t = prv_msu_prop_map_new("upnp:genre",
+ MSU_UPNP_MASK_PROP_GENRE,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_GENRE, prop_t);
+ g_hash_table_insert(p_map, "upnp:genre", MSU_INTERFACE_PROP_GENRE);
+
+ /* upnp:originalTrackNumber */
+ prop_t = prv_msu_prop_map_new("upnp:originalTrackNumber",
+ MSU_UPNP_MASK_PROP_TRACK_NUMBER,
+ TRUE, TRUE, TRUE);
+ g_hash_table_insert(f_map, MSU_INTERFACE_PROP_TRACK_NUMBER, prop_t);
+ g_hash_table_insert(p_map, "upnp:originalTrackNumber",
+ MSU_INTERFACE_PROP_TRACK_NUMBER);
- prop_map = prv_msu_prop_map_new("res@bitsPerSample",
- MSU_UPNP_MASK_PROP_BITS_PER_SAMPLE,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_BITS_PER_SAMPLE,
- prop_map);
-
- prop_map = prv_msu_prop_map_new("res@resolution",
- MSU_UPNP_MASK_PROP_WIDTH, TRUE, FALSE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_WIDTH, prop_map);
-
- prop_map = prv_msu_prop_map_new("res@resolution",
- MSU_UPNP_MASK_PROP_HEIGHT, TRUE, FALSE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_HEIGHT, prop_map);
-
- prop_map = prv_msu_prop_map_new("res@colorDepth",
- MSU_UPNP_MASK_PROP_COLOR_DEPTH,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_COLOR_DEPTH,
- prop_map);
+ *filter_map = f_map;
+ *property_map = p_map;
+}
- prop_map = prv_msu_prop_map_new("upnp:albumArtURI",
- MSU_UPNP_MASK_PROP_ALBUM_ART_URL,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_ALBUM_ART_URL,
- prop_map);
-
- prop_map = prv_msu_prop_map_new("res", MSU_UPNP_MASK_PROP_RESOURCES,
- TRUE, FALSE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_RESOURCES,
- prop_map);
-
- prop_map = prv_msu_prop_map_new("res", MSU_UPNP_MASK_PROP_URL,
- TRUE, FALSE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_URL, prop_map);
-
- prop_map = prv_msu_prop_map_new("@refID", MSU_UPNP_MASK_PROP_REFPATH,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_REFPATH, prop_map);
-
- prop_map = prv_msu_prop_map_new("@restricted",
- MSU_UPNP_MASK_PROP_RESTRICTED,
- TRUE, TRUE);
- g_hash_table_insert(filter_map,
- (gpointer) MSU_INTERFACE_PROP_RESTRICTED, prop_map);
+static gchar *prv_compute_upnp_filter(GHashTable *upnp_props)
+{
+ gpointer key;
+ GString *str;
+ GHashTableIter iter;
- return filter_map;
+ str = g_string_new("");
+ g_hash_table_iter_init(&iter, upnp_props);
+ if (g_hash_table_iter_next(&iter, &key, NULL)) {
+ g_string_append(str, (const gchar *) key);
+ while (g_hash_table_iter_next(&iter, &key, NULL)) {
+ g_string_append(str, ",");
+ g_string_append(str, (const gchar *) key);
+ }
+ }
+
+ return g_string_free(str, FALSE);
}
static guint32 prv_parse_filter_list(GHashTable *filter_map, GVariant *filter,
const gchar *prop;
msu_prop_map_t *prop_map;
GHashTable *upnp_props;
- GHashTableIter iter;
guint32 mask = 0;
- gpointer key;
- GString *str;
upnp_props = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, NULL);
(gpointer) prop_map->upnp_prop_name, NULL);
}
- str = g_string_new("");
- g_hash_table_iter_init(&iter, upnp_props);
- if (g_hash_table_iter_next(&iter, &key, NULL)) {
- g_string_append(str, (const gchar *) key);
- while (g_hash_table_iter_next(&iter, &key, NULL)) {
- g_string_append(str, ",");
- g_string_append(str, (const gchar *) key);
- }
- }
- *upnp_filter = g_string_free(str, FALSE);
+ *upnp_filter = prv_compute_upnp_filter(upnp_props);
g_hash_table_unref(upnp_props);
return mask;
return mask;
}
+gboolean msu_props_parse_update_filter(GHashTable *filter_map,
+ GVariant *to_add_update,
+ GVariant *to_delete, guint32 *mask,
+ gchar **upnp_filter)
+{
+ GVariantIter viter;
+ const gchar *prop;
+ GVariant *value;
+ msu_prop_map_t *prop_map;
+ GHashTable *upnp_props;
+ gboolean retval = FALSE;
+
+ *mask = 0;
+
+ upnp_props = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, NULL);
+
+ (void) g_variant_iter_init(&viter, to_add_update);
+
+ while (g_variant_iter_next(&viter, "{&sv}", &prop, &value)) {
+ MSU_LOG_DEBUG("to_add_update = %s", prop);
+
+ prop_map = g_hash_table_lookup(filter_map, prop);
+
+ if ((!prop_map) || (!prop_map->updateable))
+ goto on_error;
+
+ *mask |= prop_map->type;
+
+ if (!prop_map->filter)
+ continue;
+
+ g_hash_table_insert(upnp_props,
+ (gpointer) prop_map->upnp_prop_name, NULL);
+ }
+
+ (void) g_variant_iter_init(&viter, to_delete);
+
+ while (g_variant_iter_next(&viter, "&s", &prop)) {
+ MSU_LOG_DEBUG("to_delete = %s", prop);
+
+ prop_map = g_hash_table_lookup(filter_map, prop);
+
+ if ((!prop_map) || (!prop_map->updateable) ||
+ (*mask & prop_map->type) != 0)
+ goto on_error;
+
+ *mask |= prop_map->type;
+
+ if (!prop_map->filter)
+ continue;
+
+ g_hash_table_insert(upnp_props,
+ (gpointer) prop_map->upnp_prop_name, NULL);
+ }
+
+ *upnp_filter = prv_compute_upnp_filter(upnp_props);
+
+ retval = TRUE;
+
+on_error:
+
+ g_hash_table_unref(upnp_props);
+
+ return retval;
+}
+
static void prv_add_string_prop(GVariantBuilder *vb, const gchar *key,
const gchar *value)
{
g_variant_new_int32(value));
}
+static void prv_add_variant_prop(GVariantBuilder *vb, const gchar *key,
+ GVariant *prop)
+{
+ if (prop)
+ g_variant_builder_add(vb, "{sv}", key, prop);
+}
+
void msu_props_add_child_count(GVariantBuilder *item_vb, gint value)
{
prv_add_int_prop(item_vb, MSU_INTERFACE_PROP_CHILD_COUNT, value);
}
}
-void msu_props_add_device(GUPnPDeviceInfo *proxy, GVariantBuilder *vb)
+static void prv_add_list_dlna_str(gpointer data, gpointer user_data)
+{
+ GVariantBuilder *vb = (GVariantBuilder *) user_data;
+ gchar *cap_str = (gchar *) data;
+ gchar *str;
+ int value = 0;
+
+ if (g_str_has_prefix(cap_str, "srs-rt-retention-period-")) {
+ str = cap_str + strlen("srs-rt-retention-period-");
+ cap_str = "srs-rt-retention-period";
+
+ if (*str) {
+ if (!g_strcmp0(str, "infinity"))
+ value = -1;
+ else
+ value = atoi(str);
+ }
+ }
+
+ prv_add_uint_prop(vb, cap_str, value);
+}
+
+static GVariant *prv_add_list_dlna_prop(GList* list)
+{
+ GVariantBuilder vb;
+
+ g_variant_builder_init(&vb, G_VARIANT_TYPE("a{sv}"));
+
+ g_list_foreach(list, prv_add_list_dlna_str, &vb);
+
+ return g_variant_builder_end(&vb);
+}
+
+static void prv_add_list_artists_str(gpointer data, gpointer user_data)
+{
+ GVariantBuilder *vb = (GVariantBuilder *) user_data;
+ GUPnPDIDLLiteContributor *contributor = data;
+ const char *str;
+
+ str = gupnp_didl_lite_contributor_get_name(contributor);
+ g_variant_builder_add(vb, "s", str);
+}
+
+static GVariant *prv_get_artists_prop(GList *list)
+{
+ GVariantBuilder vb;
+
+ g_variant_builder_init(&vb, G_VARIANT_TYPE("as"));
+ g_list_foreach(list, prv_add_list_artists_str, &vb);
+
+ return g_variant_builder_end(&vb);
+}
+
+void msu_props_add_device(GUPnPDeviceInfo *proxy,
+ msu_device_t *device,
+ GVariantBuilder *vb)
{
gchar *str;
+ GList *list;
+ GVariant *dlna_caps;
prv_add_string_prop(vb, MSU_INTERFACE_PROP_LOCATION,
gupnp_device_info_get_location(proxy));
NULL, NULL, NULL, NULL);
prv_add_string_prop(vb, MSU_INTERFACE_PROP_ICON_URL, str);
g_free(str);
+
+ list = gupnp_device_info_list_dlna_capabilities(proxy);
+ if (list != NULL){
+ dlna_caps = prv_add_list_dlna_prop(list);
+ g_variant_builder_add(vb, "{sv}",
+ MSU_INTERFACE_PROP_SV_DLNA_CAPABILITIES,
+ dlna_caps);
+ g_list_free_full(list, g_free);
+ }
+
+ if (device->search_caps != NULL)
+ g_variant_builder_add(vb, "{sv}",
+ MSU_INTERFACE_PROP_SV_SEARCH_CAPABILITIES,
+ device->search_caps);
+
+ if (device->sort_caps != NULL)
+ g_variant_builder_add(vb, "{sv}",
+ MSU_INTERFACE_PROP_SV_SORT_CAPABILITIES,
+ device->sort_caps);
+
+ if (device->sort_ext_caps != NULL)
+ g_variant_builder_add(vb, "{sv}",
+ MSU_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES,
+ device->sort_ext_caps);
+
+ if (device->feature_list != NULL)
+ g_variant_builder_add(vb, "{sv}",
+ MSU_INTERFACE_PROP_SV_FEATURE_LIST,
+ device->feature_list);
}
-GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy, const gchar *prop)
+GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy,
+ msu_device_t *device,
+ const gchar *prop)
{
+ GVariant *dlna_caps = NULL;
GVariant *retval = NULL;
const gchar *str = NULL;
gchar *copy = NULL;
+ GList *list;
if (!strcmp(MSU_INTERFACE_PROP_LOCATION, prop)) {
str = gupnp_device_info_get_location(proxy);
-1, -1, -1, FALSE,
NULL, NULL, NULL, NULL);
str = copy;
- }
+ } else if (!strcmp(MSU_INTERFACE_PROP_SV_DLNA_CAPABILITIES, prop)) {
+ list = gupnp_device_info_list_dlna_capabilities(proxy);
+ if (list != NULL){
+ dlna_caps = prv_add_list_dlna_prop(list);
+ g_list_free_full(list, g_free);
+ retval = g_variant_ref_sink(dlna_caps);
+
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ copy = g_variant_print(dlna_caps, FALSE);
+ MSU_LOG_DEBUG("Prop %s = %s", prop, copy);
+#endif
+ }
+ } else if (!strcmp(MSU_INTERFACE_PROP_SV_SEARCH_CAPABILITIES, prop)) {
+ if (device->search_caps != NULL){
+ retval = g_variant_ref(device->search_caps);
- if (str) {
- MSU_LOG_DEBUG("Prop %s = %s", prop, str);
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ copy = g_variant_print(device->search_caps, FALSE);
+ MSU_LOG_DEBUG("Prop %s = %s", prop, copy);
+#endif
+ }
+ } else if (!strcmp(MSU_INTERFACE_PROP_SV_SORT_CAPABILITIES, prop)) {
+ if (device->sort_caps != NULL){
+ retval = g_variant_ref(device->sort_caps);
- retval = g_variant_ref_sink(g_variant_new_string(str));
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ copy = g_variant_print(device->sort_caps, FALSE);
+ MSU_LOG_DEBUG("Prop %s = %s", prop, copy);
+#endif
+ }
+ } else if (!strcmp(MSU_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES, prop)) {
+ if (device->sort_ext_caps != NULL){
+ retval = g_variant_ref(device->sort_ext_caps);
+
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ copy = g_variant_print(device->sort_ext_caps, FALSE);
+ MSU_LOG_DEBUG("Prop %s = %s", prop, copy);
+#endif
+ }
+ } else if (!strcmp(MSU_INTERFACE_PROP_SV_FEATURE_LIST, prop)) {
+ if (device->feature_list != NULL){
+ retval = g_variant_ref(device->feature_list);
+
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ copy = g_variant_print(device->feature_list, FALSE);
+ MSU_LOG_DEBUG("Prop %s = %s", prop, copy);
+#endif
+ }
}
+
+ if (!retval){
+ if (str) {
+ MSU_LOG_DEBUG("Prop %s = %s", prop, str);
+
+ retval = g_variant_ref_sink(g_variant_new_string(str));
+ }
#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_WARNING
- else
- MSU_LOG_WARNING("Property %s not defined for device", prop);
+ else
+ MSU_LOG_WARNING("Property %s not defined", prop);
#endif
+ }
g_free(copy);
}
}
+static GVariant *prv_compute_create_classes(GUPnPDIDLLiteContainer *container)
+{
+ GVariantBuilder create_classes_vb;
+ GList *create_classes;
+ GList *ptr;
+ GUPnPDIDLLiteCreateClass *create_class;
+ const char *content;
+ gboolean inc_derived;
+
+ g_variant_builder_init(&create_classes_vb, G_VARIANT_TYPE("a(sb)"));
+
+ create_classes = gupnp_didl_lite_container_get_create_classes_full(
+ container);
+ ptr = create_classes;
+ while (ptr) {
+ create_class = ptr->data;
+ content = gupnp_didl_lite_create_class_get_content(
+ create_class);
+ inc_derived = gupnp_didl_lite_create_class_get_include_derived(
+ create_class);
+ g_variant_builder_add(&create_classes_vb,
+ "(sb)", content, inc_derived);
+ g_object_unref(ptr->data);
+ ptr = g_list_next(ptr);
+ }
+ g_list_free(create_classes);
+
+ return g_variant_builder_end(&create_classes_vb);
+}
+
const gchar *msu_props_media_spec_to_upnp_class(const gchar *m2spec_class)
{
const gchar *retval = NULL;
return retval;
}
+static GVariant *prv_props_get_dlna_managed_dict(GUPnPOCMFlags flags)
+{
+ GVariantBuilder builder;
+ gboolean managed;
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sb}"));
+
+ managed = (flags & GUPNP_OCM_FLAGS_UPLOAD);
+ g_variant_builder_add(&builder, "{sb}", "Upload", managed);
+
+ managed = (flags & GUPNP_OCM_FLAGS_CREATE_CONTAINER);
+ g_variant_builder_add(&builder, "{sb}", "CreateContainer", managed);
+
+ managed = (flags & GUPNP_OCM_FLAGS_DESTROYABLE);
+ g_variant_builder_add(&builder, "{sb}", "Delete", managed);
+
+ managed = (flags & GUPNP_OCM_FLAGS_UPLOAD_DESTROYABLE);
+ g_variant_builder_add(&builder, "{sb}", "UploadDelete", managed);
+
+ managed = (flags & GUPNP_OCM_FLAGS_CHANGE_METADATA);
+ g_variant_builder_add(&builder, "{sb}", "ChangeMeta", managed);
+
+ return g_variant_builder_end(&builder);
+}
+
gboolean msu_props_add_object(GVariantBuilder *item_vb,
GUPnPDIDLLiteObject *object,
const char *root_path,
gchar *path = NULL;
const char *id;
const char *title;
+ const char *creator;
const char *upnp_class;
const char *media_spec_type;
gboolean retval = FALSE;
gboolean rest;
+ GUPnPOCMFlags flags;
id = gupnp_didl_lite_object_get_id(object);
if (!id)
goto on_error;
title = gupnp_didl_lite_object_get_title(object);
+ creator = gupnp_didl_lite_object_get_creator(object);
rest = gupnp_didl_lite_object_get_restricted(object);
path = msu_path_from_id(root_path, id);
prv_add_string_prop(item_vb, MSU_INTERFACE_PROP_DISPLAY_NAME,
title);
+ if (filter_mask & MSU_UPNP_MASK_PROP_CREATOR)
+ prv_add_string_prop(item_vb, MSU_INTERFACE_PROP_CREATOR,
+ creator);
+
if (filter_mask & MSU_UPNP_MASK_PROP_PATH)
prv_add_path_prop(item_vb, MSU_INTERFACE_PROP_PATH, path);
if (filter_mask & MSU_UPNP_MASK_PROP_RESTRICTED)
prv_add_bool_prop(item_vb, MSU_INTERFACE_PROP_RESTRICTED, rest);
+ if (filter_mask & MSU_UPNP_MASK_PROP_DLNA_MANAGED) {
+ flags = gupnp_didl_lite_object_get_dlna_managed(object);
+ prv_add_variant_prop(item_vb,
+ MSU_INTERFACE_PROP_DLNA_MANAGED,
+ prv_props_get_dlna_managed_dict(flags));
+ }
+
retval = TRUE;
on_error:
prv_add_bool_prop(item_vb, MSU_INTERFACE_PROP_SEARCHABLE,
searchable);
}
+
+ if (filter_mask & MSU_UPNP_MASK_PROP_CREATE_CLASSES)
+ prv_add_variant_prop(item_vb,
+ MSU_INTERFACE_PROP_CREATE_CLASSES,
+ prv_compute_create_classes(object));
}
static GVariant *prv_compute_resources(GUPnPDIDLLiteObject *object,
GUPnPDIDLLiteResource *res;
const char *str_val;
char *path;
+ GList *list;
if (filter_mask & MSU_UPNP_MASK_PROP_ARTIST)
prv_add_string_prop(item_vb, MSU_INTERFACE_PROP_ARTIST,
gupnp_didl_lite_object_get_artist(object));
+ if (filter_mask & MSU_UPNP_MASK_PROP_ARTISTS) {
+ list = gupnp_didl_lite_object_get_artists(object);
+ prv_add_variant_prop(item_vb, MSU_INTERFACE_PROP_ARTISTS,
+ prv_get_artists_prop(list));
+ g_list_free_full(list, g_object_unref);
+ }
+
if (filter_mask & MSU_UPNP_MASK_PROP_ALBUM)
prv_add_string_prop(item_vb, MSU_INTERFACE_PROP_ALBUM,
gupnp_didl_lite_object_get_album(object));
const char *title;
gboolean rest;
GVariant *retval = NULL;
+ GUPnPOCMFlags dlna_managed;
if (!strcmp(prop, MSU_INTERFACE_PROP_PARENT)) {
id = gupnp_didl_lite_object_get_parent_id(object);
MSU_LOG_DEBUG("Prop %s = %s", prop, title);
retval = g_variant_ref_sink(g_variant_new_string(title));
+ } else if (!strcmp(prop, MSU_INTERFACE_PROP_CREATOR)) {
+ title = gupnp_didl_lite_object_get_creator(object);
+ if (!title)
+ goto on_error;
+
+ MSU_LOG_DEBUG("Prop %s = %s", prop, title);
+
+ retval = g_variant_ref_sink(g_variant_new_string(title));
} else if (!strcmp(prop, MSU_INTERFACE_PROP_RESTRICTED)) {
rest = gupnp_didl_lite_object_get_restricted(object);
MSU_LOG_DEBUG("Prop %s = %d", prop, rest);
retval = g_variant_ref_sink(g_variant_new_boolean(rest));
+ } else if (!strcmp(prop, MSU_INTERFACE_PROP_DLNA_MANAGED)) {
+ dlna_managed = gupnp_didl_lite_object_get_dlna_managed(object);
+
+ MSU_LOG_DEBUG("Prop %s = %0x", prop, dlna_managed);
+
+ retval = g_variant_ref_sink(
+ prv_props_get_dlna_managed_dict(dlna_managed));
}
on_error:
gint track_number;
GUPnPDIDLLiteResource *res;
GVariant *retval = NULL;
+ GList *list;
if (GUPNP_IS_DIDL_LITE_CONTAINER(object))
goto on_error;
MSU_LOG_DEBUG("Prop %s = %s", prop, str);
retval = g_variant_ref_sink(g_variant_new_string(str));
+ } else if (!strcmp(prop, MSU_INTERFACE_PROP_ARTISTS)) {
+ list = gupnp_didl_lite_object_get_artists(object);
+ if (!list)
+ goto on_error;
+
+ retval = g_variant_ref_sink(prv_get_artists_prop(list));
+ g_list_free_full(list, g_object_unref);
+
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ path = g_variant_print(retval, FALSE);
+ MSU_LOG_DEBUG("Prop %s = %s", prop, path);
+ g_free(path);
+#endif
} else if (!strcmp(prop, MSU_INTERFACE_PROP_ALBUM)) {
str = gupnp_didl_lite_object_get_album(object);
if (!str)
gboolean searchable;
GUPnPDIDLLiteContainer *container;
GVariant *retval = NULL;
-
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ gchar *create_classes;
+#endif
if (!GUPNP_IS_DIDL_LITE_CONTAINER(object))
goto on_error;
retval = g_variant_ref_sink(
g_variant_new_boolean(searchable));
+ } else if (!strcmp(prop, MSU_INTERFACE_PROP_CREATE_CLASSES)) {
+ retval = g_variant_ref_sink(
+ prv_compute_create_classes(container));
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
+ create_classes = g_variant_print(retval, FALSE);
+ MSU_LOG_DEBUG("Prop %s = %s", prop, create_classes);
+ g_free(create_classes);
+#endif
}
on_error:
#define MSU_PROPS_H__
#include <libgupnp-av/gupnp-av.h>
+#include "async.h"
enum msu_upnp_prop_mask_ {
MSU_UPNP_MASK_PROP_PARENT = 1,
MSU_UPNP_MASK_PROP_RESOURCES = 1 << 23,
MSU_UPNP_MASK_PROP_URL = 1 << 24,
MSU_UPNP_MASK_PROP_REFPATH = 1 << 25,
- MSU_UPNP_MASK_PROP_RESTRICTED = 1 << 26
+ MSU_UPNP_MASK_PROP_RESTRICTED = 1 << 26,
+ MSU_UPNP_MASK_PROP_DLNA_MANAGED = 1 << 27,
+ MSU_UPNP_MASK_PROP_CREATOR = 1 << 28,
+ MSU_UPNP_MASK_PROP_ARTISTS = 1 << 29,
+ MSU_UPNP_MASK_PROP_CREATE_CLASSES = 1 << 30
};
typedef enum msu_upnp_prop_mask_ msu_upnp_prop_mask;
msu_upnp_prop_mask type;
gboolean filter;
gboolean searchable;
+ gboolean updateable;
};
-GHashTable *msu_prop_maps_new(void);
+void msu_prop_maps_new(GHashTable **property_map, GHashTable **filter_map);
+
guint32 msu_props_parse_filter(GHashTable *filter_map, GVariant *filter,
gchar **upnp_filter);
-void msu_props_add_device(GUPnPDeviceInfo *proxy, GVariantBuilder *vb);
-GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy, const gchar *prop);
+
+gboolean msu_props_parse_update_filter(GHashTable *filter_map,
+ GVariant *to_add_update,
+ GVariant *to_delete, guint32 *mask,
+ gchar **upnp_filter);
+
+void msu_props_add_device(GUPnPDeviceInfo *proxy,
+ msu_device_t *device,
+ GVariantBuilder *vb);
+
+GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy,
+ msu_device_t *device,
+ const gchar *prop);
gboolean msu_props_add_object(GVariantBuilder *item_vb,
GUPnPDIDLLiteObject *object,
const char *root_path,
const gchar *parent_path,
guint32 filter_mask);
+
GVariant *msu_props_get_object_prop(const gchar *prop, const gchar *root_path,
GUPnPDIDLLiteObject *object);
gboolean *have_child_count);
void msu_props_add_child_count(GVariantBuilder *item_vb, gint value);
+
GVariant *msu_props_get_container_prop(const gchar *prop,
GUPnPDIDLLiteObject *object);
GUPnPDIDLLiteObject *object,
guint32 filter_mask,
const gchar *protocol_info);
+
void msu_props_add_item(GVariantBuilder *item_vb,
GUPnPDIDLLiteObject *object,
const gchar *root_path,
guint32 filter_mask,
const gchar *protocol_info);
+
GVariant *msu_props_get_item_prop(const gchar *prop, const gchar *root_path,
GUPnPDIDLLiteObject *object,
const gchar *protocol_info);
const gchar *msu_props_media_spec_to_upnp_class(const gchar *m2spec_class);
-const gchar *msu_props_upnp_class_to_media_spec(const gchar *upnp_class);
+const gchar *msu_props_upnp_class_to_media_spec(const gchar *upnp_class);
#endif
if (sys_path != NULL) {
*sys_path = NULL;
- if (SYS_CONFIG_DIR && *SYS_CONFIG_DIR)
+ if (*SYS_CONFIG_DIR)
*sys_path = g_strdup_printf("%s/%s", SYS_CONFIG_DIR,
MSU_SETTINGS_KEYFILE_NAME);
}
return task;
}
+msu_task_t *msu_task_prefer_local_addresses_new(
+ GDBusMethodInvocation *invocation,
+ GVariant *parameters)
+{
+ msu_task_t *task = g_new0(msu_task_t, 1);
+
+ task->type = MSU_TASK_SET_PREFER_LOCAL_ADDRESSES;
+ task->invocation = invocation;
+ task->synchronous = TRUE;
+ g_variant_get(parameters, "(b)",
+ &task->ut.prefer_local_addresses.prefer);
+
+ return task;
+}
msu_task_t *msu_task_upload_to_any_new(GDBusMethodInvocation *invocation,
const gchar *path, GVariant *parameters)
path, parameters);
}
+msu_task_t *msu_task_get_upload_status_new(GDBusMethodInvocation *invocation,
+ const gchar *path,
+ GVariant *parameters)
+{
+ msu_task_t *task;
+
+ task = prv_m2spec_task_new(MSU_TASK_GET_UPLOAD_STATUS, invocation, path,
+ "(stt)");
+
+ g_variant_get(parameters, "(u)",
+ &task->ut.upload_action.upload_id);
+ task->synchronous = TRUE;
+ task->multiple_retvals = TRUE;
+
+ return task;
+}
+
+msu_task_t *msu_task_get_upload_ids_new(GDBusMethodInvocation *invocation,
+ const gchar *path)
+{
+ msu_task_t *task;
+
+ task = prv_m2spec_task_new(MSU_TASK_GET_UPLOAD_IDS, invocation, path,
+ "(@au)");
+
+ task->synchronous = TRUE;
+
+ return task;
+}
+
+msu_task_t *msu_task_cancel_upload_new(GDBusMethodInvocation *invocation,
+ const gchar *path,
+ GVariant *parameters)
+{
+ msu_task_t *task;
+
+ task = prv_m2spec_task_new(MSU_TASK_CANCEL_UPLOAD, invocation, path,
+ NULL);
+
+ g_variant_get(parameters, "(u)",
+ &task->ut.upload_action.upload_id);
+ task->synchronous = TRUE;
+
+ return task;
+}
+
+msu_task_t *msu_task_delete_new(GDBusMethodInvocation *invocation,
+ const gchar *path)
+{
+ msu_task_t *task;
+
+ task = prv_m2spec_task_new(MSU_TASK_DELETE_OBJECT, invocation,
+ path, NULL);
+ return task;
+}
+
+msu_task_t *msu_task_create_container_new_generic(
+ GDBusMethodInvocation *invocation,
+ msu_task_type_t type,
+ const gchar *path,
+ GVariant *parameters)
+{
+ msu_task_t *task;
+
+ task = prv_m2spec_task_new(type, invocation, path, "(@o)");
+
+ g_variant_get(parameters, "(ss@as)",
+ &task->ut.create_container.display_name,
+ &task->ut.create_container.type,
+ &task->ut.create_container.child_types);
+
+ return task;
+}
+
+msu_task_t *msu_task_update_new(GDBusMethodInvocation *invocation,
+ const gchar *path, GVariant *parameters)
+{
+ msu_task_t *task;
+
+ task = prv_m2spec_task_new(MSU_TASK_UPDATE_OBJECT, invocation, path,
+ NULL);
+
+ g_variant_get(parameters, "(@a{sv}@as)",
+ &task->ut.update.to_add_update,
+ &task->ut.update.to_delete);
+
+ return task;
+}
+
static void prv_msu_task_delete(msu_task_t *task)
{
switch (task->type) {
g_free(task->ut.upload.display_name);
g_free(task->ut.upload.file_path);
break;
+ case MSU_TASK_CREATE_CONTAINER:
+ case MSU_TASK_CREATE_CONTAINER_IN_ANY:
+ g_free(task->ut.create_container.display_name);
+ g_free(task->ut.create_container.type);
+ g_variant_unref(task->ut.create_container.child_types);
+ break;
+ case MSU_TASK_UPDATE_OBJECT:
+ if (task->ut.update.to_add_update)
+ g_variant_unref(task->ut.update.to_add_update);
+ if (task->ut.update.to_delete)
+ g_variant_unref(task->ut.update.to_delete);
+ break;
default:
break;
}
MSU_TASK_GET_PROP,
MSU_TASK_SEARCH,
MSU_TASK_GET_RESOURCE,
+ MSU_TASK_SET_PREFER_LOCAL_ADDRESSES,
MSU_TASK_SET_PROTOCOL_INFO,
MSU_TASK_UPLOAD_TO_ANY,
- MSU_TASK_UPLOAD
+ MSU_TASK_UPLOAD,
+ MSU_TASK_GET_UPLOAD_STATUS,
+ MSU_TASK_GET_UPLOAD_IDS,
+ MSU_TASK_CANCEL_UPLOAD,
+ MSU_TASK_DELETE_OBJECT,
+ MSU_TASK_CREATE_CONTAINER,
+ MSU_TASK_CREATE_CONTAINER_IN_ANY,
+ MSU_TASK_UPDATE_OBJECT
};
typedef enum msu_task_type_t_ msu_task_type_t;
GVariant *filter;
};
+typedef struct msu_task_set_prefer_local_addresses_t_
+ msu_task_set_prefer_local_addresses_t;
+struct msu_task_set_prefer_local_addresses_t_ {
+ gboolean prefer;
+};
+
typedef struct msu_task_set_protocol_info_t_ msu_task_set_protocol_info_t;
struct msu_task_set_protocol_info_t_ {
gchar *protocol_info;
gchar *file_path;
};
+typedef struct msu_task_upload_action_t_ msu_task_upload_action_t;
+struct msu_task_upload_action_t_ {
+ guint upload_id;
+};
+
+typedef struct msu_task_create_container_t_ msu_task_create_container_t;
+struct msu_task_create_container_t_ {
+ gchar *display_name;
+ gchar *type;
+ GVariant *child_types;
+};
+
+typedef struct msu_task_update_t_ msu_task_update_t;
+struct msu_task_update_t_ {
+ GVariant *to_add_update;
+ GVariant *to_delete;
+};
+
typedef struct msu_task_t_ msu_task_t;
struct msu_task_t_ {
msu_task_type_t type;
msu_task_get_prop_t get_prop;
msu_task_search_t search;
msu_task_get_resource_t resource;
+ msu_task_set_prefer_local_addresses_t prefer_local_addresses;
msu_task_set_protocol_info_t protocol_info;
msu_task_upload_t upload;
+ msu_task_upload_action_t upload_action;
+ msu_task_create_container_t create_container;
+ msu_task_update_t update;
} ut;
};
const gchar *path, GVariant *parameters);
msu_task_t *msu_task_set_protocol_info_new(GDBusMethodInvocation *invocation,
GVariant *parameters);
+msu_task_t *msu_task_prefer_local_addresses_new(
+ GDBusMethodInvocation *invocation,
+ GVariant *parameters);
msu_task_t *msu_task_upload_to_any_new(GDBusMethodInvocation *invocation,
const gchar *path, GVariant *parameters);
msu_task_t *msu_task_upload_new(GDBusMethodInvocation *invocation,
const gchar *path, GVariant *parameters);
+msu_task_t *msu_task_get_upload_status_new(GDBusMethodInvocation *invocation,
+ const gchar *path,
+ GVariant *parameters);
+msu_task_t *msu_task_get_upload_ids_new(GDBusMethodInvocation *invocation,
+ const gchar *path);
+msu_task_t *msu_task_cancel_upload_new(GDBusMethodInvocation *invocation,
+ const gchar *path,
+ GVariant *parameters);
+msu_task_t *msu_task_delete_new(GDBusMethodInvocation *invocation,
+ const gchar *path);
+msu_task_t *msu_task_create_container_new_generic(
+ GDBusMethodInvocation *invocation,
+ msu_task_type_t type,
+ const gchar *path,
+ GVariant *parameters);
+msu_task_t *msu_task_update_new(GDBusMethodInvocation *invocation,
+ const gchar *path, GVariant *parameters);
void msu_task_complete_and_delete(msu_task_t *task);
void msu_task_fail_and_delete(msu_task_t *task, GError *error);
void msu_task_cancel_and_delete(msu_task_t *task);
#include <string.h>
+#include <libgssdp/gssdp-resource-browser.h>
#include <libgupnp/gupnp-control-point.h>
#include <libgupnp/gupnp-error.h>
#include "async.h"
+#include "chain-task.h"
#include "device.h"
#include "error.h"
#include "interface.h"
GDBusConnection *connection;
msu_interface_info_t *interface_info;
GHashTable *filter_map;
+ GHashTable *property_map;
msu_upnp_callback_t found_server;
msu_upnp_callback_t lost_server;
GUPnPContextManager *context_manager;
void *user_data;
GHashTable *server_udn_map;
+ GHashTable *server_uc_map;
guint counter;
};
+/* Private structure used in chain task */
+typedef struct prv_device_new_ct_t_ prv_device_new_ct_t;
+struct prv_device_new_ct_t_ {
+ msu_upnp_t *upnp;
+ const char *udn;
+ msu_device_t *device;
+ msu_chain_task_t *chain;
+};
+
static gchar **prv_subtree_enumerate(GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
if (!strcmp(MSU_INTERFACE_MEDIA_CONTAINER, interface_name))
retval = upnp->interface_info[
MSU_INTERFACE_INFO_CONTAINER].vtable;
+ else if (!strcmp(MSU_INTERFACE_MEDIA_OBJECT, interface_name))
+ retval = upnp->interface_info[
+ MSU_INTERFACE_INFO_OBJECT].vtable;
else if (!strcmp(MSU_INTERFACE_PROPERTIES, interface_name))
retval = upnp->interface_info[
MSU_INTERFACE_INFO_PROPERTIES].vtable;
return retval;
}
+static void prv_device_chain_end(msu_chain_task_t *chain, gpointer data)
+{
+ msu_device_t *device;
+ gboolean canceled;
+ prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *) data;
+
+ device = msu_chain_task_get_device(chain);
+ canceled = msu_chain_task_is_canceled(chain);
+ if (canceled)
+ goto on_clear;
+
+ MSU_LOG_DEBUG("Notify new server available: %s", device->path);
+ g_hash_table_insert(priv_t->upnp->server_udn_map, g_strdup(priv_t->udn),
+ device);
+ priv_t->upnp->found_server(device->path, priv_t->upnp->user_data);
+
+on_clear:
+
+ g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
+ msu_chain_task_delete(chain);
+ g_free(priv_t);
+
+ if (canceled)
+ msu_device_delete(device);
+
+ MSU_LOG_DEBUG_NL();
+}
+
static void prv_server_available_cb(GUPnPControlPoint *cp,
GUPnPDeviceProxy *proxy,
gpointer user_data)
msu_device_t *device;
const gchar *ip_address;
msu_device_context_t *context;
+ msu_chain_task_t *chain;
unsigned int i;
-
- MSU_LOG_DEBUG("Enter");
+ prv_device_new_ct_t *priv_t;
udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *) proxy);
if (!udn)
device = g_hash_table_lookup(upnp->server_udn_map, udn);
if (!device) {
+ priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
+
+ if (priv_t)
+ device = priv_t->device;
+ }
+
+ if (!device) {
MSU_LOG_DEBUG("Device not found. Adding");
+ MSU_LOG_DEBUG_NL();
- if (msu_device_new(upnp->connection, proxy,
- ip_address, &gSubtreeVtable, upnp,
- upnp->counter, &device)) {
- upnp->counter++;
- g_hash_table_insert(upnp->server_udn_map, g_strdup(udn),
- device);
- upnp->found_server(device->path, upnp->user_data);
- }
+ priv_t = g_new0(prv_device_new_ct_t, 1);
+ chain = msu_chain_task_new(prv_device_chain_end, priv_t);
+ device = msu_device_new(upnp->connection, proxy, ip_address,
+ &gSubtreeVtable, upnp,
+ upnp->property_map, upnp->counter,
+ chain);
+
+ upnp->counter++;
+
+ priv_t->upnp = upnp;
+ priv_t->udn = udn;
+ priv_t->chain = chain;
+ priv_t->device = device;
+
+ g_hash_table_insert(upnp->server_uc_map, g_strdup(udn), priv_t);
} else {
MSU_LOG_DEBUG("Device Found");
msu_device_append_new_context(device, ip_address,
proxy);
}
+
+ MSU_LOG_DEBUG_NL();
}
on_error:
- MSU_LOG_DEBUG("Exit");
- MSU_LOG_DEBUG_NL();
-
return;
}
unsigned int i;
msu_device_context_t *context;
gboolean subscribed;
+ gboolean under_construction = FALSE;
+ prv_device_new_ct_t *priv_t;
MSU_LOG_DEBUG("Enter");
MSU_LOG_DEBUG("IP Address %s", ip_address);
device = g_hash_table_lookup(upnp->server_udn_map, udn);
+
+ if (!device) {
+ priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
+
+ if (priv_t) {
+ device = priv_t->device;
+ under_construction = TRUE;
+ }
+ }
+
if (!device) {
MSU_LOG_WARNING("Device not found. Ignoring");
goto on_error;
(void) g_ptr_array_remove_index(device->contexts, i);
if (device->contexts->len == 0) {
- MSU_LOG_DEBUG("Last Context lost. Delete device");
- upnp->lost_server(device->path, upnp->user_data);
- g_hash_table_remove(upnp->server_udn_map, udn);
+ if (!under_construction) {
+ MSU_LOG_DEBUG("Last Context lost. " \
+ "Delete device");
+
+ upnp->lost_server(device->path,
+ upnp->user_data);
+ g_hash_table_remove(upnp->server_udn_map, udn);
+ } else {
+ MSU_LOG_WARNING("Device under construction. "\
+ "Cancelling");
+
+ msu_chain_task_cancel(priv_t->chain);
+ prv_device_chain_end(priv_t->chain, priv_t);
+ }
} else if (subscribed && !device->timeout_id) {
MSU_LOG_DEBUG("Subscribe on new context");
upnp->server_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free,
msu_device_delete);
- upnp->filter_map = msu_prop_maps_new();
+
+ upnp->server_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, NULL);
+
+ msu_prop_maps_new(&upnp->property_map, &upnp->filter_map);
+
upnp->context_manager = gupnp_context_manager_create(0);
g_signal_connect(upnp->context_manager, "context-available",
{
if (upnp) {
g_object_unref(upnp->context_manager);
+ g_hash_table_unref(upnp->property_map);
g_hash_table_unref(upnp->filter_map);
g_hash_table_unref(upnp->server_udn_map);
+ g_hash_table_unref(upnp->server_uc_map);
g_free(upnp->interface_info);
g_free(upnp);
}
return retval;
}
-void msu_upnp_get_children(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+void msu_upnp_get_children(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
msu_async_cb_data_t *cb_data;
msu_async_bas_t *cb_task_data;
MSU_LOG_DEBUG("Start: %u", task->ut.get_children.start);
MSU_LOG_DEBUG("Count: %u", task->ut.get_children.count);
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.bas;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
MSU_LOG_DEBUG("Sort By %s", sort_by);
- cb_task_data->protocol_info = protocol_info;
+ cb_task_data->protocol_info = client->protocol_info;
- msu_device_get_children(device, task, cb_data,
+ msu_device_get_children(device, client, task, cb_data,
upnp_filter, sort_by, cancellable);
on_error:
MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
}
-void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
gboolean root_object;
msu_async_cb_data_t *cb_data;
MSU_LOG_DEBUG("Path: %s", task->path);
MSU_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.get_all;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
goto on_error;
}
- cb_task_data->protocol_info = protocol_info;
+ cb_task_data->protocol_info = client->protocol_info;
- msu_device_get_all_props(device, task, cb_data, root_object,
+ msu_device_get_all_props(device, client, task, cb_data, root_object,
cancellable);
MSU_LOG_DEBUG("Exit with SUCCESS");
MSU_LOG_DEBUG("Exit with FAIL");
}
-void msu_upnp_get_prop(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+void msu_upnp_get_prop(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
gboolean root_object;
msu_async_cb_data_t *cb_data;
MSU_LOG_DEBUG("Prop.%s", task->ut.get_prop.prop_name);
task_data = &task->ut.get_prop;
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.get_prop;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
goto on_error;
}
- cb_task_data->protocol_info = protocol_info;
+ cb_task_data->protocol_info = client->protocol_info;
prop_map = g_hash_table_lookup(upnp->filter_map, task_data->prop_name);
- msu_device_get_prop(device, task, cb_data, prop_map,
+ msu_device_get_prop(device, client, task, cb_data, prop_map,
root_object, cancellable);
MSU_LOG_DEBUG("Exit with SUCCESS");
MSU_LOG_DEBUG("Exit with FAIL");
}
-void msu_upnp_search(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+void msu_upnp_search(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
gchar *upnp_filter = NULL;
gchar *upnp_query = NULL;
MSU_LOG_DEBUG("Start: %u", task->ut.search.start);
MSU_LOG_DEBUG("Count: %u", task->ut.search.count);
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.bas;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
MSU_LOG_DEBUG("Sort By %s", sort_by);
- cb_task_data->protocol_info = protocol_info;
+ cb_task_data->protocol_info = client->protocol_info;
- msu_device_search(device, task, cb_data, upnp_filter,
+ msu_device_search(device, client, task, cb_data, upnp_filter,
upnp_query, sort_by, cancellable);
on_error:
MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
}
-void msu_upnp_get_resource(msu_upnp_t *upnp, msu_task_t *task,
+void msu_upnp_get_resource(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
msu_async_cb_data_t *cb_data;
msu_async_get_all_t *cb_task_data;
MSU_LOG_DEBUG("Protocol Info: %s ", task->ut.resource.protocol_info);
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.get_all;
if (!msu_path_get_path_and_id(task->path, &root_path, &cb_data->id,
MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
- msu_device_get_resource(device, task, cb_data, upnp_filter,
+ msu_device_get_resource(device, client, task, cb_data, upnp_filter,
cancellable);
on_error:
return FALSE;
}
-void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_task_t *task,
+void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
msu_async_cb_data_t *cb_data;
msu_async_upload_t *cb_task_data;
MSU_LOG_DEBUG("Enter");
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.upload;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
- msu_device_upload(device, task, "DLNA.ORG_AnyContainer", cb_data,
- cancellable);
+ msu_device_upload(device, client, task, "DLNA.ORG_AnyContainer",
+ cb_data, cancellable);
on_error:
MSU_LOG_DEBUG("Exit");
}
-void msu_upnp_upload(msu_upnp_t *upnp, msu_task_t *task,
+void msu_upnp_upload(msu_upnp_t *upnp, msu_client_t *client, msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data)
+ msu_upnp_task_complete_t cb)
{
msu_async_cb_data_t *cb_data;
msu_async_upload_t *cb_task_data;
MSU_LOG_DEBUG("Enter");
- cb_data = msu_async_cb_data_new(task, cb, user_data);
+ cb_data = msu_async_cb_data_new(task, cb);
cb_task_data = &cb_data->ut.upload;
if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
- msu_device_upload(device, task, cb_data->id, cb_data, cancellable);
+ msu_device_upload(device, client, task, cb_data->id, cb_data,
+ cancellable);
+
+on_error:
+
+ if (!cb_data->action)
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_get_upload_status(msu_upnp_t *upnp, msu_task_t *task)
+{
+ gchar *root_path = NULL;
+ gchar *id = NULL;
+ GError *error = NULL;
+ msu_device_t *device;
+
+ MSU_LOG_DEBUG("Enter");
+
+ if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
+
+ device = msu_device_from_path(root_path, upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ root_path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ if (strcmp(id, "0")) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+ "GetUploadStatus must be executed "
+ " on a root path");
+ goto on_error;
+ }
+
+ (void) msu_device_get_upload_status(device, task, &error);
+
+on_error:
+
+ if (error) {
+ msu_task_fail_and_delete(task, error);
+ g_error_free(error);
+ } else {
+ msu_task_complete_and_delete(task);
+ }
+
+ g_free(id);
+ g_free(root_path);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_get_upload_ids(msu_upnp_t *upnp, msu_task_t *task)
+{
+ gchar *root_path = NULL;
+ gchar *id = NULL;
+ GError *error = NULL;
+ msu_device_t *device;
+
+ MSU_LOG_DEBUG("Enter");
+
+ if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
+
+ device = msu_device_from_path(root_path, upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ root_path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ if (strcmp(id, "0")) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+ "GetUploadIDs must be executed "
+ " on a root path");
+ goto on_error;
+ }
+
+ msu_device_get_upload_ids(device, task);
+
+on_error:
+
+ if (error) {
+ msu_task_fail_and_delete(task, error);
+ g_error_free(error);
+ } else {
+ msu_task_complete_and_delete(task);
+ }
+
+ g_free(id);
+ g_free(root_path);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_cancel_upload(msu_upnp_t *upnp, msu_task_t *task)
+{
+ gchar *root_path = NULL;
+ gchar *id = NULL;
+ GError *error = NULL;
+ msu_device_t *device;
+
+ MSU_LOG_DEBUG("Enter");
+
+ if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
+
+ device = msu_device_from_path(root_path, upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ root_path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ if (strcmp(id, "0")) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+ "CancelUpload must be executed "
+ " on a root path");
+ goto on_error;
+ }
+
+ (void) msu_device_cancel_upload(device, task, &error);
+
+on_error:
+
+ if (error) {
+ msu_task_fail_and_delete(task, error);
+ g_error_free(error);
+ } else {
+ msu_task_complete_and_delete(task);
+ }
+
+ g_free(id);
+ g_free(root_path);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_delete_object(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb)
+{
+ msu_async_cb_data_t *cb_data;
+ msu_device_t *device;
+ gchar *root_path = NULL;
+
+ MSU_LOG_DEBUG("Enter");
+
+ cb_data = msu_async_cb_data_new(task, cb);
+
+ if (!msu_path_get_path_and_id(task->path, &root_path,
+ &cb_data->id, &cb_data->error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", root_path,
+ cb_data->id);
+
+ device = msu_device_from_path(root_path, upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ root_path);
+
+ cb_data->error =
+ g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ msu_device_delete_object(device, client, task, cb_data, cancellable);
+
+on_error:
+
+ if (root_path)
+ g_free(root_path);
+ if (!cb_data->action)
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_create_container(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb)
+{
+ msu_async_cb_data_t *cb_data;
+ msu_async_create_container_t *cb_task_data;
+ msu_device_t *device;
+
+ MSU_LOG_DEBUG("Enter");
+
+ cb_data = msu_async_cb_data_new(task, cb);
+ cb_task_data = &cb_data->ut.create_container;
+
+ if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
+ &cb_data->id, &cb_data->error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
+ cb_data->id);
+
+ device = msu_device_from_path(cb_task_data->root_path,
+ upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ cb_task_data->root_path);
+
+ cb_data->error =
+ g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ msu_device_create_container(device, client, task, cb_data->id,
+ cb_data, cancellable);
on_error:
MSU_LOG_DEBUG("Exit");
}
+
+void msu_upnp_create_container_in_any(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb)
+{
+ msu_async_cb_data_t *cb_data;
+ msu_async_create_container_t *cb_task_data;
+ msu_device_t *device;
+
+ MSU_LOG_DEBUG("Enter");
+
+ cb_data = msu_async_cb_data_new(task, cb);
+ cb_task_data = &cb_data->ut.create_container;
+
+ if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
+ &cb_data->id, &cb_data->error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
+ cb_data->id);
+
+ if (strcmp(cb_data->id, "0")) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ cb_data->error =
+ g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+ "CreateContainerInAnyContainer must be "
+ "executed on a root path");
+ goto on_error;
+ }
+
+ device = msu_device_from_path(cb_task_data->root_path,
+ upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s",
+ cb_task_data->root_path);
+
+ cb_data->error =
+ g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ msu_device_create_container(device, client, task,
+ "DLNA.ORG_AnyContainer",
+ cb_data, cancellable);
+
+on_error:
+
+ if (!cb_data->action)
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+
+ MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_update_object(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb)
+{
+ msu_async_cb_data_t *cb_data;
+ msu_async_update_t *cb_task_data;
+ msu_device_t *device;
+ guint32 mask;
+ gchar *root_path = NULL;
+ gchar *upnp_filter = NULL;
+ msu_task_update_t *task_data;
+
+ MSU_LOG_DEBUG("Enter");
+
+ cb_data = msu_async_cb_data_new(task, cb);
+ cb_task_data = &cb_data->ut.update;
+ task_data = &task->ut.update;
+
+ if (!msu_path_get_path_and_id(task->path, &root_path,
+ &cb_data->id, &cb_data->error)) {
+ MSU_LOG_WARNING("Bad path %s", task->path);
+
+ goto on_error;
+ }
+
+ MSU_LOG_DEBUG("Root Path = %s, Id = %s", root_path, cb_data->id);
+
+ device = msu_device_from_path(root_path, upnp->server_udn_map);
+ if (!device) {
+ MSU_LOG_WARNING("Cannot locate device for %s", root_path);
+
+ cb_data->error =
+ g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+ "Cannot locate device corresponding to"
+ " the specified path");
+ goto on_error;
+ }
+
+ if (!msu_props_parse_update_filter(upnp->filter_map,
+ task_data->to_add_update,
+ task_data->to_delete,
+ &mask, &upnp_filter)) {
+ MSU_LOG_WARNING("Invalid Parameter");
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Invalid Parameter");
+ goto on_error;
+ }
+
+ cb_task_data->map = upnp->filter_map;
+
+ MSU_LOG_DEBUG("Filter = %s", upnp_filter);
+ MSU_LOG_DEBUG("Mask = 0x%x", mask);
+
+ if (mask == 0) {
+ MSU_LOG_WARNING("Empty Parameters");
+
+ cb_data->error = g_error_new(MSU_ERROR,
+ MSU_ERROR_OPERATION_FAILED,
+ "Empty Parameters");
+
+ goto on_error;
+ }
+
+ msu_device_update_object(device, client, task, cb_data, upnp_filter,
+ cancellable);
+
+on_error:
+
+ if (root_path)
+ g_free(root_path);
+
+ g_free(upnp_filter);
+
+ if (!cb_data->action)
+ (void) g_idle_add(msu_async_complete_task, cb_data);
+
+ MSU_LOG_DEBUG("Exit");
+}
#ifndef MSU_UPNP_H__
#define MSU_UPNP_H__
+#include "client.h"
#include "task.h"
typedef struct msu_upnp_t_ msu_upnp_t;
typedef void (*msu_upnp_callback_t)(const gchar *path, void *user_data);
typedef void (*msu_upnp_task_complete_t)(msu_task_t *task, GVariant *result,
- GError *error, void *user_data);
+ GError *error);
msu_upnp_t *msu_upnp_new(GDBusConnection *connection,
msu_interface_info_t *interface_info,
void *user_data);
void msu_upnp_delete(msu_upnp_t *upnp);
GVariant *msu_upnp_get_server_ids(msu_upnp_t *upnp);
-void msu_upnp_get_children(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+void msu_upnp_get_children(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data);
-void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+ msu_upnp_task_complete_t cb);
+void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data);
-void msu_upnp_get_prop(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+ msu_upnp_task_complete_t cb);
+void msu_upnp_get_prop(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data);
-void msu_upnp_search(msu_upnp_t *upnp, msu_task_t *task,
- const gchar *protocol_info,
+ msu_upnp_task_complete_t cb);
+void msu_upnp_search(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data);
-void msu_upnp_get_resource(msu_upnp_t *upnp, msu_task_t *task,
+ msu_upnp_task_complete_t cb);
+void msu_upnp_get_resource(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data);
-void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_task_t *task,
+ msu_upnp_task_complete_t cb);
+void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data);
-void msu_upnp_upload(msu_upnp_t *upnp, msu_task_t *task,
+ msu_upnp_task_complete_t cb);
+void msu_upnp_upload(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
GCancellable *cancellable,
- msu_upnp_task_complete_t cb,
- void *user_data);
-
-
+ msu_upnp_task_complete_t cb);
+void msu_upnp_get_upload_status(msu_upnp_t *upnp, msu_task_t *task);
+void msu_upnp_get_upload_ids(msu_upnp_t *upnp, msu_task_t *task);
+void msu_upnp_cancel_upload(msu_upnp_t *upnp, msu_task_t *task);
+void msu_upnp_delete_object(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb);
+void msu_upnp_create_container(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb);
+void msu_upnp_create_container_in_any(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb);
+void msu_upnp_update_object(msu_upnp_t *upnp, msu_client_t *client,
+ msu_task_t *task,
+ GCancellable *cancellable,
+ msu_upnp_task_complete_t cb);
#endif
self.__propsIF = dbus.Interface(bus.get_object(
'com.intel.media-service-upnp', path),
'org.freedesktop.DBus.Properties')
+ self.__objIF = dbus.Interface(bus.get_object(
+ 'com.intel.media-service-upnp', path),
+ 'org.gnome.UPnP.MediaObject2')
+
def get_props(self, iface = ""):
return self.__propsIF.GetAll(iface)
i = i + 2
print
+ def delete(self):
+ return self.__objIF.Delete()
+
+ def update(self, to_add_update, to_delete):
+ return self.__objIF.Update(to_add_update, to_delete)
+
class Item(MediaObject):
def __init__(self, path):
MediaObject.__init__(self, path)
print "Transfer ID: " + str(tid)
print "Path: " + path
+ def create_container(self, name, type, child_types):
+ path = self.__containerIF.CreateContainer(name, type, child_types)
+ print "New container path: " + path
+
class Device(Container):
def __init__(self, path):
print "Transfer ID: " + str(tid)
print "Path: " + path
+ def create_container_in_any(self, name, type, child_types):
+ path = self.__deviceIF.CreateContainerInAnyContainer(name, type,
+ child_types)
+ print "New container path: " + path
+
+ def get_upload_status(self, id):
+ (status, length, total) = self.__deviceIF.GetUploadStatus(id)
+ print "Status: " + status
+ print "Length: " + str(length)
+ print "Total: " + str(total)
+
+ def get_upload_ids(self):
+ upload_ids = self.__deviceIF.GetUploadIDs()
+ print_properties(upload_ids)
+
+ def cancel_upload(self, id):
+ self.__deviceIF.CancelUpload(id)
+
class UPNP(object):
def __init__(self):
def set_protocol_info(self, protocol_info):
self.__manager.SetProtocolInfo(protocol_info)
+ def prefer_local_addresses(self, prefer):
+ self.__manager.PreferLocalAddresses(prefer)