├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile.am ├── NEWS ├── README ├── autogen.sh ├── bootstrap-configure ├── configure.ac ├── doc ├── TODO.txt ├── coding-style.txt ├── logging.txt └── server │ └── dbus │ └── API.txt ├── libdleyna └── server │ ├── Makefile.am │ ├── async.c │ ├── async.h │ ├── client.h │ ├── control-point-server.h │ ├── device.c │ ├── device.h │ ├── dleyna-server-service.conf.in │ ├── ifaddrs.h │ ├── interface.h │ ├── manager.c │ ├── manager.h │ ├── path.c │ ├── path.h │ ├── props.c │ ├── props.h │ ├── search.c │ ├── search.h │ ├── server.c │ ├── server.h │ ├── sort.c │ ├── sort.h │ ├── task.c │ ├── task.h │ ├── upnp.c │ ├── upnp.h │ ├── xml-util.c │ └── xml-util.h ├── m4 ├── compiler-flags.m4 └── log.m4 ├── server ├── Makefile.am ├── com.intel.dleyna-server.service.in ├── daemon.c └── dleyna-server-service-1.0.pc.in └── test └── dbus ├── Makefile.am ├── dms-info.c ├── download_sync_controller.py ├── dsc.sh ├── lost_client_test.py ├── mc.sh ├── mediaconsole.py ├── monitor_changed.py ├── monitor_contents_changes.py ├── monitor_upload_update.py ├── stress_test.py ├── upload_sync_controller.py └── usc.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lo 3 | *~ 4 | *.la 5 | *.pc 6 | *.tgz 7 | *.gz 8 | *.pyc 9 | .dirstamp 10 | 11 | Makefile 12 | Makefile.in 13 | aclocal.m4 14 | autom4te.cache/ 15 | compile 16 | config.guess 17 | config.h 18 | config.h.in 19 | config.log 20 | config.status 21 | config.sub 22 | configure 23 | depcomp 24 | install-sh 25 | libtool 26 | ltmain.sh 27 | missing 28 | .deps/ 29 | .libs/ 30 | stamp-h1 31 | INSTALL 32 | 33 | m4/libtool.m4 34 | m4/ltoptions.m4 35 | m4/ltsugar.m4 36 | m4/ltversion.m4 37 | m4/lt~obsolete.m4 38 | 39 | server/com.intel.dleyna-server.service 40 | libdleyna/server/dleyna-server-service.conf 41 | libdleyna/server/dleyna-server-1.0.pc 42 | 43 | server/dleyna-server-service 44 | test/dbus/dms-info 45 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Mark Ryan (mark.d.ryan@intel.com) 2 | Ludovic Ferrandis (ludovic.ferrandis@intel.com) 3 | Sébastien Bianti (sebastien.bianti@intel.com) 4 | Regis Merlino (regis.merlino@intel.com) 5 | Christophe Guiraud (christophe.guiraud@intel.com) 6 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | version 0.6.0 2 | - [Props] Fix ChildCount property type 3 | - Added new core.c and core.h to Makefile.am. 4 | - Add Artist and AlbumArtURL to MediaContainer2 5 | - ifaddrs.h for Andriod compile 6 | - [m4] Don't use bash arrays in m4 macros 7 | - [m4] Don't use bash "let" builtin 8 | - [m4] Use AS_VAR_APPEND macro instead of "+=" 9 | Merge pull request #149 10 | - Fix possible use-after-free on exit 11 | Merge pull request #151 12 | - fix for issue #156 13 | Invalid log line 14 | https://github.com/01org/dleyna-server/issues/156 15 | Merge pull request #157 16 | - fix for issues #154 and #155 17 | Dereference of undefined pointer value 18 | https://github.com/01org/dleyna-server/issues/154 19 | Result of operation is garbage or undefined 20 | https://github.com/01org/dleyna-server/issues/155 21 | Merge pull request #158 22 | - Include libgupnp/gupnp-context-manager.h 23 | Merge pull request #159 24 | - Changed the Copyright to 2017 25 | 26 | version 0.5.0 27 | - [Build] Fix out-of-source-tree builds 28 | https://github.com/01org/dleyna-server/issues/143 29 | - Fix various configure & build issues 30 | [Autoconf] Sub Makefile: Remove ACLOCAL_AMFLAGS 31 | https://github.com/01org/dleyna-collabora-android/issues/127 32 | [Autoconf] Add --no-undefined to compiler option 33 | - [upnp] Use "port" setting when creating GUPnPContextManager 34 | https://github.com/01org/dleyna-collabora-android/issues/140 35 | - [Deprecated API] Use new API instead of deprecated 36 | https://github.com/01org/dleyna-server/issues/104 37 | - [Device] Fix wake-on ip address used for broadcast 38 | - [Device] Sleeping devices cache cleanup 39 | - [Device] Improve sleeping context lookup 40 | - [Device] Move the network interface info storage 41 | - [Device] Improve Network Interface info and device context matching 42 | - [Device] Retrieve sleeping state via GetInterfaceInfo action 43 | - [Device] Add sleeping device memory cache 44 | - [Device] Add wake packet sending support 45 | - [Device] Add Energy Management features 46 | - [Configuration] Remove libdleyna-server .pc file 47 | https://github.com/01org/dleyna-server/issues/113 48 | - [Documentation] Fix URL to MediaServer2Spec 49 | - [test] Save changed ServiceResetToken in configuration 50 | - [test] Survive a missing ServiceResetToken in dsc 51 | - [Tests] Fix a typo in the Upload Sync Controller's error management 52 | 53 | version 0.4.0 54 | - Logs: provide correct component version 55 | - Don't return empty properties in GetAll 56 | - Refactor the filtering for GetAll 57 | - Add a new MediaDevice BrowseObjects API 58 | https://github.com/01org/dleyna-server/issues/114 59 | - Support for a new "Error" property, used in BrowseObjects 60 | - Deprecate LastChange in favor of Changed signal 61 | https://github.com/01org/dleyna-server/issues/109 62 | - Fix a memory leak 63 | https://github.com/01org/dleyna-collabora-android/issues/58 64 | - Support of the ChildCount property 65 | https://github.com/01org/dleyna-server/issues/122 66 | - New whitelist APIs 67 | - Add a 'never quit' property to the Manager object 68 | 69 | version 0.2.1 70 | - Various build optimizations 71 | - Fix a crash case when the server stops 72 | - Added the new TypeEx property and fixed Type 73 | - Some documentation fixes 74 | - Code cleanup 75 | - Add a sample upload sync controller app 76 | - Add network filtering support 77 | 78 | version 0.1.0 79 | - Prepare for first stable branch 80 | 81 | version 0.0.2 82 | - Add a new method GetMetaData to the org.gnome.UPnP.MediaObject2 interface 83 | to allow the retrieval of the Meta data information of an object in 84 | DIDL-Lite XML format 85 | - Handle wild cards for SortCaps & SearchCaps properties 86 | - Add a new property and a new function to media container objects: 87 | Resource and GetCompatibleResource() 88 | - Fixed bug: CreateContainer does not specify the correct DLNAManaged flags 89 | https://github.com/01org/dleyna-server/issues/24 90 | - Add MediaItem2 resource properties to container objects: 91 | URLs, Size, DLNAProfile & MimeType 92 | - Fixed bug: ObjectUpdateID and ContainerUpdateID are reported on all 93 | objects and containers 94 | https://github.com/01org/dleyna-server/issues/27 95 | - Fixed bug: dleyna-server can fail to discover a device if a network 96 | connection is lost during device construction 97 | https://github.com/01org/dleyna-server/issues/14 98 | - Fixed bug: We don't display media with invalid metadata 99 | https://github.com/01org/dleyna-renderer/issues/30 100 | - Fixed bug: MediaConnect DMS crashes dLeyna 101 | https://github.com/01org/dleyna-server/issues/49 102 | - Two new methods have been added to the UPNP class, server_from_name and 103 | server_from_udn. These methods can be used to construct Device objects 104 | from UDNs or friendly names 105 | - Add new org.gnome.MediaContainer2 properties: 106 | DLNAConversion, DLNAFlags & DLNAOperation 107 | - Add a Rescan method to Manager interface 108 | - Add autogen.sh script to call `autoreconf -i` 109 | - Remove CreatePlayListInAnyContainer() from 110 | com.intel.dLeynaServer.MediaDevice 111 | - Remove CreatePlayList() from org.gnome.MediaContainer2 112 | - Add CreateReference method to org.gnome.MediaContainer2 113 | - Add support for object.container.playlistContainer and 114 | object.container.storageFolder object classes 115 | - Fixed bug: The dLeyna-server CreateClasses property is incorrect 116 | https://github.com/01org/dleyna-server/issues/94 117 | - Fixed bug: Incorrect Parent Path reported for XBMC 118 | https://github.com/01org/dleyna-server/issues/32 119 | - Add a GetIcon() method to com.intel.dLeynaServer.MediaDevice 120 | 121 | version 0.0.1 122 | - Initial version of dleyna-server. 123 | - Enable support of deleyna-server as git submodules. 124 | 125 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = libdleyna/server 2 | 3 | if BUILD_SERVER 4 | SUBDIRS += server test/dbus 5 | endif 6 | 7 | ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} 8 | 9 | MAINTAINERCLEANFILES = Makefile.in \ 10 | aclocal.m4 \ 11 | configure \ 12 | config.h.in \ 13 | config.h.in~ \ 14 | build-aux/depcomp \ 15 | build-aux/compile \ 16 | build-aux/missing \ 17 | build-aux/install-sh 18 | 19 | maintainer-clean-local: 20 | rm -rf build-aux 21 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/dleyna-server/8665ecf6c4c28a330419921871d8fefa32aa6734/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | DISCONTINUATION OF PROJECT. 2 | 3 | This project will no longer be maintained by Intel. 4 | 5 | Intel will not provide or guarantee development of or support for this project, including but not limited to, maintenance, bug fixes, new releases or updates. 6 | 7 | Patches to this project are no longer accepted by Intel. 8 | 9 | If you have an ongoing need to use this project, are interested in independently developing it, 10 | or would like to maintain patches for the community, please create your own fork of the project. 11 | 12 | Introduction: 13 | ------------- 14 | 15 | TODO 16 | 17 | Compilation 18 | ------------ 19 | 20 | TODO 21 | 22 | Working with the source code repository 23 | --------------------------------------- 24 | 25 | dleyna-server can be downloaded, compiled and installed as 26 | follows: 27 | 28 | Clone repository 29 | # git clone git://github.com/01org/dleyna-server.git 30 | # cd dleyna-server 31 | 32 | Configure and build 33 | # ./autogen.sh 34 | # make 35 | 36 | Final installation 37 | # sudo make install 38 | 39 | These instructions are suitable for users who simply want to install 40 | and run dleyna-server. However, developers wishing to contribute 41 | to the project should follow a separate "Configure and build" step. 42 | 43 | Configure and build 44 | # ./bootstrap-configure 45 | # make 46 | 47 | The script "bootstrap-configure" cleans the repository, calls 48 | autreconf and then invokes configure with proper settings for 49 | development. These settings include the enabling of 50 | maintainer mode and debugging. 51 | 52 | Developers can remove autogenerated files with the following command 53 | 54 | # make maintainer-clean 55 | 56 | Configure Options: 57 | ------------------ 58 | 59 | --enable-werror 60 | 61 | This option is disabled by default. To enable use --enable-werror. 62 | When enabled, all warnings are treated as errors during compilation. 63 | Should be enabled during development to ensure that errors do not 64 | creep into the code base. This option is enabled by 65 | bootstrap-configure. 66 | 67 | --enable-debug 68 | 69 | This option is disabled by default. To enable use 70 | --enable-debug. When enabled, the make files produce debug builds. 71 | This option is enabled by bootstrap-configure. 72 | 73 | --enable-optimization 74 | 75 | This option is enabled by default. To disable use 76 | --disable-optimization. When enabled it turns on compiler 77 | optimizations. Disable = -O0, enable = -O2. 78 | 79 | --enable-never-quit 80 | 81 | This option is disabled by default. To enable use --enable-never-quit. 82 | When enabled, dleyna-server-service doesn't quit when the last 83 | client disconnects. 84 | 85 | --with-log-type 86 | 87 | See logging.txt for more information about logging. 88 | 89 | --with-log-level 90 | 91 | See logging.txt for more information about logging. 92 | 93 | --with-connector-name 94 | 95 | Set the IPC mechanism to be used. 96 | 97 | --enable-lib-only 98 | 99 | This option is disabled by default. To enable use --enable-lib-only. 100 | When enabled, only the libdleyna-server library is built. 101 | 102 | --with-ua-prefix 103 | 104 | This option allows a prefix to be added to the SOUP session user agent. 105 | For example, --with-ua-prefix=MyPrefix can be used to change a default user 106 | agent string from "dLeyna/0.0.1 GUPnP/0.19.4 DLNADOC/1.50" to 107 | "MyPrefix dLeyna/0.0.1 GUPnP/0.19.4 DLNADOC/1.50". 108 | 109 | --with-dbus-service-dir 110 | 111 | By default, the dbus service files are installed in $(datadir)/dbus-1/services. 112 | This option allows to choose another installation directory. 113 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run this to generate all the initial makefiles, etc. 3 | # Derived from https://git.gnome.org/browse/glib/tree/autogen.sh 4 | 5 | test -n "$srcdir" || srcdir=`dirname "$0"` 6 | test -n "$srcdir" || srcdir=. 7 | 8 | olddir=`pwd` 9 | cd "$srcdir" 10 | 11 | AUTORECONF=`which autoreconf` 12 | if test -z $AUTORECONF; then 13 | echo "*** No autoreconf found, please install it ***" 14 | exit 1 15 | fi 16 | 17 | autoreconf --force --install --verbose || exit $? 18 | 19 | cd "$olddir" 20 | test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" 21 | -------------------------------------------------------------------------------- /bootstrap-configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -f config.status ]; then 4 | make maintainer-clean 5 | fi 6 | 7 | ./autogen.sh --enable-maintainer-mode \ 8 | --enable-silent-rules \ 9 | --disable-optimization \ 10 | --enable-debug \ 11 | --with-log-level=8 $* 12 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.66]) 2 | 3 | AC_INIT([dleyna-server], 4 | [0.6.0], 5 | [https://github.com/01org/dleyna-server/issues/new], 6 | , 7 | [https://01.org/dleyna/]) 8 | 9 | AC_CONFIG_HEADERS([config.h]) 10 | AC_CONFIG_AUX_DIR([build-aux]) 11 | AC_CONFIG_MACRO_DIR([m4]) 12 | AC_CONFIG_SRCDIR([libdleyna/server/server.c]) 13 | 14 | AC_PREFIX_DEFAULT(/usr/local) 15 | 16 | AM_INIT_AUTOMAKE([subdir-objects]) 17 | 18 | AM_MAINTAINER_MODE 19 | AM_SILENT_RULES([yes]) 20 | 21 | DLEYNA_SERVER_COMPILER_FLAGS 22 | 23 | # Checks for languages. 24 | AC_LANG_C 25 | 26 | # Checks for programs. 27 | AC_PROG_CC 28 | AM_PROG_CC_C_O 29 | AC_PROG_MKDIR_P 30 | 31 | # Initialize libtool 32 | # Disable generation of static libraries 33 | LT_PREREQ([2.2.6]) 34 | LT_INIT([dlopen disable-static]) 35 | LT_LANG([C]) 36 | 37 | # Checks for libraries. 38 | PKG_PROG_PKG_CONFIG(0.16) 39 | PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.36]) 40 | PKG_CHECK_MODULES([GIO], [gio-2.0 >= 2.36]) 41 | PKG_CHECK_MODULES([GSSDP], [gssdp-1.2 >= 0.13.2]) 42 | PKG_CHECK_MODULES([GUPNP], [gupnp-1.2 >= 0.20.3]) 43 | PKG_CHECK_MODULES([GUPNPAV], [gupnp-av-1.0 >= 0.11.5]) 44 | PKG_CHECK_MODULES([GUPNPDLNA], [gupnp-dlna-2.0 >= 0.9.4]) 45 | PKG_CHECK_MODULES([SOUP], [libsoup-2.4 >= 2.28.2]) 46 | PKG_CHECK_MODULES([LIBXML], [libxml-2.0]) 47 | 48 | # Checks for header files. 49 | AC_CHECK_HEADERS([stdlib.h string.h syslog.h]) 50 | 51 | # Checks for typedefs, structures, and compiler characteristics. 52 | AC_TYPE_UINT8_T 53 | AC_HEADER_STDBOOL 54 | AC_TYPE_SIZE_T 55 | 56 | # Checks for library functions. 57 | AC_FUNC_MALLOC 58 | AC_FUNC_REALLOC 59 | AC_CHECK_FUNCS([memset strchr strrchr strstr]) 60 | 61 | # Define Log Level values 62 | LOG_LEVEL_0=0x00 63 | LOG_LEVEL_1=0x01 64 | LOG_LEVEL_2=0x02 65 | LOG_LEVEL_3=0x04 66 | LOG_LEVEL_4=0x08 67 | LOG_LEVEL_5=0x10 68 | LOG_LEVEL_6=0x20 69 | LOG_LEVEL_7=0x13 70 | LOG_LEVEL_8=0x3F 71 | 72 | AC_DEFINE_UNQUOTED([DLEYNA_LOG_LEVEL_DISABLED], [${LOG_LEVEL_0}], [Log level flag for disabled messages]) 73 | AC_DEFINE_UNQUOTED([DLEYNA_LOG_LEVEL_ERROR], [${LOG_LEVEL_1}], [Log level flag for errors]) 74 | AC_DEFINE_UNQUOTED([DLEYNA_LOG_LEVEL_CRITICAL], [${LOG_LEVEL_2}], [Log level flag for critical messages]) 75 | AC_DEFINE_UNQUOTED([DLEYNA_LOG_LEVEL_WARNING], [${LOG_LEVEL_3}], [Log level flag for warnings]) 76 | AC_DEFINE_UNQUOTED([DLEYNA_LOG_LEVEL_MESSAGE], [${LOG_LEVEL_4}], [Log level flag for messages]) 77 | AC_DEFINE_UNQUOTED([DLEYNA_LOG_LEVEL_INFO], [${LOG_LEVEL_5}], [Log level flag for informational messages]) 78 | AC_DEFINE_UNQUOTED([DLEYNA_LOG_LEVEL_DEBUG], [${LOG_LEVEL_6}], [Log level flag for debug messages]) 79 | AC_DEFINE_UNQUOTED([DLEYNA_LOG_LEVEL_DEFAULT], [${LOG_LEVEL_7}], [Log level flag to display default level messages]) 80 | AC_DEFINE_UNQUOTED([DLEYNA_LOG_LEVEL_ALL], [${LOG_LEVEL_8}], [Log level flag for all messages]) 81 | 82 | AC_ARG_ENABLE(master-build,, 83 | [], 84 | [master_build=no]) 85 | 86 | AS_IF([test "x$master_build" = "xno"], 87 | [PKG_CHECK_MODULES([DLEYNA_CORE], [dleyna-core-1.0 >= 0.6.0])], 88 | [this_abs_top_srcdir=`cd "$srcdir" && pwd`; 89 | DLEYNA_CORE_CFLAGS="-I$this_abs_top_srcdir/../dleyna-core"; 90 | DLEYNA_CORE_LIBS="-L$this_abs_top_srcdir/../dleyna-core/.libs -ldleyna-core-1.0" 91 | ]) 92 | 93 | AC_ARG_ENABLE(debug, 94 | AS_HELP_STRING( 95 | [--enable-debug], 96 | [enable compiling with debugging information]), 97 | [], 98 | [enable_debug=no]) 99 | 100 | AS_CASE("${enable_debug}", 101 | [yes], [CFLAGS="$CFLAGS -g"; 102 | AC_DEFINE_UNQUOTED([DLEYNA_DEBUG_ENABLED],[1], [Compiling with debugging information enabled]) 103 | ], 104 | [no], [], 105 | [AC_MSG_ERROR([bad value ${enable_debug} for --enable-debug])]) 106 | 107 | 108 | AC_ARG_ENABLE(werror, 109 | AS_HELP_STRING( 110 | [--enable-werror], 111 | [warnings are treated as errors]), 112 | [], 113 | [enable_werror=no]) 114 | 115 | AS_CASE("${enable_werror}", 116 | [yes], [CFLAGS="$CFLAGS -Werror"], 117 | [no], [], 118 | [AC_MSG_ERROR([bad value ${enable_werror} for --enable-werror])]) 119 | 120 | 121 | AC_ARG_ENABLE(optimization, 122 | AS_HELP_STRING( 123 | [--disable-optimization], 124 | [disable code optimization through compiler]), 125 | [], 126 | [enable_optimization=yes]) 127 | 128 | AS_CASE("${enable_optimization}", 129 | [yes], [disable_optimization=no], 130 | [no], [CFLAGS="$CFLAGS -O0"; disable_optimization=yes], 131 | [AC_MSG_ERROR([bad value ${enable_optimization} for --enable-werror])]) 132 | 133 | 134 | AC_ARG_ENABLE(never-quit, 135 | AS_HELP_STRING( 136 | [--enable-never-quit], 137 | [Service doesn't quit when last client disconnects]), 138 | [], 139 | [enable_never_quit=no]) 140 | 141 | AS_CASE("${enable_never_quit}", 142 | [yes], [never_quit=true], 143 | [no], [never_quit=false], 144 | [AC_MSG_ERROR([bad value ${enable_never_quit} for --enable-never-quit])]) 145 | 146 | 147 | AC_ARG_WITH(connector-name, 148 | AS_HELP_STRING( 149 | [--with-connector-name], 150 | [IPC connector name]), 151 | [], 152 | [with_connector_name=dbus]) 153 | 154 | 155 | AC_ARG_WITH(log-level, 156 | AS_HELP_STRING( 157 | [--with-log-level], 158 | [enable logging information (0,1..6,7,8)\ 159 | 0=disabled \ 160 | 7=default (=1,2,5) \ 161 | 8=all (=1,2,3,4,5,6) \ 162 | 1,..,6=a comma separated list of log level\ 163 | ]), 164 | [], 165 | [with_log_level=7]) 166 | 167 | DLEYNA_LOG_LEVEL_CHECK([${with_log_level}]) 168 | 169 | 170 | AC_ARG_WITH(log-type, 171 | AS_HELP_STRING( 172 | [--with-log-type], 173 | [Select log output technology \ 174 | 0=syslog 1=GLib \ 175 | ]), 176 | [], 177 | [with_log_type=0]) 178 | 179 | DLEYNA_LOG_TYPE_CHECK([${with_log_type}]) 180 | 181 | 182 | AC_ARG_WITH(ua-prefix, 183 | AS_HELP_STRING( 184 | [--with-ua-prefix], 185 | [Specify a user agent prefix]), 186 | [with_ua_prefix = "$withval"; AC_DEFINE_UNQUOTED([UA_PREFIX], "$with_ua_prefix", [User Agent prefix])], 187 | []) 188 | 189 | AC_ARG_WITH(dbus_service_dir, 190 | AS_HELP_STRING([--with-dbus-service-dir=PATH],[choose directory for dbus service files, [default=PREFIX/share/dbus-1/services]]), 191 | with_dbus_service_dir="$withval", with_dbus_service_dir=$datadir/dbus-1/services) 192 | DBUS_SERVICE_DIR=$with_dbus_service_dir 193 | AC_SUBST(DBUS_SERVICE_DIR) 194 | 195 | 196 | AC_ARG_ENABLE(lib-only, 197 | AS_HELP_STRING( 198 | [--enable-lib-only], 199 | [compile only the libdleyna-server library]), 200 | [], 201 | [enable_lib_only=no]) 202 | 203 | AM_CONDITIONAL([BUILD_SERVER], [test "x$enable_lib_only" = "xno"]) 204 | 205 | AC_DEFINE([DLEYNA_SERVER_OBJECT], "/com/intel/dLeynaServer", [Name of object exposed by dleyna-server]) 206 | AC_DEFINE([DLEYNA_SERVER_PATH], "/com/intel/dLeynaServer/server", [Path of server objects]) 207 | 208 | DLEYNA_SERVER_NAME=com.intel.dleyna-server 209 | AC_SUBST(DLEYNA_SERVER_NAME) 210 | AC_DEFINE([DLEYNA_SERVER_NAME], "com.intel.dleyna-server", 211 | [d-Bus Name of dleyna-server]) 212 | 213 | DLEYNA_SERVER_INTERFACE_MANAGER=com.intel.dLeynaServer.Manager 214 | AC_SUBST(DLEYNA_SERVER_INTERFACE_MANAGER) 215 | AC_DEFINE([DLEYNA_SERVER_INTERFACE_MANAGER], "com.intel.dLeynaServer.Manager", 216 | [d-Bus Name of dleyna-server main interface]) 217 | 218 | DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE=com.intel.dLeynaServer.MediaDevice 219 | AC_SUBST(DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE) 220 | AC_DEFINE([DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE], "com.intel.dLeynaServer.MediaDevice", 221 | [d-Bus Name of dleyna-server device interface]) 222 | 223 | AC_SUBST([never_quit]) 224 | AC_SUBST([with_connector_name]) 225 | AC_SUBST([with_log_level]) 226 | AC_SUBST([with_log_type]) 227 | 228 | AC_CONFIG_FILES([Makefile \ 229 | libdleyna/server/Makefile \ 230 | libdleyna/server/dleyna-server-service.conf \ 231 | server/dleyna-server-service-1.0.pc \ 232 | server/Makefile \ 233 | test/dbus/Makefile 234 | ]) 235 | 236 | AC_OUTPUT 237 | 238 | AS_ECHO(["------------------------------------------------- 239 | 240 | ${PACKAGE_NAME} Version ${PACKAGE_VERSION} 241 | 242 | Prefix : '${prefix}' 243 | Compiler : '${CC}' 244 | CFLAGS : '${CFLAGS}' 245 | 246 | -Package features: 247 | - enable-werror : ${enable_werror} 248 | - enable-debug : ${enable_debug} 249 | - enable-never-quit : ${enable_never_quit} 250 | - with-connector-name : ${with_connector_name} 251 | - disable-optimization : ${disable_optimization} 252 | - with-log-level : ${with_log_level} 253 | - with-log-type : ${with_log_type} 254 | - with-ua-prefix : ${with_ua_prefix} 255 | - enable-lib-only : ${enable_lib_only} 256 | - with-dbus-service-dir : ${with_dbus_service_dir} 257 | 258 | --------------------------------------------------"]) 259 | -------------------------------------------------------------------------------- /doc/TODO.txt: -------------------------------------------------------------------------------- 1 | TODO: 2 | ----- 3 | 4 | You can check the list of features we have planned or are currently working on 5 | in github: 6 | 7 | 8 | -------------------------------------------------------------------------------- /doc/coding-style.txt: -------------------------------------------------------------------------------- 1 | dLeyna-server uses the dLeyna-core coding guidelines: 2 | 3 | https://github.com/01org/dleyna-core/blob/master/doc/coding-style.txt -------------------------------------------------------------------------------- /doc/logging.txt: -------------------------------------------------------------------------------- 1 | dLeyna-server uses the dLeyna-core logging guidelines: 2 | 3 | https://github.com/01org/dleyna-core/blob/master/doc/logging.txt -------------------------------------------------------------------------------- /libdleyna/server/Makefile.am: -------------------------------------------------------------------------------- 1 | DLEYNA_SERVER_VERSION = 1:3:0 2 | 3 | AM_CFLAGS = $(GLIB_CFLAGS) \ 4 | $(GIO_CFLAGS) \ 5 | $(DLEYNA_CORE_CFLAGS) \ 6 | $(GSSDP_CFLAGS) \ 7 | $(GUPNP_CFLAGS) \ 8 | $(GUPNPAV_CFLAGS) \ 9 | $(GUPNPDLNA_CFLAGS) \ 10 | $(SOUP_CFLAGS) \ 11 | $(LIBXML_CFLAGS) \ 12 | -include config.h 13 | 14 | pkglib_LTLIBRARIES = libdleyna-server-1.0.la 15 | 16 | libdleyna_serverincdir = $(includedir)/dleyna-1.0/libdleyna/server 17 | 18 | libdleyna_serverinc_HEADERS = control-point-server.h 19 | 20 | libdleyna_server_1_0_la_LDFLAGS = -version-info $(DLEYNA_SERVER_VERSION) \ 21 | -no-undefined 22 | 23 | libdleyna_server_1_0_la_SOURCES = $(libdleyna_serverinc_HEADERS) \ 24 | server.c \ 25 | async.c \ 26 | device.c \ 27 | manager.c \ 28 | path.c \ 29 | props.c \ 30 | search.c \ 31 | sort.c \ 32 | task.c \ 33 | upnp.c \ 34 | xml-util.c 35 | 36 | libdleyna_server_1_0_la_LIBADD = $(GLIB_LIBS) \ 37 | $(GIO_LIBS) \ 38 | $(DLEYNA_CORE_LIBS) \ 39 | $(GSSDP_LIBS) \ 40 | $(GUPNP_LIBS) \ 41 | $(GUPNPAV_LIBS) \ 42 | $(GUPNPDLNA_LIBS) \ 43 | $(SOUP_LIBS) \ 44 | $(LIBXML_LIBS) 45 | 46 | MAINTAINERCLEANFILES = Makefile.in \ 47 | aclocal.m4 \ 48 | configure \ 49 | config.h.in \ 50 | config.h.in~ \ 51 | build-aux/depcomp \ 52 | build-aux/compile \ 53 | build-aux/missing \ 54 | build-aux/install-sh 55 | 56 | sysconf_DATA = dleyna-server-service.conf 57 | 58 | EXTRA_DIST = $(sysconf_DATA) \ 59 | async.h \ 60 | client.h \ 61 | device.h \ 62 | interface.h \ 63 | manager.h \ 64 | path.h \ 65 | props.h \ 66 | search.h \ 67 | server.h \ 68 | sort.h \ 69 | task.h \ 70 | upnp.h \ 71 | xml-util.h 72 | 73 | CLEANFILES = dleyna-server-service.conf 74 | DISTCLEANFILES = dleyna-server-service.conf 75 | 76 | maintainer-clean-local: 77 | rm -rf build-aux 78 | -------------------------------------------------------------------------------- /libdleyna/server/async.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "async.h" 27 | #include "server.h" 28 | 29 | void dls_async_task_delete(dls_async_task_t *cb_data) 30 | { 31 | switch (cb_data->task.type) { 32 | case DLS_TASK_GET_CHILDREN: 33 | case DLS_TASK_SEARCH: 34 | if (cb_data->ut.bas.vbs) 35 | g_ptr_array_unref(cb_data->ut.bas.vbs); 36 | break; 37 | case DLS_TASK_MANAGER_GET_ALL_PROPS: 38 | case DLS_TASK_GET_ALL_PROPS: 39 | case DLS_TASK_GET_RESOURCE: 40 | if (cb_data->ut.get_all.vb) 41 | g_variant_builder_unref(cb_data->ut.get_all.vb); 42 | break; 43 | case DLS_TASK_BROWSE_OBJECTS: 44 | if (cb_data->ut.browse_objects.avb) 45 | g_variant_builder_unref(cb_data->ut.browse_objects.avb); 46 | g_free(cb_data->ut.browse_objects.objects_id); 47 | g_free(cb_data->ut.browse_objects.upnp_filter); 48 | break; 49 | case DLS_TASK_UPLOAD_TO_ANY: 50 | case DLS_TASK_UPLOAD: 51 | g_free(cb_data->ut.upload.mime_type); 52 | break; 53 | case DLS_TASK_UPDATE_OBJECT: 54 | g_free(cb_data->ut.update.current_tag_value); 55 | g_free(cb_data->ut.update.new_tag_value); 56 | break; 57 | default: 58 | break; 59 | } 60 | 61 | if (cb_data->cancellable) 62 | g_object_unref(cb_data->cancellable); 63 | } 64 | 65 | gboolean dls_async_task_complete(gpointer user_data) 66 | { 67 | dls_async_task_t *cb_data = user_data; 68 | 69 | DLEYNA_LOG_DEBUG("Enter. Error %p", (void *)cb_data->error); 70 | DLEYNA_LOG_DEBUG_NL(); 71 | 72 | if (cb_data->proxy != NULL) 73 | g_object_remove_weak_pointer((G_OBJECT(cb_data->proxy)), 74 | (gpointer *)&cb_data->proxy); 75 | 76 | cb_data->cb(&cb_data->task, cb_data->error); 77 | 78 | return FALSE; 79 | } 80 | 81 | void dls_async_task_cancelled_cb(GCancellable *cancellable, gpointer user_data) 82 | { 83 | dls_async_task_t *cb_data = user_data; 84 | 85 | if (cb_data->proxy != NULL) 86 | gupnp_service_proxy_cancel_action(cb_data->proxy, 87 | cb_data->action); 88 | 89 | if (!cb_data->error) 90 | cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, 91 | DLEYNA_ERROR_CANCELLED, 92 | "Operation cancelled."); 93 | (void) g_idle_add(dls_async_task_complete, cb_data); 94 | } 95 | 96 | void dls_async_task_cancel(dls_async_task_t *cb_data) 97 | { 98 | if (cb_data->cancellable) 99 | g_cancellable_cancel(cb_data->cancellable); 100 | } 101 | -------------------------------------------------------------------------------- /libdleyna/server/async.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #ifndef DLS_ASYNC_H__ 24 | #define DLS_ASYNC_H__ 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include "server.h" 32 | #include "task.h" 33 | #include "upnp.h" 34 | 35 | typedef struct dls_async_task_t_ dls_async_task_t; 36 | typedef guint64 dls_upnp_prop_mask; 37 | 38 | typedef void (*dls_async_cb_t)(dls_async_task_t *cb_data); 39 | 40 | typedef struct dls_async_bas_t_ dls_async_bas_t; 41 | struct dls_async_bas_t_ { 42 | dls_upnp_prop_mask filter_mask; 43 | GPtrArray *vbs; 44 | const gchar *protocol_info; 45 | gboolean need_child_count; 46 | guint retrieved; 47 | guint max_count; 48 | dls_async_cb_t get_children_cb; 49 | }; 50 | 51 | typedef struct dls_async_get_prop_t_ dls_async_get_prop_t; 52 | struct dls_async_get_prop_t_ { 53 | GCallback prop_func; 54 | const gchar *protocol_info; 55 | }; 56 | 57 | typedef struct dls_async_get_all_t_ dls_async_get_all_t; 58 | struct dls_async_get_all_t_ { 59 | GCallback prop_func; 60 | GVariantBuilder *vb; 61 | dls_upnp_prop_mask filter_mask; 62 | const gchar *protocol_info; 63 | gboolean need_child_count; 64 | gboolean device_object; 65 | GUPnPServiceProxy *proxy; 66 | }; 67 | 68 | typedef struct dls_async_upload_t_ dls_async_upload_t; 69 | struct dls_async_upload_t_ { 70 | const gchar *object_class; 71 | gchar *mime_type; 72 | }; 73 | 74 | typedef struct dls_async_update_t_ dls_async_update_t; 75 | struct dls_async_update_t_ { 76 | gchar *current_tag_value; 77 | gchar *new_tag_value; 78 | GHashTable *map; 79 | }; 80 | 81 | typedef struct dls_async_browse_objects_t_ dls_async_browse_objects_t; 82 | struct dls_async_browse_objects_t_ { 83 | dls_async_get_all_t get_all; /* pseudo inheritance - MUST be first */ 84 | GVariantBuilder *avb; 85 | gchar *upnp_filter; 86 | const dleyna_task_queue_key_t *queue_id; 87 | const gchar **objects_id; 88 | guint object_count; 89 | guint index; 90 | }; 91 | 92 | struct dls_async_task_t_ { 93 | dls_task_t task; /* pseudo inheritance - MUST be first field */ 94 | dls_upnp_task_complete_t cb; 95 | GError *error; 96 | GUPnPServiceProxyAction *action; 97 | GUPnPServiceProxy *proxy; 98 | GCancellable *cancellable; 99 | gulong cancel_id; 100 | union { 101 | dls_async_bas_t bas; 102 | dls_async_get_prop_t get_prop; 103 | dls_async_get_all_t get_all; 104 | dls_async_upload_t upload; 105 | dls_async_update_t update; 106 | dls_async_browse_objects_t browse_objects; 107 | } ut; 108 | }; 109 | 110 | void dls_async_task_delete(dls_async_task_t *cb_data); 111 | 112 | gboolean dls_async_task_complete(gpointer user_data); 113 | 114 | void dls_async_task_cancelled_cb(GCancellable *cancellable, gpointer user_data); 115 | 116 | void dls_async_task_cancel(dls_async_task_t *cb_data); 117 | 118 | #endif /* DLS_ASYNC_H__ */ 119 | -------------------------------------------------------------------------------- /libdleyna/server/client.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Regis Merlino 20 | * 21 | */ 22 | 23 | #ifndef DLS_CLIENT_H__ 24 | #define DLS_CLIENT_H__ 25 | 26 | #include 27 | 28 | typedef struct dls_client_t_ dls_client_t; 29 | struct dls_client_t_ { 30 | gchar *protocol_info; 31 | gboolean prefer_local_addresses; 32 | }; 33 | 34 | #endif /* DLS_CLIENT_H__ */ 35 | -------------------------------------------------------------------------------- /libdleyna/server/control-point-server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Regis Merlino 20 | * 21 | */ 22 | 23 | #ifndef DLEYNA_CONTROL_POINT_SERVER_H__ 24 | #define DLEYNA_CONTROL_POINT_SERVER_H__ 25 | 26 | #include 27 | 28 | const dleyna_control_point_t *dleyna_control_point_get_server(void); 29 | 30 | #endif /* DLEYNA_CONTROL_POINT_SERVER_H__ */ 31 | -------------------------------------------------------------------------------- /libdleyna/server/device.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #ifndef DLS_DEVICE_H__ 24 | #define DLS_DEVICE_H__ 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include "async.h" 32 | #include "client.h" 33 | #include "props.h" 34 | 35 | typedef struct dls_network_if_info_t_ dls_network_if_info_t; 36 | struct dls_network_if_info_t_ { 37 | gchar *system_name; 38 | gchar *mac_address; 39 | gchar *device_uuid; 40 | gchar *network_if_mode; 41 | gchar *wake_on_pattern; 42 | gchar *wake_transport; 43 | guint max_wake_on_delay; 44 | GList *ip_addresses; 45 | guint ip_address_position; 46 | }; 47 | 48 | typedef struct dls_service_t_ dls_service_t; 49 | struct dls_service_t_ { 50 | GUPnPServiceProxy *proxy; 51 | gboolean subscribed; 52 | guint timeout_id; 53 | }; 54 | 55 | struct dls_device_context_t_ { 56 | gchar *ip_address; 57 | GUPnPDeviceProxy *device_proxy; 58 | GUPnPDeviceInfo *device_info; 59 | dls_device_t *device; 60 | dls_service_t cds; 61 | dls_service_t ems; 62 | }; 63 | 64 | typedef struct dls_device_icon_t_ dls_device_icon_t; 65 | struct dls_device_icon_t_ { 66 | gchar *mime_type; 67 | guchar *bytes; 68 | gsize size; 69 | }; 70 | 71 | struct dls_device_t_ { 72 | dleyna_connector_id_t connection; 73 | guint id; 74 | gchar *path; 75 | GPtrArray *contexts; 76 | dls_device_context_t *sleeping_context; 77 | guint wake_on_timeout_id; 78 | guint timeout_id; 79 | GHashTable *uploads; 80 | GHashTable *upload_jobs; 81 | guint upload_id; 82 | guint system_update_id; 83 | GVariant *search_caps; 84 | GVariant *sort_caps; 85 | GVariant *sort_ext_caps; 86 | GVariant *feature_list; 87 | gboolean shutting_down; 88 | gboolean has_last_change; 89 | guint construct_step; 90 | dls_device_icon_t icon; 91 | gboolean sleeping; 92 | dls_network_if_info_t *network_if_info; 93 | }; 94 | 95 | dls_device_context_t *dls_device_append_new_context(dls_device_t *device, 96 | const gchar *ip_address, 97 | GUPnPDeviceProxy *proxy, 98 | GUPnPDeviceInfo *device_info); 99 | 100 | void dls_device_delete(void *device); 101 | 102 | void dls_device_unsubscribe(void *device); 103 | 104 | void dls_device_construct( 105 | dls_device_t *dev, 106 | dls_device_context_t *context, 107 | dleyna_connector_id_t connection, 108 | const dleyna_connector_dispatch_cb_t *dispatch_table, 109 | GHashTable *property_map, 110 | const dleyna_task_queue_key_t *queue_id); 111 | 112 | dls_device_t *dls_device_new( 113 | dleyna_connector_id_t connection, 114 | GUPnPDeviceProxy *proxy, 115 | GUPnPDeviceInfo *device_info, 116 | const gchar *ip_address, 117 | const dleyna_connector_dispatch_cb_t *dispatch_table, 118 | GHashTable *filter_map, 119 | const char *udn, 120 | const dleyna_task_queue_key_t *queue_id); 121 | 122 | dls_device_t *dls_device_from_path(const gchar *path, GHashTable *device_list); 123 | 124 | dls_device_context_t *dls_device_get_context(const dls_device_t *device, 125 | dls_client_t *client); 126 | 127 | void dls_device_delete_context(dls_device_context_t *context); 128 | 129 | void dls_device_get_children(dls_client_t *client, 130 | dls_task_t *task, 131 | const gchar *upnp_filter, const gchar *sort_by); 132 | 133 | void dls_device_get_all_props(dls_client_t *client, 134 | dls_task_t *task, 135 | gboolean root_object); 136 | 137 | void dls_device_get_prop(dls_client_t *client, 138 | dls_task_t *task, 139 | dls_prop_map_t *prop_map, gboolean root_object); 140 | 141 | void dls_device_search(dls_client_t *client, 142 | dls_task_t *task, 143 | const gchar *upnp_filter, const gchar *upnp_query, 144 | const gchar *sort_by); 145 | 146 | void dls_device_browse_objects(dls_client_t *client, dls_task_t *task); 147 | 148 | void dls_device_get_resource(dls_client_t *client, 149 | dls_task_t *task, 150 | const gchar *upnp_filter); 151 | 152 | void dls_device_subscribe_to_service_changes(dls_device_t *device); 153 | 154 | void dls_device_upload(dls_client_t *client, 155 | dls_task_t *task, const gchar *parent_id); 156 | 157 | gboolean dls_device_get_upload_status(dls_task_t *task, GError **error); 158 | 159 | gboolean dls_device_cancel_upload(dls_task_t *task, GError **error); 160 | 161 | void dls_device_get_upload_ids(dls_task_t *task); 162 | 163 | void dls_device_delete_object(dls_client_t *client, 164 | dls_task_t *task); 165 | 166 | void dls_device_create_container(dls_client_t *client, 167 | dls_task_t *task, 168 | const gchar *parent_id); 169 | 170 | void dls_device_update_object(dls_client_t *client, 171 | dls_task_t *task, 172 | const gchar *upnp_filter); 173 | 174 | void dls_device_get_object_metadata(dls_client_t *client, 175 | dls_task_t *task, 176 | const gchar *parent_id); 177 | 178 | void dls_device_create_reference(dls_client_t *client, 179 | dls_task_t *task); 180 | 181 | void dls_device_get_icon(dls_client_t *client, 182 | dls_task_t *task); 183 | 184 | void dls_device_wake(dls_client_t *client, 185 | dls_task_t *task); 186 | 187 | #endif /* DLS_DEVICE_H__ */ 188 | -------------------------------------------------------------------------------- /libdleyna/server/dleyna-server-service.conf.in: -------------------------------------------------------------------------------- 1 | # Configuration file for dleyna-server 2 | # 3 | # 4 | # 5 | # General configuration options 6 | [general] 7 | 8 | # true: Service always stay in memory running 9 | # false: Service quit when the last client disconnects. 10 | never-quit=@never_quit@ 11 | 12 | # IPC connector name 13 | connector-name=@with_connector_name@ 14 | 15 | # Source port for SSDP messages 16 | #port=4321 17 | 18 | # Log configuration options 19 | [log] 20 | 21 | # Define the logging output method. 3 technologies are defined: 22 | # 23 | # 0=Syslog 24 | # 1=GLib 25 | # 2=File 26 | log-type=@with_log_type@ 27 | 28 | # Comma-separated list of logging level. 29 | # Log levels are: 1=critical, 2=error, 3=warning, 4=message, 5=info, 6=debug 30 | # 31 | # Allowed values for log-levels are 32 | # 0 = disabled 33 | # 7 = default (=1,2,5) 34 | # 8 = all (=1,2,3,4,5,6) 35 | # 1,..,6 = a comma separated list of log level 36 | # 37 | # IMPORTANT: This log level is a subset of the log level defined at compile time 38 | # You can't enable levels disabled at compile time 39 | # level=8 means all level flags defined at compile time. 40 | log-level=@with_log_level@ 41 | 42 | 43 | # Network filtering 44 | [netf] 45 | 46 | # true: Enable the network filtering. 47 | # false: Disable the network filtering. 48 | netf-enabled=false 49 | 50 | # Comma-separated list of interface name, SSID or IP address. 51 | # If netf is enabled but the list is empty, it behaves as disabled. 52 | netf-list= 53 | -------------------------------------------------------------------------------- /libdleyna/server/ifaddrs.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | **************************************************************************** 3 | *** 4 | *** This header was generated from a glibc header of the same name. 5 | *** It contains only constants, structures, and macros generated from 6 | *** the original header, and thus, contains no copyrightable information. 7 | *** 8 | **************************************************************************** 9 | ****************************************************************************/ 10 | #ifndef _IFADDRS_H 11 | #define _IFADDRS_H 12 | 13 | #include 14 | 15 | struct ifaddrs { 16 | struct ifaddrs *ifa_next; 17 | char *ifa_name; 18 | unsigned int ifa_flags; 19 | struct sockaddr *ifa_addr; 20 | struct sockaddr *ifa_netmask; 21 | union { 22 | struct sockaddr *ifu_broadaddr; 23 | struct sockaddr *ifu_dstaddr; 24 | } ifa_ifu; 25 | #define ifa_broadaddr ifa_ifu.ifu_broadaddr 26 | #define ifa_dstaddr ifa_ifu.ifu_dstaddr 27 | void *ifa_data; 28 | }; 29 | 30 | extern int getifaddrs(struct ifaddrs **ifap); 31 | 32 | extern void freeifaddrs(struct ifaddrs *ifa); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /libdleyna/server/interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Regis Merlino 20 | * 21 | */ 22 | 23 | #ifndef DLEYNA_SERVER_INTERFACE_H__ 24 | #define DLEYNA_SERVER_INTERFACE_H__ 25 | 26 | enum dls_manager_interface_type_ { 27 | DLS_MANAGER_INTERFACE_MANAGER, 28 | DLS_MANAGER_INTERFACE_INFO_PROPERTIES, 29 | DLS_MANAGER_INTERFACE_INFO_MAX 30 | }; 31 | 32 | enum dls_interface_type_ { 33 | DLS_INTERFACE_INFO_PROPERTIES, 34 | DLS_INTERFACE_INFO_OBJECT, 35 | DLS_INTERFACE_INFO_CONTAINER, 36 | DLS_INTERFACE_INFO_ITEM, 37 | DLS_INTERFACE_INFO_DEVICE, 38 | DLS_INTERFACE_INFO_MAX 39 | }; 40 | 41 | #define DLS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" 42 | #define DLS_INTERFACE_MEDIA_CONTAINER "org.gnome.UPnP.MediaContainer2" 43 | #define DLS_INTERFACE_MEDIA_OBJECT "org.gnome.UPnP.MediaObject2" 44 | #define DLS_INTERFACE_MEDIA_ITEM "org.gnome.UPnP.MediaItem2" 45 | 46 | #define DLS_INTERFACE_PROP_ERROR "Error" 47 | #define DLS_INTERFACE_PROP_ERROR_ID "ID" 48 | #define DLS_INTERFACE_PROP_ERROR_NAME "Name" 49 | #define DLS_INTERFACE_PROP_ERROR_MESSAGE "Message" 50 | 51 | /* Manager Properties */ 52 | #define DLS_INTERFACE_PROP_NEVER_QUIT "NeverQuit" 53 | #define DLS_INTERFACE_PROP_WHITE_LIST_ENTRIES "WhiteListEntries" 54 | #define DLS_INTERFACE_PROP_WHITE_LIST_ENABLED "WhiteListEnabled" 55 | 56 | /* Object Properties */ 57 | #define DLS_INTERFACE_PROP_PATH "Path" 58 | #define DLS_INTERFACE_PROP_PARENT "Parent" 59 | #define DLS_INTERFACE_PROP_RESTRICTED "Restricted" 60 | #define DLS_INTERFACE_PROP_DISPLAY_NAME "DisplayName" 61 | #define DLS_INTERFACE_PROP_TYPE "Type" 62 | #define DLS_INTERFACE_PROP_TYPE_EX "TypeEx" 63 | #define DLS_INTERFACE_PROP_CREATOR "Creator" 64 | #define DLS_INTERFACE_PROP_DLNA_MANAGED "DLNAManaged" 65 | #define DLS_INTERFACE_PROP_OBJECT_UPDATE_ID "ObjectUpdateID" 66 | 67 | /* Item Properties */ 68 | #define DLS_INTERFACE_PROP_REFPATH "RefPath" 69 | #define DLS_INTERFACE_PROP_ARTIST "Artist" 70 | #define DLS_INTERFACE_PROP_ARTISTS "Artists" 71 | #define DLS_INTERFACE_PROP_ALBUM "Album" 72 | #define DLS_INTERFACE_PROP_DATE "Date" 73 | #define DLS_INTERFACE_PROP_GENRE "Genre" 74 | #define DLS_INTERFACE_PROP_TRACK_NUMBER "TrackNumber" 75 | #define DLS_INTERFACE_PROP_ALBUM_ART_URL "AlbumArtURL" 76 | #define DLS_INTERFACE_PROP_RESOURCES "Resources" 77 | 78 | /* Container Properties */ 79 | #define DLS_INTERFACE_PROP_SEARCHABLE "Searchable" 80 | #define DLS_INTERFACE_PROP_CHILD_COUNT "ChildCount" 81 | #define DLS_INTERFACE_PROP_CREATE_CLASSES "CreateClasses" 82 | #define DLS_INTERFACE_PROP_CONTAINER_UPDATE_ID "ContainerUpdateID" 83 | #define DLS_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT "TotalDeletedChildCount" 84 | 85 | /* Device Properties */ 86 | #define DLS_INTERFACE_PROP_LOCATION "Location" 87 | #define DLS_INTERFACE_PROP_UDN "UDN" 88 | #define DLS_INTERFACE_PROP_ROOT_UDN "RootUDN" 89 | #define DLS_INTERFACE_PROP_DEVICE_TYPE "DeviceType" 90 | #define DLS_INTERFACE_PROP_FRIENDLY_NAME "FriendlyName" 91 | #define DLS_INTERFACE_PROP_MANUFACTURER "Manufacturer" 92 | #define DLS_INTERFACE_PROP_MANUFACTURER_URL "ManufacturerUrl" 93 | #define DLS_INTERFACE_PROP_MODEL_DESCRIPTION "ModelDescription" 94 | #define DLS_INTERFACE_PROP_MODEL_NAME "ModelName" 95 | #define DLS_INTERFACE_PROP_MODEL_NUMBER "ModelNumber" 96 | #define DLS_INTERFACE_PROP_MODEL_URL "ModelURL" 97 | #define DLS_INTERFACE_PROP_SERIAL_NUMBER "SerialNumber" 98 | #define DLS_INTERFACE_PROP_PRESENTATION_URL "PresentationURL" 99 | #define DLS_INTERFACE_PROP_ICON_URL "IconURL" 100 | #define DLS_INTERFACE_PROP_SLEEPING "Sleeping" 101 | #define DLS_INTERFACE_PROP_SV_DLNA_CAPABILITIES "DLNACaps" 102 | #define DLS_INTERFACE_PROP_SV_SEARCH_CAPABILITIES "SearchCaps" 103 | #define DLS_INTERFACE_PROP_SV_SORT_CAPABILITIES "SortCaps" 104 | #define DLS_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES "SortExtCaps" 105 | #define DLS_INTERFACE_PROP_SV_FEATURE_LIST "FeatureList" 106 | #define DLS_INTERFACE_PROP_SV_SERVICE_RESET_TOKEN "ServiceResetToken" 107 | 108 | /* Resources Properties */ 109 | #define DLS_INTERFACE_PROP_MIME_TYPE "MIMEType" 110 | #define DLS_INTERFACE_PROP_DLNA_PROFILE "DLNAProfile" 111 | #define DLS_INTERFACE_PROP_DLNA_CONVERSION "DLNAConversion" 112 | #define DLS_INTERFACE_PROP_DLNA_OPERATION "DLNAOperation" 113 | #define DLS_INTERFACE_PROP_DLNA_FLAGS "DLNAFlags" 114 | #define DLS_INTERFACE_PROP_SIZE "Size" 115 | #define DLS_INTERFACE_PROP_DURATION "Duration" 116 | #define DLS_INTERFACE_PROP_BITRATE "Bitrate" 117 | #define DLS_INTERFACE_PROP_SAMPLE_RATE "SampleRate" 118 | #define DLS_INTERFACE_PROP_BITS_PER_SAMPLE "BitsPerSample" 119 | #define DLS_INTERFACE_PROP_WIDTH "Width" 120 | #define DLS_INTERFACE_PROP_HEIGHT "Height" 121 | #define DLS_INTERFACE_PROP_COLOR_DEPTH "ColorDepth" 122 | #define DLS_INTERFACE_PROP_URLS "URLs" 123 | #define DLS_INTERFACE_PROP_URL "URL" 124 | #define DLS_INTERFACE_PROP_UPDATE_COUNT "UpdateCount" 125 | 126 | /* Evented State Variable Properties */ 127 | #define DLS_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID "SystemUpdateID" 128 | 129 | /* Changed event properties */ 130 | #define DLS_INTERFACE_PROP_CHANGE_TYPE "ChangeType" 131 | #define DLS_INTERFACE_PROP_UPDATE_ID "UpdateID" 132 | #define DLS_INTERFACE_PROP_SUBTREE_UPDATE "SubTreeUpdate" 133 | 134 | #define DLS_INTERFACE_GET_VERSION "GetVersion" 135 | #define DLS_INTERFACE_GET_SERVERS "GetServers" 136 | #define DLS_INTERFACE_RESCAN "Rescan" 137 | #define DLS_INTERFACE_RELEASE "Release" 138 | #define DLS_INTERFACE_SET_PROTOCOL_INFO "SetProtocolInfo" 139 | #define DLS_INTERFACE_PREFER_LOCAL_ADDRESSES "PreferLocalAddresses" 140 | 141 | #define DLS_INTERFACE_WHITE_LIST_ENABLE "WhiteListEnable" 142 | #define DLS_INTERFACE_WHITE_LIST_ADD_ENTRIES "WhiteListAddEntries" 143 | #define DLS_INTERFACE_WHITE_LIST_REMOVE_ENTRIES "WhiteListRemoveEntries" 144 | #define DLS_INTERFACE_WHITE_LIST_CLEAR "WhiteListClear" 145 | 146 | #define DLS_INTERFACE_FOUND_SERVER "FoundServer" 147 | #define DLS_INTERFACE_LOST_SERVER "LostServer" 148 | 149 | #define DLS_INTERFACE_LIST_CHILDREN "ListChildren" 150 | #define DLS_INTERFACE_LIST_CHILDREN_EX "ListChildrenEx" 151 | #define DLS_INTERFACE_LIST_ITEMS "ListItems" 152 | #define DLS_INTERFACE_LIST_ITEMS_EX "ListItemsEx" 153 | #define DLS_INTERFACE_LIST_CONTAINERS "ListContainers" 154 | #define DLS_INTERFACE_LIST_CONTAINERS_EX "ListContainersEx" 155 | #define DLS_INTERFACE_SEARCH_OBJECTS "SearchObjects" 156 | #define DLS_INTERFACE_SEARCH_OBJECTS_EX "SearchObjectsEx" 157 | #define DLS_INTERFACE_UPDATE "Update" 158 | 159 | #define DLS_INTERFACE_GET_COMPATIBLE_RESOURCE "GetCompatibleResource" 160 | 161 | #define DLS_INTERFACE_GET "Get" 162 | #define DLS_INTERFACE_GET_ALL "GetAll" 163 | #define DLS_INTERFACE_SET "Set" 164 | #define DLS_INTERFACE_INTERFACE_NAME "InterfaceName" 165 | #define DLS_INTERFACE_PROPERTY_NAME "PropertyName" 166 | #define DLS_INTERFACE_PROPERTIES_VALUE "Properties" 167 | #define DLS_INTERFACE_VALUE "Value" 168 | #define DLS_INTERFACE_CHILD_TYPES "ChildTypes" 169 | 170 | #define DLS_INTERFACE_VERSION "Version" 171 | #define DLS_INTERFACE_SERVERS "Servers" 172 | 173 | #define DLS_INTERFACE_CRITERIA "Criteria" 174 | #define DLS_INTERFACE_DICT "Dictionary" 175 | #define DLS_INTERFACE_PATH "Path" 176 | #define DLS_INTERFACE_QUERY "Query" 177 | #define DLS_INTERFACE_PROTOCOL_INFO "ProtocolInfo" 178 | #define DLS_INTERFACE_PREFER "Prefer" 179 | 180 | #define DLS_INTERFACE_OFFSET "Offset" 181 | #define DLS_INTERFACE_MAX "Max" 182 | #define DLS_INTERFACE_FILTER "Filter" 183 | #define DLS_INTERFACE_CHILDREN "Children" 184 | #define DLS_INTERFACE_SORT_BY "SortBy" 185 | #define DLS_INTERFACE_TOTAL_ITEMS "TotalItems" 186 | 187 | #define DLS_INTERFACE_PROPERTIES_CHANGED "PropertiesChanged" 188 | #define DLS_INTERFACE_CHANGED_PROPERTIES "ChangedProperties" 189 | #define DLS_INTERFACE_INVALIDATED_PROPERTIES "InvalidatedProperties" 190 | #define DLS_INTERFACE_ESV_CONTAINER_UPDATE_IDS "ContainerUpdateIDs" 191 | #define DLS_INTERFACE_CONTAINER_PATHS_ID "ContainerPathsIDs" 192 | #define DLS_INTERFACE_CHANGED_EVENT "Changed" 193 | #define DLS_INTERFACE_CHANGED_OBJECTS "ChangedObjects" 194 | 195 | #define DLS_INTERFACE_DELETE "Delete" 196 | 197 | #define DLS_INTERFACE_CREATE_CONTAINER "CreateContainer" 198 | #define DLS_INTERFACE_CREATE_CONTAINER_IN_ANY "CreateContainerInAnyContainer" 199 | 200 | #define DLS_INTERFACE_UPLOAD "Upload" 201 | #define DLS_INTERFACE_UPLOAD_TO_ANY "UploadToAnyContainer" 202 | #define DLS_INTERFACE_GET_UPLOAD_STATUS "GetUploadStatus" 203 | #define DLS_INTERFACE_GET_UPLOAD_IDS "GetUploadIDs" 204 | #define DLS_INTERFACE_CANCEL_UPLOAD "CancelUpload" 205 | #define DLS_INTERFACE_TOTAL "Total" 206 | #define DLS_INTERFACE_LENGTH "Length" 207 | #define DLS_INTERFACE_FILE_PATH "FilePath" 208 | #define DLS_INTERFACE_UPLOAD_ID "UploadId" 209 | #define DLS_INTERFACE_UPLOAD_IDS "UploadIDs" 210 | #define DLS_INTERFACE_UPLOAD_STATUS "UploadStatus" 211 | #define DLS_INTERFACE_UPLOAD_UPDATE "UploadUpdate" 212 | #define DLS_INTERFACE_TO_ADD_UPDATE "ToAddUpdate" 213 | #define DLS_INTERFACE_TO_DELETE "ToDelete" 214 | #define DLS_INTERFACE_CANCEL "Cancel" 215 | #define DLS_INTERFACE_GET_ICON "GetIcon" 216 | #define DLS_INTERFACE_RESOLUTION "Resolution" 217 | #define DLS_INTERFACE_ICON_BYTES "Bytes" 218 | #define DLS_INTERFACE_MIME_TYPE "MimeType" 219 | #define DLS_INTERFACE_REQ_MIME_TYPE "RequestedMimeType" 220 | #define DLS_INTERFACE_WAKE "Wake" 221 | 222 | #define DLS_INTERFACE_GET_METADATA "GetMetaData" 223 | #define DLS_INTERFACE_METADATA "MetaData" 224 | 225 | #define DLS_INTERFACE_BROWSE_OBJECTS "BrowseObjects" 226 | #define DLS_INTERFACE_OBJECTS_PATH "Objects" 227 | 228 | #define DLS_INTERFACE_CREATE_REFERENCE "CreateReference" 229 | #define DLS_INTERFACE_REFPATH "RefPath" 230 | 231 | #define DLS_INTERFACE_ENTRY_LIST "EntryList" 232 | #define DLS_INTERFACE_IS_ENABLED "IsEnabled" 233 | 234 | #endif /* DLEYNA_SERVER_INTERFACE_H__ */ 235 | -------------------------------------------------------------------------------- /libdleyna/server/manager.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Ludovic Ferrandis 20 | * 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "interface.h" 32 | #include "manager.h" 33 | #include "props.h" 34 | 35 | struct dls_manager_t_ { 36 | dleyna_connector_id_t connection; 37 | GUPnPContextManager *cm; 38 | dleyna_white_list_t *wl; 39 | }; 40 | 41 | static void prv_wl_notify_prop(dls_manager_t *manager, 42 | const gchar *prop_name, 43 | GVariant *prop_val) 44 | { 45 | GVariant *val; 46 | GVariantBuilder array; 47 | 48 | g_variant_builder_init(&array, G_VARIANT_TYPE("a{sv}")); 49 | g_variant_builder_add(&array, "{sv}", prop_name, prop_val); 50 | 51 | val = g_variant_new("(s@a{sv}as)", DLEYNA_SERVER_INTERFACE_MANAGER, 52 | g_variant_builder_end(&array), 53 | NULL); 54 | 55 | (void) dls_server_get_connector()->notify(manager->connection, 56 | DLEYNA_SERVER_OBJECT, 57 | DLS_INTERFACE_PROPERTIES, 58 | DLS_INTERFACE_PROPERTIES_CHANGED, 59 | val, 60 | NULL); 61 | } 62 | 63 | dls_manager_t *dls_manager_new(dleyna_connector_id_t connection, 64 | GUPnPContextManager *connection_manager) 65 | { 66 | dls_manager_t *manager = g_new0(dls_manager_t, 1); 67 | GUPnPWhiteList *gupnp_wl; 68 | 69 | gupnp_wl = gupnp_context_manager_get_white_list(connection_manager); 70 | 71 | manager->connection = connection; 72 | manager->cm = connection_manager; 73 | manager->wl = dleyna_white_list_new(gupnp_wl); 74 | 75 | return manager; 76 | } 77 | 78 | void dls_manager_delete(dls_manager_t *manager) 79 | { 80 | if (manager != NULL) { 81 | dleyna_white_list_delete(manager->wl); 82 | g_free(manager); 83 | } 84 | } 85 | 86 | dleyna_white_list_t *dls_manager_get_white_list(dls_manager_t *manager) 87 | { 88 | return manager->wl; 89 | } 90 | 91 | void dls_manager_get_all_props(dls_manager_t *manager, 92 | dleyna_settings_t *settings, 93 | dls_task_t *task, 94 | dls_manager_task_complete_t cb) 95 | { 96 | dls_async_task_t *cb_data = (dls_async_task_t *)task; 97 | dls_async_get_all_t *cb_task_data; 98 | dls_task_get_props_t *task_data = &task->ut.get_props; 99 | gchar *i_name = task_data->interface_name; 100 | 101 | DLEYNA_LOG_DEBUG("Enter"); 102 | DLEYNA_LOG_DEBUG("Path: %s", task->target.path); 103 | DLEYNA_LOG_DEBUG("Interface %s", i_name); 104 | 105 | cb_data->cb = cb; 106 | 107 | cb_task_data = &cb_data->ut.get_all; 108 | cb_task_data->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); 109 | 110 | if (!strcmp(i_name, DLEYNA_SERVER_INTERFACE_MANAGER) || 111 | !strcmp(i_name, "")) { 112 | dls_props_add_manager(settings, cb_task_data->vb); 113 | 114 | cb_data->task.result = g_variant_ref_sink( 115 | g_variant_builder_end( 116 | cb_task_data->vb)); 117 | } else { 118 | DLEYNA_LOG_WARNING("Interface is unknown."); 119 | 120 | cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, 121 | DLEYNA_ERROR_UNKNOWN_INTERFACE, 122 | "Interface is unknown."); 123 | } 124 | 125 | (void) g_idle_add(dls_async_task_complete, cb_data); 126 | 127 | DLEYNA_LOG_DEBUG("Exit"); 128 | } 129 | 130 | void dls_manager_get_prop(dls_manager_t *manager, 131 | dleyna_settings_t *settings, 132 | dls_task_t *task, 133 | dls_manager_task_complete_t cb) 134 | { 135 | dls_async_task_t *cb_data = (dls_async_task_t *)task; 136 | dls_task_get_prop_t *task_data = &task->ut.get_prop; 137 | gchar *i_name = task_data->interface_name; 138 | gchar *name = task_data->prop_name; 139 | 140 | DLEYNA_LOG_DEBUG("Enter"); 141 | DLEYNA_LOG_DEBUG("Path: %s", task->target.path); 142 | DLEYNA_LOG_DEBUG("Interface %s", i_name); 143 | DLEYNA_LOG_DEBUG("Prop.%s", name); 144 | 145 | cb_data->cb = cb; 146 | 147 | if (!strcmp(i_name, DLEYNA_SERVER_INTERFACE_MANAGER) || 148 | !strcmp(i_name, "")) { 149 | cb_data->task.result = dls_props_get_manager_prop(settings, 150 | name); 151 | 152 | if (!cb_data->task.result) 153 | cb_data->error = g_error_new( 154 | DLEYNA_SERVER_ERROR, 155 | DLEYNA_ERROR_UNKNOWN_PROPERTY, 156 | "Unknown property"); 157 | } else { 158 | DLEYNA_LOG_WARNING("Interface is unknown."); 159 | 160 | cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, 161 | DLEYNA_ERROR_UNKNOWN_INTERFACE, 162 | "Interface is unknown."); 163 | } 164 | 165 | (void) g_idle_add(dls_async_task_complete, cb_data); 166 | 167 | DLEYNA_LOG_DEBUG("Exit"); 168 | } 169 | 170 | static void prv_set_prop_never_quit(dls_manager_t *manager, 171 | dleyna_settings_t *settings, 172 | gboolean never_quit, 173 | GError **error) 174 | { 175 | GVariant *prop_val; 176 | gboolean old_val; 177 | 178 | DLEYNA_LOG_DEBUG("Enter %d", never_quit); 179 | 180 | old_val = dleyna_settings_is_never_quit(settings); 181 | 182 | if (old_val == never_quit) 183 | goto exit; 184 | 185 | /* If no error, the white list will be updated in the reload callack 186 | */ 187 | dleyna_settings_set_never_quit(settings, never_quit, error); 188 | 189 | if (*error == NULL) { 190 | prop_val = g_variant_new_boolean(never_quit); 191 | prv_wl_notify_prop(manager, 192 | DLS_INTERFACE_PROP_NEVER_QUIT, 193 | prop_val); 194 | } 195 | 196 | exit: 197 | DLEYNA_LOG_DEBUG("Exit"); 198 | return; 199 | } 200 | 201 | static void prv_set_prop_wl_enabled(dls_manager_t *manager, 202 | dleyna_settings_t *settings, 203 | gboolean enabled, 204 | GError **error) 205 | { 206 | GVariant *prop_val; 207 | gboolean old_val; 208 | 209 | DLEYNA_LOG_DEBUG("Enter %d", enabled); 210 | 211 | old_val = dleyna_settings_is_white_list_enabled(settings); 212 | 213 | if (old_val == enabled) 214 | goto exit; 215 | 216 | /* If no error, the white list will be updated in the reload callack 217 | */ 218 | dleyna_settings_set_white_list_enabled(settings, enabled, error); 219 | 220 | if (*error == NULL) { 221 | dleyna_white_list_enable(manager->wl, enabled); 222 | 223 | prop_val = g_variant_new_boolean(enabled); 224 | prv_wl_notify_prop(manager, 225 | DLS_INTERFACE_PROP_WHITE_LIST_ENABLED, 226 | prop_val); 227 | } 228 | 229 | exit: 230 | DLEYNA_LOG_DEBUG("Exit"); 231 | return; 232 | } 233 | 234 | static void prv_set_prop_wl_entries(dls_manager_t *manager, 235 | dleyna_settings_t *settings, 236 | GVariant *entries, 237 | GError **error) 238 | { 239 | DLEYNA_LOG_DEBUG("Enter"); 240 | 241 | if (strcmp(g_variant_get_type_string(entries), "as")) { 242 | DLEYNA_LOG_WARNING("Invalid parameter type. 'as' expected."); 243 | 244 | *error = g_error_new(DLEYNA_SERVER_ERROR, 245 | DLEYNA_ERROR_BAD_QUERY, 246 | "Invalid parameter type. 'as' expected."); 247 | goto exit; 248 | } 249 | 250 | /* If no error, the white list will be updated in the reload callack 251 | * callack 252 | */ 253 | dleyna_settings_set_white_list_entries(settings, entries, error); 254 | 255 | if (*error == NULL) { 256 | dleyna_white_list_clear(manager->wl); 257 | dleyna_white_list_add_entries(manager->wl, entries); 258 | 259 | prv_wl_notify_prop(manager, 260 | DLS_INTERFACE_PROP_WHITE_LIST_ENTRIES, 261 | entries); 262 | } 263 | 264 | exit: 265 | DLEYNA_LOG_DEBUG("Exit"); 266 | } 267 | 268 | void dls_manager_set_prop(dls_manager_t *manager, 269 | dleyna_settings_t *settings, 270 | dls_task_t *task, 271 | dls_manager_task_complete_t cb) 272 | { 273 | dls_async_task_t *cb_data = (dls_async_task_t *)task; 274 | dls_task_set_prop_t *task_data = &task->ut.set_prop; 275 | GVariant *param = task_data->params; 276 | gchar *name = task_data->prop_name; 277 | gchar *i_name = task_data->interface_name; 278 | GError *error = NULL; 279 | 280 | DLEYNA_LOG_DEBUG("Enter"); 281 | DLEYNA_LOG_DEBUG("Path: %s", task->target.path); 282 | DLEYNA_LOG_DEBUG("Interface %s", i_name); 283 | DLEYNA_LOG_DEBUG("Prop.%s", name); 284 | 285 | cb_data->cb = cb; 286 | 287 | if (strcmp(i_name, DLEYNA_SERVER_INTERFACE_MANAGER) && 288 | strcmp(i_name, "")) { 289 | DLEYNA_LOG_WARNING("Interface is unknown."); 290 | 291 | cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, 292 | DLEYNA_ERROR_UNKNOWN_INTERFACE, 293 | "Interface is unknown."); 294 | goto exit; 295 | } 296 | 297 | if (!strcmp(name, DLS_INTERFACE_PROP_NEVER_QUIT)) 298 | prv_set_prop_never_quit(manager, settings, 299 | g_variant_get_boolean(param), 300 | &error); 301 | else if (!strcmp(name, DLS_INTERFACE_PROP_WHITE_LIST_ENABLED)) 302 | prv_set_prop_wl_enabled(manager, settings, 303 | g_variant_get_boolean(param), 304 | &error); 305 | else if (!strcmp(name, DLS_INTERFACE_PROP_WHITE_LIST_ENTRIES)) 306 | prv_set_prop_wl_entries(manager, settings, param, &error); 307 | else 308 | cb_data->error = g_error_new(DLEYNA_SERVER_ERROR, 309 | DLEYNA_ERROR_UNKNOWN_PROPERTY, 310 | "Unknown property"); 311 | 312 | if (error != NULL) 313 | cb_data->error = error; 314 | 315 | exit: 316 | (void) g_idle_add(dls_async_task_complete, cb_data); 317 | DLEYNA_LOG_DEBUG("Exit"); 318 | } 319 | -------------------------------------------------------------------------------- /libdleyna/server/manager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Ludovic Ferrandis 20 | * 21 | */ 22 | 23 | #ifndef DLS_MANAGER_H__ 24 | #define DLS_MANAGER_H__ 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include "task.h" 31 | 32 | typedef struct dls_manager_t_ dls_manager_t; 33 | typedef void (*dls_manager_task_complete_t)(dls_task_t *task, GError *error); 34 | 35 | dls_manager_t *dls_manager_new(dleyna_connector_id_t connection, 36 | GUPnPContextManager *connection_manager); 37 | 38 | void dls_manager_delete(dls_manager_t *manager); 39 | 40 | dleyna_white_list_t *dls_manager_get_white_list(dls_manager_t *manager); 41 | 42 | void dls_manager_get_all_props(dls_manager_t *manager, 43 | dleyna_settings_t *settings, 44 | dls_task_t *task, 45 | dls_manager_task_complete_t cb); 46 | 47 | void dls_manager_get_prop(dls_manager_t *manager, 48 | dleyna_settings_t *settings, 49 | dls_task_t *task, 50 | dls_manager_task_complete_t cb); 51 | 52 | void dls_manager_set_prop(dls_manager_t *manager, 53 | dleyna_settings_t *settings, 54 | dls_task_t *task, 55 | dls_manager_task_complete_t cb); 56 | 57 | #endif /* DLS_MANAGER_H__ */ 58 | -------------------------------------------------------------------------------- /libdleyna/server/path.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include "path.h" 29 | #include "server.h" 30 | 31 | gboolean dls_path_get_non_root_id(const gchar *object_path, 32 | const gchar **slash_before_id) 33 | { 34 | gboolean retval = FALSE; 35 | unsigned int offset = strlen(DLEYNA_SERVER_PATH) + 1; 36 | 37 | if (!g_str_has_prefix(object_path, DLEYNA_SERVER_PATH "/")) 38 | goto on_error; 39 | 40 | if (!object_path[offset]) 41 | goto on_error; 42 | 43 | *slash_before_id = strchr(&object_path[offset], '/'); 44 | retval = TRUE; 45 | 46 | on_error: 47 | 48 | return retval; 49 | } 50 | 51 | static gchar *prv_object_name_to_id(const gchar *object_name) 52 | { 53 | gchar *retval = NULL; 54 | unsigned int object_len = strlen(object_name); 55 | unsigned int i; 56 | gint hex; 57 | gchar byte; 58 | 59 | if (object_len & 1) 60 | goto on_error; 61 | 62 | retval = g_malloc((object_len >> 1) + 1); 63 | 64 | for (i = 0; i < object_len; i += 2) { 65 | hex = g_ascii_xdigit_value(object_name[i]); 66 | 67 | if (hex == -1) 68 | goto on_error; 69 | 70 | byte = hex << 4; 71 | hex = g_ascii_xdigit_value(object_name[i + 1]); 72 | 73 | if (hex == -1) 74 | goto on_error; 75 | 76 | byte |= hex; 77 | retval[i >> 1] = byte; 78 | } 79 | retval[i >> 1] = 0; 80 | 81 | return retval; 82 | 83 | on_error: 84 | 85 | g_free(retval); 86 | 87 | return NULL; 88 | } 89 | 90 | gboolean dls_path_get_path_and_id(const gchar *object_path, gchar **root_path, 91 | gchar **id, GError **error) 92 | { 93 | const gchar *slash; 94 | gchar *coded_id; 95 | 96 | if (!dls_path_get_non_root_id(object_path, &slash)) 97 | goto on_error; 98 | 99 | if (!slash) { 100 | *root_path = g_strdup(object_path); 101 | *id = g_strdup("0"); 102 | } else { 103 | if (!slash[1]) 104 | goto on_error; 105 | 106 | coded_id = prv_object_name_to_id(slash + 1); 107 | 108 | if (!coded_id) 109 | goto on_error; 110 | 111 | *root_path = g_strndup(object_path, slash - object_path); 112 | *id = coded_id; 113 | } 114 | 115 | return TRUE; 116 | 117 | on_error: 118 | if (error) 119 | *error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_BAD_PATH, 120 | "object path is badly formed."); 121 | 122 | return FALSE; 123 | } 124 | 125 | static gchar *prv_id_to_object_name(const gchar *id) 126 | { 127 | gchar *retval; 128 | unsigned int i; 129 | unsigned int data_len = strlen(id); 130 | 131 | retval = g_malloc((data_len << 1) + 1); 132 | retval[0] = 0; 133 | 134 | for (i = 0; i < data_len; i++) 135 | sprintf(&retval[i << 1], "%0x", (guint8) id[i]); 136 | 137 | return retval; 138 | } 139 | 140 | gchar *dls_path_from_id(const gchar *root_path, const gchar *id) 141 | { 142 | gchar *coded_id; 143 | gchar *path; 144 | 145 | if (!strcmp(id, "0")) { 146 | path = g_strdup(root_path); 147 | } else { 148 | coded_id = prv_id_to_object_name(id); 149 | path = g_strdup_printf("%s/%s", root_path, coded_id); 150 | g_free(coded_id); 151 | } 152 | 153 | return path; 154 | } 155 | -------------------------------------------------------------------------------- /libdleyna/server/path.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #ifndef DLS_PATH_H__ 24 | #define DLS_PATH_H__ 25 | 26 | #include 27 | 28 | gboolean dls_path_get_non_root_id(const gchar *object_path, 29 | const gchar **slash_before_id); 30 | 31 | gboolean dls_path_get_path_and_id(const gchar *object_path, gchar **root_path, 32 | gchar **id, GError **error); 33 | 34 | gchar *dls_path_from_id(const gchar *root_path, const gchar *id); 35 | 36 | #endif /* DLS_PATH_H__ */ 37 | -------------------------------------------------------------------------------- /libdleyna/server/props.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #ifndef DLS_PROPS_H__ 24 | #define DLS_PROPS_H__ 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include "async.h" 32 | 33 | #define DLS_UPNP_MASK_PROP_PARENT (1LL << 0) 34 | #define DLS_UPNP_MASK_PROP_TYPE (1LL << 1) 35 | #define DLS_UPNP_MASK_PROP_PATH (1LL << 2) 36 | #define DLS_UPNP_MASK_PROP_DISPLAY_NAME (1LL << 3) 37 | #define DLS_UPNP_MASK_PROP_CHILD_COUNT (1LL << 4) 38 | #define DLS_UPNP_MASK_PROP_SEARCHABLE (1LL << 5) 39 | #define DLS_UPNP_MASK_PROP_URLS (1LL << 6) 40 | #define DLS_UPNP_MASK_PROP_MIME_TYPE (1LL << 7) 41 | #define DLS_UPNP_MASK_PROP_ARTIST (1LL << 8) 42 | #define DLS_UPNP_MASK_PROP_ALBUM (1LL << 9) 43 | #define DLS_UPNP_MASK_PROP_DATE (1LL << 10) 44 | #define DLS_UPNP_MASK_PROP_GENRE (1LL << 11) 45 | #define DLS_UPNP_MASK_PROP_DLNA_PROFILE (1LL << 12) 46 | #define DLS_UPNP_MASK_PROP_TRACK_NUMBER (1LL << 13) 47 | #define DLS_UPNP_MASK_PROP_SIZE (1LL << 14) 48 | #define DLS_UPNP_MASK_PROP_DURATION (1LL << 15) 49 | #define DLS_UPNP_MASK_PROP_BITRATE (1LL << 16) 50 | #define DLS_UPNP_MASK_PROP_SAMPLE_RATE (1LL << 17) 51 | #define DLS_UPNP_MASK_PROP_BITS_PER_SAMPLE (1LL << 18) 52 | #define DLS_UPNP_MASK_PROP_WIDTH (1LL << 19) 53 | #define DLS_UPNP_MASK_PROP_HEIGHT (1LL << 20) 54 | #define DLS_UPNP_MASK_PROP_COLOR_DEPTH (1LL << 21) 55 | #define DLS_UPNP_MASK_PROP_ALBUM_ART_URL (1LL << 22) 56 | #define DLS_UPNP_MASK_PROP_RESOURCES (1LL << 23) 57 | #define DLS_UPNP_MASK_PROP_URL (1LL << 24) 58 | #define DLS_UPNP_MASK_PROP_REFPATH (1LL << 25) 59 | #define DLS_UPNP_MASK_PROP_RESTRICTED (1LL << 26) 60 | #define DLS_UPNP_MASK_PROP_DLNA_MANAGED (1LL << 27) 61 | #define DLS_UPNP_MASK_PROP_CREATOR (1LL << 28) 62 | #define DLS_UPNP_MASK_PROP_ARTISTS (1LL << 29) 63 | #define DLS_UPNP_MASK_PROP_CREATE_CLASSES (1LL << 30) 64 | #define DLS_UPNP_MASK_PROP_OBJECT_UPDATE_ID (1LL << 31) 65 | #define DLS_UPNP_MASK_PROP_UPDATE_COUNT (1LL << 32) 66 | #define DLS_UPNP_MASK_PROP_CONTAINER_UPDATE_ID (1LL << 33) 67 | #define DLS_UPNP_MASK_PROP_TOTAL_DELETED_CHILD_COUNT (1LL << 34) 68 | #define DLS_UPNP_MASK_PROP_DLNA_CONVERSION (1LL << 35) 69 | #define DLS_UPNP_MASK_PROP_DLNA_OPERATION (1LL << 36) 70 | #define DLS_UPNP_MASK_PROP_DLNA_FLAGS (1LL << 37) 71 | #define DLS_UPNP_MASK_PROP_TYPE_EX (1LL << 38) 72 | 73 | #define DLS_UPNP_MASK_ALL_PROPS 0xffffffffffffffff 74 | 75 | typedef struct dls_prop_map_t_ dls_prop_map_t; 76 | struct dls_prop_map_t_ { 77 | const gchar *upnp_prop_name; 78 | dls_upnp_prop_mask type; 79 | gboolean filter; 80 | gboolean searchable; 81 | gboolean updateable; 82 | }; 83 | 84 | void dls_prop_maps_new(GHashTable **property_map, GHashTable **filter_map); 85 | 86 | dls_upnp_prop_mask dls_props_parse_filter(GHashTable *filter_map, 87 | GVariant *filter, 88 | gchar **upnp_filter); 89 | 90 | gboolean dls_props_parse_update_filter(GHashTable *filter_map, 91 | GVariant *to_add_update, 92 | GVariant *to_delete, 93 | dls_upnp_prop_mask *mask, 94 | gchar **upnp_filter); 95 | 96 | void dls_props_add_device(GUPnPDeviceInfo *root_proxy, 97 | GUPnPDeviceInfo *proxy, 98 | GUPnPServiceProxy *ems_proxy, 99 | const dls_device_t *device, 100 | GVariantBuilder *vb); 101 | 102 | GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *root_proxy, 103 | GUPnPDeviceInfo *proxy, 104 | const dls_device_t *device, 105 | const gchar *prop); 106 | 107 | gboolean dls_props_add_object(GVariantBuilder *item_vb, 108 | GUPnPDIDLLiteObject *object, 109 | const char *root_path, 110 | const gchar *parent_path, 111 | dls_upnp_prop_mask filter_mask); 112 | 113 | GVariant *dls_props_get_object_prop(const gchar *prop, const gchar *root_path, 114 | GUPnPDIDLLiteObject *object); 115 | 116 | void dls_props_add_container(GVariantBuilder *item_vb, 117 | GUPnPDIDLLiteContainer *object, 118 | dls_upnp_prop_mask filter_mask, 119 | const gchar *protocol_info, 120 | gboolean *have_child_count); 121 | 122 | void dls_props_add_child_count(GVariantBuilder *item_vb, gint value); 123 | 124 | GVariant *dls_props_get_container_prop(const gchar *prop, 125 | GUPnPDIDLLiteObject *object, 126 | const gchar *protocol_info); 127 | 128 | void dls_props_add_resource(GVariantBuilder *item_vb, 129 | GUPnPDIDLLiteObject *object, 130 | dls_upnp_prop_mask filter_mask, 131 | const gchar *protocol_info); 132 | 133 | void dls_props_add_item(GVariantBuilder *item_vb, 134 | GUPnPDIDLLiteObject *object, 135 | const gchar *root_path, 136 | dls_upnp_prop_mask filter_mask, 137 | const gchar *protocol_info); 138 | 139 | GVariant *dls_props_get_item_prop(const gchar *prop, const gchar *root_path, 140 | GUPnPDIDLLiteObject *object, 141 | const gchar *protocol_info); 142 | 143 | const gchar *dls_props_media_spec_to_upnp_class(const gchar *m2spec_class); 144 | 145 | gchar *dls_props_media_spec_ex_to_upnp_class(const gchar *m2spec_class); 146 | 147 | const gchar *dls_props_upnp_class_to_media_spec(const gchar *upnp_class); 148 | 149 | const gchar *dls_props_upnp_class_to_media_spec_ex(const gchar *upnp_class); 150 | 151 | void dls_props_add_manager(dleyna_settings_t *settings, GVariantBuilder *vb); 152 | 153 | GVariant *dls_props_get_manager_prop(dleyna_settings_t *settings, 154 | const gchar *prop); 155 | 156 | GVariant *dls_props_get_error_prop(GError *error); 157 | 158 | #endif /* DLS_PROPS_H__ */ 159 | -------------------------------------------------------------------------------- /libdleyna/server/search.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #include 24 | 25 | #include "interface.h" 26 | #include "path.h" 27 | #include "props.h" 28 | #include "search.h" 29 | 30 | gchar *dls_search_translate_search_string(GHashTable *filter_map, 31 | const gchar *search_string) 32 | { 33 | GRegex *reg; 34 | gchar *retval = NULL; 35 | GMatchInfo *match_info = NULL; 36 | gchar *prop = NULL; 37 | gchar *op = NULL; 38 | gchar *value = NULL; 39 | const gchar *translated_value; 40 | gchar *translated_type_ex; 41 | dls_prop_map_t *prop_map; 42 | GString *str; 43 | gint start_pos; 44 | gint end_pos; 45 | gint old_end_pos = 0; 46 | unsigned int skipped; 47 | unsigned int search_string_len = strlen(search_string); 48 | gchar *root_path; 49 | gchar *id; 50 | 51 | reg = g_regex_new("(\\w+)\\s+(=|!=|<|<=|>|>|contains|doesNotContain|"\ 52 | "derivedfrom|exists)\\s+"\ 53 | "(\"[^\"]*\"|true|false)", 54 | 0, 0, NULL); 55 | str = g_string_new(""); 56 | 57 | g_regex_match(reg, search_string, 0, &match_info); 58 | while (g_match_info_matches(match_info)) { 59 | prop = g_match_info_fetch(match_info, 1); 60 | if (!prop) 61 | goto on_error; 62 | 63 | op = g_match_info_fetch(match_info, 2); 64 | if (!op) 65 | goto on_error; 66 | 67 | value = g_match_info_fetch(match_info, 3); 68 | if (!value) 69 | goto on_error; 70 | 71 | /* Handle special cases where we need to translate 72 | value as well as property name */ 73 | 74 | if (!strcmp(prop, DLS_INTERFACE_PROP_TYPE)) { 75 | /* Skip the quotes */ 76 | 77 | value[strlen(value) - 1] = 0; 78 | translated_value = dls_props_media_spec_to_upnp_class( 79 | value + 1); 80 | if (!translated_value) 81 | goto on_error; 82 | g_free(value); 83 | value = g_strdup_printf("\"%s\"", translated_value); 84 | } else if (!strcmp(prop, DLS_INTERFACE_PROP_TYPE_EX)) { 85 | /* Skip the quotes */ 86 | 87 | value[strlen(value) - 1] = 0; 88 | translated_type_ex = 89 | dls_props_media_spec_ex_to_upnp_class( 90 | value + 1); 91 | if (!translated_type_ex) 92 | goto on_error; 93 | g_free(value); 94 | value = g_strdup_printf("\"%s\"", translated_type_ex); 95 | g_free(translated_type_ex); 96 | } else if (!strcmp(prop, DLS_INTERFACE_PROP_PARENT) || 97 | !strcmp(prop, DLS_INTERFACE_PROP_PATH)) { 98 | value[strlen(value) - 1] = 0; 99 | if (!dls_path_get_path_and_id(value + 1, &root_path, 100 | &id, NULL)) 101 | goto on_error; 102 | g_free(root_path); 103 | g_free(value); 104 | value = g_strdup_printf("\"%s\"", id); 105 | g_free(id); 106 | } 107 | 108 | prop_map = g_hash_table_lookup(filter_map, prop); 109 | if (!prop_map) 110 | goto on_error; 111 | 112 | if (!prop_map->searchable) 113 | goto on_error; 114 | 115 | if (!g_match_info_fetch_pos(match_info, 0, &start_pos, 116 | &end_pos)) 117 | goto on_error; 118 | 119 | skipped = start_pos - old_end_pos; 120 | if (skipped > 0) 121 | g_string_append_len(str, &search_string[old_end_pos], 122 | skipped); 123 | g_string_append_printf(str, "%s %s %s", 124 | prop_map->upnp_prop_name, op, value); 125 | old_end_pos = end_pos; 126 | 127 | g_free(value); 128 | g_free(prop); 129 | g_free(op); 130 | 131 | value = NULL; 132 | prop = NULL; 133 | op = NULL; 134 | 135 | g_match_info_next(match_info, NULL); 136 | } 137 | 138 | skipped = search_string_len - old_end_pos; 139 | if (skipped > 0) 140 | g_string_append_len(str, &search_string[old_end_pos], 141 | skipped); 142 | 143 | retval = g_string_free(str, FALSE); 144 | str = NULL; 145 | 146 | on_error: 147 | 148 | g_free(value); 149 | g_free(prop); 150 | g_free(op); 151 | 152 | if (match_info) 153 | g_match_info_free(match_info); 154 | 155 | if (str) 156 | g_string_free(str, TRUE); 157 | 158 | g_regex_unref(reg); 159 | 160 | return retval; 161 | } 162 | -------------------------------------------------------------------------------- /libdleyna/server/search.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #ifndef DLS_SEARCH_H__ 24 | #define DLS_SEARCH_H__ 25 | 26 | #include 27 | 28 | gchar *dls_search_translate_search_string(GHashTable *filter_map, 29 | const gchar *search_string); 30 | 31 | #endif /* DLS_PROPS_H__ */ 32 | -------------------------------------------------------------------------------- /libdleyna/server/server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Regis Merlino 20 | * 21 | */ 22 | 23 | #ifndef DLS_SERVER_H__ 24 | #define DLS_SERVER_H__ 25 | 26 | #include 27 | #include 28 | 29 | #define DLS_SERVER_SINK "dleyna-server" 30 | 31 | typedef struct dls_device_t_ dls_device_t; 32 | typedef struct dls_device_context_t_ dls_device_context_t; 33 | typedef struct dls_upnp_t_ dls_upnp_t; 34 | 35 | gboolean dls_server_get_object_info(const gchar *object_path, 36 | gchar **root_path, 37 | gchar **object_id, 38 | dls_device_t **device, 39 | GError **error); 40 | 41 | dls_upnp_t *dls_server_get_upnp(void); 42 | 43 | gboolean dls_server_is_device_sleeping(dls_device_t *dev); 44 | 45 | void dls_server_delete_sleeping_device(dls_device_t *dev); 46 | 47 | dleyna_task_processor_t *dls_server_get_task_processor(void); 48 | 49 | const dleyna_connector_t *dls_server_get_connector(void); 50 | 51 | #endif /* DLS_SERVER_H__ */ 52 | -------------------------------------------------------------------------------- /libdleyna/server/sort.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #include 24 | 25 | #include "props.h" 26 | #include "sort.h" 27 | 28 | gchar *dls_sort_translate_sort_string(GHashTable *filter_map, 29 | const gchar *sort_string) 30 | { 31 | GRegex *reg; 32 | gchar *retval = NULL; 33 | GMatchInfo *match_info = NULL; 34 | gchar *prop = NULL; 35 | gchar *op = NULL; 36 | dls_prop_map_t *prop_map; 37 | GString *str; 38 | 39 | if (!g_regex_match_simple( 40 | "^((\\+|\\-)([^,\\+\\-]+))?(,(\\+|\\-)([^,\\+\\-]+))*$", 41 | sort_string, 0, 0)) 42 | goto no_free; 43 | 44 | reg = g_regex_new("(\\+|\\-)(\\w+)", 0, 0, NULL); 45 | str = g_string_new(""); 46 | 47 | g_regex_match(reg, sort_string, 0, &match_info); 48 | while (g_match_info_matches(match_info)) { 49 | op = g_match_info_fetch(match_info, 1); 50 | if (!op) 51 | goto on_error; 52 | 53 | prop = g_match_info_fetch(match_info, 2); 54 | if (!prop) 55 | goto on_error; 56 | 57 | prop_map = g_hash_table_lookup(filter_map, prop); 58 | if (!prop_map) 59 | goto on_error; 60 | 61 | if (!prop_map->searchable) 62 | goto on_error; 63 | 64 | g_string_append_printf(str, "%s%s,", op, 65 | prop_map->upnp_prop_name); 66 | 67 | g_free(prop); 68 | g_free(op); 69 | 70 | prop = NULL; 71 | op = NULL; 72 | 73 | g_match_info_next(match_info, NULL); 74 | } 75 | 76 | if (str->len > 0) 77 | str = g_string_truncate(str, str->len - 1); 78 | retval = g_string_free(str, FALSE); 79 | 80 | str = NULL; 81 | 82 | on_error: 83 | 84 | g_free(prop); 85 | g_free(op); 86 | 87 | if (match_info) 88 | g_match_info_free(match_info); 89 | 90 | if (str) 91 | g_string_free(str, TRUE); 92 | 93 | g_regex_unref(reg); 94 | 95 | no_free: 96 | 97 | return retval; 98 | } 99 | -------------------------------------------------------------------------------- /libdleyna/server/sort.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #ifndef DLS_SORT_H__ 24 | #define DLS_SORT_H__ 25 | 26 | #include 27 | 28 | gchar *dls_sort_translate_sort_string(GHashTable *filter_map, 29 | const gchar *sort_string); 30 | 31 | #endif /* DLS_SORT_H__ */ 32 | -------------------------------------------------------------------------------- /libdleyna/server/task.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "async.h" 27 | #include "path.h" 28 | 29 | static void prv_delete(dls_task_t *task) 30 | { 31 | if (!task->synchronous) 32 | dls_async_task_delete((dls_async_task_t *)task); 33 | 34 | switch (task->type) { 35 | case DLS_TASK_GET_CHILDREN: 36 | if (task->ut.get_children.filter) 37 | g_variant_unref(task->ut.get_children.filter); 38 | g_free(task->ut.get_children.sort_by); 39 | break; 40 | case DLS_TASK_MANAGER_GET_ALL_PROPS: 41 | case DLS_TASK_GET_ALL_PROPS: 42 | g_free(task->ut.get_props.interface_name); 43 | break; 44 | case DLS_TASK_MANAGER_GET_PROP: 45 | case DLS_TASK_GET_PROP: 46 | g_free(task->ut.get_prop.interface_name); 47 | g_free(task->ut.get_prop.prop_name); 48 | break; 49 | case DLS_TASK_MANAGER_SET_PROP: 50 | g_free(task->ut.set_prop.interface_name); 51 | g_free(task->ut.set_prop.prop_name); 52 | g_variant_unref(task->ut.set_prop.params); 53 | break; 54 | case DLS_TASK_SEARCH: 55 | g_free(task->ut.search.query); 56 | if (task->ut.search.filter) 57 | g_variant_unref(task->ut.search.filter); 58 | g_free(task->ut.search.sort_by); 59 | break; 60 | case DLS_TASK_BROWSE_OBJECTS: 61 | if (task->ut.browse_objects.objects) 62 | g_variant_unref(task->ut.browse_objects.objects); 63 | if (task->ut.browse_objects.filter) 64 | g_variant_unref(task->ut.browse_objects.filter); 65 | break; 66 | case DLS_TASK_GET_RESOURCE: 67 | if (task->ut.resource.filter) 68 | g_variant_unref(task->ut.resource.filter); 69 | g_free(task->ut.resource.protocol_info); 70 | break; 71 | case DLS_TASK_SET_PROTOCOL_INFO: 72 | if (task->ut.protocol_info.protocol_info) 73 | g_free(task->ut.protocol_info.protocol_info); 74 | break; 75 | case DLS_TASK_UPLOAD_TO_ANY: 76 | case DLS_TASK_UPLOAD: 77 | g_free(task->ut.upload.display_name); 78 | g_free(task->ut.upload.file_path); 79 | break; 80 | case DLS_TASK_CREATE_CONTAINER: 81 | case DLS_TASK_CREATE_CONTAINER_IN_ANY: 82 | g_free(task->ut.create_container.display_name); 83 | g_free(task->ut.create_container.type); 84 | if (task->ut.create_container.child_types) 85 | g_variant_unref(task->ut.create_container.child_types); 86 | break; 87 | case DLS_TASK_UPDATE_OBJECT: 88 | if (task->ut.update.to_add_update) 89 | g_variant_unref(task->ut.update.to_add_update); 90 | if (task->ut.update.to_delete) 91 | g_variant_unref(task->ut.update.to_delete); 92 | break; 93 | case DLS_TASK_CREATE_REFERENCE: 94 | g_free(task->ut.create_reference.item_path); 95 | break; 96 | case DLS_TASK_GET_ICON: 97 | g_free(task->ut.get_icon.resolution); 98 | g_free(task->ut.get_icon.mime_type); 99 | break; 100 | case DLS_TASK_WAKE: 101 | break; 102 | default: 103 | break; 104 | } 105 | 106 | g_free(task->target.path); 107 | g_free(task->target.root_path); 108 | g_free(task->target.id); 109 | 110 | if (task->result) 111 | g_variant_unref(task->result); 112 | 113 | g_free(task); 114 | } 115 | 116 | dls_task_t *dls_task_rescan_new(dleyna_connector_msg_id_t invocation) 117 | { 118 | dls_task_t *task = g_new0(dls_task_t, 1); 119 | 120 | task->type = DLS_TASK_RESCAN; 121 | task->invocation = invocation; 122 | task->synchronous = TRUE; 123 | 124 | return task; 125 | } 126 | 127 | dls_task_t *dls_task_get_version_new(dleyna_connector_msg_id_t invocation) 128 | { 129 | dls_task_t *task = g_new0(dls_task_t, 1); 130 | 131 | task->type = DLS_TASK_GET_VERSION; 132 | task->invocation = invocation; 133 | task->result_format = "(@s)"; 134 | task->synchronous = TRUE; 135 | 136 | return task; 137 | } 138 | 139 | dls_task_t *dls_task_get_servers_new(dleyna_connector_msg_id_t invocation) 140 | { 141 | dls_task_t *task = g_new0(dls_task_t, 1); 142 | 143 | task->type = DLS_TASK_GET_SERVERS; 144 | task->invocation = invocation; 145 | task->result_format = "(@ao)"; 146 | task->synchronous = TRUE; 147 | 148 | return task; 149 | } 150 | 151 | dls_task_t *dls_task_manager_get_prop_new(dleyna_connector_msg_id_t invocation, 152 | const gchar *path, 153 | GVariant *parameters, 154 | GError **error) 155 | { 156 | dls_task_t *task = (dls_task_t *)g_new0(dls_async_task_t, 1); 157 | 158 | g_variant_get(parameters, "(ss)", &task->ut.get_prop.interface_name, 159 | &task->ut.get_prop.prop_name); 160 | g_strstrip(task->ut.get_prop.interface_name); 161 | g_strstrip(task->ut.get_prop.prop_name); 162 | 163 | task->target.path = g_strstrip(g_strdup(path)); 164 | 165 | task->type = DLS_TASK_MANAGER_GET_PROP; 166 | task->invocation = invocation; 167 | task->result_format = "(v)"; 168 | 169 | return task; 170 | } 171 | 172 | dls_task_t *dls_task_manager_get_props_new(dleyna_connector_msg_id_t invocation, 173 | const gchar *path, 174 | GVariant *parameters, 175 | GError **error) 176 | { 177 | dls_task_t *task = (dls_task_t *)g_new0(dls_async_task_t, 1); 178 | 179 | g_variant_get(parameters, "(s)", &task->ut.get_props.interface_name); 180 | g_strstrip(task->ut.get_props.interface_name); 181 | 182 | task->target.path = g_strstrip(g_strdup(path)); 183 | 184 | task->type = DLS_TASK_MANAGER_GET_ALL_PROPS; 185 | task->invocation = invocation; 186 | task->result_format = "(@a{sv})"; 187 | 188 | return task; 189 | } 190 | 191 | dls_task_t *dls_task_manager_set_prop_new(dleyna_connector_msg_id_t invocation, 192 | const gchar *path, 193 | GVariant *parameters, 194 | GError **error) 195 | { 196 | dls_task_t *task = (dls_task_t *)g_new0(dls_async_task_t, 1); 197 | 198 | g_variant_get(parameters, "(ssv)", 199 | &task->ut.set_prop.interface_name, 200 | &task->ut.set_prop.prop_name, 201 | &task->ut.set_prop.params); 202 | 203 | g_strstrip(task->ut.set_prop.interface_name); 204 | g_strstrip(task->ut.set_prop.prop_name); 205 | 206 | task->target.path = g_strstrip(g_strdup(path)); 207 | 208 | task->type = DLS_TASK_MANAGER_SET_PROP; 209 | task->invocation = invocation; 210 | 211 | return task; 212 | } 213 | 214 | static gboolean prv_set_task_target_info(dls_task_t *task, const gchar *path, 215 | GError **error) 216 | { 217 | task->target.path = g_strdup(path); 218 | g_strstrip(task->target.path); 219 | 220 | return dls_server_get_object_info(path, &task->target.root_path, 221 | &task->target.id, 222 | &task->target.device, error); 223 | } 224 | 225 | static gboolean prv_is_task_allowed(dls_task_t *task, GError **error) 226 | { 227 | if (dls_server_is_device_sleeping(task->target.device)) { 228 | if (task->type != DLS_TASK_WAKE && 229 | task->type != DLS_TASK_GET_PROP) 230 | goto on_error; 231 | } 232 | 233 | return TRUE; 234 | 235 | on_error: 236 | *error = g_error_new(DLEYNA_SERVER_ERROR, 237 | DLEYNA_ERROR_OPERATION_FAILED, 238 | "Target device is sleeping"); 239 | 240 | return FALSE; 241 | } 242 | 243 | static dls_task_t *prv_m2spec_task_new(dls_task_type_t type, 244 | dleyna_connector_msg_id_t invocation, 245 | const gchar *path, 246 | const gchar *result_format, 247 | GError **error, 248 | gboolean synchronous) 249 | { 250 | dls_task_t *task; 251 | 252 | if (synchronous) { 253 | task = g_new0(dls_task_t, 1); 254 | task->synchronous = TRUE; 255 | } else { 256 | task = (dls_task_t *)g_new0(dls_async_task_t, 1); 257 | } 258 | 259 | task->type = type; 260 | 261 | if (!prv_set_task_target_info(task, path, error) || 262 | !prv_is_task_allowed(task, error)) { 263 | prv_delete(task); 264 | task = NULL; 265 | 266 | goto finished; 267 | } 268 | 269 | task->invocation = invocation; 270 | task->result_format = result_format; 271 | 272 | finished: 273 | 274 | return task; 275 | } 276 | 277 | dls_task_t *dls_task_get_children_new(dleyna_connector_msg_id_t invocation, 278 | const gchar *path, GVariant *parameters, 279 | gboolean items, gboolean containers, 280 | GError **error) 281 | { 282 | dls_task_t *task; 283 | 284 | task = prv_m2spec_task_new(DLS_TASK_GET_CHILDREN, invocation, path, 285 | "(@aa{sv})", error, FALSE); 286 | if (!task) 287 | goto finished; 288 | 289 | task->ut.get_children.containers = containers; 290 | task->ut.get_children.items = items; 291 | 292 | g_variant_get(parameters, "(uu@as)", 293 | &task->ut.get_children.start, 294 | &task->ut.get_children.count, 295 | &task->ut.get_children.filter); 296 | 297 | task->ut.get_children.sort_by = g_strdup(""); 298 | 299 | finished: 300 | 301 | return task; 302 | } 303 | 304 | dls_task_t *dls_task_get_children_ex_new(dleyna_connector_msg_id_t invocation, 305 | const gchar *path, 306 | GVariant *parameters, gboolean items, 307 | gboolean containers, 308 | GError **error) 309 | { 310 | dls_task_t *task; 311 | 312 | task = prv_m2spec_task_new(DLS_TASK_GET_CHILDREN, invocation, path, 313 | "(@aa{sv})", error, FALSE); 314 | if (!task) 315 | goto finished; 316 | 317 | task->ut.get_children.containers = containers; 318 | task->ut.get_children.items = items; 319 | 320 | g_variant_get(parameters, "(uu@ass)", 321 | &task->ut.get_children.start, 322 | &task->ut.get_children.count, 323 | &task->ut.get_children.filter, 324 | &task->ut.get_children.sort_by); 325 | 326 | finished: 327 | 328 | return task; 329 | } 330 | 331 | dls_task_t *dls_task_get_prop_new(dleyna_connector_msg_id_t invocation, 332 | const gchar *path, GVariant *parameters, 333 | GError **error) 334 | { 335 | dls_task_t *task; 336 | 337 | task = prv_m2spec_task_new(DLS_TASK_GET_PROP, invocation, path, "(v)", 338 | error, FALSE); 339 | if (!task) 340 | goto finished; 341 | 342 | g_variant_get(parameters, "(ss)", &task->ut.get_prop.interface_name, 343 | &task->ut.get_prop.prop_name); 344 | 345 | g_strstrip(task->ut.get_prop.interface_name); 346 | g_strstrip(task->ut.get_prop.prop_name); 347 | 348 | finished: 349 | 350 | return task; 351 | } 352 | 353 | dls_task_t *dls_task_get_props_new(dleyna_connector_msg_id_t invocation, 354 | const gchar *path, GVariant *parameters, 355 | GError **error) 356 | { 357 | dls_task_t *task; 358 | 359 | task = prv_m2spec_task_new(DLS_TASK_GET_ALL_PROPS, invocation, path, 360 | "(@a{sv})", error, FALSE); 361 | if (!task) 362 | goto finished; 363 | 364 | g_variant_get(parameters, "(s)", &task->ut.get_props.interface_name); 365 | g_strstrip(task->ut.get_props.interface_name); 366 | 367 | finished: 368 | 369 | return task; 370 | } 371 | 372 | dls_task_t *dls_task_search_new(dleyna_connector_msg_id_t invocation, 373 | const gchar *path, GVariant *parameters, 374 | GError **error) 375 | { 376 | dls_task_t *task; 377 | 378 | task = prv_m2spec_task_new(DLS_TASK_SEARCH, invocation, path, 379 | "(@aa{sv})", error, FALSE); 380 | if (!task) 381 | goto finished; 382 | 383 | g_variant_get(parameters, "(suu@as)", &task->ut.search.query, 384 | &task->ut.search.start, &task->ut.search.count, 385 | &task->ut.search.filter); 386 | 387 | task->ut.search.sort_by = g_strdup(""); 388 | 389 | finished: 390 | return task; 391 | } 392 | 393 | dls_task_t *dls_task_search_ex_new(dleyna_connector_msg_id_t invocation, 394 | const gchar *path, GVariant *parameters, 395 | GError **error) 396 | { 397 | dls_task_t *task; 398 | 399 | task = prv_m2spec_task_new(DLS_TASK_SEARCH, invocation, path, 400 | "(@aa{sv}u)", error, FALSE); 401 | if (!task) 402 | goto finished; 403 | 404 | g_variant_get(parameters, "(suu@ass)", &task->ut.search.query, 405 | &task->ut.search.start, &task->ut.search.count, 406 | &task->ut.search.filter, &task->ut.search.sort_by); 407 | 408 | task->multiple_retvals = TRUE; 409 | 410 | finished: 411 | 412 | return task; 413 | } 414 | 415 | dls_task_t *dls_task_browse_objects_new(dleyna_connector_msg_id_t invocation, 416 | const gchar *path, GVariant *parameters, 417 | GError **error) 418 | { 419 | dls_task_t *task; 420 | 421 | task = prv_m2spec_task_new(DLS_TASK_BROWSE_OBJECTS, invocation, path, 422 | "(@aa{sv})", error, FALSE); 423 | if (!task) 424 | goto finished; 425 | 426 | g_variant_get(parameters, "(@ao@as)", 427 | &task->ut.browse_objects.objects, 428 | &task->ut.browse_objects.filter); 429 | 430 | finished: 431 | 432 | return task; 433 | } 434 | 435 | dls_task_t *dls_task_get_resource_new(dleyna_connector_msg_id_t invocation, 436 | const gchar *path, GVariant *parameters, 437 | GError **error) 438 | { 439 | dls_task_t *task; 440 | 441 | task = prv_m2spec_task_new(DLS_TASK_GET_RESOURCE, invocation, path, 442 | "(@a{sv})", error, FALSE); 443 | if (!task) 444 | goto finished; 445 | 446 | g_variant_get(parameters, "(s@as)", 447 | &task->ut.resource.protocol_info, 448 | &task->ut.resource.filter); 449 | 450 | finished: 451 | 452 | return task; 453 | } 454 | 455 | dls_task_t *dls_task_set_protocol_info_new(dleyna_connector_msg_id_t invocation, 456 | GVariant *parameters) 457 | { 458 | dls_task_t *task = g_new0(dls_task_t, 1); 459 | 460 | task->type = DLS_TASK_SET_PROTOCOL_INFO; 461 | task->invocation = invocation; 462 | task->synchronous = TRUE; 463 | g_variant_get(parameters, "(s)", &task->ut.protocol_info.protocol_info); 464 | 465 | return task; 466 | } 467 | 468 | static dls_task_t *prv_upload_new_generic(dls_task_type_t type, 469 | dleyna_connector_msg_id_t invocation, 470 | const gchar *path, 471 | GVariant *parameters, 472 | GError **error) 473 | { 474 | dls_task_t *task; 475 | 476 | task = prv_m2spec_task_new(type, invocation, path, 477 | "(uo)", error, FALSE); 478 | if (!task) 479 | goto finished; 480 | 481 | g_variant_get(parameters, "(ss)", &task->ut.upload.display_name, 482 | &task->ut.upload.file_path); 483 | g_strstrip(task->ut.upload.file_path); 484 | task->multiple_retvals = TRUE; 485 | 486 | finished: 487 | 488 | return task; 489 | } 490 | 491 | dls_task_t *dls_task_prefer_local_addresses_new( 492 | dleyna_connector_msg_id_t invocation, 493 | GVariant *parameters) 494 | { 495 | dls_task_t *task = g_new0(dls_task_t, 1); 496 | 497 | task->type = DLS_TASK_SET_PREFER_LOCAL_ADDRESSES; 498 | task->invocation = invocation; 499 | task->synchronous = TRUE; 500 | g_variant_get(parameters, "(b)", 501 | &task->ut.prefer_local_addresses.prefer); 502 | 503 | return task; 504 | } 505 | 506 | dls_task_t *dls_task_upload_to_any_new(dleyna_connector_msg_id_t invocation, 507 | const gchar *path, GVariant *parameters, 508 | GError **error) 509 | { 510 | return prv_upload_new_generic(DLS_TASK_UPLOAD_TO_ANY, invocation, 511 | path, parameters, error); 512 | } 513 | 514 | dls_task_t *dls_task_upload_new(dleyna_connector_msg_id_t invocation, 515 | const gchar *path, GVariant *parameters, 516 | GError **error) 517 | { 518 | return prv_upload_new_generic(DLS_TASK_UPLOAD, invocation, 519 | path, parameters, error); 520 | } 521 | 522 | dls_task_t *dls_task_get_upload_status_new(dleyna_connector_msg_id_t invocation, 523 | const gchar *path, 524 | GVariant *parameters, 525 | GError **error) 526 | { 527 | dls_task_t *task; 528 | 529 | task = prv_m2spec_task_new(DLS_TASK_GET_UPLOAD_STATUS, invocation, path, 530 | "(stt)", error, TRUE); 531 | if (!task) 532 | goto finished; 533 | 534 | g_variant_get(parameters, "(u)", 535 | &task->ut.upload_action.upload_id); 536 | task->multiple_retvals = TRUE; 537 | 538 | finished: 539 | 540 | return task; 541 | } 542 | 543 | dls_task_t *dls_task_get_upload_ids_new(dleyna_connector_msg_id_t invocation, 544 | const gchar *path, 545 | GError **error) 546 | { 547 | dls_task_t *task; 548 | 549 | task = prv_m2spec_task_new(DLS_TASK_GET_UPLOAD_IDS, invocation, path, 550 | "(@au)", error, TRUE); 551 | 552 | return task; 553 | } 554 | 555 | dls_task_t *dls_task_cancel_upload_new(dleyna_connector_msg_id_t invocation, 556 | const gchar *path, 557 | GVariant *parameters, 558 | GError **error) 559 | { 560 | dls_task_t *task; 561 | 562 | task = prv_m2spec_task_new(DLS_TASK_CANCEL_UPLOAD, invocation, path, 563 | NULL, error, TRUE); 564 | if (!task) 565 | goto finished; 566 | 567 | g_variant_get(parameters, "(u)", 568 | &task->ut.upload_action.upload_id); 569 | 570 | finished: 571 | 572 | return task; 573 | } 574 | 575 | dls_task_t *dls_task_delete_new(dleyna_connector_msg_id_t invocation, 576 | const gchar *path, 577 | GError **error) 578 | { 579 | dls_task_t *task; 580 | 581 | task = prv_m2spec_task_new(DLS_TASK_DELETE_OBJECT, invocation, 582 | path, NULL, error, FALSE); 583 | return task; 584 | } 585 | 586 | dls_task_t *dls_task_create_container_new_generic( 587 | dleyna_connector_msg_id_t invocation, 588 | dls_task_type_t type, 589 | const gchar *path, 590 | GVariant *parameters, 591 | GError **error) 592 | { 593 | dls_task_t *task; 594 | 595 | task = prv_m2spec_task_new(type, invocation, path, 596 | "(@o)", error, FALSE); 597 | if (!task) 598 | goto finished; 599 | 600 | g_variant_get(parameters, "(ss@as)", 601 | &task->ut.create_container.display_name, 602 | &task->ut.create_container.type, 603 | &task->ut.create_container.child_types); 604 | 605 | finished: 606 | 607 | return task; 608 | } 609 | 610 | dls_task_t *dls_task_create_reference_new(dleyna_connector_msg_id_t invocation, 611 | dls_task_type_t type, 612 | const gchar *path, 613 | GVariant *parameters, 614 | GError **error) 615 | { 616 | dls_task_t *task; 617 | 618 | task = prv_m2spec_task_new(type, invocation, path, 619 | "(@o)", error, FALSE); 620 | if (!task) 621 | goto finished; 622 | 623 | g_variant_get(parameters, "(o)", &task->ut.create_reference.item_path); 624 | (void) g_strstrip(task->ut.create_reference.item_path); 625 | 626 | finished: 627 | 628 | return task; 629 | } 630 | 631 | dls_task_t *dls_task_update_new(dleyna_connector_msg_id_t invocation, 632 | const gchar *path, GVariant *parameters, 633 | GError **error) 634 | { 635 | dls_task_t *task; 636 | 637 | task = prv_m2spec_task_new(DLS_TASK_UPDATE_OBJECT, invocation, path, 638 | NULL, error, FALSE); 639 | if (!task) 640 | goto finished; 641 | 642 | g_variant_get(parameters, "(@a{sv}@as)", 643 | &task->ut.update.to_add_update, 644 | &task->ut.update.to_delete); 645 | 646 | finished: 647 | 648 | return task; 649 | } 650 | 651 | dls_task_t *dls_task_get_metadata_new(dleyna_connector_msg_id_t invocation, 652 | const gchar *path, GError **error) 653 | { 654 | dls_task_t *task; 655 | 656 | task = prv_m2spec_task_new(DLS_TASK_GET_OBJECT_METADATA, invocation, 657 | path, "(@s)", error, FALSE); 658 | 659 | return task; 660 | } 661 | 662 | dls_task_t *dls_task_get_icon_new(dleyna_connector_msg_id_t invocation, 663 | const gchar *path, GVariant *parameters, 664 | GError **error) 665 | { 666 | dls_task_t *task; 667 | 668 | task = prv_m2spec_task_new(DLS_TASK_GET_ICON, invocation, path, 669 | "(@ays)", error, FALSE); 670 | if (!task) 671 | goto finished; 672 | 673 | task->multiple_retvals = TRUE; 674 | 675 | g_variant_get(parameters, "(ss)", &task->ut.get_icon.mime_type, 676 | &task->ut.get_icon.resolution); 677 | 678 | finished: 679 | 680 | return task; 681 | } 682 | 683 | dls_task_t *dls_task_wake_new(dleyna_connector_msg_id_t invocation, 684 | const gchar *path, GError **error) 685 | { 686 | dls_task_t *task; 687 | 688 | task = prv_m2spec_task_new(DLS_TASK_WAKE, invocation, path, 689 | NULL, error, FALSE); 690 | 691 | return task; 692 | } 693 | 694 | void dls_task_complete(dls_task_t *task) 695 | { 696 | GVariant *variant = NULL; 697 | 698 | if (!task) 699 | goto finished; 700 | 701 | if (task->invocation) { 702 | if (task->result_format) { 703 | if (task->multiple_retvals) 704 | variant = g_variant_ref(task->result); 705 | else 706 | variant = g_variant_ref_sink( 707 | g_variant_new(task->result_format, 708 | task->result)); 709 | } 710 | 711 | dls_server_get_connector()->return_response(task->invocation, 712 | variant); 713 | if (variant) 714 | g_variant_unref(variant); 715 | 716 | task->invocation = NULL; 717 | } 718 | 719 | finished: 720 | 721 | return; 722 | } 723 | 724 | void dls_task_fail(dls_task_t *task, GError *error) 725 | { 726 | if (!task) 727 | goto finished; 728 | 729 | if (task->invocation) { 730 | dls_server_get_connector()->return_error(task->invocation, 731 | error); 732 | task->invocation = NULL; 733 | } 734 | 735 | finished: 736 | 737 | return; 738 | } 739 | 740 | void dls_task_cancel(dls_task_t *task) 741 | { 742 | GError *error; 743 | 744 | if (!task) 745 | goto finished; 746 | 747 | if (task->invocation) { 748 | error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_CANCELLED, 749 | "Operation cancelled."); 750 | dls_server_get_connector()->return_error(task->invocation, 751 | error); 752 | task->invocation = NULL; 753 | g_error_free(error); 754 | } 755 | 756 | if (!task->synchronous) 757 | dls_async_task_cancel((dls_async_task_t *)task); 758 | 759 | finished: 760 | 761 | return; 762 | } 763 | 764 | void dls_task_delete(dls_task_t *task) 765 | { 766 | GError *error; 767 | 768 | if (!task) 769 | goto finished; 770 | 771 | if (task->invocation) { 772 | error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_DIED, 773 | "Unable to complete command."); 774 | dls_server_get_connector()->return_error(task->invocation, 775 | error); 776 | g_error_free(error); 777 | } 778 | 779 | prv_delete(task); 780 | 781 | finished: 782 | 783 | return; 784 | } 785 | -------------------------------------------------------------------------------- /libdleyna/server/task.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #ifndef DLS_TASK_H__ 24 | #define DLS_TASK_H__ 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | #include "server.h" 33 | 34 | enum dls_task_type_t_ { 35 | DLS_TASK_GET_VERSION, 36 | DLS_TASK_GET_SERVERS, 37 | DLS_TASK_RESCAN, 38 | DLS_TASK_GET_CHILDREN, 39 | DLS_TASK_GET_ALL_PROPS, 40 | DLS_TASK_GET_PROP, 41 | DLS_TASK_SEARCH, 42 | DLS_TASK_BROWSE_OBJECTS, 43 | DLS_TASK_GET_RESOURCE, 44 | DLS_TASK_SET_PREFER_LOCAL_ADDRESSES, 45 | DLS_TASK_SET_PROTOCOL_INFO, 46 | DLS_TASK_UPLOAD_TO_ANY, 47 | DLS_TASK_UPLOAD, 48 | DLS_TASK_GET_UPLOAD_STATUS, 49 | DLS_TASK_GET_UPLOAD_IDS, 50 | DLS_TASK_CANCEL_UPLOAD, 51 | DLS_TASK_DELETE_OBJECT, 52 | DLS_TASK_CREATE_CONTAINER, 53 | DLS_TASK_CREATE_CONTAINER_IN_ANY, 54 | DLS_TASK_UPDATE_OBJECT, 55 | DLS_TASK_GET_OBJECT_METADATA, 56 | DLS_TASK_CREATE_REFERENCE, 57 | DLS_TASK_GET_ICON, 58 | DLS_TASK_MANAGER_GET_ALL_PROPS, 59 | DLS_TASK_MANAGER_GET_PROP, 60 | DLS_TASK_MANAGER_SET_PROP, 61 | DLS_TASK_WAKE 62 | }; 63 | typedef enum dls_task_type_t_ dls_task_type_t; 64 | 65 | typedef void (*dls_cancel_task_t)(void *handle); 66 | 67 | typedef struct dls_task_get_children_t_ dls_task_get_children_t; 68 | struct dls_task_get_children_t_ { 69 | gboolean containers; 70 | gboolean items; 71 | guint start; 72 | guint count; 73 | GVariant *filter; 74 | gchar *sort_by; 75 | }; 76 | 77 | typedef struct dls_task_get_props_t_ dls_task_get_props_t; 78 | struct dls_task_get_props_t_ { 79 | gchar *interface_name; 80 | }; 81 | 82 | typedef struct dls_task_get_prop_t_ dls_task_get_prop_t; 83 | struct dls_task_get_prop_t_ { 84 | gchar *prop_name; 85 | gchar *interface_name; 86 | }; 87 | 88 | typedef struct dls_task_set_prop_t_ dls_task_set_prop_t; 89 | struct dls_task_set_prop_t_ { 90 | gchar *prop_name; 91 | gchar *interface_name; 92 | GVariant *params; 93 | }; 94 | 95 | typedef struct dls_task_search_t_ dls_task_search_t; 96 | struct dls_task_search_t_ { 97 | gchar *query; 98 | guint start; 99 | guint count; 100 | gchar *sort_by; 101 | GVariant *filter; 102 | }; 103 | 104 | typedef struct dls_task_browse_objects_t_ dls_task_browse_objects_t; 105 | struct dls_task_browse_objects_t_ { 106 | GVariant *objects; 107 | GVariant *filter; 108 | }; 109 | 110 | typedef struct dls_task_get_resource_t_ dls_task_get_resource_t; 111 | struct dls_task_get_resource_t_ { 112 | gchar *protocol_info; 113 | GVariant *filter; 114 | }; 115 | 116 | typedef struct dls_task_set_prefer_local_addresses_t_ 117 | dls_task_set_prefer_local_addresses_t; 118 | struct dls_task_set_prefer_local_addresses_t_ { 119 | gboolean prefer; 120 | }; 121 | 122 | typedef struct dls_task_set_protocol_info_t_ dls_task_set_protocol_info_t; 123 | struct dls_task_set_protocol_info_t_ { 124 | gchar *protocol_info; 125 | }; 126 | 127 | typedef struct dls_task_upload_t_ dls_task_upload_t; 128 | struct dls_task_upload_t_ { 129 | gchar *display_name; 130 | gchar *file_path; 131 | }; 132 | 133 | typedef struct dls_task_upload_action_t_ dls_task_upload_action_t; 134 | struct dls_task_upload_action_t_ { 135 | guint upload_id; 136 | }; 137 | 138 | typedef struct dls_task_create_container_t_ dls_task_create_container_t; 139 | struct dls_task_create_container_t_ { 140 | gchar *display_name; 141 | gchar *type; 142 | GVariant *child_types; 143 | }; 144 | 145 | typedef struct dls_task_update_t_ dls_task_update_t; 146 | struct dls_task_update_t_ { 147 | GVariant *to_add_update; 148 | GVariant *to_delete; 149 | }; 150 | 151 | typedef struct dls_task_create_reference_t_ dls_task_create_reference_t; 152 | struct dls_task_create_reference_t_ { 153 | gchar *item_path; 154 | }; 155 | 156 | typedef struct dls_task_target_info_t_ dls_task_target_info_t; 157 | struct dls_task_target_info_t_ { 158 | gchar *path; 159 | gchar *root_path; 160 | gchar *id; 161 | dls_device_t *device; 162 | }; 163 | 164 | typedef struct dls_task_get_icon_t_ dls_task_get_icon_t; 165 | struct dls_task_get_icon_t_ { 166 | gchar *mime_type; 167 | gchar *resolution; 168 | }; 169 | 170 | typedef struct dls_task_t_ dls_task_t; 171 | struct dls_task_t_ { 172 | dleyna_task_atom_t atom; /* pseudo inheritance - MUST be first field */ 173 | dls_task_type_t type; 174 | dls_task_target_info_t target; 175 | const gchar *result_format; 176 | GVariant *result; 177 | dleyna_connector_msg_id_t invocation; 178 | gboolean synchronous; 179 | gboolean multiple_retvals; 180 | union { 181 | dls_task_get_children_t get_children; 182 | dls_task_get_props_t get_props; 183 | dls_task_get_prop_t get_prop; 184 | dls_task_set_prop_t set_prop; 185 | dls_task_search_t search; 186 | dls_task_get_resource_t resource; 187 | dls_task_set_prefer_local_addresses_t prefer_local_addresses; 188 | dls_task_set_protocol_info_t protocol_info; 189 | dls_task_upload_t upload; 190 | dls_task_upload_action_t upload_action; 191 | dls_task_create_container_t create_container; 192 | dls_task_update_t update; 193 | dls_task_create_reference_t create_reference; 194 | dls_task_get_icon_t get_icon; 195 | dls_task_browse_objects_t browse_objects; 196 | } ut; 197 | }; 198 | 199 | dls_task_t *dls_task_rescan_new(dleyna_connector_msg_id_t invocation); 200 | 201 | dls_task_t *dls_task_get_version_new(dleyna_connector_msg_id_t invocation); 202 | 203 | dls_task_t *dls_task_get_servers_new(dleyna_connector_msg_id_t invocation); 204 | 205 | dls_task_t *dls_task_get_children_new(dleyna_connector_msg_id_t invocation, 206 | const gchar *path, GVariant *parameters, 207 | gboolean items, gboolean containers, 208 | GError **error); 209 | 210 | dls_task_t *dls_task_get_children_ex_new(dleyna_connector_msg_id_t invocation, 211 | const gchar *path, 212 | GVariant *parameters, gboolean items, 213 | gboolean containers, 214 | GError **error); 215 | 216 | dls_task_t *dls_task_get_prop_new(dleyna_connector_msg_id_t invocation, 217 | const gchar *path, GVariant *parameters, 218 | GError **error); 219 | 220 | dls_task_t *dls_task_get_props_new(dleyna_connector_msg_id_t invocation, 221 | const gchar *path, GVariant *parameters, 222 | GError **error); 223 | 224 | dls_task_t *dls_task_search_new(dleyna_connector_msg_id_t invocation, 225 | const gchar *path, GVariant *parameters, 226 | GError **error); 227 | 228 | dls_task_t *dls_task_search_ex_new(dleyna_connector_msg_id_t invocation, 229 | const gchar *path, GVariant *parameters, 230 | GError **error); 231 | 232 | dls_task_t *dls_task_browse_objects_new(dleyna_connector_msg_id_t invocation, 233 | const gchar *path, GVariant *parameters, 234 | GError **error); 235 | 236 | dls_task_t *dls_task_get_resource_new(dleyna_connector_msg_id_t invocation, 237 | const gchar *path, GVariant *parameters, 238 | GError **error); 239 | 240 | dls_task_t *dls_task_set_protocol_info_new(dleyna_connector_msg_id_t invocation, 241 | GVariant *parameters); 242 | 243 | dls_task_t *dls_task_prefer_local_addresses_new( 244 | dleyna_connector_msg_id_t invocation, 245 | GVariant *parameters); 246 | 247 | dls_task_t *dls_task_upload_to_any_new(dleyna_connector_msg_id_t invocation, 248 | const gchar *path, GVariant *parameters, 249 | GError **error); 250 | 251 | dls_task_t *dls_task_upload_new(dleyna_connector_msg_id_t invocation, 252 | const gchar *path, GVariant *parameters, 253 | GError **error); 254 | 255 | dls_task_t *dls_task_get_upload_status_new(dleyna_connector_msg_id_t invocation, 256 | const gchar *path, 257 | GVariant *parameters, 258 | GError **error); 259 | 260 | dls_task_t *dls_task_get_upload_ids_new(dleyna_connector_msg_id_t invocation, 261 | const gchar *path, 262 | GError **error); 263 | 264 | dls_task_t *dls_task_cancel_upload_new(dleyna_connector_msg_id_t invocation, 265 | const gchar *path, 266 | GVariant *parameters, 267 | GError **error); 268 | 269 | dls_task_t *dls_task_delete_new(dleyna_connector_msg_id_t invocation, 270 | const gchar *path, 271 | GError **error); 272 | 273 | dls_task_t *dls_task_create_container_new_generic( 274 | dleyna_connector_msg_id_t invocation, 275 | dls_task_type_t type, 276 | const gchar *path, 277 | GVariant *parameters, 278 | GError **error); 279 | 280 | dls_task_t *dls_task_create_reference_new(dleyna_connector_msg_id_t invocation, 281 | dls_task_type_t type, 282 | const gchar *path, 283 | GVariant *parameters, 284 | GError **error); 285 | 286 | dls_task_t *dls_task_update_new(dleyna_connector_msg_id_t invocation, 287 | const gchar *path, GVariant *parameters, 288 | GError **error); 289 | 290 | dls_task_t *dls_task_get_metadata_new(dleyna_connector_msg_id_t invocation, 291 | const gchar *path, 292 | GError **error); 293 | 294 | dls_task_t *dls_task_get_icon_new(dleyna_connector_msg_id_t invocation, 295 | const gchar *path, GVariant *parameters, 296 | GError **error); 297 | 298 | dls_task_t *dls_task_manager_get_prop_new(dleyna_connector_msg_id_t invocation, 299 | const gchar *path, 300 | GVariant *parameters, 301 | GError **error); 302 | 303 | dls_task_t *dls_task_manager_get_props_new(dleyna_connector_msg_id_t invocation, 304 | const gchar *path, 305 | GVariant *parameters, 306 | GError **error); 307 | 308 | dls_task_t *dls_task_manager_set_prop_new(dleyna_connector_msg_id_t invocation, 309 | const gchar *path, 310 | GVariant *parameters, 311 | GError **error); 312 | 313 | dls_task_t *dls_task_wake_new(dleyna_connector_msg_id_t invocation, 314 | const gchar *path, 315 | GError **error); 316 | 317 | void dls_task_cancel(dls_task_t *task); 318 | 319 | void dls_task_complete(dls_task_t *task); 320 | 321 | void dls_task_fail(dls_task_t *task, GError *error); 322 | 323 | void dls_task_delete(dls_task_t *task); 324 | 325 | #endif /* DLS_TASK_H__ */ 326 | -------------------------------------------------------------------------------- /libdleyna/server/upnp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * 21 | */ 22 | 23 | #ifndef DLS_UPNP_H__ 24 | #define DLS_UPNP_H__ 25 | 26 | #include 27 | #include 28 | 29 | #include "client.h" 30 | #include "async.h" 31 | 32 | typedef void (*dls_upnp_callback_t)(const gchar *path, void *user_data); 33 | typedef void (*dls_upnp_task_complete_t)(dls_task_t *task, GError *error); 34 | 35 | dls_upnp_t *dls_upnp_new(dleyna_connector_id_t connection, 36 | guint port, 37 | const dleyna_connector_dispatch_cb_t *dispatch_table, 38 | dls_upnp_callback_t found_server, 39 | dls_upnp_callback_t lost_server, 40 | void *user_data); 41 | 42 | void dls_upnp_delete(dls_upnp_t *upnp); 43 | 44 | GVariant *dls_upnp_get_device_ids(dls_upnp_t *upnp); 45 | 46 | GHashTable *dls_upnp_get_device_udn_map(dls_upnp_t *upnp); 47 | 48 | GHashTable *dls_upnp_get_sleeping_device_udn_map(dls_upnp_t *upnp); 49 | 50 | void dls_upnp_delete_sleeping_device(dls_upnp_t *upnp, dls_device_t *device); 51 | 52 | void dls_upnp_get_children(dls_upnp_t *upnp, dls_client_t *client, 53 | dls_task_t *task, 54 | dls_upnp_task_complete_t cb); 55 | 56 | void dls_upnp_get_all_props(dls_upnp_t *upnp, dls_client_t *client, 57 | dls_task_t *task, 58 | dls_upnp_task_complete_t cb); 59 | 60 | void dls_upnp_get_prop(dls_upnp_t *upnp, dls_client_t *client, 61 | dls_task_t *task, 62 | dls_upnp_task_complete_t cb); 63 | 64 | void dls_upnp_search(dls_upnp_t *upnp, dls_client_t *client, 65 | dls_task_t *task, 66 | dls_upnp_task_complete_t cb); 67 | 68 | void dls_upnp_browse_objects(dls_upnp_t *upnp, dls_client_t *client, 69 | dls_task_t *task, 70 | dls_upnp_task_complete_t cb); 71 | 72 | void dls_upnp_get_resource(dls_upnp_t *upnp, dls_client_t *client, 73 | dls_task_t *task, 74 | dls_upnp_task_complete_t cb); 75 | 76 | void dls_upnp_upload_to_any(dls_upnp_t *upnp, dls_client_t *client, 77 | dls_task_t *task, 78 | dls_upnp_task_complete_t cb); 79 | 80 | void dls_upnp_upload(dls_upnp_t *upnp, dls_client_t *client, 81 | dls_task_t *task, 82 | dls_upnp_task_complete_t cb); 83 | 84 | void dls_upnp_get_upload_status(dls_upnp_t *upnp, dls_task_t *task); 85 | 86 | void dls_upnp_get_upload_ids(dls_upnp_t *upnp, dls_task_t *task); 87 | 88 | void dls_upnp_cancel_upload(dls_upnp_t *upnp, dls_task_t *task); 89 | 90 | void dls_upnp_delete_object(dls_upnp_t *upnp, dls_client_t *client, 91 | dls_task_t *task, 92 | dls_upnp_task_complete_t cb); 93 | 94 | void dls_upnp_create_container(dls_upnp_t *upnp, dls_client_t *client, 95 | dls_task_t *task, 96 | dls_upnp_task_complete_t cb); 97 | 98 | void dls_upnp_create_container_in_any(dls_upnp_t *upnp, dls_client_t *client, 99 | dls_task_t *task, 100 | dls_upnp_task_complete_t cb); 101 | 102 | void dls_upnp_update_object(dls_upnp_t *upnp, dls_client_t *client, 103 | dls_task_t *task, 104 | dls_upnp_task_complete_t cb); 105 | 106 | void dls_upnp_get_object_metadata(dls_upnp_t *upnp, dls_client_t *client, 107 | dls_task_t *task, 108 | dls_upnp_task_complete_t cb); 109 | 110 | void dls_upnp_create_reference(dls_upnp_t *upnp, dls_client_t *client, 111 | dls_task_t *task, 112 | dls_upnp_task_complete_t cb); 113 | 114 | void dls_upnp_get_icon(dls_upnp_t *upnp, dls_client_t *client, 115 | dls_task_t *task, 116 | dls_upnp_task_complete_t cb); 117 | 118 | void dls_upnp_wake(dls_upnp_t *upnp, dls_client_t *client, 119 | dls_task_t *task, 120 | dls_upnp_task_complete_t cb); 121 | 122 | void dls_upnp_unsubscribe(dls_upnp_t *upnp); 123 | 124 | gboolean dls_upnp_device_context_exist(dls_device_t *device, 125 | dls_device_context_t *context); 126 | 127 | void dls_upnp_rescan(dls_upnp_t *upnp); 128 | 129 | GUPnPContextManager *dls_upnp_get_context_manager(dls_upnp_t *upnp); 130 | 131 | #endif /* DLS_UPNP_H__ */ 132 | -------------------------------------------------------------------------------- /libdleyna/server/xml-util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Christophe Guiraud 20 | * 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "xml-util.h" 27 | 28 | static xmlNode *prv_get_child_node(xmlNode *node, va_list args) 29 | { 30 | const gchar *name; 31 | 32 | name = va_arg(args, const gchar *); 33 | while (name != NULL) { 34 | node = node->children; 35 | while (node != NULL) { 36 | if (node->name != NULL && 37 | !strcmp(name, (char *)node->name)) 38 | break; 39 | 40 | node = node->next; 41 | } 42 | 43 | if (node == NULL) 44 | break; 45 | 46 | name = va_arg(args, const gchar *); 47 | } 48 | 49 | return node; 50 | } 51 | 52 | static GList *prv_get_children_list(xmlNode *node, const gchar *name) 53 | { 54 | GList *child_list = NULL; 55 | 56 | node = node->children; 57 | while (node != NULL) { 58 | if (node->name != NULL && 59 | !strcmp(name, (char *)node->name)) 60 | child_list = g_list_prepend(child_list, node); 61 | 62 | node = node->next; 63 | } 64 | 65 | return child_list; 66 | } 67 | 68 | GList *xml_util_get_child_string_list_content_by_name(xmlNode *node, ...) 69 | { 70 | xmlChar *content; 71 | va_list args; 72 | GList *child_list = NULL; 73 | GList *next; 74 | GList *str_list = NULL; 75 | xmlNode *child_list_node; 76 | xmlNode *child_node; 77 | 78 | va_start(args, node); 79 | 80 | child_node = prv_get_child_node(node, args); 81 | 82 | va_end(args); 83 | 84 | if (child_node != NULL) { 85 | child_list = prv_get_children_list(child_node->parent, 86 | (const gchar *)child_node->name); 87 | next = child_list; 88 | while (next) { 89 | child_list_node = (xmlNode *)next->data; 90 | 91 | content = xmlNodeGetContent(child_list_node); 92 | 93 | if (content != NULL) { 94 | str_list = g_list_prepend(str_list, 95 | g_strdup((gchar *)content)); 96 | 97 | xmlFree(content); 98 | } 99 | 100 | next = g_list_next(next); 101 | } 102 | 103 | g_list_free(child_list); 104 | } 105 | 106 | return str_list; 107 | } 108 | 109 | gchar *xml_util_get_child_string_content_by_name(xmlNode *node, ...) 110 | { 111 | xmlChar *content; 112 | va_list args; 113 | gchar *str = NULL; 114 | xmlNode *child_node; 115 | 116 | va_start(args, node); 117 | 118 | child_node = prv_get_child_node(node, args); 119 | 120 | va_end(args); 121 | 122 | if (child_node != NULL) { 123 | content = xmlNodeGetContent(child_node); 124 | 125 | if (content != NULL) { 126 | str = g_strdup((gchar *)content); 127 | 128 | xmlFree(content); 129 | } 130 | } 131 | 132 | return str; 133 | } 134 | -------------------------------------------------------------------------------- /libdleyna/server/xml-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Christophe Guiraud 20 | * 21 | */ 22 | 23 | 24 | #ifndef DLS_XML_UTIL_H__ 25 | #define DLS_XML_UTIL_H__ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | GList *xml_util_get_child_string_list_content_by_name(xmlNode *node, ...); 32 | 33 | gchar *xml_util_get_child_string_content_by_name(xmlNode *node, ...); 34 | 35 | #endif /* DLS_XML_UTIL_H__ */ 36 | -------------------------------------------------------------------------------- /m4/compiler-flags.m4: -------------------------------------------------------------------------------- 1 | dnl 2 | dnl dLeyna 3 | dnl 4 | dnl Copyright (C) 2012-2015 Intel Corporation. All rights reserved. 5 | dnl 6 | dnl This program is free software; you can redistribute it and/or modify it 7 | dnl under the terms and conditions of the GNU Lesser General Public License, 8 | dnl version 2.1, as published by the Free Software Foundation. 9 | dnl 10 | dnl This program is distributed in the hope it will be useful, but WITHOUT 11 | dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | dnl for more details. 14 | dnl 15 | dnl You should have received a copy of the GNU Lesser General Public License 16 | dnl along with this program; if not, write to the Free Software Foundation, Inc., 17 | dnl 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | dnl 19 | dnl Ludovic Ferrandis 20 | dnl Regis Merlino 21 | dnl 22 | 23 | AC_DEFUN_ONCE([DLEYNA_SERVER_COMPILER_FLAGS], [ 24 | if test x"${CFLAGS}" = x""; then 25 | CFLAGS="-Wall" 26 | AS_VAR_APPEND([CFLAGS], [" -O2"]) 27 | AS_VAR_APPEND([CFLAGS], [" -D_FORTIFY_SOURCE=2"]) 28 | fi 29 | 30 | if test x"$USE_MAINTAINER_MODE" = x"yes"; then 31 | AS_VAR_APPEND([CFLAGS], [" -Wextra"]) 32 | AS_VAR_APPEND([CFLAGS], [" -Wno-unused-parameter"]) 33 | AS_VAR_APPEND([CFLAGS], [" -Wno-missing-field-initializers"]) 34 | AS_VAR_APPEND([CFLAGS], [" -Wdeclaration-after-statement"]) 35 | AS_VAR_APPEND([CFLAGS], [" -Wmissing-declarations"]) 36 | AS_VAR_APPEND([CFLAGS], [" -Wredundant-decls"]) 37 | AS_VAR_APPEND([CFLAGS], [" -Wcast-align"]) 38 | 39 | AS_VAR_APPEND([CFLAGS], [" -Wstrict-prototypes"]) 40 | AS_VAR_APPEND([CFLAGS], [" -Wmissing-prototypes"]) 41 | AS_VAR_APPEND([CFLAGS], [" -Wnested-externs"]) 42 | AS_VAR_APPEND([CFLAGS], [" -Wshadow"]) 43 | AS_VAR_APPEND([CFLAGS], [" -Wformat=2"]) 44 | AS_VAR_APPEND([CFLAGS], [" -Winit-self"]) 45 | 46 | AS_VAR_APPEND([CFLAGS], [" -std=gnu99"]) 47 | AS_VAR_APPEND([CFLAGS], [" -pedantic"]) 48 | AS_VAR_APPEND([CFLAGS], [" -Wno-overlength-strings"]) 49 | 50 | AS_VAR_APPEND([CFLAGS], [" -DG_DISABLE_DEPRECATED"]) 51 | AS_VAR_APPEND([CFLAGS], [" -DGLIB_DISABLE_DEPRECATION_WARNINGS"]) 52 | fi 53 | 54 | AS_VAR_APPEND([CFLAGS], [" -Wno-format-extra-args"]) 55 | AS_VAR_APPEND([CFLAGS], [" -Wl,--no-undefined"]) 56 | ]) 57 | -------------------------------------------------------------------------------- /m4/log.m4: -------------------------------------------------------------------------------- 1 | dnl 2 | dnl dLeyna 3 | dnl 4 | dnl Copyright (C) 2012-2015 Intel Corporation. All rights reserved. 5 | dnl 6 | dnl This program is free software; you can redistribute it and/or modify it 7 | dnl under the terms and conditions of the GNU Lesser General Public License, 8 | dnl version 2.1, as published by the Free Software Foundation. 9 | dnl 10 | dnl This program is distributed in the hope it will be useful, but WITHOUT 11 | dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | dnl for more details. 14 | dnl 15 | dnl You should have received a copy of the GNU Lesser General Public License 16 | dnl along with this program; if not, write to the Free Software Foundation, Inc., 17 | dnl 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | dnl 19 | dnl Ludovic Ferrandis 20 | dnl 21 | 22 | 23 | AC_DEFUN([_DLEYNA_LOG_LEVEL_CHECK_VALUE], 24 | [ 25 | AS_CASE($1, 26 | [[[1-6]]], [AS_IF([test "x${log_unique}" = xyes], 27 | [ 28 | AC_MSG_ERROR(["Log levels 0, 7 and 8 cannot be combined with other values"], 1) 29 | ]) 30 | : $((log_level_count++)) 31 | ], 32 | 33 | [0|7|8], [AS_IF([test ${log_level_count} -ne 0], 34 | [ 35 | AC_MSG_ERROR(["Log level $1 cannot be combined with other values"], 1) 36 | ]) 37 | log_unique=yes 38 | ], 39 | [AC_MSG_ERROR(["$1 is not a valid value"], 1)] 40 | ) 41 | ] 42 | ) 43 | 44 | AC_DEFUN([DLEYNA_LOG_LEVEL_CHECK], 45 | [ 46 | AC_MSG_CHECKING([for --with-log-level=$1]) 47 | 48 | old_IFS=${IFS} 49 | IFS="," 50 | 51 | log_ok=yes 52 | log_unique=no 53 | log_level_count=0 54 | LOG_LEVEL=0 55 | 56 | for log_level in $1 57 | do 58 | IFS=${old_IFS} 59 | _DLEYNA_LOG_LEVEL_CHECK_VALUE([$log_level]) 60 | IFS="," 61 | log_name=LOG_LEVEL_${log_level} 62 | eval log_value=\$${log_name} 63 | : $((LOG_LEVEL |= ${log_value})) 64 | done 65 | 66 | IFS=${old_IFS} 67 | 68 | AC_DEFINE_UNQUOTED([DLEYNA_LOG_LEVEL], [${LOG_LEVEL}], [Log level flag for debug messages]) 69 | 70 | AC_MSG_RESULT([ok]) 71 | ] 72 | ) 73 | 74 | AC_DEFUN([DLEYNA_LOG_TYPE_CHECK], 75 | [ 76 | AC_MSG_CHECKING([for --with-log-type=$1]) 77 | 78 | AS_CASE($1, 79 | [0|1], [], 80 | 81 | [AC_MSG_ERROR(["$1 is not a valid value"], 1)] 82 | ) 83 | 84 | AC_MSG_RESULT([ok]) 85 | ] 86 | ) 87 | -------------------------------------------------------------------------------- /server/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = $(GLIB_CFLAGS) \ 2 | $(GIO_CFLAGS) \ 3 | $(DLEYNA_CORE_CFLAGS) \ 4 | -I$(top_srcdir) \ 5 | -include config.h 6 | 7 | libexec_PROGRAMS = dleyna-server-service 8 | 9 | dleyna_server_service_SOURCES = daemon.c 10 | 11 | dleyna_server_service_LDADD = $(GLIB_LIBS) \ 12 | $(GIO_LIBS) \ 13 | $(DLEYNA_CORE_LIBS) \ 14 | $(top_builddir)/libdleyna/server/libdleyna-server-1.0.la 15 | 16 | dbusservicedir = $(DBUS_SERVICE_DIR) 17 | dbusservice_in_files = com.intel.dleyna-server.service.in 18 | dbusservice_DATA = com.intel.dleyna-server.service 19 | 20 | # Replace the 'libexecdir' marker with its fully expanded value 21 | %.service: %.service.in Makefile 22 | $(AM_V_GEN) $(SED) -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ 23 | 24 | pkgconfigdir = $(libdir)/pkgconfig 25 | pkgconfig_DATA = dleyna-server-service-1.0.pc 26 | 27 | EXTRA_DIST = $(dbusservice_in_files) 28 | 29 | CLEANFILES = $(dbusservice_DATA) 30 | DISTCLEANFILES = $(dbusservice_DATA) 31 | -------------------------------------------------------------------------------- /server/com.intel.dleyna-server.service.in: -------------------------------------------------------------------------------- 1 | [D-BUS Service] 2 | Name=com.intel.dleyna-server 3 | Exec=@libexecdir@/dleyna-server-service 4 | 5 | -------------------------------------------------------------------------------- /server/daemon.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dLeyna 3 | * 4 | * Copyright (C) 2013 Intel Corporation. All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms and conditions of the GNU Lesser General Public License, 8 | * version 2.1, as published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | * for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public License 16 | * along with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | * Mark Ryan 20 | * Regis Merlino 21 | * 22 | */ 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #define DLS_SERVER_SERVICE_NAME "dleyna-server-service" 31 | 32 | static guint g_sig_id; 33 | 34 | static gboolean prv_quit_handler(GIOChannel *source, GIOCondition condition, 35 | gpointer user_data) 36 | { 37 | dleyna_main_loop_quit(); 38 | g_sig_id = 0; 39 | 40 | return FALSE; 41 | } 42 | 43 | static gboolean prv_init_signal_handler(sigset_t mask) 44 | { 45 | gboolean retval = FALSE; 46 | int fd = -1; 47 | GIOChannel *channel = NULL; 48 | 49 | fd = signalfd(-1, &mask, SFD_NONBLOCK); 50 | if (fd == -1) 51 | goto on_error; 52 | 53 | channel = g_io_channel_unix_new(fd); 54 | g_io_channel_set_close_on_unref(channel, TRUE); 55 | 56 | if (g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL) != 57 | G_IO_STATUS_NORMAL) 58 | goto on_error; 59 | 60 | if (g_io_channel_set_encoding(channel, NULL, NULL) != 61 | G_IO_STATUS_NORMAL) 62 | goto on_error; 63 | 64 | g_sig_id = g_io_add_watch(channel, G_IO_IN | G_IO_PRI, 65 | prv_quit_handler, 66 | NULL); 67 | 68 | retval = TRUE; 69 | 70 | on_error: 71 | 72 | if (channel) 73 | g_io_channel_unref(channel); 74 | 75 | return retval; 76 | } 77 | 78 | int main(int argc, char *argv[]) 79 | { 80 | sigset_t mask; 81 | int retval = 1; 82 | 83 | sigemptyset(&mask); 84 | sigaddset(&mask, SIGTERM); 85 | sigaddset(&mask, SIGINT); 86 | 87 | if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) 88 | goto out; 89 | 90 | if (!prv_init_signal_handler(mask)) 91 | goto out; 92 | 93 | retval = dleyna_main_loop_start(DLS_SERVER_SERVICE_NAME, 94 | dleyna_control_point_get_server(), 95 | NULL); 96 | 97 | out: 98 | 99 | if (g_sig_id) 100 | (void) g_source_remove(g_sig_id); 101 | 102 | return retval; 103 | } 104 | -------------------------------------------------------------------------------- /server/dleyna-server-service-1.0.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libexecdir=@libexecdir@ 4 | 5 | Name: @PACKAGE@-service 6 | Description: UPnP & DLNA media content management 7 | Requires.private: glib-2.0 gio-2.0 dleyna-core-1.0 8 | Version: @VERSION@ 9 | -------------------------------------------------------------------------------- /test/dbus/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = $(GLIB_CFLAGS) \ 2 | $(GIO_CFLAGS) 3 | 4 | dms_info_sources = dms-info.c 5 | 6 | noinst_PROGRAMS = dms-info 7 | dms_info_SOURCES = $(dms_info_sources) 8 | 9 | dms_info_CFLAGS = $(GLIB_CFLAGS) \ 10 | $(GIO_CFLAGS) 11 | 12 | dms_info_LDADD = $(GLIB_LIBS) \ 13 | $(GIO_LIBS) 14 | -------------------------------------------------------------------------------- /test/dbus/dms-info.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dms-info 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms and conditions of the GNU Lesser General Public License, 6 | * version 2.1, as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 11 | * for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public License 14 | * along with this program; if not, write to the Free Software Foundation, Inc., 15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 16 | * 17 | * Copyright (C) 2012-2015 Intel Corporation. All rights reserved. 18 | * 19 | * Mark Ryan 20 | * 21 | ******************************************************************************/ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | #define DMS_INFO_SERVICE "com.intel.dleyna-server" 33 | #define DMS_INFO_MANAGER_IF "com.intel.dLeynaServer.Manager" 34 | #define DMS_INFO_MANAGER_OBJ "/com/intel/dLeynaServer" 35 | #define DMS_INFO_GET_SERVERS "GetServers" 36 | #define DMS_INFO_GET_ALL "GetAll" 37 | #define DMS_INFO_PROPERTIES_IF "org.freedesktop.DBus.Properties" 38 | 39 | typedef struct dms_info_t_ dms_info_t; 40 | struct dms_info_t_ 41 | { 42 | guint sig_id; 43 | GMainLoop *main_loop; 44 | GDBusProxy *manager_proxy; 45 | GCancellable *cancellable; 46 | GHashTable *dmss; 47 | unsigned int async; 48 | }; 49 | 50 | typedef struct dms_server_data_t_ dms_server_data_t; 51 | struct dms_server_data_t_ { 52 | GCancellable *cancellable; 53 | GDBusProxy *proxy; 54 | }; 55 | 56 | static dms_server_data_t *prv_dms_server_data_new(GDBusProxy *proxy) 57 | { 58 | dms_server_data_t *data = g_new(dms_server_data_t, 1); 59 | data->proxy = proxy; 60 | data->cancellable = g_cancellable_new(); 61 | return data; 62 | } 63 | 64 | static void prv_dms_server_data_delete(gpointer user_data) 65 | { 66 | dms_server_data_t *data = user_data; 67 | g_object_unref(data->cancellable); 68 | g_object_unref(data->proxy); 69 | g_free(data); 70 | } 71 | 72 | static void prv_dms_info_free(dms_info_t *info) 73 | { 74 | if (info->manager_proxy) 75 | g_object_unref(info->manager_proxy); 76 | 77 | if (info->sig_id) 78 | (void) g_source_remove(info->sig_id); 79 | 80 | if (info->main_loop) 81 | g_main_loop_unref(info->main_loop); 82 | 83 | if (info->cancellable) 84 | g_object_unref(info->cancellable); 85 | 86 | if (info->dmss) 87 | g_hash_table_unref(info->dmss); 88 | } 89 | 90 | static void prv_dump_container_props(GVariant *props) 91 | { 92 | GVariantIter iter; 93 | GVariant *dictionary; 94 | gchar *key; 95 | GVariant *value; 96 | gchar *formatted_value; 97 | 98 | dictionary = g_variant_get_child_value(props, 0); 99 | (void) g_variant_iter_init(&iter, dictionary); 100 | 101 | printf("\n"); 102 | while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) { 103 | formatted_value = g_variant_print(value, FALSE); 104 | printf("%s: %s\n", key, formatted_value); 105 | g_free(formatted_value); 106 | g_variant_unref(value); 107 | } 108 | } 109 | 110 | static void prv_get_props_cb(GObject *source_object, GAsyncResult *res, 111 | gpointer user_data) 112 | { 113 | GVariant *variant; 114 | dms_info_t *info = user_data; 115 | dms_server_data_t *data; 116 | const gchar *obj_path; 117 | 118 | obj_path = g_dbus_proxy_get_object_path((GDBusProxy *) source_object); 119 | data = g_hash_table_lookup(info->dmss, obj_path); 120 | 121 | --info->async; 122 | 123 | if (g_cancellable_is_cancelled(data->cancellable)) { 124 | if (info->async == 0) 125 | g_main_loop_quit(info->main_loop); 126 | printf("Get Properties cancelled.\n"); 127 | } else { 128 | variant = g_dbus_proxy_call_finish(info->manager_proxy, res, 129 | NULL); 130 | if (!variant) { 131 | printf("Get Properties failed.\n"); 132 | } else { 133 | prv_dump_container_props(variant); 134 | g_variant_unref(variant); 135 | } 136 | } 137 | } 138 | 139 | static void prv_get_container_props(dms_info_t *info, const gchar *container) 140 | { 141 | dms_server_data_t *data; 142 | GDBusProxy *proxy; 143 | GDBusProxyFlags flags; 144 | 145 | if (!g_hash_table_lookup_extended(info->dmss, container, NULL, NULL)) { 146 | printf("Container Object Found: %s\n", container); 147 | 148 | /* We'll create these proxies synchronously. The server 149 | is already started and we don't want to retrieve any 150 | properties so it should be fast. Okay, we do want 151 | to retrieve properties but we want to do so for all 152 | interfaces and not just org.gnome.UPnP.MediaContainer2. 153 | To do this we will need to call GetAll(""). 154 | */ 155 | 156 | flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES; 157 | proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SESSION, 158 | flags, NULL, 159 | DMS_INFO_SERVICE, 160 | container, 161 | DMS_INFO_PROPERTIES_IF, 162 | NULL, NULL); 163 | if (!proxy) { 164 | printf("Unable to create Container Proxy for %s\n", 165 | container); 166 | } else { 167 | data = prv_dms_server_data_new(proxy); 168 | g_hash_table_insert(info->dmss, g_strdup(container), 169 | data); 170 | ++info->async; 171 | g_dbus_proxy_call(proxy, DMS_INFO_GET_ALL, 172 | g_variant_new("(s)", ""), 173 | G_DBUS_CALL_FLAGS_NONE, -1, 174 | data->cancellable, 175 | prv_get_props_cb, 176 | info); 177 | } 178 | } 179 | } 180 | 181 | static void prv_get_root_folders(dms_info_t *info, GVariant *servers) 182 | { 183 | GVariantIter iter; 184 | GVariant *array; 185 | const gchar *container; 186 | gsize count; 187 | 188 | /* Results always seem to be packed inside a tuple. We need 189 | to extract our array from the tuple */ 190 | 191 | array = g_variant_get_child_value(servers, 0); 192 | count = g_variant_iter_init(&iter, array); 193 | 194 | printf("Found %"G_GSIZE_FORMAT" DMS Root Containers\n", count); 195 | 196 | while (g_variant_iter_next(&iter, "o", &container)) 197 | prv_get_container_props(info, container); 198 | } 199 | 200 | static void prv_get_servers_cb(GObject *source_object, GAsyncResult *res, 201 | gpointer user_data) 202 | { 203 | GVariant *variant; 204 | dms_info_t *info = user_data; 205 | 206 | --info->async; 207 | 208 | if (g_cancellable_is_cancelled(info->cancellable)) { 209 | if (info->async == 0) 210 | g_main_loop_quit(info->main_loop); 211 | printf("Get Servers cancelled\n"); 212 | } else { 213 | variant = g_dbus_proxy_call_finish(info->manager_proxy, res, 214 | NULL); 215 | if (!variant) { 216 | printf("Get Servers failed.\n"); 217 | } else { 218 | prv_get_root_folders(info, variant); 219 | g_variant_unref(variant); 220 | } 221 | } 222 | } 223 | 224 | static void prv_on_signal(GDBusProxy *proxy, gchar *sender_name, 225 | gchar *signal_name, GVariant *parameters, 226 | gpointer user_data) 227 | { 228 | gchar *container; 229 | dms_info_t *info = user_data; 230 | 231 | if (!strcmp(signal_name, "FoundServer")) { 232 | g_variant_get(parameters, "(&o)", &container); 233 | if (!g_hash_table_lookup_extended(info->dmss, container, NULL, 234 | NULL)) { 235 | printf("\nFound DMS %s\n", container); 236 | prv_get_container_props(info, container); 237 | } 238 | } else if (!strcmp(signal_name, "LostServer")) { 239 | g_variant_get(parameters, "(&o)", &container); 240 | printf("\nLost DMS %s\n", container); 241 | (void) g_hash_table_remove(info->dmss, container); 242 | } 243 | } 244 | 245 | static void prv_manager_proxy_created(GObject *source_object, 246 | GAsyncResult *result, 247 | gpointer user_data) 248 | { 249 | dms_info_t *info = user_data; 250 | GDBusProxy *proxy; 251 | 252 | --info->async; 253 | 254 | if (g_cancellable_is_cancelled(info->cancellable)) { 255 | printf("Manager proxy creation cancelled.\n"); 256 | if (info->async == 0) 257 | g_main_loop_quit(info->main_loop); 258 | } else { 259 | proxy = g_dbus_proxy_new_finish(result, NULL); 260 | if (!proxy) { 261 | printf("Unable to create manager proxy.\n"); 262 | } else { 263 | info->manager_proxy = proxy; 264 | 265 | /* Set up signals to be notified when servers 266 | appear and dissapear */ 267 | 268 | g_signal_connect(proxy, "g-signal", 269 | G_CALLBACK (prv_on_signal), info); 270 | 271 | /* Now we need to retrieve a list of the DMSes on 272 | the network. This involves IPC so we will do 273 | this asynchronously.*/ 274 | 275 | ++info->async; 276 | g_cancellable_reset(info->cancellable); 277 | g_dbus_proxy_call(proxy, DMS_INFO_GET_SERVERS, 278 | NULL, G_DBUS_CALL_FLAGS_NONE, -1, 279 | info->cancellable, prv_get_servers_cb, 280 | info); 281 | } 282 | } 283 | } 284 | 285 | static gboolean prv_quit_handler(GIOChannel *source, GIOCondition condition, 286 | gpointer user_data) 287 | { 288 | dms_info_t *info = user_data; 289 | GHashTableIter iter; 290 | gpointer value; 291 | dms_server_data_t *data; 292 | 293 | /* We cannot quit straight away if asynchronous calls our outstanding. 294 | First we need to cancel them. Each time one is cancel info->async 295 | will drop by 1. Once it reaches 0 the callback function associated 296 | with the command being cancelled will quit the mainloop. */ 297 | 298 | if (info->async == 0) { 299 | g_main_loop_quit(info->main_loop); 300 | } else { 301 | g_cancellable_cancel(info->cancellable); 302 | g_hash_table_iter_init(&iter, info->dmss); 303 | while (g_hash_table_iter_next(&iter, NULL, &value)) { 304 | data = value; 305 | g_cancellable_cancel(data->cancellable); 306 | } 307 | } 308 | 309 | info->sig_id = 0; 310 | 311 | return FALSE; 312 | } 313 | 314 | static bool prv_init_signal_handler(sigset_t mask, dms_info_t *info) 315 | { 316 | bool retval = false; 317 | int fd = -1; 318 | GIOChannel *channel = NULL; 319 | 320 | fd = signalfd(-1, &mask, SFD_NONBLOCK); 321 | if (fd == -1) 322 | goto on_error; 323 | 324 | channel = g_io_channel_unix_new(fd); 325 | g_io_channel_set_close_on_unref(channel, TRUE); 326 | 327 | if (g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL) != 328 | G_IO_STATUS_NORMAL) 329 | goto on_error; 330 | 331 | if (g_io_channel_set_encoding(channel, NULL, NULL) != 332 | G_IO_STATUS_NORMAL) 333 | goto on_error; 334 | 335 | info->sig_id = g_io_add_watch(channel, G_IO_IN | G_IO_PRI, 336 | prv_quit_handler, 337 | info); 338 | 339 | retval = true; 340 | 341 | on_error: 342 | 343 | if (channel) 344 | g_io_channel_unref(channel); 345 | 346 | return retval; 347 | } 348 | 349 | int main(int argc, char *argv[]) 350 | { 351 | dms_info_t info; 352 | sigset_t mask; 353 | 354 | memset(&info, 0, sizeof(info)); 355 | 356 | sigemptyset(&mask); 357 | sigaddset(&mask, SIGTERM); 358 | sigaddset(&mask, SIGINT); 359 | 360 | if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) 361 | goto on_error; 362 | 363 | /* Create proxy for com.intel.dLeynaServer.Manager. The Manager 364 | object has no properties. We will create the proxy asynchronously 365 | and use G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES to ensure that 366 | gio does not contact the server to retrieve remote properties. Creating 367 | the proxy will force dleyna-media-service be to launched if it is not 368 | already running. */ 369 | 370 | info.cancellable = g_cancellable_new(); 371 | info.async = 1; 372 | g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION, 373 | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, 374 | NULL, DMS_INFO_SERVICE, DMS_INFO_MANAGER_OBJ, 375 | DMS_INFO_MANAGER_IF, info.cancellable, 376 | prv_manager_proxy_created, &info); 377 | 378 | info.dmss = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, 379 | prv_dms_server_data_delete); 380 | 381 | info.main_loop = g_main_loop_new(NULL, FALSE); 382 | 383 | if (!prv_init_signal_handler(mask, &info)) 384 | goto on_error; 385 | 386 | g_main_loop_run(info.main_loop); 387 | 388 | on_error: 389 | 390 | prv_dms_info_free(&info); 391 | 392 | return 0; 393 | } 394 | -------------------------------------------------------------------------------- /test/dbus/download_sync_controller.py: -------------------------------------------------------------------------------- 1 | # download_sync_controller 2 | # 3 | # Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 4 | # 5 | # This program is free software; you can redistribute it and/or modify it 6 | # under the terms and conditions of the GNU Lesser General Public License, 7 | # version 2.1, as published by the Free Software Foundation. 8 | # 9 | # This program is distributed in the hope it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 12 | # for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public License 15 | # along with this program; if not, write to the Free Software Foundation, Inc., 16 | # 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17 | # 18 | # Regis Merlino 19 | # 20 | 21 | import ConfigParser 22 | import os 23 | import shutil 24 | import urllib 25 | import dbus 26 | 27 | from mediaconsole import UPNP, Container, Device 28 | 29 | class _DscUpnp(UPNP): 30 | def __init__(self): 31 | UPNP.__init__(self) 32 | 33 | def get_servers(self): 34 | return self._manager.GetServers() 35 | 36 | class _DscContainer(Container): 37 | def __init__(self, path): 38 | Container.__init__(self, path) 39 | self.__path = path 40 | 41 | def find_containers(self): 42 | return self._containerIF.SearchObjectsEx( 43 | 'Type derivedfrom "container"', 44 | 0, 0, 45 | ['DisplayName', 'Path', 'Type'], '')[0] 46 | def find_updates(self, upd_id): 47 | return self._containerIF.SearchObjectsEx( 48 | 'ObjectUpdateID > "{0}"'.format(upd_id), 49 | 0, 0, 50 | ['DisplayName', 'Path', 'RefPath', 'URLs', 51 | 'Type', 'Parent'], '')[0] 52 | 53 | def find_children(self): 54 | return self._containerIF.ListChildrenEx(0, 0, 55 | ['DisplayName', 'Path', 'RefPath', 56 | 'URLs', 'Parent', 'Type'], '') 57 | 58 | class DscError(Exception): 59 | """A Download Sync Controller error.""" 60 | def __init__(self, message): 61 | """ 62 | message: description of the error 63 | 64 | """ 65 | Exception.__init__(self, message) 66 | self.message = message 67 | 68 | def __str__(self): 69 | return 'DscError: ' + self.message 70 | 71 | class _DscDownloader(object): 72 | def __init__(self, url, path): 73 | self.url = url 74 | self.path = path 75 | 76 | def download(self): 77 | urllib.urlretrieve(self.url, self.path) 78 | 79 | class _DscStore(object): 80 | SYNC_SECTION = 'sync_info' 81 | SYNC_OPTION = 'sync_contents' 82 | CUR_ID_OPTION = 'current_id' 83 | MEDIA_SECTION = 'media_info' 84 | 85 | NAME_SUFFIX = '-name' 86 | 87 | ITEM_NEW = 1 88 | ITEM_UPDATE = 2 89 | CONTAINER_NEW = 3 90 | 91 | def __init__(self, root_path, server_id): 92 | self.__root_path = root_path + '/' + server_id 93 | self.__config_path = self.__root_path + '/' + 'tracking.conf' 94 | 95 | self.__config = ConfigParser.ConfigParser() 96 | self.__cur_id = 0 97 | self.__sync = False 98 | 99 | def initialize(self, sync): 100 | if not os.path.exists(self.__root_path): 101 | os.makedirs(self.__root_path) 102 | 103 | self.__config.read(self.__config_path) 104 | 105 | if not self.__config.has_section(_DscStore.SYNC_SECTION): 106 | self.__config.add_section(_DscStore.SYNC_SECTION) 107 | self.__config.set(_DscStore.SYNC_SECTION, 108 | _DscStore.CUR_ID_OPTION, '0') 109 | if sync: 110 | self.__config.set(_DscStore.SYNC_SECTION, 111 | _DscStore.SYNC_OPTION, 'yes') 112 | else: 113 | self.__config.set(_DscStore.SYNC_SECTION, 114 | _DscStore.SYNC_OPTION, 'no') 115 | 116 | 117 | if not self.__config.has_section(_DscStore.MEDIA_SECTION): 118 | self.__config.add_section(_DscStore.MEDIA_SECTION) 119 | 120 | self.__cur_id = self.__config.getint(_DscStore.SYNC_SECTION, 121 | _DscStore.CUR_ID_OPTION) 122 | 123 | self.__sync = self.__config.getboolean(_DscStore.SYNC_SECTION, 124 | _DscStore.SYNC_OPTION) 125 | 126 | def __write_config(self): 127 | with open(self.__config_path, 'wb') as configfile: 128 | self.__config.write(configfile) 129 | 130 | def __id_from_path(self, path): 131 | return os.path.basename(path) 132 | 133 | def __orig_id(self, media_object): 134 | try: 135 | return self.__id_from_path(media_object['RefPath']) 136 | except KeyError: 137 | return self.__id_from_path(media_object['Path']) 138 | 139 | def __removed_items(self, local_ids, remote_items): 140 | for local_id in local_ids: 141 | found = False 142 | 143 | for remote in remote_items: 144 | remote_id = self.__id_from_path(remote['Path']) 145 | if local_id.endswith(_DscStore.NAME_SUFFIX) or \ 146 | local_id == remote_id: 147 | found = True 148 | 149 | if not found: 150 | yield local_id 151 | 152 | def __sync_item(self, obj, obj_id, parent_id, status, write_conf): 153 | orig = self.__orig_id(obj) 154 | 155 | if status == _DscStore.ITEM_UPDATE: 156 | old_path = self.__config.get(_DscStore.MEDIA_SECTION, orig) 157 | new_path = self.__create_path_for_name(obj['DisplayName']) 158 | print u'\tMedia "{0}" updated'.format(obj['DisplayName']) 159 | print u'\t\tto "{0}"'.format(new_path) 160 | self.__config.set(_DscStore.MEDIA_SECTION, orig, new_path) 161 | os.rename(old_path, new_path) 162 | elif status == _DscStore.ITEM_NEW: 163 | print u'\tNew media "{0}" tracked'.format(obj['DisplayName']) 164 | self.__config.set(parent_id, obj_id, orig) 165 | self.__config.set(parent_id, obj_id + _DscStore.NAME_SUFFIX, 166 | obj['DisplayName']) 167 | if not self.__config.has_option(_DscStore.MEDIA_SECTION, orig) and \ 168 | self.__sync: 169 | local_path = self.__create_path_for_name(obj['DisplayName']) 170 | self.__config.set(_DscStore.MEDIA_SECTION, orig, local_path) 171 | print u'\tDownloading contents from "{0}"'.format(obj['URLs'][0]) 172 | print u'\t\tinto "{0}"...'.format(local_path) 173 | downloader = _DscDownloader(obj['URLs'][0], local_path) 174 | downloader.download() 175 | else: 176 | pass 177 | 178 | if write_conf: 179 | self.__write_config() 180 | 181 | def __create_path_for_name(self, file_name): 182 | new_path = self.__root_path + '/' + str(self.__cur_id) + '-' + file_name 183 | 184 | self.__cur_id += 1 185 | self.__config.set(_DscStore.SYNC_SECTION, _DscStore.CUR_ID_OPTION, 186 | str(self.__cur_id)) 187 | 188 | return new_path 189 | 190 | def remove(self): 191 | if os.path.exists(self.__root_path): 192 | shutil.rmtree(self.__root_path) 193 | 194 | def sync_container(self, container, items): 195 | print u'Syncing container "{0}"...'.format(container['DisplayName']) 196 | 197 | container_id = self.__id_from_path(container['Path']) 198 | if not self.__config.has_section(container_id): 199 | self.__config.add_section(container_id) 200 | 201 | for remote in items: 202 | remote_id = self.__id_from_path(remote['Path']) 203 | if not self.__config.has_option(container_id, remote_id): 204 | if remote['Type'] == 'container': 205 | status = _DscStore.CONTAINER_NEW 206 | else: 207 | status = _DscStore.ITEM_NEW 208 | self.__sync_item(remote, remote_id, container_id, status, False) 209 | 210 | for local in self.__removed_items( 211 | self.__config.options(container_id), items): 212 | if self.__config.has_section(local): 213 | print u'\tRemoved a container' 214 | self.__config.remove_option(container_id, local) 215 | self.__config.remove_section(local) 216 | else: 217 | orig = self.__config.get(container_id, local) 218 | name = self.__config.get(container_id, 219 | local + _DscStore.NAME_SUFFIX) 220 | print u'\tRemoved media "{0}"'.format(name) 221 | self.__config.remove_option(container_id, local) 222 | self.__config.remove_option(container_id, 223 | local + _DscStore.NAME_SUFFIX) 224 | if local == orig: 225 | orig_name = self.__config.get(_DscStore.MEDIA_SECTION, orig) 226 | self.__config.remove_option(_DscStore.MEDIA_SECTION, orig) 227 | if self.__sync: 228 | print u'\tRemoved local downloaded contents "{0}"' \ 229 | .format(orig_name) 230 | if os.path.exists(orig_name): 231 | os.remove(orig_name) 232 | 233 | self.__write_config() 234 | 235 | def sync_item(self, obj): 236 | print u'Syncing item "{0}"...'.format(obj['DisplayName']) 237 | obj_id = self.__id_from_path(obj['Path']) 238 | parent_id = self.__id_from_path(obj['Parent']) 239 | if self.__config.has_option(parent_id, obj_id): 240 | status = _DscStore.ITEM_UPDATE 241 | else: 242 | status = _DscStore.ITEM_NEW 243 | 244 | self.__sync_item(obj, obj_id, parent_id, status, True) 245 | 246 | class DscController(object): 247 | """A Download Sync Controller. 248 | 249 | The Download Sync Controller receive changes in the content or metadata 250 | stored on media servers (DMS/M-DMS) and apply those changes to 251 | the local storage. 252 | Media servers must expose the 'content-synchronization' capability to 253 | be tracked by this controller. 254 | 255 | The three main methods are servers(), track() and sync(). 256 | * servers() lists the media servers available on the network 257 | * track() is used to add a media server to the list of servers that are 258 | to be synchronized. 259 | * sync() launches the servers synchronisation to a local storage 260 | 261 | Sample usage: 262 | >>> controller.servers() 263 | >>> controller.track('/com/intel/dLeynaServer/server/0') 264 | >>> controller.sync() 265 | 266 | """ 267 | CONFIG_PATH = os.environ['HOME'] + '/.config/download-sync-controller.conf' 268 | SUID_OPTION = 'system_update_id' 269 | SRT_OPTION = 'service_reset_token' 270 | SYNC_OPTION = 'sync_contents' 271 | DATA_PATH_SECTION = '__data_path__' 272 | DATA_PATH_OPTION = 'path' 273 | 274 | def __init__(self, rel_path = None): 275 | """ 276 | rel_path: if provided, contains the relative local storage path, 277 | from the user's HOME directory. 278 | If not provided, the local storage path will be 279 | '$HOME/download-sync-controller' 280 | 281 | """ 282 | self.__upnp = _DscUpnp() 283 | 284 | self.__config = ConfigParser.ConfigParser() 285 | self.__config.read(DscController.CONFIG_PATH) 286 | 287 | if rel_path: 288 | self.__set_data_path(rel_path) 289 | elif not self.__config.has_section(DscController.DATA_PATH_SECTION): 290 | self.__set_data_path('download-sync-controller') 291 | 292 | self.__store_path = self.__config.get(DscController.DATA_PATH_SECTION, 293 | DscController.DATA_PATH_OPTION) 294 | 295 | def __write_config(self): 296 | with open(DscController.CONFIG_PATH, 'wb') as configfile: 297 | self.__config.write(configfile) 298 | 299 | def __set_data_path(self, rel_path): 300 | data_path = os.environ['HOME'] + '/' + rel_path 301 | 302 | if not self.__config.has_section(DscController.DATA_PATH_SECTION): 303 | self.__config.add_section(DscController.DATA_PATH_SECTION) 304 | 305 | self.__config.set(DscController.DATA_PATH_SECTION, 306 | DscController.DATA_PATH_OPTION, data_path) 307 | 308 | self.__write_config() 309 | 310 | def __need_sync(self, servers): 311 | for item in servers: 312 | device = Device(item) 313 | uuid = device.get_prop('UDN') 314 | 315 | if self.__config.has_section(uuid): 316 | new_id = device.get_prop('SystemUpdateID') 317 | new_srt = device.get_prop('ServiceResetToken') 318 | cur_id = self.__config.getint(uuid, DscController.SUID_OPTION) 319 | cur_srt = self.__config.get(uuid, DscController.SRT_OPTION) 320 | if cur_id == -1 or cur_srt != new_srt: 321 | print 322 | print u'Server {0} needs *full* sync:'.format(uuid) 323 | yield item, uuid, 0, new_id, new_srt, True 324 | elif cur_id < new_id: 325 | print 326 | print u'Server {0} needs sync:'.format(uuid) 327 | yield item, uuid, cur_id, new_id, new_srt, False 328 | 329 | def __check_trackable(self, server): 330 | try: 331 | try: 332 | srt = server.get_prop('ServiceResetToken') 333 | except: 334 | raise DscError("'ServiceResetToken' variable not supported") 335 | 336 | try: 337 | dlna_caps = server.get_prop('DLNACaps') 338 | if not 'content-synchronization' in dlna_caps: 339 | raise 340 | except: 341 | raise DscError("'content-synchronization' cap not supported") 342 | 343 | try: 344 | search_caps = server.get_prop('SearchCaps') 345 | if not [x for x in search_caps if 'ObjectUpdateID' in x]: 346 | raise 347 | if not [x for x in search_caps if 'ContainerUpdateID' in x]: 348 | raise 349 | except: 350 | raise DscError("'objectUpdateID' search cap not supported") 351 | 352 | return srt 353 | except DscError as err: 354 | print err 355 | return None 356 | 357 | def track(self, server_path, track = True, sync_contents = True): 358 | """Adds or removes a media server to/from the controller's list. 359 | 360 | server_path: d-bus path for the media server 361 | track: when 'True', adds a server to the list 362 | when 'False' removes a server from the list 363 | sync_contents: when 'True', downloads media contents to the local 364 | storage upon synchronization. 365 | 366 | """ 367 | server = Device(server_path) 368 | server_uuid = server.get_prop('UDN') 369 | 370 | if track and not self.__config.has_section(server_uuid): 371 | srt = self.__check_trackable(server) 372 | if srt != None: 373 | self.__config.add_section(server_uuid) 374 | 375 | self.__config.set(server_uuid, DscController.SUID_OPTION, '-1') 376 | self.__config.set(server_uuid, DscController.SRT_OPTION, srt) 377 | if sync_contents: 378 | self.__config.set(server_uuid, DscController.SYNC_OPTION, 379 | 'yes') 380 | else: 381 | self.__config.set(server_uuid, DscController.SYNC_OPTION, 382 | 'no') 383 | 384 | self.__write_config() 385 | else: 386 | print u"Sorry, the server {0} has no such capability and " \ 387 | "will not be tracked.".format(server_path) 388 | 389 | elif not track and self.__config.has_section(server_uuid): 390 | self.__config.remove_section(server_uuid) 391 | self.__write_config() 392 | 393 | store = _DscStore(self.__store_path, server_uuid) 394 | store.remove() 395 | 396 | def track_reset(self, server_path, sync_contents = True): 397 | """Removes local contents and meta data for a media server. 398 | 399 | The next synchronization will be a *full* synchronization. 400 | 401 | server_path: d-bus path for the media server 402 | sync_contents: when 'True', downloads media contents to the local 403 | storage upon synchronization. 404 | 405 | """ 406 | self.track(server_path, False, sync_contents) 407 | self.track(server_path, True, sync_contents) 408 | 409 | def servers(self): 410 | """Displays media servers available on the network. 411 | 412 | Displays media servers information as well as the tracked status. 413 | 414 | """ 415 | print u'Running servers:' 416 | 417 | for item in self.__upnp.get_servers(): 418 | try: 419 | server = Container(item) 420 | try: 421 | folder_name = server.get_prop('FriendlyName') 422 | except Exception: 423 | folder_name = server.get_prop('DisplayName') 424 | device = Device(item) 425 | dev_uuid = device.get_prop('UDN') 426 | dev_path = device.get_prop('Path') 427 | 428 | print u'{0:<25} Tracked({2}) {3} {1}'.format(folder_name, 429 | dev_path, 430 | self.__config.has_option(dev_uuid, 431 | DscController.SUID_OPTION), 432 | dev_uuid) 433 | 434 | except dbus.exceptions.DBusException as err: 435 | print u'Cannot retrieve properties for ' + item 436 | print str(err).strip()[:-1] 437 | 438 | def tracked_servers(self): 439 | """Displays the list of servers currently tracked by the controller.""" 440 | print u'Tracked servers:' 441 | 442 | for name in self.__config.sections(): 443 | if name != DscController.DATA_PATH_SECTION: 444 | print u'{0:<30}'.format(name) 445 | 446 | def sync(self): 447 | """Performs a synchronization for all the tracked media servers. 448 | 449 | Displays some progress information during the process. 450 | 451 | """ 452 | print u'Syncing...' 453 | 454 | for item, uuid, cur, new_id, new_srt, full_sync in \ 455 | self.__need_sync(self.__upnp.get_servers()): 456 | sync = self.__config.getboolean(uuid, DscController.SYNC_OPTION) 457 | 458 | if full_sync: 459 | print u'Resetting local contents for server {0}'.format(uuid) 460 | 461 | self.track_reset(item) 462 | 463 | objects = _DscContainer(item).find_containers() 464 | else: 465 | objects = _DscContainer(item).find_updates(cur) 466 | 467 | store = _DscStore(self.__store_path, uuid) 468 | store.initialize(sync) 469 | 470 | for obj in objects: 471 | if obj['Type'] == 'container': 472 | children = _DscContainer(obj['Path']).find_children() 473 | store.sync_container(obj, children) 474 | else: 475 | store.sync_item(obj) 476 | 477 | self.__config.set(uuid, DscController.SUID_OPTION, str(new_id)) 478 | if full_sync: 479 | self.__config.set(uuid, DscController.SRT_OPTION, str(new_srt)) 480 | self.__write_config() 481 | 482 | print 483 | print u'Done.' 484 | 485 | def reset(self): 486 | """Removes local contents and meta data for all the tracked servers. 487 | 488 | After the call, the list of tracked servers will be empty. 489 | 490 | """ 491 | for name in self.__config.sections(): 492 | if name != DscController.DATA_PATH_SECTION: 493 | self.__config.remove_section(name) 494 | 495 | store = _DscStore(self.__store_path, name) 496 | store.remove() 497 | 498 | self.__write_config() 499 | 500 | 501 | if __name__ == '__main__': 502 | controller = DscController() 503 | controller.servers() 504 | print 505 | print u'"controller" instance is ready for use.' 506 | print u'Type "help(DscController)" for more details and usage samples.' 507 | -------------------------------------------------------------------------------- /test/dbus/dsc.sh: -------------------------------------------------------------------------------- 1 | python -i -m download_sync_controller 2 | -------------------------------------------------------------------------------- /test/dbus/lost_client_test.py: -------------------------------------------------------------------------------- 1 | # test_lost_client 2 | # 3 | # Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 4 | # 5 | # This program is free software; you can redistribute it and/or modify it 6 | # under the terms and conditions of the GNU Lesser General Public License, 7 | # version 2.1, as published by the Free Software Foundation. 8 | # 9 | # This program is distributed in the hope it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 12 | # for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public License 15 | # along with this program; if not, write to the Free Software Foundation, Inc., 16 | # 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17 | # 18 | # Regis Merlino 19 | # 20 | 21 | import gobject 22 | import dbus 23 | import dbus.mainloop.glib 24 | 25 | def handle_browse_reply(objects): 26 | print "Total Items: " + str(len(objects)) 27 | print 28 | loop.quit() 29 | 30 | def handle_error(e): 31 | print "An error occured" 32 | loop.quit() 33 | 34 | def make_async_call(): 35 | root.ListChildrenEx(0, 36 | 5, 37 | ["DisplayName", "Type"], 38 | "-DisplayName", 39 | reply_handler=handle_browse_reply, 40 | error_handler=handle_error) 41 | root.ListChildrenEx(0, 42 | 5, 43 | ["DisplayName", "Type"], 44 | "-DisplayName", 45 | reply_handler=handle_browse_reply, 46 | error_handler=handle_error) 47 | root.ListChildrenEx(0, 48 | 5, 49 | ["DisplayName", "Type"], 50 | "-DisplayName", 51 | reply_handler=handle_browse_reply, 52 | error_handler=handle_error) 53 | root.ListChildrenEx(0, 54 | 5, 55 | ["DisplayName", "Type"], 56 | "-DisplayName", 57 | reply_handler=handle_browse_reply, 58 | error_handler=handle_error) 59 | root.ListChildrenEx(0, 60 | 5, 61 | ["DisplayName", "Type"], 62 | "-DisplayName", 63 | reply_handler=handle_browse_reply, 64 | error_handler=handle_error) 65 | # Test: force quit - this should cancel the search on server side 66 | loop.quit() 67 | 68 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 69 | 70 | bus = dbus.SessionBus() 71 | root = dbus.Interface(bus.get_object( 72 | 'com.intel.dleyna-server', 73 | '/com/intel/dLeynaServer/server/0'), 74 | 'org.gnome.UPnP.MediaContainer2') 75 | 76 | gobject.timeout_add(1000, make_async_call) 77 | 78 | loop = gobject.MainLoop() 79 | loop.run() 80 | -------------------------------------------------------------------------------- /test/dbus/mc.sh: -------------------------------------------------------------------------------- 1 | python -i -m mediaconsole 2 | -------------------------------------------------------------------------------- /test/dbus/mediaconsole.py: -------------------------------------------------------------------------------- 1 | # mediaconsole 2 | # 3 | # Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 4 | # 5 | # This program is free software; you can redistribute it and/or modify it 6 | # under the terms and conditions of the GNU Lesser General Public License, 7 | # version 2.1, as published by the Free Software Foundation. 8 | # 9 | # This program is distributed in the hope it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 12 | # for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public License 15 | # along with this program; if not, write to the Free Software Foundation, Inc., 16 | # 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17 | # 18 | # Mark Ryan 19 | # 20 | 21 | import dbus 22 | import sys 23 | import json 24 | 25 | from xml.dom import minidom 26 | 27 | def print_properties(props): 28 | print json.dumps(props, indent=4, sort_keys=True) 29 | 30 | class MediaObject(object): 31 | 32 | def __init__(self, path): 33 | bus = dbus.SessionBus() 34 | self._propsIF = dbus.Interface(bus.get_object( 35 | 'com.intel.dleyna-server', path), 36 | 'org.freedesktop.DBus.Properties') 37 | self.__objIF = dbus.Interface(bus.get_object( 38 | 'com.intel.dleyna-server', path), 39 | 'org.gnome.UPnP.MediaObject2') 40 | 41 | def get_props(self, iface = ""): 42 | return self._propsIF.GetAll(iface) 43 | 44 | def get_prop(self, prop_name, iface = ""): 45 | return self._propsIF.Get(iface, prop_name) 46 | 47 | def print_prop(self, prop_name, iface = ""): 48 | print_properties(self._propsIF.Get(iface, prop_name)) 49 | 50 | def print_props(self, iface = ""): 51 | print_properties(self._propsIF.GetAll(iface)) 52 | 53 | def print_dms_id(self): 54 | path = self._propsIF.Get("", "Path") 55 | dms_id = path[path.rfind("/") + 1:] 56 | i = 0 57 | while i+1 < len(dms_id): 58 | num = dms_id[i] + dms_id[i+1] 59 | sys.stdout.write(unichr(int(num, 16))) 60 | i = i + 2 61 | print 62 | 63 | def print_metadata(self): 64 | metadata = self.__objIF.GetMetaData() 65 | print minidom.parseString(metadata).toprettyxml(indent=' '*4) 66 | 67 | def delete(self): 68 | return self.__objIF.Delete() 69 | 70 | def update(self, to_add_update, to_delete): 71 | return self.__objIF.Update(to_add_update, to_delete) 72 | 73 | def get_metadata(self): 74 | return self.__objIF.GetMetaData() 75 | 76 | class Item(MediaObject): 77 | def __init__(self, path): 78 | MediaObject.__init__(self, path) 79 | bus = dbus.SessionBus() 80 | self._itemIF = dbus.Interface(bus.get_object( 81 | 'com.intel.dleyna-server', path), 82 | 'org.gnome.UPnP.MediaItem2') 83 | 84 | def print_compatible_resource(self, protocol_info, fltr): 85 | print_properties(self._itemIF.GetCompatibleResource(protocol_info, 86 | fltr)) 87 | 88 | class Container(MediaObject): 89 | 90 | def __init__(self, path): 91 | MediaObject.__init__(self, path) 92 | bus = dbus.SessionBus() 93 | self._containerIF = dbus.Interface(bus.get_object( 94 | 'com.intel.dleyna-server', path), 95 | 'org.gnome.UPnP.MediaContainer2') 96 | 97 | def list_children(self, offset, count, fltr, sort=""): 98 | objects = self._containerIF.ListChildrenEx(offset, count, fltr, sort) 99 | for item in objects: 100 | print_properties(item) 101 | print "" 102 | 103 | def list_containers(self, offset, count, fltr, sort=""): 104 | objects = self._containerIF.ListContainersEx(offset, count, fltr, sort) 105 | for item in objects: 106 | print_properties(item) 107 | print "" 108 | 109 | def list_items(self, offset, count, fltr, sort=""): 110 | objects = self._containerIF.ListItemsEx(offset, count, fltr, sort) 111 | for item in objects: 112 | print_properties(item) 113 | print "" 114 | 115 | def search(self, query, offset, count, fltr, sort=""): 116 | objects, total = self._containerIF.SearchObjectsEx(query, offset, 117 | count, fltr, sort) 118 | print "Total Items: " + str(total) 119 | print 120 | for item in objects: 121 | print_properties(item) 122 | print "" 123 | 124 | def tree(self, level=0): 125 | objects = self._containerIF.ListChildren( 126 | 0, 0, ["DisplayName", "Path", "Type"]) 127 | for props in objects: 128 | print (" " * (level * 4) + props["DisplayName"] + 129 | " : (" + props["Path"]+ ")") 130 | if props["Type"] == "container": 131 | Container(props["Path"]).tree(level + 1) 132 | 133 | def upload(self, name, file_path): 134 | (tid, path) = self._containerIF.Upload(name, file_path) 135 | print "Transfer ID: " + str(tid) 136 | print u"Path: " + path 137 | 138 | def create_container(self, name, type, child_types): 139 | path = self._containerIF.CreateContainer(name, type, child_types) 140 | print u"New container path: " + path 141 | 142 | def print_compatible_resource(self, protocol_info, fltr): 143 | print_properties(self._containerIF.GetCompatibleResource(protocol_info, 144 | fltr)) 145 | def create_reference(self, file_path): 146 | path = self._containerIF.CreateReference(file_path) 147 | print u"Reference Path: " + path 148 | 149 | class Device(Container): 150 | 151 | def __init__(self, path): 152 | Container.__init__(self, path) 153 | bus = dbus.SessionBus() 154 | self._deviceIF = dbus.Interface(bus.get_object( 155 | 'com.intel.dleyna-server', path), 156 | 'com.intel.dLeynaServer.MediaDevice') 157 | 158 | def browse_objects(self, paths, fltr=['*']): 159 | objects = self._deviceIF.BrowseObjects(paths, fltr) 160 | for item in objects: 161 | print_properties(item) 162 | print "" 163 | 164 | def upload_to_any(self, name, file_path): 165 | (tid, path) = self._deviceIF.UploadToAnyContainer(name, file_path) 166 | print "Transfer ID: " + str(tid) 167 | print u"Path: " + path 168 | 169 | def create_container_in_any(self, name, type, child_types): 170 | path = self._deviceIF.CreateContainerInAnyContainer(name, type, 171 | child_types) 172 | print u"New container path: " + path 173 | 174 | def get_upload_status(self, id): 175 | (status, length, total) = self._deviceIF.GetUploadStatus(id) 176 | print "Status: " + status 177 | print "Length: " + str(length) 178 | print "Total: " + str(total) 179 | 180 | def get_upload_ids(self): 181 | upload_ids = self._deviceIF.GetUploadIDs() 182 | print_properties(upload_ids) 183 | 184 | def cancel_upload(self, id): 185 | self._deviceIF.CancelUpload(id) 186 | 187 | def cancel(self): 188 | return self._deviceIF.Cancel() 189 | 190 | def print_icon(self, mime_type, resolution): 191 | bytes, mime = self._deviceIF.GetIcon(mime_type, resolution) 192 | print "Icon mime type: " + mime 193 | 194 | def wake(self): 195 | return self._deviceIF.Wake() 196 | 197 | class UPNP(object): 198 | 199 | def __init__(self): 200 | bus = dbus.SessionBus() 201 | self._manager = dbus.Interface(bus.get_object( 202 | 'com.intel.dleyna-server', 203 | '/com/intel/dLeynaServer'), 204 | 'com.intel.dLeynaServer.Manager') 205 | self._propsIF = dbus.Interface(bus.get_object( 206 | 'com.intel.dleyna-server', 207 | '/com/intel/dLeynaServer'), 208 | 'org.freedesktop.DBus.Properties') 209 | 210 | def get_props(self, iface = ""): 211 | return self._propsIF.GetAll(iface) 212 | 213 | def get_prop(self, prop_name, iface = ""): 214 | return self._propsIF.Get(iface, prop_name) 215 | 216 | def set_prop(self, prop_name, val, iface = ""): 217 | return self._propsIF.Set(iface, prop_name, val) 218 | 219 | def print_prop(self, prop_name, iface = ""): 220 | print_properties(self._propsIF.Get(iface, prop_name)) 221 | 222 | def print_props(self, iface = ""): 223 | print_properties(self._propsIF.GetAll(iface)) 224 | 225 | def server_from_name(self, friendly_name): 226 | retval = None 227 | for i in self._manager.GetServers(): 228 | server = Device(i) 229 | server_name = server.get_prop("FriendlyName").lower() 230 | if server_name.find(friendly_name.lower()) != -1: 231 | retval = server 232 | break 233 | return retval 234 | 235 | def server_from_udn(self, udn): 236 | retval = None 237 | for i in self._manager.GetServers(): 238 | server = Device(i) 239 | if server.get_prop("UDN") == udn: 240 | retval = server 241 | break 242 | return retval 243 | 244 | def servers(self): 245 | for i in self._manager.GetServers(): 246 | try: 247 | server = Container(i) 248 | try: 249 | folderName = server.get_prop("FriendlyName"); 250 | except Exception: 251 | folderName = server.get_prop("DisplayName"); 252 | print u'{0:<30}{1:<30}'.format(folderName , i) 253 | except dbus.exceptions.DBusException, err: 254 | print u"Cannot retrieve properties for " + i 255 | print str(err).strip()[:-1] 256 | 257 | def version(self): 258 | print self._manager.GetVersion() 259 | 260 | def set_protocol_info(self, protocol_info): 261 | self._manager.SetProtocolInfo(protocol_info) 262 | 263 | def prefer_local_addresses(self, prefer): 264 | self._manager.PreferLocalAddresses(prefer) 265 | 266 | def rescan(self): 267 | self._manager.Rescan() 268 | 269 | def white_list_enable(self, enable): 270 | self.set_prop("WhiteListEnabled", enable) 271 | 272 | def white_list_add(self, entries): 273 | white_list = set(self.get_prop('WhiteListEntries')) 274 | white_list = white_list | set(entries) 275 | self.set_prop("WhiteListEntries", list(white_list)) 276 | 277 | def white_list_remove(self, entries): 278 | white_list = set(self.get_prop('WhiteListEntries')) 279 | white_list = white_list - set(entries) 280 | self.set_prop("WhiteListEntries", list(white_list)) 281 | 282 | def white_list_clear(self): 283 | self.set_prop("WhiteListEntries", ['']) 284 | -------------------------------------------------------------------------------- /test/dbus/monitor_changed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # monitor_last_change 4 | # 5 | # Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 6 | # 7 | # This program is free software; you can redistribute it and/or modify it 8 | # under the terms and conditions of the GNU Lesser General Public License, 9 | # version 2.1, as published by the Free Software Foundation. 10 | # 11 | # This program is distributed in the hope it will be useful, but WITHOUT 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 14 | # for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License 17 | # along with this program; if not, write to the Free Software Foundation, Inc., 18 | # 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 19 | # 20 | # Regis Merlino 21 | # Mark Ryan 22 | # 23 | 24 | import gobject 25 | import dbus 26 | import dbus.mainloop.glib 27 | import json 28 | 29 | def print_properties(props): 30 | print json.dumps(props, indent=4, sort_keys=True) 31 | 32 | def changed(objects, path): 33 | print "Changed signal from [%s]" % path 34 | print "Objects:" 35 | print_properties(objects) 36 | 37 | if __name__ == '__main__': 38 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 39 | 40 | bus = dbus.SessionBus() 41 | 42 | bus.add_signal_receiver(changed, 43 | bus_name="com.intel.dleyna-server", 44 | signal_name = "Changed", 45 | path_keyword="path") 46 | 47 | mainloop = gobject.MainLoop() 48 | mainloop.run() 49 | -------------------------------------------------------------------------------- /test/dbus/monitor_contents_changes.py: -------------------------------------------------------------------------------- 1 | # monitor_contents_changes 2 | # 3 | # Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 4 | # 5 | # This program is free software; you can redistribute it and/or modify it 6 | # under the terms and conditions of the GNU Lesser General Public License, 7 | # version 2.1, as published by the Free Software Foundation. 8 | # 9 | # This program is distributed in the hope it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 12 | # for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public License 15 | # along with this program; if not, write to the Free Software Foundation, Inc., 16 | # 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17 | # 18 | # Regis Merlino 19 | # 20 | 21 | import gobject 22 | import dbus 23 | import dbus.mainloop.glib 24 | import json 25 | 26 | def print_properties(props): 27 | print json.dumps(props, indent=4, sort_keys=True) 28 | 29 | def properties_changed(iface, changed, invalidated, path): 30 | print "PropertiesChanged signal from {%s} [%s]" % (iface, path) 31 | print "Changed:" 32 | print_properties(changed) 33 | print "Invalidated:" 34 | print_properties(invalidated) 35 | 36 | def container_update(id_list, path, interface): 37 | iface = interface[interface.rfind(".") + 1:] 38 | print "ContainerUpdateIDs signal from {%s} [%s]" % (iface, path) 39 | for (id_path, sys_id) in id_list: 40 | print "-->\t %s : %u" % (id_path, sys_id) 41 | 42 | if __name__ == '__main__': 43 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 44 | 45 | bus = dbus.SessionBus() 46 | 47 | bus.add_signal_receiver(properties_changed, 48 | bus_name="com.intel.dleyna-server", 49 | signal_name = "PropertiesChanged", 50 | path_keyword="path") 51 | bus.add_signal_receiver(container_update, 52 | bus_name="com.intel.dleyna-server", 53 | signal_name = "ContainerUpdateIDs", 54 | path_keyword="path", 55 | interface_keyword="interface") 56 | 57 | mainloop = gobject.MainLoop() 58 | mainloop.run() 59 | -------------------------------------------------------------------------------- /test/dbus/monitor_upload_update.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # monitor_upload_update 4 | # 5 | # Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 6 | # 7 | # This program is free software; you can redistribute it and/or modify it 8 | # under the terms and conditions of the GNU Lesser General Public License, 9 | # version 2.1, as published by the Free Software Foundation. 10 | # 11 | # This program is distributed in the hope it will be useful, but WITHOUT 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 14 | # for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License 17 | # along with this program; if not, write to the Free Software Foundation, Inc., 18 | # 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 19 | # 20 | # Regis Merlino 21 | # Mark Ryan 22 | # 23 | 24 | import gobject 25 | import dbus 26 | import dbus.mainloop.glib 27 | 28 | def upload_update(upload_id, status, uploaded, to_upload, path): 29 | print "UploadUpdate signal from [%s]" % (path) 30 | print "Upload ID: " + str(upload_id) 31 | print "Status: " + status 32 | print "Uploaded: " + str(uploaded) 33 | print "To Upload: " + str(to_upload) 34 | 35 | if __name__ == '__main__': 36 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 37 | 38 | bus = dbus.SessionBus() 39 | 40 | bus.add_signal_receiver(upload_update, 41 | bus_name="com.intel.dleyna-server", 42 | signal_name = "UploadUpdate", 43 | path_keyword="path") 44 | 45 | mainloop = gobject.MainLoop() 46 | mainloop.run() 47 | -------------------------------------------------------------------------------- /test/dbus/stress_test.py: -------------------------------------------------------------------------------- 1 | # stress-test 2 | # 3 | # Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 4 | # 5 | # This program is free software; you can redistribute it and/or modify it 6 | # under the terms and conditions of the GNU Lesser General Public License, 7 | # version 2.1, as published by the Free Software Foundation. 8 | # 9 | # This program is distributed in the hope it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 12 | # for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public License 15 | # along with this program; if not, write to the Free Software Foundation, Inc., 16 | # 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17 | # 18 | # Regis Merlino 19 | # 20 | 21 | import gobject 22 | import dbus 23 | import dbus.mainloop.glib 24 | 25 | def handle_browse_reply(objects): 26 | print "Total Items: " + str(len(objects)) 27 | 28 | def handle_error(err): 29 | if err.get_dbus_name() == 'com.intel.dleyna.Cancelled': 30 | print "Cancelled..." 31 | else: 32 | print "An error occured" 33 | print err 34 | loop.quit() 35 | 36 | def make_async_calls(): 37 | i = 0 38 | while i < 5: 39 | root.ListChildrenEx(0, 40 | 5, 41 | ["DisplayName", "Type"], 42 | "-DisplayName", 43 | reply_handler=handle_browse_reply, 44 | error_handler=handle_error) 45 | i += 1 46 | device.Cancel() 47 | gobject.timeout_add(1000, make_async_calls) 48 | 49 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 50 | 51 | bus = dbus.SessionBus() 52 | root = dbus.Interface(bus.get_object( 53 | 'com.intel.dleyna-server', 54 | '/com/intel/dLeynaServer/server/0'), 55 | 'org.gnome.UPnP.MediaContainer2') 56 | device = dbus.Interface(bus.get_object( 57 | 'com.intel.dleyna-server', 58 | '/com/intel/dLeynaServer/server/0'), 59 | 'com.intel.dLeynaServer.MediaDevice') 60 | 61 | gobject.timeout_add(1000, make_async_calls) 62 | 63 | loop = gobject.MainLoop() 64 | loop.run() 65 | -------------------------------------------------------------------------------- /test/dbus/upload_sync_controller.py: -------------------------------------------------------------------------------- 1 | # upload_sync_controller 2 | # 3 | # Copyright (C) 2012-2017 Intel Corporation. All rights reserved. 4 | # 5 | # This program is free software; you can redistribute it and/or modify it 6 | # under the terms and conditions of the GNU Lesser General Public License, 7 | # version 2.1, as published by the Free Software Foundation. 8 | # 9 | # This program is distributed in the hope it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 12 | # for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public License 15 | # along with this program; if not, write to the Free Software Foundation, Inc., 16 | # 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17 | # 18 | # Regis Merlino 19 | # 20 | 21 | import ConfigParser 22 | import os 23 | import shutil 24 | import urllib 25 | import dbus 26 | import gio 27 | import glib 28 | 29 | from mediaconsole import UPNP, MediaObject, Container, Device 30 | 31 | class _UscUpnp(UPNP): 32 | def __init__(self): 33 | UPNP.__init__(self) 34 | 35 | def get_servers(self): 36 | return self._manager.GetServers() 37 | 38 | class _UscDevice(Device): 39 | def __init__(self, path): 40 | Device.__init__(self, path) 41 | 42 | def create_container_in_any(self, name, type, child_types): 43 | return self._deviceIF.CreateContainerInAnyContainer(name, type, 44 | child_types) 45 | 46 | class _UscContainer(Container): 47 | def __init__(self, path): 48 | Container.__init__(self, path) 49 | 50 | def create_container(self, name, type, child_types): 51 | return self._containerIF.CreateContainer(name, type, child_types) 52 | 53 | def upload(self, name, file_path): 54 | return self._containerIF.Upload(name, file_path) 55 | 56 | class UscError(Exception): 57 | """An Upload Sync Controller error.""" 58 | 59 | def __init__(self, message): 60 | """ 61 | message: description of the error 62 | """ 63 | 64 | Exception.__init__(self, message) 65 | self.message = message 66 | 67 | def __str__(self): 68 | return 'UscError: ' + self.message 69 | 70 | class _UscStore(object): 71 | REMOTE_ID_OPTION = 'remote_id' 72 | TYPE_OPTION = 'type' 73 | 74 | def __init__(self, root_path, server_id): 75 | if not os.path.exists(root_path): 76 | os.makedirs(root_path) 77 | 78 | self.__config_path = os.path.join(root_path, server_id + '.conf') 79 | 80 | self.__config = ConfigParser.ConfigParser() 81 | 82 | def initialize(self): 83 | self.__config.read(self.__config_path) 84 | 85 | def __write_config(self): 86 | with open(self.__config_path, 'wb') as configfile: 87 | self.__config.write(configfile) 88 | 89 | def remove(self): 90 | if os.path.exists(self.__config_path): 91 | os.remove(self.__config_path) 92 | 93 | def __parent_deleted(self, path, deleted_containers): 94 | for del_path in deleted_containers: 95 | if path.startswith(del_path): 96 | return True 97 | 98 | return False 99 | 100 | def remove_file(self, path): 101 | id = self.__config.get(path, self.REMOTE_ID_OPTION) 102 | print u'\tDeleting server object {0}'.format(id) 103 | try: 104 | obj = MediaObject(id) 105 | obj.delete() 106 | except: 107 | pass 108 | 109 | print u'\tDeleting local cache {0}'.format(path) 110 | self.__config.remove_section(path) 111 | 112 | def sync_deleted_files(self, path): 113 | deleted_containers = [] 114 | 115 | sections = self.__config.sections() 116 | if not sections: 117 | return 118 | 119 | for path in sections: 120 | if self.__parent_deleted(path, deleted_containers): 121 | print u'\tDeleting local cache {0}'.format(path) 122 | self.__config.remove_section(path) 123 | elif not os.path.exists(path): 124 | if self.__config.get(path, self.TYPE_OPTION) == 'container': 125 | deleted_containers.append(path + os.sep) 126 | 127 | self.remove_file(path) 128 | 129 | self.__write_config() 130 | 131 | def add_file(self, container, name, parent): 132 | new_path = os.path.join(parent, name) 133 | if os.path.isdir(new_path): 134 | if self.__config.has_section(new_path): 135 | id = self.__config.get(new_path, self.REMOTE_ID_OPTION) 136 | else: 137 | print u'\tCreating server container for {0}'.format(new_path) 138 | id = container.create_container(name, 'container', ['*']) 139 | 140 | print u'\tStoring cached data for {0}'.format(id) 141 | self.__config.add_section(new_path) 142 | self.__config.set(new_path, self.REMOTE_ID_OPTION, id) 143 | self.__config.set(new_path, self.TYPE_OPTION, 'container') 144 | 145 | new_container = _UscContainer(id) 146 | self.sync_added_files(new_container, new_path) 147 | elif not self.__config.has_section(new_path): 148 | print u'\tUploading file {0}'.format(new_path) 149 | (up, id) = container.upload(name, new_path) 150 | 151 | print u'\tStoring cached data for {0}'.format(id) 152 | self.__config.add_section(new_path) 153 | self.__config.set(new_path, self.REMOTE_ID_OPTION, id) 154 | self.__config.set(new_path, self.TYPE_OPTION, 'item') 155 | 156 | def sync_added_files(self, container, path): 157 | children = os.listdir(path) 158 | for child in children: 159 | self.add_file(container, child, path) 160 | 161 | self.__write_config() 162 | 163 | def set_root(self, path, id): 164 | self.__config.add_section(path) 165 | self.__config.set(path, self.REMOTE_ID_OPTION, id) 166 | self.__config.set(path, self.TYPE_OPTION, 'container') 167 | 168 | self.__write_config() 169 | 170 | def object_id_from_path(self, path): 171 | return self.__config.get(path, self.REMOTE_ID_OPTION) 172 | 173 | def rename_file(self, path1, path2): 174 | self.__config.add_section(path2) 175 | 176 | id = self.__config.get(path1, self.REMOTE_ID_OPTION) 177 | self.__config.set(path2, self.REMOTE_ID_OPTION, id) 178 | type = self.__config.get(path1, self.TYPE_OPTION) 179 | self.__config.set(path2, self.TYPE_OPTION, type) 180 | 181 | self.__config.remove_section(path1) 182 | 183 | self.__write_config() 184 | 185 | class UscController(object): 186 | """An Upload Sync Controller sample app. 187 | 188 | The Upload Sync Controller propagates changes in a local folder to media 189 | servers (DMS/M-DMS) to be added to their list of available content. 190 | Media servers must expose the 'content-synchronization' capability to 191 | be managed by this controller. 192 | 193 | The four main methods are servers(), track(), add_server() and start_sync(). 194 | * servers() lists the media servers available on the network 195 | * track() is used to set the local folder that is to be synchronized 196 | * add_server() is used to add a media server to the list of servers that 197 | are to be synchronized 198 | * start_sync() launches the servers synchronisation from the local storage 199 | 200 | Sample usage: 201 | >>> controller.servers() 202 | >>> controller.track('/home/user/local_folder') 203 | >>> controller.add_server('/com/intel/dLeynaServer/server/0') 204 | >>> controller.start_sync() 205 | """ 206 | 207 | CONFIG_PATH = os.path.join(os.environ['HOME'], 208 | '.config/upload-sync-controller.conf') 209 | ROOT_CONTAINER_ID_OPTION = 'root_container_id' 210 | DATA_PATH_SECTION = '__paths__' 211 | DATA_PATH_OPTION = 'data_path' 212 | TRACK_PATH_OPTION = 'track_path' 213 | 214 | def __init__(self, rel_path = None): 215 | """ 216 | rel_path: if provided, contains the relative local database path, 217 | from the user's HOME directory. 218 | If not provided, the local database path will be 219 | '$HOME/upload-sync-controller' 220 | """ 221 | 222 | self.__upnp = _UscUpnp() 223 | 224 | self.__config = ConfigParser.ConfigParser() 225 | self.__config.read(UscController.CONFIG_PATH) 226 | 227 | if rel_path: 228 | self.__set_data_path(rel_path) 229 | elif not self.__config.has_section(UscController.DATA_PATH_SECTION): 230 | self.__set_data_path('upload-sync-controller') 231 | 232 | self.__store_path = self.__config.get(UscController.DATA_PATH_SECTION, 233 | UscController.DATA_PATH_OPTION) 234 | try: 235 | self.__track_path = self.__config.get( 236 | UscController.DATA_PATH_SECTION, 237 | UscController.TRACK_PATH_OPTION) 238 | except: 239 | self.__track_path = None 240 | 241 | def __write_config(self): 242 | with open(UscController.CONFIG_PATH, 'wb') as configfile: 243 | self.__config.write(configfile) 244 | 245 | def __set_data_path(self, rel_path): 246 | data_path = os.environ['HOME'] + os.sep + rel_path 247 | 248 | if not self.__config.has_section(UscController.DATA_PATH_SECTION): 249 | self.__config.add_section(UscController.DATA_PATH_SECTION) 250 | 251 | self.__config.set(UscController.DATA_PATH_SECTION, 252 | UscController.DATA_PATH_OPTION, data_path) 253 | 254 | self.__write_config() 255 | 256 | def __check_trackable(self, server): 257 | try: 258 | try: 259 | srt = server.get_prop('ServiceResetToken') 260 | except: 261 | raise UscError("'ServiceResetToken' variable not supported") 262 | 263 | try: 264 | dlna_caps = server.get_prop('DLNACaps') 265 | if not 'content-synchronization' in dlna_caps: 266 | raise 267 | except: 268 | raise UscError("'content-synchronization' cap not supported") 269 | 270 | try: 271 | search_caps = server.get_prop('SearchCaps') 272 | if not [x for x in search_caps if 'ObjectUpdateID' in x]: 273 | raise 274 | if not [x for x in search_caps if 'ContainerUpdateID' in x]: 275 | raise 276 | except: 277 | raise UscError("'objectUpdateID' search cap not supported") 278 | 279 | return srt 280 | except UscError as err: 281 | print err 282 | return None 283 | 284 | def __need_sync(self, servers): 285 | for item in servers: 286 | device = _UscDevice(item) 287 | uuid = device.get_prop('UDN') 288 | 289 | if self.__config.has_section(uuid): 290 | yield device, uuid, self.__config.has_option(uuid, 291 | UscController.ROOT_CONTAINER_ID_OPTION) 292 | 293 | def __remove_monitor(self, path): 294 | for item in self.__monitor_list.keys(): 295 | if item.startswith(path): 296 | print u'\tStop monitoring {0}'.format(path) 297 | del self.__monitor_list[item] 298 | 299 | def __add_monitor(self, path): 300 | print u'\tStart monitoring {0}'.format(path) 301 | gfile = gio.File(path) 302 | monitor = gfile.monitor_directory(gio.FILE_MONITOR_SEND_MOVED, None) 303 | monitor.connect("changed", self.__directory_changed) 304 | self.__monitor_list[path] = monitor 305 | 306 | def __monitor_directory(self, path): 307 | self.__add_monitor(path) 308 | children = os.listdir(path) 309 | for child in children: 310 | new_path = os.path.join(path, child) 311 | if os.path.isdir(new_path): 312 | self.__monitor_directory(new_path) 313 | 314 | def __start_monitoring(self): 315 | self.__monitor_list = {} 316 | self.__monitor_directory(self.__track_path) 317 | 318 | print u'Type ctrl-c to stop.' 319 | try: 320 | main_loop = glib.MainLoop() 321 | main_loop.run() 322 | except: 323 | print u'Monitoring stopped.' 324 | 325 | def __directory_changed(self, monitor, file1, file2, evt_type): 326 | print 327 | if evt_type == gio.FILE_MONITOR_EVENT_CREATED: 328 | (parent, name) = os.path.split(file1.get_path()) 329 | for store in self.__store_list: 330 | parent_id = store.object_id_from_path(parent) 331 | container = _UscContainer(parent_id) 332 | store.add_file(container, name, parent) 333 | 334 | if os.path.isdir(file1.get_path()): 335 | self.__monitor_directory(file1.get_path()) 336 | elif evt_type == gio.FILE_MONITOR_EVENT_MOVED: 337 | (parent1, name1) = os.path.split(file1.get_path()) 338 | (parent2, name2) = os.path.split(file2.get_path()) 339 | renamed = (parent1 == parent2) 340 | 341 | if file1.get_path() in self.__monitor_list: 342 | self.__remove_monitor(file1.get_path()) 343 | 344 | for store in self.__store_list: 345 | object_id = store.object_id_from_path(file1.get_path()) 346 | obj = MediaObject(object_id) 347 | dlna_managed = obj.get_prop('DLNAManaged') 348 | 349 | if renamed and dlna_managed['ChangeMeta']: 350 | print u'\tRenaming {0} to {1}'.format(name1, name2) 351 | 352 | props = {'DisplayName' : name2} 353 | obj.update(props, []) 354 | 355 | store.rename_file(file1.get_path(), file2.get_path()) 356 | else: 357 | store.remove_file(file1.get_path()) 358 | 359 | parent_id = store.object_id_from_path(parent2) 360 | container = _UscContainer(parent_id) 361 | 362 | store.add_file(container, name2, parent2) 363 | 364 | if os.path.isdir(file2.get_path()): 365 | self.__monitor_directory(file2.get_path()) 366 | elif evt_type == gio.FILE_MONITOR_EVENT_DELETED: 367 | if file1.get_path() in self.__monitor_list: 368 | self.__remove_monitor(file1.get_path()) 369 | 370 | for store in self.__store_list: 371 | store.remove_file(file1.get_path()) 372 | else: 373 | return 374 | 375 | print u'Type ctrl-c to stop.' 376 | 377 | def track(self, track_path): 378 | """Sets the local folder that is to be synchronized.""" 379 | 380 | self.__track_path = track_path 381 | self.__config.set(UscController.DATA_PATH_SECTION, 382 | UscController.TRACK_PATH_OPTION, track_path) 383 | 384 | self.__write_config() 385 | 386 | def start_sync(self): 387 | """Performs a synchronization for all the media servers. 388 | 389 | Displays some progress information during the process. 390 | """ 391 | 392 | if not self.__track_path: 393 | print u'Error: track path is not set' 394 | return 395 | 396 | self.__store_list = [] 397 | print u'Syncing...' 398 | for device, uuid, init in self.__need_sync(self.__upnp.get_servers()): 399 | store = _UscStore(self.__store_path, uuid) 400 | store.initialize() 401 | self.__store_list.append(store) 402 | 403 | if not init: 404 | print u'Performing initial sync for server {0}:'.format(uuid) 405 | root = device.create_container_in_any('usc_root', 'container', 406 | ['image']) 407 | self.__config.set(uuid, UscController.ROOT_CONTAINER_ID_OPTION, 408 | root) 409 | self.__write_config() 410 | store.set_root(self.__track_path, root) 411 | else: 412 | print u'Performing normal sync for server {0}:'.format(uuid) 413 | root = self.__config.get(uuid, 414 | UscController.ROOT_CONTAINER_ID_OPTION) 415 | 416 | print u'\tRoot container is {0}'.format(root) 417 | root_container = _UscContainer(root) 418 | store.sync_deleted_files(self.__track_path) 419 | store.sync_added_files(root_container, self.__track_path) 420 | print u'Done.' 421 | 422 | if len(self.__store_list) == 0: 423 | print u'Nothing to do, stopping.' 424 | return 425 | 426 | print u'Now monitoring local changes...' 427 | self.__start_monitoring() 428 | 429 | def servers(self): 430 | """Displays media servers available on the network. 431 | 432 | Displays media servers information as well as the synchronized status. 433 | """ 434 | 435 | print u'Running servers:' 436 | 437 | for item in self.__upnp.get_servers(): 438 | try: 439 | server = Container(item) 440 | try: 441 | folder_name = server.get_prop('FriendlyName') 442 | except Exception: 443 | folder_name = server.get_prop('DisplayName') 444 | device = Device(item) 445 | dev_uuid = device.get_prop('UDN') 446 | dev_path = device.get_prop('Path') 447 | 448 | print u'{0:<25} Synchronized({2}) {3} {1}'.format( 449 | folder_name, 450 | dev_path, 451 | self.__config.has_section(dev_uuid), 452 | dev_uuid) 453 | 454 | except dbus.exceptions.DBusException as err: 455 | print u'Cannot retrieve properties for ' + item 456 | print str(err).strip()[:-1] 457 | 458 | def synchronized(self): 459 | """Displays the list of servers currently synchronized.""" 460 | 461 | print u'Synchronized servers:' 462 | 463 | for name in self.__config.sections(): 464 | if name != UscController.DATA_PATH_SECTION: 465 | print u'{0:<30}'.format(name) 466 | 467 | def add_server(self, server_path): 468 | """Adds a media server to the controller's list. 469 | 470 | server_path: d-bus path for the media server 471 | """ 472 | 473 | server = Device(server_path) 474 | server_uuid = server.get_prop('UDN') 475 | 476 | if not self.__config.has_section(server_uuid): 477 | srt = self.__check_trackable(server) 478 | if srt != None: 479 | self.__config.add_section(server_uuid) 480 | self.__write_config() 481 | else: 482 | print u"Sorry, the server {0} has no such capability and " \ 483 | "will not be synchronized.".format(server_path) 484 | 485 | def __remove_server(self, server_uuid): 486 | try: 487 | root = self.__config.get(server_uuid, 488 | UscController.ROOT_CONTAINER_ID_OPTION) 489 | MediaObject(root).delete() 490 | except: 491 | pass 492 | self.__config.remove_section(server_uuid) 493 | 494 | store = _UscStore(self.__store_path, server_uuid) 495 | store.remove() 496 | 497 | def remove_server(self, server_path): 498 | """Removes a media server from the controller's list. 499 | 500 | Also removes the server side synchronized file and folders. 501 | server_path: d-bus path for the media server 502 | """ 503 | 504 | server = Device(server_path) 505 | server_uuid = server.get_prop('UDN') 506 | 507 | if self.__config.has_section(server_uuid): 508 | self.__remove_server(server_uuid) 509 | 510 | self.__write_config() 511 | 512 | def reset(self): 513 | """Removes all media servers from the controller's list 514 | 515 | Also removes the server side synchronized file and folders. 516 | """ 517 | 518 | for name in self.__config.sections(): 519 | if name != UscController.DATA_PATH_SECTION: 520 | self.__remove_server(name) 521 | 522 | self.__write_config() 523 | 524 | if __name__ == '__main__': 525 | print u'An Upload Sync Controller sample app.' 526 | print 527 | controller = UscController() 528 | controller.servers() 529 | print 530 | print u'"controller" instance is ready for use.' 531 | print u'Type "help(UscController)" for more details and usage samples.' 532 | -------------------------------------------------------------------------------- /test/dbus/usc.sh: -------------------------------------------------------------------------------- 1 | python -i -m upload_sync_controller 2 | --------------------------------------------------------------------------------