Updated media-service-upnp to commit 8a6065c 85/2685/1 submit/2.0alpha/20130116.124026
authorMark Ryan <mark.d.ryan@intel.com>
Wed, 16 Jan 2013 12:19:00 +0000 (13:19 +0100)
committerMark Ryan <mark.d.ryan@intel.com>
Wed, 16 Jan 2013 12:34:31 +0000 (13:34 +0100)
This was necessary to fix TIVI-412

26 files changed:
Makefile.am
Makefile.in
README
src/async.c
src/async.h
src/chain-task.c
src/device.c
src/device.h
src/interface.h
src/log.c
src/media-service-upnp.c
src/media-service-upnp.h [new file with mode: 0644]
src/path.c
src/path.h
src/props.c
src/props.h
src/search.c
src/settings.c
src/task-atom.h [new file with mode: 0644]
src/task-processor.c [new file with mode: 0644]
src/task-processor.h [new file with mode: 0644]
src/task.c
src/task.h
src/upnp.c
src/upnp.h
test/mediaconsole.py

index 2559712..f89ad14 100644 (file)
@@ -17,29 +17,33 @@ media_service_upnp_sources =        src/async.c              \
                                src/chain-task.c         \
                                src/device.c             \
                                src/error.c              \
-                               src/media-service-upnp.c \
                                src/log.c                \
+                               src/media-service-upnp.c \
                                src/path.c               \
                                src/props.c              \
                                src/search.c             \
                                src/settings.c           \
                                src/sort.c               \
                                src/task.c               \
+                               src/task-processor.c     \
                                src/upnp.c
 
-media_service_upnp_headers =   src/async.h             \
-                               src/chain-task.h        \
-                               src/client.h            \
-                               src/device.h            \
-                               src/error.h             \
-                               src/interface.h         \
-                               src/log.h               \
-                               src/path.h              \
-                               src/props.h             \
-                               src/search.h            \
-                               src/settings.h          \
-                               src/sort.h              \
-                               src/task.h              \
+media_service_upnp_headers =   src/async.h              \
+                               src/chain-task.h         \
+                               src/client.h             \
+                               src/device.h             \
+                               src/error.h              \
+                               src/interface.h          \
+                               src/log.h                \
+                               src/media-service-upnp.h \
+                               src/path.h               \
+                               src/props.h              \
+                               src/search.h             \
+                               src/settings.h           \
+                               src/sort.h               \
+                               src/task.h               \
+                               src/task-atom.h          \
+                               src/task-processor.h     \
                                src/upnp.h
 
 
index a0e4157..d68ec2b 100644 (file)
@@ -85,11 +85,11 @@ dms_info_LINK = $(CCLD) $(dms_info_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
        $(LDFLAGS) -o $@
 am__objects_2 =
 am__objects_3 = src/async.$(OBJEXT) src/chain-task.$(OBJEXT) \
-       src/device.$(OBJEXT) src/error.$(OBJEXT) \
-       src/media-service-upnp.$(OBJEXT) src/log.$(OBJEXT) \
-       src/path.$(OBJEXT) src/props.$(OBJEXT) src/search.$(OBJEXT) \
+       src/device.$(OBJEXT) src/error.$(OBJEXT) src/log.$(OBJEXT) \
+       src/media-service-upnp.$(OBJEXT) src/path.$(OBJEXT) \
+       src/props.$(OBJEXT) src/search.$(OBJEXT) \
        src/settings.$(OBJEXT) src/sort.$(OBJEXT) src/task.$(OBJEXT) \
-       src/upnp.$(OBJEXT)
+       src/task-processor.$(OBJEXT) src/upnp.$(OBJEXT)
 am_media_service_upnp_OBJECTS = $(am__objects_2) $(am__objects_3)
 media_service_upnp_OBJECTS = $(am_media_service_upnp_OBJECTS)
 media_service_upnp_DEPENDENCIES = $(am__DEPENDENCIES_1) \
@@ -299,29 +299,33 @@ media_service_upnp_sources = src/async.c           \
                                src/chain-task.c         \
                                src/device.c             \
                                src/error.c              \
-                               src/media-service-upnp.c \
                                src/log.c                \
+                               src/media-service-upnp.c \
                                src/path.c               \
                                src/props.c              \
                                src/search.c             \
                                src/settings.c           \
                                src/sort.c               \
                                src/task.c               \
+                               src/task-processor.c     \
                                src/upnp.c
 
-media_service_upnp_headers = src/async.h               \
-                               src/chain-task.h        \
-                               src/client.h            \
-                               src/device.h            \
-                               src/error.h             \
-                               src/interface.h         \
-                               src/log.h               \
-                               src/path.h              \
-                               src/props.h             \
-                               src/search.h            \
-                               src/settings.h          \
-                               src/sort.h              \
-                               src/task.h              \
+media_service_upnp_headers = src/async.h                \
+                               src/chain-task.h         \
+                               src/client.h             \
+                               src/device.h             \
+                               src/error.h              \
+                               src/interface.h          \
+                               src/log.h                \
+                               src/media-service-upnp.h \
+                               src/path.h               \
+                               src/props.h              \
+                               src/search.h             \
+                               src/settings.h           \
+                               src/sort.h               \
+                               src/task.h               \
+                               src/task-atom.h          \
+                               src/task-processor.h     \
                                src/upnp.h
 
 media_service_upnp_SOURCES = $(media_service_upnp_headers)     \
@@ -487,9 +491,9 @@ src/chain-task.$(OBJEXT): src/$(am__dirstamp) \
 src/device.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
 src/error.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/log.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 src/media-service-upnp.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
-src/log.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 src/path.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 src/props.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 src/search.$(OBJEXT): src/$(am__dirstamp) \
@@ -498,6 +502,8 @@ src/settings.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
 src/sort.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 src/task.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/task-processor.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
 src/upnp.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 media-service-upnp$(EXEEXT): $(media_service_upnp_OBJECTS) $(media_service_upnp_DEPENDENCIES) $(EXTRA_media_service_upnp_DEPENDENCIES) 
        @rm -f media-service-upnp$(EXEEXT)
@@ -516,6 +522,7 @@ mostlyclean-compile:
        -rm -f src/search.$(OBJEXT)
        -rm -f src/settings.$(OBJEXT)
        -rm -f src/sort.$(OBJEXT)
+       -rm -f src/task-processor.$(OBJEXT)
        -rm -f src/task.$(OBJEXT)
        -rm -f src/upnp.$(OBJEXT)
        -rm -f test/dms_info-dms-info.$(OBJEXT)
@@ -534,6 +541,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/search.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/settings.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sort.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/task-processor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/task.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/upnp.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/dms_info-dms-info.Po@am__quote@
diff --git a/README b/README
index 8496d3e..c623d7a 100644 (file)
--- a/README
+++ b/README
@@ -126,3 +126,16 @@ This option is enabled by bootstrap-configure.
 This option is enabled by default. To disable use
 --disable-optimization. When enabled it turns on compiler
 optimizations. Disable = -O0, enable = -O2.
+
+--enable-never-quit
+
+This option is disabled by default.  To enable use --enable-never-quit.
+When enabled, media-service-upnp doesn't quit when the last client disconnects.
+
+--with-log-type
+
+See logging.txt for more information about logging.
+
+--with-log-level
+
+See logging.txt for more information about logging.
index 7f6c440..fa8bd5a 100644 (file)
@@ -42,27 +42,18 @@ void msu_async_cb_data_delete(msu_async_cb_data_t *cb_data)
                switch (cb_data->type) {
                case MSU_TASK_GET_CHILDREN:
                case MSU_TASK_SEARCH:
-                       g_free(cb_data->ut.bas.root_path);
                        if (cb_data->ut.bas.vbs)
                                g_ptr_array_unref(cb_data->ut.bas.vbs);
                        break;
-               case MSU_TASK_GET_PROP:
-                       g_free(cb_data->ut.get_prop.root_path);
-                       break;
                case MSU_TASK_GET_ALL_PROPS:
                case MSU_TASK_GET_RESOURCE:
-                       g_free(cb_data->ut.get_all.root_path);
                        if (cb_data->ut.get_all.vb)
                                g_variant_builder_unref(cb_data->ut.get_all.vb);
                        break;
                case MSU_TASK_UPLOAD_TO_ANY:
                case MSU_TASK_UPLOAD:
-                       g_free(cb_data->ut.upload.root_path);
                        g_free(cb_data->ut.upload.mime_type);
                        break;
-               case MSU_TASK_CREATE_CONTAINER:
-                       g_free(cb_data->ut.create_container.root_path);
-                       break;
                case MSU_TASK_UPDATE_OBJECT:
                        g_free(cb_data->ut.update.current_tag_value);
                        g_free(cb_data->ut.update.new_tag_value);
@@ -71,7 +62,6 @@ void msu_async_cb_data_delete(msu_async_cb_data_t *cb_data)
                        break;
                }
 
-               g_free(cb_data->id);
                g_free(cb_data);
        }
 }
@@ -80,7 +70,7 @@ gboolean msu_async_complete_task(gpointer user_data)
 {
        msu_async_cb_data_t *cb_data = user_data;
 
-       MSU_LOG_DEBUG("Enter. Error %p", (void *) cb_data->error);
+       MSU_LOG_DEBUG("Enter. Error %p", (void *)cb_data->error);
        MSU_LOG_DEBUG_NL();
 
        cb_data->cb(cb_data->task, cb_data->result, cb_data->error);
index 0bc4a8c..03b0ce4 100644 (file)
 
 #include <libgupnp/gupnp-control-point.h>
 
+#include "media-service-upnp.h"
 #include "task.h"
 #include "upnp.h"
 
 typedef struct msu_async_cb_data_t_ msu_async_cb_data_t;
-typedef struct msu_device_t_ msu_device_t;
+typedef guint64 msu_upnp_prop_mask;
 
 typedef void (*msu_async_cb_t)(msu_async_cb_data_t *cb_data);
 
 typedef struct msu_async_bas_t_ msu_async_bas_t;
 struct msu_async_bas_t_ {
-       guint32 filter_mask;
-       gchar *root_path;
+       msu_upnp_prop_mask filter_mask;
        GPtrArray *vbs;
        const gchar *protocol_info;
        gboolean need_child_count;
@@ -48,7 +48,6 @@ struct msu_async_bas_t_ {
 typedef struct msu_async_get_prop_t_ msu_async_get_prop_t;
 struct msu_async_get_prop_t_ {
        GCallback prop_func;
-       gchar *root_path;
        const gchar *protocol_info;
 };
 
@@ -56,25 +55,16 @@ typedef struct msu_async_get_all_t_ msu_async_get_all_t;
 struct msu_async_get_all_t_ {
        GCallback prop_func;
        GVariantBuilder *vb;
-       gchar *root_path;
-       guint32 filter_mask;
+       msu_upnp_prop_mask filter_mask;
        const gchar *protocol_info;
        gboolean need_child_count;
        gboolean device_object;
-       msu_device_t *device;
 };
 
 typedef struct msu_async_upload_t_ msu_async_upload_t;
 struct msu_async_upload_t_ {
        const gchar *object_class;
-       gchar *root_path;
        gchar *mime_type;
-       msu_device_t *device;
-};
-
-typedef struct msu_async_create_container_t_ msu_async_create_container_t;
-struct msu_async_create_container_t_ {
-       gchar *root_path;
 };
 
 typedef struct msu_async_update_t_ msu_async_update_t;
@@ -94,13 +84,11 @@ struct msu_async_cb_data_t_ {
        GUPnPServiceProxy *proxy;
        GCancellable *cancellable;
        gulong cancel_id;
-       gchar *id;
        union {
                msu_async_bas_t bas;
                msu_async_get_prop_t get_prop;
                msu_async_get_all_t get_all;
                msu_async_upload_t upload;
-               msu_async_create_container_t create_container;
                msu_async_update_t update;
        } ut;
 };
index 27f99fb..987dc0e 100644 (file)
@@ -63,7 +63,7 @@ static gboolean prv_idle_end_func(gpointer user_data)
 
 static gboolean prv_idle_next_task(gpointer user_data)
 {
-       msu_chain_task_t *chain = (msu_chain_task_t *) user_data;
+       msu_chain_task_t *chain = (msu_chain_task_t *)user_data;
        GList *head = chain->task_list;
 
        chain->task_list = g_list_remove_link(chain->task_list, head);
@@ -127,7 +127,7 @@ void msu_chain_task_begin_action_cb(GUPnPServiceProxy *proxy,
                                    GUPnPServiceProxyAction *action,
                                    gpointer user_data)
 {
-       msu_chain_task_t *chain = (msu_chain_task_t *) user_data;
+       msu_chain_task_t *chain = (msu_chain_task_t *)user_data;
        msu_chain_task_atom_t *current;
 
        if (chain != NULL) {
index 871daf6..3b9d22e 100644 (file)
@@ -40,8 +40,8 @@
 #define MSU_UPLOAD_STATUS_ERROR "ERROR"
 #define MSU_UPLOAD_STATUS_COMPLETED "COMPLETED"
 
-typedef gboolean (*msu_device_count_cb_t)(msu_async_cb_data_t *cb_data,
-                                         gint count);
+typedef gboolean(*msu_device_count_cb_t)(msu_async_cb_data_t *cb_data,
+                                        gint count);
 
 typedef struct msu_device_count_data_t_ msu_device_count_data_t;
 struct msu_device_count_data_t_ {
@@ -98,7 +98,7 @@ static void prv_system_update_cb(GUPnPServiceProxy *proxy,
 static void prv_msu_device_upload_delete(gpointer up);
 static void prv_msu_upload_job_delete(gpointer up);
 static void prv_get_sr_token_for_props(GUPnPServiceProxy *proxy,
-                            msu_device_t *device,
+                            const msu_device_t *device,
                             GCancellable *cancellable,
                             msu_async_cb_data_t *cb_data);
 
@@ -137,11 +137,13 @@ static void prv_msu_context_delete(gpointer context)
                        (void) g_source_remove(ctx->timeout_id);
 
                if (ctx->subscribed) {
-                       gupnp_service_proxy_remove_notify(ctx->service_proxy,
+                       gupnp_service_proxy_remove_notify(
+                                               ctx->service_proxy,
                                                MSU_SYSTEM_UPDATE_VAR,
                                                prv_system_update_cb,
                                                ctx->device);
-                       gupnp_service_proxy_remove_notify(ctx->service_proxy,
+                       gupnp_service_proxy_remove_notify(
+                                               ctx->service_proxy,
                                                MSU_CONTAINER_UPDATE_VAR,
                                                prv_container_update_cb,
                                                ctx->device);
@@ -174,7 +176,7 @@ static void prv_msu_context_new(const gchar *ip_address,
        ctx->device = device;
        g_object_ref(proxy);
        ctx->service_proxy = (GUPnPServiceProxy *)
-               gupnp_device_info_get_service((GUPnPDeviceInfo *) proxy,
+               gupnp_device_info_get_service((GUPnPDeviceInfo *)proxy,
                                              service_type);
        ctx->subscribed = FALSE;
        ctx->timeout_id = 0;
@@ -247,16 +249,17 @@ static void prv_container_update_cb(GUPnPServiceProxy *proxy,
 
        g_variant_builder_init(&array, G_VARIANT_TYPE("ao"));
        prv_build_container_update_array(device->path,
-                                       g_value_get_string(value),
-                                       &array);
+                                        g_value_get_string(value),
+                                        &array);
 
        (void) g_dbus_connection_emit_signal(device->connection,
-                       NULL,
-                       device->path,
-                       MSU_INTERFACE_MEDIA_DEVICE,
-                       MSU_INTERFACE_CONTAINER_UPDATE,
-                       g_variant_new("(@ao)", g_variant_builder_end(&array)),
-                       NULL);
+                                            NULL,
+                                            device->path,
+                                            MSU_INTERFACE_MEDIA_DEVICE,
+                                            MSU_INTERFACE_CONTAINER_UPDATE,
+                                            g_variant_new("(@ao)",
+                                            g_variant_builder_end(&array)),
+                                            NULL);
 }
 
 static void prv_system_update_cb(GUPnPServiceProxy *proxy,
@@ -308,8 +311,9 @@ static void prv_subscription_lost_cb(GUPnPServiceProxy *proxy,
 
        if (!context->timeout_id) {
                gupnp_service_proxy_set_subscribed(context->service_proxy,
-                                                                       TRUE);
-               context->timeout_id = g_timeout_add_seconds(10,
+                                                  TRUE);
+               context->timeout_id = g_timeout_add_seconds(
+                                               10,
                                                prv_re_enable_subscription,
                                                context);
        } else {
@@ -338,27 +342,27 @@ void msu_device_subscribe_to_contents_change(msu_device_t *device)
                      context->ip_address);
 
        gupnp_service_proxy_add_notify(context->service_proxy,
-                               MSU_SYSTEM_UPDATE_VAR,
-                               G_TYPE_UINT,
-                               prv_system_update_cb,
-                               device);
+                                      MSU_SYSTEM_UPDATE_VAR,
+                                      G_TYPE_UINT,
+                                      prv_system_update_cb,
+                                      device);
 
        gupnp_service_proxy_add_notify(context->service_proxy,
-                               MSU_CONTAINER_UPDATE_VAR,
-                               G_TYPE_STRING,
-                               prv_container_update_cb,
-                               device);
+                                      MSU_CONTAINER_UPDATE_VAR,
+                                      G_TYPE_STRING,
+                                      prv_container_update_cb,
+                                      device);
 
        context->subscribed = TRUE;
        gupnp_service_proxy_set_subscribed(context->service_proxy, TRUE);
 
        g_signal_connect(context->service_proxy,
-                               "subscription-lost",
-                               G_CALLBACK(prv_subscription_lost_cb),
-                               context);
+                        "subscription-lost",
+                        G_CALLBACK(prv_subscription_lost_cb),
+                        context);
 }
 
-static void prv_feature_list_add_feature(gcharroot_path,
+static void prv_feature_list_add_feature(gchar *root_path,
                                         GUPnPFeature *feature,
                                         GVariantBuilder *vb)
 {
@@ -419,7 +423,7 @@ static void prv_get_feature_list_analyze(msu_device_t *device, gchar *result)
        item = list;
 
        while (item != NULL) {
-               feature = (GUPnPFeature *) item->data;
+               feature = (GUPnPFeature *)item->data;
                prv_feature_list_add_feature(device->path, feature, &vb);
                g_object_unref(feature);
                item = g_list_next(item);
@@ -447,7 +451,7 @@ static void prv_get_feature_list_cb(GUPnPServiceProxy *proxy,
 {
        gchar *result = NULL;
        GError *error = NULL;
-       prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *) user_data;
+       prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *)user_data;
 
        if (!gupnp_service_proxy_end_action(proxy, action, &error,
                                            "FeatureList", G_TYPE_STRING,
@@ -512,7 +516,7 @@ static void prv_get_sort_ext_capabilities_analyze(msu_device_t *device,
 #if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
        props = g_variant_print(device->sort_ext_caps, FALSE);
        MSU_LOG_DEBUG("%s = %s", MSU_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES,
-                                props);
+                     props);
        g_free(props);
 #endif
 }
@@ -523,7 +527,7 @@ static void prv_get_sort_ext_capabilities_cb(GUPnPServiceProxy *proxy,
 {
        gchar *result = NULL;
        GError *error = NULL;
-       prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *) user_data;
+       prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *)user_data;
 
        if (!gupnp_service_proxy_end_action(proxy, action, &error,
                                            "SortExtensionCaps",
@@ -603,7 +607,7 @@ static void prv_get_sort_capabilities_cb(GUPnPServiceProxy *proxy,
 {
        gchar *result = NULL;
        GError *error = NULL;
-       prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *) user_data;
+       prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *)user_data;
 
        if (!gupnp_service_proxy_end_action(proxy, action, &error, "SortCaps",
                                            G_TYPE_STRING, &result, NULL)) {
@@ -648,7 +652,7 @@ static void prv_get_search_capabilities_cb(GUPnPServiceProxy *proxy,
 {
        gchar *result = NULL;
        GError *error = NULL;
-       prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *) user_data;
+       prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *)user_data;
 
        if (!gupnp_service_proxy_end_action(proxy, action, &error, "SearchCaps",
                                            G_TYPE_STRING, &result, NULL)) {
@@ -710,7 +714,7 @@ static GUPnPServiceProxyAction *prv_declare(msu_chain_task_t *chain,
 
        device = msu_chain_task_get_device(chain);
 
-       priv_t = (prv_new_device_ct_t *) msu_chain_task_get_user_data(chain);
+       priv_t = (prv_new_device_ct_t *)msu_chain_task_get_user_data(chain);
 
        flags = G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES;
        id =  g_dbus_connection_register_subtree(priv_t->connection,
@@ -722,16 +726,20 @@ static GUPnPServiceProxyAction *prv_declare(msu_chain_task_t *chain,
        if (id) {
                device->id = id;
 
-               device->uploads = g_hash_table_new_full(g_int_hash, g_int_equal,
+               device->uploads = g_hash_table_new_full(
+                                               g_int_hash,
+                                               g_int_equal,
                                                g_free,
                                                prv_msu_device_upload_delete);
                device->upload_jobs =
-                       g_hash_table_new_full(g_int_hash, g_int_equal,
+                       g_hash_table_new_full(g_int_hash,
+                                             g_int_equal,
                                              g_free,
                                              prv_msu_upload_job_delete);
 
-       } else
-               MSU_LOG_ERROR("g_dbus_connection_register_subtree FAILED");
+       } else {
+               MSU_LOG_WARNING("g_dbus_connection_register_subtree FAILED");
+       }
 
        *failed = (!id);
 
@@ -822,7 +830,7 @@ msu_device_t *msu_device_from_path(const gchar *path, GHashTable *device_list)
        return retval;
 }
 
-msu_device_context_t *msu_device_get_context(msu_device_t *device,
+msu_device_context_t *msu_device_get_context(const msu_device_t *device,
                                             msu_client_t *client)
 {
        msu_device_context_t *context;
@@ -876,13 +884,13 @@ static void prv_found_child(GUPnPDIDLLiteParser *parser,
 
        builder->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
 
-       if (!msu_props_add_object(builder->vb, object, cb_task_data->root_path,
-                                 task->path, cb_task_data->filter_mask))
+       if (!msu_props_add_object(builder->vb, object, task->target.root_path,
+                                 task->target.path, cb_task_data->filter_mask))
                goto on_error;
 
        if (GUPNP_IS_DIDL_LITE_CONTAINER(object)) {
                msu_props_add_container(builder->vb,
-                                       (GUPnPDIDLLiteContainer *) object,
+                                       (GUPnPDIDLLiteContainer *)object,
                                        cb_task_data->filter_mask,
                                        &have_child_count);
 
@@ -895,7 +903,7 @@ static void prv_found_child(GUPnPDIDLLiteParser *parser,
                }
        } else {
                msu_props_add_item(builder->vb, object,
-                                  cb_task_data->root_path,
+                                  task->target.root_path,
                                   cb_task_data->filter_mask,
                                   cb_task_data->protocol_info);
        }
@@ -1002,7 +1010,7 @@ static void prv_get_children_cb(GUPnPServiceProxy *proxy,
                                            "Result", G_TYPE_STRING,
                                            &result, NULL)) {
                MSU_LOG_WARNING("Browse operation failed: %s",
-                             upnp_error->message);
+                               upnp_error->message);
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_OPERATION_FAILED,
@@ -1021,15 +1029,15 @@ static void prv_get_children_cb(GUPnPServiceProxy *proxy,
        cb_task_data->vbs = g_ptr_array_new_with_free_func(
                prv_msu_device_object_builder_delete);
 
-       if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error)
-               && upnp_error->code != GUPNP_XML_ERROR_EMPTY_NODE) {
+       if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error) &&
+           upnp_error->code != GUPNP_XML_ERROR_EMPTY_NODE) {
                MSU_LOG_WARNING("Unable to parse results of browse: %s",
-                             upnp_error->message);
+                               upnp_error->message);
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_OPERATION_FAILED,
-                                            "Unable to parse results of "
-                                            "browse: %s", upnp_error->message);
+                                            "Unable to parse results of browse: %s",
+                                            upnp_error->message);
                goto on_error;
        }
 
@@ -1061,7 +1069,7 @@ no_complete:
        MSU_LOG_DEBUG("Exit");
 }
 
-void msu_device_get_children(msu_device_t *device, msu_client_t *client,
+void msu_device_get_children(msu_client_t *client,
                             msu_task_t *task, msu_async_cb_data_t *cb_data,
                             const gchar *upnp_filter, const gchar *sort_by,
                             GCancellable *cancellable)
@@ -1070,7 +1078,7 @@ void msu_device_get_children(msu_device_t *device, msu_client_t *client,
 
        MSU_LOG_DEBUG("Enter");
 
-       context = msu_device_get_context(device, client);
+       context = msu_device_get_context(task->target.device, client);
 
        cb_data->action =
                gupnp_service_proxy_begin_action(context->service_proxy,
@@ -1078,7 +1086,7 @@ void msu_device_get_children(msu_device_t *device, msu_client_t *client,
                                                 prv_get_children_cb,
                                                 cb_data,
                                                 "ObjectID", G_TYPE_STRING,
-                                                cb_data->id,
+                                                task->target.id,
 
                                                 "BrowseFlag", G_TYPE_STRING,
                                                 "BrowseDirectChildren",
@@ -1113,14 +1121,13 @@ static void prv_get_item(GUPnPDIDLLiteParser *parser,
 
        if (!GUPNP_IS_DIDL_LITE_CONTAINER(object))
                msu_props_add_item(cb_task_data->vb, object,
-                                  cb_task_data->root_path,
-                                  0xffffffff,
+                                  cb_data->task->target.root_path,
+                                  MSU_UPNP_MASK_ALL_PROPS,
                                   cb_task_data->protocol_info);
        else
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_UNKNOWN_INTERFACE,
-                                            "Interface not supported on "
-                                            "container.");
+                                            "Interface not supported on container.");
 }
 
 static void prv_get_container(GUPnPDIDLLiteParser *parser,
@@ -1133,16 +1140,15 @@ static void prv_get_container(GUPnPDIDLLiteParser *parser,
 
        if (GUPNP_IS_DIDL_LITE_CONTAINER(object)) {
                msu_props_add_container(cb_task_data->vb,
-                                       (GUPnPDIDLLiteContainer *) object,
-                                       0xffffffff,
+                                       (GUPnPDIDLLiteContainer *)object,
+                                       MSU_UPNP_MASK_ALL_PROPS,
                                        &have_child_count);
                if (!have_child_count)
                        cb_task_data->need_child_count = TRUE;
        } else {
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_UNKNOWN_INTERFACE,
-                                            "Interface not supported on "
-                                            "item.");
+                                            "Interface not supported on item.");
        }
 }
 
@@ -1159,18 +1165,17 @@ static void prv_get_object(GUPnPDIDLLiteParser *parser,
        id = gupnp_didl_lite_object_get_parent_id(object);
 
        if (!id || !strcmp(id, "-1") || !strcmp(id, "")) {
-               parent_path = cb_task_data->root_path;
+               parent_path = cb_data->task->target.root_path;
        } else {
-               path = msu_path_from_id(cb_task_data->root_path, id);
+               path = msu_path_from_id(cb_data->task->target.root_path, id);
                parent_path = path;
        }
 
        if (!msu_props_add_object(cb_task_data->vb, object,
-                                 cb_task_data->root_path,
-                                 parent_path, 0xffffffff))
+                                 cb_data->task->target.root_path,
+                                 parent_path, MSU_UPNP_MASK_ALL_PROPS))
                cb_data->error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_RESULT,
-                                            "Unable to retrieve mandatory "
-                                            " object properties");
+                                            "Unable to retrieve mandatory object properties");
        g_free(path);
 }
 
@@ -1189,21 +1194,21 @@ static void prv_get_all(GUPnPDIDLLiteParser *parser,
                        msu_props_add_container(
                                cb_task_data->vb,
                                (GUPnPDIDLLiteContainer *)
-                               object, 0xffffffff,
+                               object, MSU_UPNP_MASK_ALL_PROPS,
                                &have_child_count);
                        if (!have_child_count)
                                cb_task_data->need_child_count = TRUE;
                } else {
                        msu_props_add_item(cb_task_data->vb,
                                           object,
-                                          cb_task_data->root_path,
-                                          0xffffffff,
+                                          cb_data->task->target.root_path,
+                                          MSU_UPNP_MASK_ALL_PROPS,
                                           cb_task_data->protocol_info);
                }
        }
 }
 
-static gboolean prv_device_subscribed(msu_device_t *device)
+static gboolean prv_device_subscribed(const msu_device_t *device)
 {
        msu_device_context_t *context;
        unsigned int i;
@@ -1234,15 +1239,16 @@ static void prv_system_update_id_for_prop_cb(GUPnPServiceProxy *proxy,
                                            "Id", G_TYPE_UINT,
                                            &id,
                                            NULL)) {
-               MSU_LOG_ERROR("Unable to retrieve ServiceUpdateID: %s %s",
-                              g_quark_to_string(upnp_error->domain),
-                              upnp_error->message);
-
-               cb_data->error = g_error_new(MSU_ERROR,
-                               MSU_ERROR_OPERATION_FAILED,
-                               "Unable to retrieve ServiceUpdateID: %s",
+               MSU_LOG_WARNING("Unable to retrieve ServiceUpdateID: %s %s",
+                               g_quark_to_string(upnp_error->domain),
                                upnp_error->message);
 
+               cb_data->error = g_error_new(
+                                  MSU_ERROR,
+                                  MSU_ERROR_OPERATION_FAILED,
+                                  "Unable to retrieve ServiceUpdateID: %s",
+                                  upnp_error->message);
+
                goto on_complete;
        }
 
@@ -1260,7 +1266,7 @@ on_complete:
 }
 
 static void prv_get_system_update_id_for_prop(GUPnPServiceProxy *proxy,
-                                    msu_device_t *device,
+                                    const msu_device_t *device,
                                     GCancellable *cancellable,
                                     msu_async_cb_data_t *cb_data)
 {
@@ -1288,8 +1294,8 @@ static void prv_get_system_update_id_for_prop(GUPnPServiceProxy *proxy,
 
        cb_data->cancel_id =
        g_cancellable_connect(cancellable,
-                                     G_CALLBACK(msu_async_task_cancelled),
-                                     cb_data, NULL);
+                             G_CALLBACK(msu_async_task_cancelled),
+                             cb_data, NULL);
        cb_data->cancellable = cancellable;
 
 on_complete:
@@ -1312,14 +1318,14 @@ static void prv_system_update_id_for_props_cb(GUPnPServiceProxy *proxy,
                                            "Id", G_TYPE_UINT,
                                            &id,
                                            NULL)) {
-               MSU_LOG_ERROR("Unable to retrieve ServiceUpdateID: %s %s",
-                              g_quark_to_string(upnp_error->domain),
-                              upnp_error->message);
+               MSU_LOG_WARNING("Unable to retrieve ServiceUpdateID: %s %s",
+                               g_quark_to_string(upnp_error->domain),
+                               upnp_error->message);
 
                cb_data->error = g_error_new(MSU_ERROR,
-                               MSU_ERROR_OPERATION_FAILED,
-                               "Unable to retrieve ServiceUpdateID: %s",
-                               upnp_error->message);
+                                  MSU_ERROR_OPERATION_FAILED,
+                                  "Unable to retrieve ServiceUpdateID: %s",
+                                  upnp_error->message);
 
                goto on_complete;
        }
@@ -1334,7 +1340,7 @@ static void prv_system_update_id_for_props_cb(GUPnPServiceProxy *proxy,
 on_complete:
 
        if (!cb_data->error)
-               prv_get_sr_token_for_props(proxy, cb_task_data->device,
+               prv_get_sr_token_for_props(proxy, cb_data->task->target.device,
                                           cb_data->cancellable, cb_data);
        else {
                (void) g_idle_add(msu_async_complete_task, cb_data);
@@ -1349,7 +1355,7 @@ on_complete:
 }
 
 static void prv_get_system_update_id_for_props(GUPnPServiceProxy *proxy,
-                                    msu_device_t *device,
+                                    const msu_device_t *device,
                                     GCancellable *cancellable,
                                     msu_async_cb_data_t *cb_data)
 {
@@ -1381,8 +1387,8 @@ static void prv_get_system_update_id_for_props(GUPnPServiceProxy *proxy,
 
        cb_data->cancel_id =
        g_cancellable_connect(cancellable,
-                                     G_CALLBACK(msu_async_task_cancelled),
-                                     cb_data, NULL);
+                             G_CALLBACK(msu_async_task_cancelled),
+                             cb_data, NULL);
        cb_data->cancellable = cancellable;
 
 on_complete:
@@ -1390,7 +1396,7 @@ on_complete:
        MSU_LOG_DEBUG("Exit");
 }
 
-static int prv_get_media_server_version(msu_device_t *device)
+static int prv_get_media_server_version(const msu_device_t *device)
 {
        msu_device_context_t *context;
        const char *device_type;
@@ -1401,7 +1407,7 @@ static int prv_get_media_server_version(msu_device_t *device)
                                                        context->device_proxy);
 
        if (strncmp(device_type, MEDIA_SERVER_DEVICE_TYPE,
-                                       sizeof(MEDIA_SERVER_DEVICE_TYPE) - 1))
+                   sizeof(MEDIA_SERVER_DEVICE_TYPE) - 1))
                goto on_error;
 
        version = device_type + sizeof(MEDIA_SERVER_DEVICE_TYPE) - 1;
@@ -1427,9 +1433,9 @@ static void prv_service_reset_for_prop_cb(GUPnPServiceProxy *proxy,
                                            "ResetToken", G_TYPE_STRING,
                                            &token,
                                            NULL)) {
-               MSU_LOG_ERROR("Unable to retrieve ServiceResetToken: %s %s",
+               MSU_LOG_WARNING("Unable to retrieve ServiceResetToken: %s %s",
                                g_quark_to_string(upnp_error->domain),
-                                upnp_error->message);
+                               upnp_error->message);
 
 
                cb_data->error = g_error_new(MSU_ERROR,
@@ -1442,10 +1448,10 @@ static void prv_service_reset_for_prop_cb(GUPnPServiceProxy *proxy,
 
        cb_data->result = g_variant_ref_sink(g_variant_new_string(token));
 
-       g_free(token);
-
        MSU_LOG_DEBUG("Service Reset %s", token);
 
+       g_free(token);
+
 on_complete:
 
        (void) g_idle_add(msu_async_complete_task, cb_data);
@@ -1458,7 +1464,7 @@ on_complete:
 }
 
 static void prv_get_sr_token_for_prop(GUPnPServiceProxy *proxy,
-                            msu_device_t *device,
+                            const msu_device_t *device,
                             GCancellable *cancellable,
                             msu_async_cb_data_t *cb_data)
 {
@@ -1506,9 +1512,9 @@ static void prv_service_reset_for_props_cb(GUPnPServiceProxy *proxy,
                                            "ResetToken", G_TYPE_STRING,
                                            &token,
                                            NULL)) {
-               MSU_LOG_ERROR("Unable to retrieve ServiceResetToken: %s %s",
-                             g_quark_to_string(upnp_error->domain),
-                             upnp_error->message);
+               MSU_LOG_WARNING("Unable to retrieve ServiceResetToken: %s %s",
+                               g_quark_to_string(upnp_error->domain),
+                               upnp_error->message);
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_OPERATION_FAILED,
@@ -1526,10 +1532,10 @@ static void prv_service_reset_for_props_cb(GUPnPServiceProxy *proxy,
        cb_data->result = g_variant_ref_sink(g_variant_builder_end(
                                                cb_task_data->vb));
 
-       g_free(token);
-
        MSU_LOG_DEBUG("Service Reset %s", token);
 
+       g_free(token);
+
 on_complete:
 
        (void) g_idle_add(msu_async_complete_task, cb_data);
@@ -1542,7 +1548,7 @@ on_complete:
 }
 
 static void prv_get_sr_token_for_props(GUPnPServiceProxy *proxy,
-                            msu_device_t *device,
+                            const msu_device_t *device,
                             GCancellable *cancellable,
                             msu_async_cb_data_t *cb_data)
 {
@@ -1571,6 +1577,10 @@ static void prv_get_sr_token_for_props(GUPnPServiceProxy *proxy,
                                        cb_data, NULL);
        cb_data->cancellable = cancellable;
 
+       MSU_LOG_DEBUG("Exit");
+
+       return;
+
 on_complete:
 
        (void) g_idle_add(msu_async_complete_task, cb_data);
@@ -1586,7 +1596,7 @@ static gboolean prv_get_all_child_count_cb(msu_async_cb_data_t *cb_data,
        msu_props_add_child_count(cb_task_data->vb, count);
        if (cb_task_data->device_object)
                prv_get_system_update_id_for_props(cb_data->proxy,
-                                                  cb_task_data->device,
+                                                  cb_data->task->target.device,
                                                   cb_data->cancellable,
                                                   cb_data);
        else
@@ -1613,7 +1623,7 @@ static void prv_get_all_ms2spec_props_cb(GUPnPServiceProxy *proxy,
                                            "Result", G_TYPE_STRING,
                                            &result, NULL)) {
                MSU_LOG_WARNING("Browse operation failed: %s",
-                             upnp_error->message);
+                               upnp_error->message);
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_OPERATION_FAILED,
@@ -1639,13 +1649,12 @@ static void prv_get_all_ms2spec_props_cb(GUPnPServiceProxy *proxy,
                                            "Property not defined for object");
                } else {
                        MSU_LOG_WARNING("Unable to parse results of browse: %s",
-                                     upnp_error->message);
+                                       upnp_error->message);
 
                        cb_data->error =
                                g_error_new(MSU_ERROR,
                                            MSU_ERROR_OPERATION_FAILED,
-                                           "Unable to parse results of "
-                                           "browse: %s",
+                                           "Unable to parse results of browse: %s",
                                            upnp_error->message);
                }
                goto on_error;
@@ -1658,13 +1667,15 @@ static void prv_get_all_ms2spec_props_cb(GUPnPServiceProxy *proxy,
                MSU_LOG_DEBUG("Need Child Count");
 
                prv_get_child_count(cb_data, prv_get_all_child_count_cb,
-                       cb_data->id);
+                                   cb_data->task->target.id);
 
                goto no_complete;
        } else if (cb_data->task->type == MSU_TASK_GET_ALL_PROPS &&
                                                cb_task_data->device_object) {
-               prv_get_system_update_id_for_props(proxy, cb_task_data->device,
-                                               cb_data->cancellable, cb_data);
+               prv_get_system_update_id_for_props(proxy,
+                                                  cb_data->task->target.device,
+                                                  cb_data->cancellable,
+                                                  cb_data);
 
                goto no_complete;
        } else {
@@ -1700,15 +1711,17 @@ static void prv_get_all_ms2spec_props(msu_device_context_t *context,
 
        MSU_LOG_DEBUG("Enter called");
 
-       if (!strcmp(MSU_INTERFACE_MEDIA_CONTAINER, task_data->interface_name))
+       if (!strcmp(MSU_INTERFACE_MEDIA_CONTAINER, task_data->interface_name)) {
                cb_task_data->prop_func = G_CALLBACK(prv_get_container);
-       else if (!strcmp(MSU_INTERFACE_MEDIA_ITEM, task_data->interface_name))
+       } else if (!strcmp(MSU_INTERFACE_MEDIA_ITEM,
+                  task_data->interface_name)) {
                cb_task_data->prop_func = G_CALLBACK(prv_get_item);
-       else if (!strcmp(MSU_INTERFACE_MEDIA_OBJECT, task_data->interface_name))
+       } else if (!strcmp(MSU_INTERFACE_MEDIA_OBJECT,
+                  task_data->interface_name)) {
                cb_task_data->prop_func = G_CALLBACK(prv_get_object);
-       else  if (!strcmp("", task_data->interface_name))
+       } else  if (!strcmp("", task_data->interface_name)) {
                cb_task_data->prop_func = G_CALLBACK(prv_get_all);
-       else {
+       else {
                MSU_LOG_WARNING("Interface is unknown.");
 
                cb_data->error =
@@ -1720,7 +1733,7 @@ static void prv_get_all_ms2spec_props(msu_device_context_t *context,
        cb_data->action = gupnp_service_proxy_begin_action(
                context->service_proxy, "Browse",
                prv_get_all_ms2spec_props_cb, cb_data,
-               "ObjectID", G_TYPE_STRING, cb_data->id,
+               "ObjectID", G_TYPE_STRING, task->target.id,
                "BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
                "Filter", G_TYPE_STRING, "*",
                "StartingIndex", G_TYPE_INT, 0,
@@ -1749,7 +1762,7 @@ on_error:
        return;
 }
 
-void msu_device_get_all_props(msu_device_t *device,  msu_client_t *client,
+void msu_device_get_all_props(msu_client_t *client,
                              msu_task_t *task, msu_async_cb_data_t *cb_data,
                              gboolean root_object,
                              GCancellable *cancellable)
@@ -1760,31 +1773,29 @@ void msu_device_get_all_props(msu_device_t *device,  msu_client_t *client,
 
        MSU_LOG_DEBUG("Enter");
 
-       context = msu_device_get_context(device, client);
+       context = msu_device_get_context(task->target.device, client);
        cb_task_data = &cb_data->ut.get_all;
 
        cb_task_data->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
        cb_task_data->device_object = root_object;
-       cb_task_data->device = device;
 
        if (!strcmp(task_data->interface_name, MSU_INTERFACE_MEDIA_DEVICE)) {
                if (root_object) {
                        msu_props_add_device(
-                               (GUPnPDeviceInfo *) context->device_proxy,
-                               device,
+                               (GUPnPDeviceInfo *)context->device_proxy,
+                               task->target.device,
                                cb_task_data->vb);
 
                        prv_get_system_update_id_for_props(
                                                        context->service_proxy,
-                                                       device,
+                                                       task->target.device,
                                                        cancellable,
                                                        cb_data);
                } else {
                        cb_data->error =
                                g_error_new(MSU_ERROR,
                                            MSU_ERROR_UNKNOWN_INTERFACE,
-                                           "Interface is only valid on "
-                                           "root objects.");
+                                           "Interface is only valid on root objects.");
 
                        (void) g_idle_add(msu_async_complete_task, cb_data);
                }
@@ -1795,8 +1806,8 @@ void msu_device_get_all_props(msu_device_t *device,  msu_client_t *client,
        } else {
                if (root_object)
                        msu_props_add_device(
-                               (GUPnPDeviceInfo *) context->device_proxy,
-                               device,
+                               (GUPnPDeviceInfo *)context->device_proxy,
+                               task->target.device,
                                cb_task_data->vb);
 
                prv_get_all_ms2spec_props(context, cancellable, cb_data);
@@ -1812,13 +1823,12 @@ static void prv_get_object_property(GUPnPDIDLLiteParser *parser,
        msu_async_cb_data_t *cb_data = user_data;
        msu_task_t *task = cb_data->task;
        msu_task_get_prop_t *task_data = &task->ut.get_prop;
-       msu_async_get_prop_t *cb_task_data = &cb_data->ut.get_prop;
 
        if (cb_data->result)
                goto on_error;
 
        cb_data->result = msu_props_get_object_prop(task_data->prop_name,
-                                                   cb_task_data->root_path,
+                                                   task->target.root_path,
                                                    object);
 
 on_error:
@@ -1839,7 +1849,7 @@ static void prv_get_item_property(GUPnPDIDLLiteParser *parser,
                goto on_error;
 
        cb_data->result = msu_props_get_item_prop(task_data->prop_name,
-                                                 cb_task_data->root_path,
+                                                 task->target.root_path,
                                                  object,
                                                  cb_task_data->protocol_info);
 
@@ -1921,7 +1931,7 @@ static void prv_count_children_cb(GUPnPServiceProxy *proxy,
                                            &count,
                                            NULL)) {
                MSU_LOG_WARNING("Browse operation failed: %s",
-                             upnp_error->message);
+                               upnp_error->message);
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_OPERATION_FAILED,
@@ -2000,7 +2010,7 @@ static void prv_get_ms2spec_prop_cb(GUPnPServiceProxy *proxy,
                                            "Result", G_TYPE_STRING,
                                            &result, NULL)) {
                MSU_LOG_WARNING("Browse operation failed: %s",
-                             upnp_error->message);
+                               upnp_error->message);
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_OPERATION_FAILED,
@@ -2026,13 +2036,12 @@ static void prv_get_ms2spec_prop_cb(GUPnPServiceProxy *proxy,
                                            "Property not defined for object");
                } else {
                        MSU_LOG_WARNING("Unable to parse results of browse: %s",
-                                     upnp_error->message);
+                                       upnp_error->message);
 
                        cb_data->error =
                                g_error_new(MSU_ERROR,
                                            MSU_ERROR_OPERATION_FAILED,
-                                           "Unable to parse results of "
-                                           "browse: %s",
+                                           "Unable to parse results of browse: %s",
                                            upnp_error->message);
                }
                goto on_error;
@@ -2055,7 +2064,7 @@ on_error:
                g_error_free(cb_data->error);
                cb_data->error = NULL;
                prv_get_child_count(cb_data, prv_get_child_count_cb,
-                                   cb_data->id);
+                                   cb_data->task->target.id);
        } else {
                (void) g_idle_add(msu_async_complete_task, cb_data);
                g_cancellable_disconnect(cb_data->cancellable,
@@ -2108,7 +2117,7 @@ static void prv_get_ms2spec_prop(msu_device_context_t *context,
                cb_task_data->prop_func = G_CALLBACK(prv_get_all_property);
        } else {
                MSU_LOG_WARNING("Interface is unknown.%s",
-                             task_data->interface_name);
+                               task_data->interface_name);
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_UNKNOWN_INTERFACE,
@@ -2120,7 +2129,7 @@ static void prv_get_ms2spec_prop(msu_device_context_t *context,
                context->service_proxy, "Browse",
                prv_get_ms2spec_prop_cb,
                cb_data,
-               "ObjectID", G_TYPE_STRING, cb_data->id,
+               "ObjectID", G_TYPE_STRING, cb_data->task->target.id,
                "BrowseFlag", G_TYPE_STRING,
                "BrowseMetadata",
                "Filter", G_TYPE_STRING, filter,
@@ -2151,7 +2160,7 @@ on_error:
        return;
 }
 
-void msu_device_get_prop(msu_device_t *device, msu_client_t *client,
+void msu_device_get_prop(msu_client_t *client,
                         msu_task_t *task, msu_async_cb_data_t *cb_data,
                         msu_prop_map_t *prop_map, gboolean root_object,
                         GCancellable *cancellable)
@@ -2162,22 +2171,24 @@ void msu_device_get_prop(msu_device_t *device, msu_client_t *client,
 
        MSU_LOG_DEBUG("Enter");
 
-       context = msu_device_get_context(device, client);
+       context = msu_device_get_context(task->target.device, client);
 
        if (!strcmp(task_data->interface_name, MSU_INTERFACE_MEDIA_DEVICE)) {
                if (root_object) {
-                       if (!strcmp(task_data->prop_name,
+                       if (!strcmp(
+                               task_data->prop_name,
                                MSU_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID)) {
                                prv_get_system_update_id_for_prop(
                                                        context->service_proxy,
-                                                       device,
+                                                       task->target.device,
                                                        cancellable,
                                                        cb_data);
-                       } else if (!strcmp(task_data->prop_name,
+                       } else if (!strcmp(
+                                 task_data->prop_name,
                                  MSU_INTERFACE_PROP_ESV_SERVICE_RESET_TOKEN)) {
                                prv_get_sr_token_for_prop(
                                                        context->service_proxy,
-                                                       device,
+                                                       task->target.device,
                                                        cancellable,
                                                        cb_data);
                        } else {
@@ -2185,7 +2196,7 @@ void msu_device_get_prop(msu_device_t *device, msu_client_t *client,
                                        msu_props_get_device_prop(
                                                (GUPnPDeviceInfo *)
                                                context->device_proxy,
-                                               device,
+                                               task->target.device,
                                                task_data->prop_name);
 
                                if (!cb_data->result)
@@ -2212,19 +2223,21 @@ void msu_device_get_prop(msu_device_t *device, msu_client_t *client,
                                     cancellable, cb_data);
        } else {
                if (root_object) {
-                       if (!strcmp(task_data->prop_name,
+                       if (!strcmp(
+                               task_data->prop_name,
                                MSU_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID)) {
                                prv_get_system_update_id_for_prop(
                                                        context->service_proxy,
-                                                       device,
+                                                       task->target.device,
                                                        cancellable,
                                                        cb_data);
                                complete = TRUE;
-                       } else if (!strcmp(task_data->prop_name,
+                       } else if (!strcmp(
+                                 task_data->prop_name,
                                  MSU_INTERFACE_PROP_ESV_SERVICE_RESET_TOKEN)) {
                                prv_get_sr_token_for_prop(
                                                        context->service_proxy,
-                                                       device,
+                                                       task->target.device,
                                                        cancellable,
                                                        cb_data);
                                complete = TRUE;
@@ -2232,7 +2245,7 @@ void msu_device_get_prop(msu_device_t *device, msu_client_t *client,
                                cb_data->result = msu_props_get_device_prop(
                                        (GUPnPDeviceInfo *)
                                        context->device_proxy,
-                                       device,
+                                       task->target.device,
                                        task_data->prop_name);
                                if (cb_data->result) {
                                        (void) g_idle_add(
@@ -2271,21 +2284,22 @@ static void prv_found_target(GUPnPDIDLLiteParser *parser,
        id = gupnp_didl_lite_object_get_parent_id(object);
 
        if (!id || !strcmp(id, "-1") || !strcmp(id, "")) {
-               parent_path = cb_task_data->root_path;
+               parent_path = cb_data->task->target.root_path;
        } else {
-               path = msu_path_from_id(cb_task_data->root_path, id);
+               path = msu_path_from_id(cb_data->task->target.root_path, id);
                parent_path = path;
        }
 
        builder->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
 
-       if (!msu_props_add_object(builder->vb, object, cb_task_data->root_path,
+       if (!msu_props_add_object(builder->vb, object,
+                                 cb_data->task->target.root_path,
                                  parent_path, cb_task_data->filter_mask))
                goto on_error;
 
        if (GUPNP_IS_DIDL_LITE_CONTAINER(object)) {
                msu_props_add_container(builder->vb,
-                                       (GUPnPDIDLLiteContainer *) object,
+                                       (GUPnPDIDLLiteContainer *)object,
                                        cb_task_data->filter_mask,
                                        &have_child_count);
 
@@ -2299,7 +2313,7 @@ static void prv_found_target(GUPnPDIDLLiteParser *parser,
        } else {
                msu_props_add_item(builder->vb,
                                   object,
-                                  cb_task_data->root_path,
+                                  cb_data->task->target.root_path,
                                   cb_task_data->filter_mask,
                                   cb_task_data->protocol_info);
        }
@@ -2340,7 +2354,7 @@ static void prv_search_cb(GUPnPServiceProxy *proxy,
                                            NULL)) {
 
                MSU_LOG_WARNING("Search operation failed %s",
-                             upnp_error->message);
+                               upnp_error->message);
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_OPERATION_FAILED,
@@ -2359,15 +2373,15 @@ static void prv_search_cb(GUPnPServiceProxy *proxy,
 
        MSU_LOG_DEBUG("Server Search result: %s", result);
 
-       if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error)
-               && upnp_error->code != GUPNP_XML_ERROR_EMPTY_NODE) {
+       if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error) &&
+           upnp_error->code != GUPNP_XML_ERROR_EMPTY_NODE) {
                MSU_LOG_WARNING("Unable to parse results of search: %s",
-                             upnp_error->message);
+                               upnp_error->message);
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_OPERATION_FAILED,
-                                            "Unable to parse results of "
-                                            "search: %s", upnp_error->message);
+                                            "Unable to parse results of search: %s",
+                                            upnp_error->message);
                goto on_error;
        }
 
@@ -2406,7 +2420,7 @@ no_complete:
        MSU_LOG_DEBUG("Exit");
 }
 
-void msu_device_search(msu_device_t *device, msu_client_t *client,
+void msu_device_search(msu_client_t *client,
                       msu_task_t *task, msu_async_cb_data_t *cb_data,
                       const gchar *upnp_filter, const gchar *upnp_query,
                       const gchar *sort_by, GCancellable *cancellable)
@@ -2415,13 +2429,13 @@ void msu_device_search(msu_device_t *device, msu_client_t *client,
 
        MSU_LOG_DEBUG("Enter");
 
-       context = msu_device_get_context(device, client);
+       context = msu_device_get_context(task->target.device, client);
 
        cb_data->action = gupnp_service_proxy_begin_action(
                context->service_proxy, "Search",
                prv_search_cb,
                cb_data,
-               "ContainerID", G_TYPE_STRING, cb_data->id,
+               "ContainerID", G_TYPE_STRING, task->target.id,
                "SearchCriteria", G_TYPE_STRING, upnp_query,
                "Filter", G_TYPE_STRING, upnp_filter,
                "StartingIndex", G_TYPE_INT, task->ut.search.start,
@@ -2456,7 +2470,7 @@ static void prv_get_resource(GUPnPDIDLLiteParser *parser,
                               task_data->protocol_info);
 }
 
-void msu_device_get_resource(msu_device_t *device, msu_client_t *client,
+void msu_device_get_resource(msu_client_t *client,
                             msu_task_t *task, msu_async_cb_data_t *cb_data,
                             const gchar *upnp_filter,
                             GCancellable *cancellable)
@@ -2464,7 +2478,7 @@ void msu_device_get_resource(msu_device_t *device, msu_client_t *client,
        msu_async_get_all_t *cb_task_data;
        msu_device_context_t *context;
 
-       context = msu_device_get_context(device, client);
+       context = msu_device_get_context(task->target.device, client);
        cb_task_data = &cb_data->ut.get_all;
 
        cb_task_data->vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
@@ -2474,7 +2488,7 @@ void msu_device_get_resource(msu_device_t *device, msu_client_t *client,
        cb_data->action = gupnp_service_proxy_begin_action(
                context->service_proxy, "Browse",
                prv_get_all_ms2spec_props_cb, cb_data,
-               "ObjectID", G_TYPE_STRING, cb_data->id,
+               "ObjectID", G_TYPE_STRING, task->target.id,
                "BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
                "Filter", G_TYPE_STRING, upnp_filter,
                "StartingIndex", G_TYPE_INT, 0,
@@ -2510,7 +2524,8 @@ static gchar *prv_create_new_container_didl(const gchar *parent_id,
        container = GUPNP_DIDL_LITE_CONTAINER(item);
 
        gupnp_didl_lite_object_set_id(item, "");
-       gupnp_didl_lite_object_set_title(item,
+       gupnp_didl_lite_object_set_title(
+                                       item,
                                        task->ut.create_container.display_name);
        gupnp_didl_lite_object_set_parent_id(item, parent_id);
        actual_type = msu_props_media_spec_to_upnp_class(
@@ -2645,7 +2660,7 @@ static gboolean prv_remove_update_job(gpointer user_data)
                                    &upload_job->upload_id);
 
                MSU_LOG_DEBUG("Removing Upload Object: %d",
-                       upload_job->upload_id);
+                             upload_job->upload_id);
        }
 
        upload_job->remove_idle = 0;
@@ -2854,7 +2869,6 @@ static void prv_create_container_cb(GUPnPServiceProxy *proxy,
                 gpointer user_data)
 {
        msu_async_cb_data_t *cb_data = user_data;
-       msu_async_create_container_t *cb_task_data;
        GError *upnp_error = NULL;
        gchar *result = NULL;
        gchar *object_id = NULL;
@@ -2862,8 +2876,6 @@ static void prv_create_container_cb(GUPnPServiceProxy *proxy,
 
        MSU_LOG_DEBUG("Enter");
 
-       cb_task_data = &cb_data->ut.create_container;
-
        if (!gupnp_service_proxy_end_action(cb_data->proxy, cb_data->action,
                                            &upnp_error,
                                            "ObjectID", G_TYPE_STRING,
@@ -2871,18 +2883,18 @@ static void prv_create_container_cb(GUPnPServiceProxy *proxy,
                                            "Result", G_TYPE_STRING,
                                            &result,
                                            NULL)) {
-               MSU_LOG_ERROR("Create Object operation failed: %s",
-                                                       upnp_error->message);
+               MSU_LOG_WARNING("Create Object operation failed: %s",
+                               upnp_error->message);
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_OPERATION_FAILED,
-                                            "Create Object operation "
-                                            " failed: %s",
+                                            "Create Object operation failed: %s",
                                             upnp_error->message);
                goto on_error;
        }
 
-       object_path = msu_path_from_id(cb_task_data->root_path, object_id);
+       object_path = msu_path_from_id(cb_data->task->target.root_path,
+                                      object_id);
        cb_data->result = g_variant_ref_sink(g_variant_new_object_path(
                                                                object_path));
        g_free(object_path);
@@ -2950,16 +2962,15 @@ static void prv_create_object_cb(GUPnPServiceProxy *proxy,
 
        MSU_LOG_DEBUG("Create Object Result: %s", result);
 
-       if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error)
-               && upnp_error->code != GUPNP_XML_ERROR_EMPTY_NODE) {
+       if (!gupnp_didl_lite_parser_parse_didl(parser, result, &upnp_error) &&
+           upnp_error->code != GUPNP_XML_ERROR_EMPTY_NODE) {
 
                MSU_LOG_WARNING("Unable to parse results of CreateObject: %s",
                                upnp_error->message);
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_OPERATION_FAILED,
-                                            "Unable to parse results of "
-                                            "CreateObject: %s",
+                                            "Unable to parse results of CreateObject: %s",
                                             upnp_error->message);
                goto on_error;
        }
@@ -2982,8 +2993,8 @@ static void prv_create_object_cb(GUPnPServiceProxy *proxy,
                goto on_error;
 
        upload_job = g_new0(msu_device_upload_job_t, 1);
-       upload_job->device = cb_task_data->device;
-       upload_job->upload_id = (gint) cb_task_data->device->upload_id;
+       upload_job->device = cb_data->task->target.device;
+       upload_job->upload_id = (gint) cb_data->task->target.device->upload_id;
 
        soup_session_queue_message(upload->soup_session, upload->msg,
                                   prv_post_finished, upload_job);
@@ -2991,9 +3002,11 @@ static void prv_create_object_cb(GUPnPServiceProxy *proxy,
 
        upload_id = g_new(gint, 1);
        *upload_id = upload_job->upload_id;
-       g_hash_table_insert(cb_task_data->device->uploads, upload_id, upload);
+       g_hash_table_insert(cb_data->task->target.device->uploads, upload_id,
+                           upload);
 
-       object_path = msu_path_from_id(cb_task_data->root_path, object_id);
+       object_path = msu_path_from_id(cb_data->task->target.root_path,
+                                      object_id);
 
        MSU_LOG_DEBUG("Upload ID %u", *upload_id);
        MSU_LOG_DEBUG("Object ID %s", object_id);
@@ -3004,17 +3017,18 @@ static void prv_create_object_cb(GUPnPServiceProxy *proxy,
        cb_data->result = g_variant_ref_sink(g_variant_new_tuple(out_params,
                                                                 2));
 
-       ++cb_task_data->device->upload_id;
-       if (cb_task_data->device->upload_id > G_MAXINT)
-               cb_task_data->device->upload_id = 0;
+       ++cb_data->task->target.device->upload_id;
+       if (cb_data->task->target.device->upload_id > G_MAXINT)
+               cb_data->task->target.device->upload_id = 0;
 
        g_free(object_path);
 
 on_error:
 
        if (cb_data->error && delete_needed) {
-               MSU_LOG_WARNING("Upload failed deleting created object "
-                               "with id %s", object_id);
+               MSU_LOG_WARNING(
+                       "Upload failed deleting created object with id %s",
+                       object_id);
 
                cb_data->action = gupnp_service_proxy_begin_action(
                        cb_data->proxy, "DestroyObject", prv_upload_delete_cb,
@@ -3040,7 +3054,7 @@ on_error:
        MSU_LOG_DEBUG("Exit");
 }
 
-void msu_device_upload(msu_device_t *device, msu_client_t *client,
+void msu_device_upload(msu_client_t *client,
                       msu_task_t *task, const gchar *parent_id,
                       msu_async_cb_data_t *cb_data, GCancellable *cancellable)
 {
@@ -3051,7 +3065,7 @@ void msu_device_upload(msu_device_t *device, msu_client_t *client,
        MSU_LOG_DEBUG("Enter");
        MSU_LOG_DEBUG("Uploading file to %s", parent_id);
 
-       context = msu_device_get_context(device, client);
+       context = msu_device_get_context(task->target.device, client);
        cb_task_data = &cb_data->ut.upload;
 
        didl = prv_create_upload_didl(parent_id, task,
@@ -3068,7 +3082,6 @@ void msu_device_upload(msu_device_t *device, msu_client_t *client,
                NULL);
 
        cb_data->proxy = context->service_proxy;
-       cb_task_data->device = device;
 
        cb_data->cancel_id =
                g_cancellable_connect(cancellable,
@@ -3081,8 +3094,7 @@ void msu_device_upload(msu_device_t *device, msu_client_t *client,
        MSU_LOG_DEBUG("Exit");
 }
 
-gboolean msu_device_get_upload_status(msu_device_t *device,
-                                     msu_task_t *task, GError **error)
+gboolean msu_device_get_upload_status(msu_task_t *task, GError **error)
 {
        msu_device_upload_t *upload;
        gboolean retval = FALSE;
@@ -3093,7 +3105,7 @@ gboolean msu_device_get_upload_status(msu_device_t *device,
 
        upload_id = task->ut.upload_action.upload_id;
 
-       upload = g_hash_table_lookup(device->uploads, &upload_id);
+       upload = g_hash_table_lookup(task->target.device->uploads, &upload_id);
        if (!upload) {
                *error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
                                     "Unknown Upload ID %u ", upload_id);
@@ -3119,7 +3131,7 @@ on_error:
        return retval;
 }
 
-void msu_device_get_upload_ids(msu_device_t *device, msu_task_t *task)
+void msu_device_get_upload_ids(msu_task_t *task)
 {
        GVariantBuilder vb;
        GHashTableIter iter;
@@ -3129,17 +3141,16 @@ void msu_device_get_upload_ids(msu_device_t *device, msu_task_t *task)
 
        g_variant_builder_init(&vb, G_VARIANT_TYPE("au"));
 
-       g_hash_table_iter_init(&iter, device->uploads);
+       g_hash_table_iter_init(&iter, task->target.device->uploads);
        while (g_hash_table_iter_next(&iter, &key, NULL))
-               g_variant_builder_add(&vb, "u", (guint32) (*((gint *) key)));
+               g_variant_builder_add(&vb, "u", (guint32) (*((gint *)key)));
 
        task->result = g_variant_ref_sink(g_variant_builder_end(&vb));
 
        MSU_LOG_DEBUG("Exit");
 }
 
-gboolean msu_device_cancel_upload(msu_device_t *device, msu_task_t *task,
-                                 GError **error)
+gboolean msu_device_cancel_upload(msu_task_t *task, GError **error)
 {
        msu_device_upload_t *upload;
        gboolean retval = FALSE;
@@ -3149,7 +3160,7 @@ gboolean msu_device_cancel_upload(msu_device_t *device, msu_task_t *task,
 
        upload_id = task->ut.upload_action.upload_id;
 
-       upload = g_hash_table_lookup(device->uploads, &upload_id);
+       upload = g_hash_table_lookup(task->target.device->uploads, &upload_id);
        if (!upload) {
                *error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
                                     "Unknown Upload ID %u ", upload_id);
@@ -3188,8 +3199,7 @@ static void prv_destroy_object_cb(GUPnPServiceProxy *proxy,
 
                cb_data->error = g_error_new(MSU_ERROR,
                                             MSU_ERROR_OPERATION_FAILED,
-                                            "Destroy Object operation "
-                                            " failed: %s",
+                                            "Destroy Object operation failed: %s",
                                             upnp_error->message);
        }
 
@@ -3202,7 +3212,7 @@ static void prv_destroy_object_cb(GUPnPServiceProxy *proxy,
        MSU_LOG_DEBUG("Exit");
 }
 
-void msu_device_delete_object(msu_device_t *device, msu_client_t *client,
+void msu_device_delete_object(msu_client_t *client,
                              msu_task_t *task,
                              msu_async_cb_data_t *cb_data,
                              GCancellable *cancellable)
@@ -3211,12 +3221,12 @@ void msu_device_delete_object(msu_device_t *device, msu_client_t *client,
 
        MSU_LOG_DEBUG("Enter");
 
-       context = msu_device_get_context(device, client);
+       context = msu_device_get_context(task->target.device, client);
 
        cb_data->action = gupnp_service_proxy_begin_action(
                                context->service_proxy, "DestroyObject",
                                prv_destroy_object_cb, cb_data,
-                               "ObjectID", G_TYPE_STRING, cb_data->id,
+                               "ObjectID", G_TYPE_STRING, task->target.id,
                                NULL);
 
        cb_data->proxy = context->service_proxy;
@@ -3229,7 +3239,7 @@ void msu_device_delete_object(msu_device_t *device, msu_client_t *client,
        MSU_LOG_DEBUG("Exit");
 }
 
-void msu_device_create_container(msu_device_t *device, msu_client_t *client,
+void msu_device_create_container(msu_client_t *client,
                                 msu_task_t *task,
                                 const gchar *parent_id,
                                 msu_async_cb_data_t *cb_data,
@@ -3240,7 +3250,7 @@ void msu_device_create_container(msu_device_t *device, msu_client_t *client,
 
        MSU_LOG_DEBUG("Enter");
 
-       context = msu_device_get_context(device, client);
+       context = msu_device_get_context(task->target.device, client);
 
        didl = prv_create_new_container_didl(parent_id, task);
 
@@ -3298,7 +3308,7 @@ static void prv_update_object_update_cb(GUPnPServiceProxy *proxy,
 }
 
 static gchar *prv_get_current_xml_fragment(GUPnPDIDLLiteObject *object,
-                                          guint32 mask)
+                                          msu_upnp_prop_mask mask)
 {
        gchar *retval = NULL;
 
@@ -3321,7 +3331,7 @@ static gchar *prv_get_current_xml_fragment(GUPnPDIDLLiteObject *object,
 }
 
 static gchar *prv_get_new_xml_fragment(GUPnPDIDLLiteObject *object,
-                                      guint32 mask,
+                                      msu_upnp_prop_mask mask,
                                       GVariant *value)
 {
        GUPnPDIDLLiteContributor *artist;
@@ -3331,18 +3341,21 @@ static gchar *prv_get_new_xml_fragment(GUPnPDIDLLiteObject *object,
        gchar *retval = NULL;
 
        if (mask & MSU_UPNP_MASK_PROP_DISPLAY_NAME) {
-               gupnp_didl_lite_object_set_title(object,
-                       g_variant_get_string(value, NULL));
+               gupnp_didl_lite_object_set_title(
+                                       object,
+                                       g_variant_get_string(value, NULL));
 
                retval = gupnp_didl_lite_object_get_title_xml_string(object);
        } else if (mask & MSU_UPNP_MASK_PROP_ALBUM) {
-               gupnp_didl_lite_object_set_album(object,
-                       g_variant_get_string(value, NULL));
+               gupnp_didl_lite_object_set_album(
+                                       object,
+                                       g_variant_get_string(value, NULL));
 
                retval = gupnp_didl_lite_object_get_album_xml_string(object);
        } else if (mask & MSU_UPNP_MASK_PROP_DATE) {
-               gupnp_didl_lite_object_set_date(object,
-                       g_variant_get_string(value, NULL));
+               gupnp_didl_lite_object_set_date(
+                                       object,
+                                       g_variant_get_string(value, NULL));
 
                retval = gupnp_didl_lite_object_get_date_xml_string(object);
        } else if (mask & MSU_UPNP_MASK_PROP_TYPE) {
@@ -3352,10 +3365,11 @@ static gchar *prv_get_new_xml_fragment(GUPnPDIDLLiteObject *object,
                gupnp_didl_lite_object_set_upnp_class(object, upnp_class);
 
                retval = gupnp_didl_lite_object_get_upnp_class_xml_string(
-                       object);
+                                                               object);
        } else if (mask & MSU_UPNP_MASK_PROP_TRACK_NUMBER) {
-               gupnp_didl_lite_object_set_track_number(object,
-                                       g_variant_get_int32(value));
+               gupnp_didl_lite_object_set_track_number(
+                                               object,
+                                               g_variant_get_int32(value));
 
                retval = gupnp_didl_lite_object_get_track_number_xml_string(
                        object);
@@ -3437,11 +3451,11 @@ static void prv_get_xml_fragments(GUPnPDIDLLiteParser *parser,
                }
 
                if (frag1) {
-                       g_string_append(current_str, (const gchar *) frag1);
+                       g_string_append(current_str, (const gchar *)frag1);
                        g_free(frag1);
                }
 
-               g_string_append(new_str, (const gchar *) frag2);
+               g_string_append(new_str, (const gchar *)frag2);
                g_free(frag2);
        }
 
@@ -3461,7 +3475,7 @@ static void prv_get_xml_fragments(GUPnPDIDLLiteParser *parser,
                else
                        first = FALSE;
 
-               g_string_append(current_str, (const gchar *) frag1);
+               g_string_append(current_str, (const gchar *)frag1);
                g_free(frag1);
        }
 
@@ -3522,13 +3536,12 @@ static void prv_update_object_browse_cb(GUPnPServiceProxy *proxy,
                                            "Property not defined for object");
                } else {
                        MSU_LOG_WARNING("Unable to parse results of browse: %s",
-                                     upnp_error->message);
+                                       upnp_error->message);
 
                        cb_data->error =
                                g_error_new(MSU_ERROR,
                                            MSU_ERROR_OPERATION_FAILED,
-                                           "Unable to parse results of "
-                                           "browse: %s",
+                                           "Unable to parse results of browse: %s",
                                            upnp_error->message);
                }
 
@@ -3538,7 +3551,7 @@ static void prv_update_object_browse_cb(GUPnPServiceProxy *proxy,
        cb_data->action = gupnp_service_proxy_begin_action(
                cb_data->proxy, "UpdateObject",
                prv_update_object_update_cb, cb_data,
-               "ObjectID", G_TYPE_STRING, cb_data->id,
+               "ObjectID", G_TYPE_STRING, cb_data->task->target.id,
                "CurrentTagValue", G_TYPE_STRING,
                cb_task_data->current_tag_value,
                "NewTagValue", G_TYPE_STRING, cb_task_data->new_tag_value,
@@ -3564,7 +3577,7 @@ no_complete:
        MSU_LOG_DEBUG("Exit");
 }
 
-void msu_device_update_object(msu_device_t *device, msu_client_t *client,
+void msu_device_update_object(msu_client_t *client,
                              msu_task_t *task,
                              msu_async_cb_data_t *cb_data,
                              const gchar *upnp_filter,
@@ -3574,12 +3587,12 @@ void msu_device_update_object(msu_device_t *device, msu_client_t *client,
 
        MSU_LOG_DEBUG("Enter");
 
-       context = msu_device_get_context(device, client);
+       context = msu_device_get_context(task->target.device, client);
 
        cb_data->action = gupnp_service_proxy_begin_action(
                                context->service_proxy, "Browse",
                                prv_update_object_browse_cb, cb_data,
-                               "ObjectID", G_TYPE_STRING, cb_data->id,
+                               "ObjectID", G_TYPE_STRING, task->target.id,
                                "BrowseFlag", G_TYPE_STRING, "BrowseMetadata",
                                "Filter", G_TYPE_STRING, upnp_filter,
                                "StartingIndex", G_TYPE_INT, 0,
index 2a7f8cd..51932c3 100644 (file)
@@ -71,49 +71,47 @@ msu_device_t *msu_device_new(GDBusConnection *connection,
                             msu_chain_task_t *chain);
 
 msu_device_t *msu_device_from_path(const gchar *path, GHashTable *device_list);
-msu_device_context_t *msu_device_get_context(msu_device_t *device,
+msu_device_context_t *msu_device_get_context(const msu_device_t *device,
                                             msu_client_t *client);
-void msu_device_get_children(msu_device_t *device, msu_client_t *client,
+void msu_device_get_children(msu_client_t *client,
                             msu_task_t *task, msu_async_cb_data_t *cb_data,
                             const gchar *upnp_filter, const gchar *sort_by,
                             GCancellable *cancellable);
-void msu_device_get_all_props(msu_device_t *device, msu_client_t *client,
+void msu_device_get_all_props(msu_client_t *client,
                              msu_task_t *task,
                              msu_async_cb_data_t *cb_data,
                              gboolean root_object,
                              GCancellable *cancellable);
-void msu_device_get_prop(msu_device_t *device, msu_client_t *client,
+void msu_device_get_prop(msu_client_t *client,
                         msu_task_t *task, msu_async_cb_data_t *cb_data,
                         msu_prop_map_t *prop_map, gboolean root_object,
                         GCancellable *cancellable);
-void msu_device_search(msu_device_t *device, msu_client_t *client,
+void msu_device_search(msu_client_t *client,
                       msu_task_t *task, msu_async_cb_data_t *cb_data,
                       const gchar *upnp_filter, const gchar *upnp_query,
                       const gchar *sort_by, GCancellable *cancellable);
-void msu_device_get_resource(msu_device_t *device, msu_client_t *client,
+void msu_device_get_resource(msu_client_t *client,
                             msu_task_t *task,
                             msu_async_cb_data_t *cb_data,
                             const gchar *upnp_filter,
                             GCancellable *cancellable);
 void msu_device_subscribe_to_contents_change(msu_device_t *device);
-void msu_device_upload(msu_device_t *device, msu_client_t *client,
+void msu_device_upload(msu_client_t *client,
                       msu_task_t *task, const gchar *parent_id,
                       msu_async_cb_data_t *cb_data, GCancellable *cancellable);
-gboolean msu_device_get_upload_status(msu_device_t *device,
-                                     msu_task_t *task, GError **error);
-gboolean msu_device_cancel_upload(msu_device_t *device, msu_task_t *task,
-                                 GError **error);
-void msu_device_get_upload_ids(msu_device_t *device, msu_task_t *task);
-void msu_device_delete_object(msu_device_t *device, msu_client_t *client,
+gboolean msu_device_get_upload_status(msu_task_t *task, GError **error);
+gboolean msu_device_cancel_upload(msu_task_t *task, GError **error);
+void msu_device_get_upload_ids(msu_task_t *task);
+void msu_device_delete_object(msu_client_t *client,
                              msu_task_t *task,
                              msu_async_cb_data_t *cb_data,
                              GCancellable *cancellable);
-void msu_device_create_container(msu_device_t *device, msu_client_t *client,
+void msu_device_create_container(msu_client_t *client,
                                 msu_task_t *task,
                                 const gchar *parent_id,
                                 msu_async_cb_data_t *cb_data,
                                 GCancellable *cancellable);
-void msu_device_update_object(msu_device_t *device, msu_client_t *client,
+void msu_device_update_object(msu_client_t *client,
                              msu_task_t *task,
                              msu_async_cb_data_t *cb_data,
                              const gchar *upnp_filter,
index ead3784..2e0eac6 100644 (file)
@@ -36,6 +36,7 @@
 #define MSU_INTERFACE_PROP_TYPE "Type"
 #define MSU_INTERFACE_PROP_CREATOR "Creator"
 #define MSU_INTERFACE_PROP_DLNA_MANAGED "DLNAManaged"
+#define MSU_INTERFACE_PROP_OBJECT_UPDATE_ID "ObjectUpdateID"
 
 /* Item Properties */
 #define MSU_INTERFACE_PROP_REFPATH "RefPath"
@@ -52,6 +53,8 @@
 #define MSU_INTERFACE_PROP_SEARCHABLE "Searchable"
 #define MSU_INTERFACE_PROP_CHILD_COUNT "ChildCount"
 #define MSU_INTERFACE_PROP_CREATE_CLASSES "CreateClasses"
+#define MSU_INTERFACE_PROP_CONTAINER_UPDATE_ID "ContainerUpdateID"
+#define MSU_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT "TotalDeletedChildCount"
 
 /* Device Properties */
 #define MSU_INTERFACE_PROP_LOCATION "Location"
@@ -86,6 +89,7 @@
 #define MSU_INTERFACE_PROP_COLOR_DEPTH "ColorDepth"
 #define MSU_INTERFACE_PROP_URLS "URLs"
 #define MSU_INTERFACE_PROP_URL "URL"
+#define MSU_INTERFACE_PROP_UPDATE_COUNT "UpdateCount"
 
 /* Evented State Variable Properties */
 #define MSU_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID "SystemUpdateID"
 #define MSU_INTERFACE_UPLOAD_UPDATE "UploadUpdate"
 #define MSU_INTERFACE_TO_ADD_UPDATE "ToAddUpdate"
 #define MSU_INTERFACE_TO_DELETE "ToDelete"
+#define MSU_INTERFACE_CANCEL "Cancel"
+
 #endif
 
index 33b120c..52a5586 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -153,9 +153,10 @@ void msu_log_init(const char *program)
                                                        prv_msu_log_handler,
                                                        &s_log_context);
 
-       if (s_log_context.log_type != MSU_LOG_TYPE_SYSLOG) {
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_INFO
+       if (s_log_context.log_type != MSU_LOG_TYPE_SYSLOG)
                MSU_LOG_INFO("Media Service UPnP version %s", VERSION);
-       }
+#endif
 }
 
 void msu_log_finalize(void)
@@ -163,9 +164,10 @@ void msu_log_finalize(void)
        (void) setlogmask(LOG_MASK(LOG_INFO));
        syslog(LOG_INFO, "Media Service UPnP: Exit");
 
-       if (s_log_context.log_type != MSU_LOG_TYPE_SYSLOG) {
+#if MSU_LOG_LEVEL & MSU_LOG_LEVEL_INFO
+       if (s_log_context.log_type != MSU_LOG_TYPE_SYSLOG)
                MSU_LOG_INFO("Media Service UPnP: Exit");
-       }
+#endif
 
        (void) g_log_set_default_handler(s_log_context.old_handler, NULL);
 
index 963ab38..153d1c0 100644 (file)
 #include <sys/signalfd.h>
 
 #include "client.h"
+#include "device.h"
+#include "error.h"
 #include "interface.h"
 #include "log.h"
+#include "path.h"
 #include "settings.h"
 #include "task.h"
+#include "task-processor.h"
 #include "upnp.h"
 
 typedef struct msu_context_t_ msu_context_t;
@@ -41,23 +45,21 @@ struct msu_context_t_ {
        bool error;
        guint msu_id;
        guint sig_id;
-       guint idle_id;
        guint owner_id;
        GDBusNodeInfo *root_node_info;
        GDBusNodeInfo *server_node_info;
        GMainLoop *main_loop;
        GDBusConnection *connection;
-       gboolean quitting;
-       GPtrArray *tasks;
        GHashTable *watchers;
-       GCancellable *cancellable;
-       msu_task_t *current_task;
+       msu_task_processor_t *processor;
        msu_upnp_t *upnp;
        msu_settings_context_t *settings;
 };
 
 static msu_context_t g_context;
 
+#define MSU_SINK "media-service-upnp"
+
 static const gchar g_msu_root_introspection[] =
        "<node>"
        "  <interface name='"MSU_INTERFACE_MANAGER"'>"
@@ -126,6 +128,8 @@ static const gchar g_msu_server_introspection[] =
        "       access='read'/>"
        "    <property type='a{sb}' name='"MSU_INTERFACE_PROP_DLNA_MANAGED"'"
        "       access='read'/>"
+       "    <property type='u' name='"MSU_INTERFACE_PROP_OBJECT_UPDATE_ID"'"
+       "       access='read'/>"
        "    <method name='"MSU_INTERFACE_DELETE"'>"
        "    </method>"
        "    <method name='"MSU_INTERFACE_UPDATE"'>"
@@ -256,6 +260,11 @@ static const gchar g_msu_server_introspection[] =
        "       access='read'/>"
        "    <property type='a(sb)' name='"MSU_INTERFACE_PROP_CREATE_CLASSES"'"
        "       access='read'/>"
+       "    <property type='u' name='"MSU_INTERFACE_PROP_CONTAINER_UPDATE_ID"'"
+       "       access='read'/>"
+       "    <property type='u' name='"
+                               MSU_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT"'"
+       "       access='read'/>"
        "  </interface>"
        "  <interface name='"MSU_INTERFACE_MEDIA_ITEM"'>"
        "    <method name='"MSU_INTERFACE_GET_COMPATIBLE_RESOURCE"'>"
@@ -346,6 +355,8 @@ static const gchar g_msu_server_introspection[] =
        "      <arg type='o' name='"MSU_INTERFACE_PATH"'"
        "           direction='out'/>"
        "    </method>"
+       "    <method name='"MSU_INTERFACE_CANCEL"'>"
+       "    </method>"
        "    <property type='s' name='"MSU_INTERFACE_PROP_LOCATION"'"
        "       access='read'/>"
        "    <property type='s' name='"MSU_INTERFACE_PROP_UDN"'"
@@ -405,11 +416,21 @@ static const gchar g_msu_server_introspection[] =
        "  </interface>"
        "</node>";
 
-static gboolean prv_process_task(gpointer user_data);
+static void prv_process_task(msu_task_atom_t *task, GCancellable **cancellable);
+
+static gboolean prv_context_quit_cb(gpointer user_data)
+{
+       MSU_LOG_DEBUG("Quitting");
+
+       g_main_loop_quit(g_context.main_loop);
+
+       return FALSE;
+}
 
-static void prv_free_msu_task_cb(gpointer data, gpointer user_data)
+static void prv_sync_task_complete(msu_task_t *task)
 {
-       msu_task_delete(data);
+       msu_task_complete(task);
+       msu_task_queue_task_completed(task->base.queue_id);
 }
 
 static void prv_process_sync_task(msu_task_t *task)
@@ -417,15 +438,13 @@ static void prv_process_sync_task(msu_task_t *task)
        const gchar *client_name;
        msu_client_t *client;
 
-       g_context.current_task = task;
-
        switch (task->type) {
        case MSU_TASK_GET_VERSION:
-               msu_task_complete_and_delete(task);
+               prv_sync_task_complete(task);
                break;
        case MSU_TASK_GET_SERVERS:
                task->result = msu_upnp_get_server_ids(g_context.upnp);
-               msu_task_complete_and_delete(task);
+               prv_sync_task_complete(task);
                break;
        case MSU_TASK_SET_PROTOCOL_INFO:
                client_name =
@@ -441,7 +460,7 @@ static void prv_process_sync_task(msu_task_t *task)
                                client->protocol_info = NULL;
                        }
                }
-               msu_task_complete_and_delete(task);
+               prv_sync_task_complete(task);
                break;
        case MSU_TASK_SET_PREFER_LOCAL_ADDRESSES:
                client_name =
@@ -451,22 +470,23 @@ static void prv_process_sync_task(msu_task_t *task)
                        client->prefer_local_addresses =
                                        task->ut.prefer_local_addresses.prefer;
                }
-               msu_task_complete_and_delete(task);
+               prv_sync_task_complete(task);
                break;
        case MSU_TASK_GET_UPLOAD_STATUS:
                msu_upnp_get_upload_status(g_context.upnp, task);
+               msu_task_queue_task_completed(task->base.queue_id);
                break;
        case MSU_TASK_GET_UPLOAD_IDS:
                msu_upnp_get_upload_ids(g_context.upnp, task);
+               msu_task_queue_task_completed(task->base.queue_id);
                break;
        case MSU_TASK_CANCEL_UPLOAD:
                msu_upnp_cancel_upload(g_context.upnp, task);
+               msu_task_queue_task_completed(task->base.queue_id);
                break;
        default:
                break;
        }
-
-       g_context.current_task = NULL;
 }
 
 static void prv_async_task_complete(msu_task_t *task, GVariant *result,
@@ -474,35 +494,27 @@ static void prv_async_task_complete(msu_task_t *task, GVariant *result,
 {
        MSU_LOG_DEBUG("Enter");
 
-       g_object_unref(g_context.cancellable);
-       g_context.cancellable = NULL;
-       g_context.current_task = NULL;
-
        if (error) {
-               msu_task_fail_and_delete(task, error);
+               msu_task_fail(task, error);
                g_error_free(error);
        } else {
                task->result = result;
-               msu_task_complete_and_delete(task);
+               msu_task_complete(task);
        }
 
-       if (g_context.quitting)
-               g_main_loop_quit(g_context.main_loop);
-       else if (g_context.tasks->len > 0)
-               g_context.idle_id = g_idle_add(prv_process_task, NULL);
+       msu_task_queue_task_completed(task->base.queue_id);
 
        MSU_LOG_DEBUG("Exit");
 }
 
-static void prv_process_async_task(msu_task_t *task)
+static void prv_process_async_task(msu_task_t *task, GCancellable **cancellable)
 {
        const gchar *client_name;
        msu_client_t *client;
 
        MSU_LOG_DEBUG("Enter");
 
-       g_context.cancellable = g_cancellable_new();
-       g_context.current_task = task;
+       *cancellable = g_cancellable_new();
        client_name =
                g_dbus_method_invocation_get_sender(task->invocation);
        client = g_hash_table_lookup(g_context.watchers, client_name);
@@ -510,57 +522,57 @@ static void prv_process_async_task(msu_task_t *task)
        switch (task->type) {
        case MSU_TASK_GET_CHILDREN:
                msu_upnp_get_children(g_context.upnp, client, task,
-                                     g_context.cancellable,
+                                     *cancellable,
                                      prv_async_task_complete);
                break;
        case MSU_TASK_GET_PROP:
                msu_upnp_get_prop(g_context.upnp, client, task,
-                                 g_context.cancellable,
+                                 *cancellable,
                                  prv_async_task_complete);
                break;
        case MSU_TASK_GET_ALL_PROPS:
                msu_upnp_get_all_props(g_context.upnp, client, task,
-                                      g_context.cancellable,
+                                      *cancellable,
                                       prv_async_task_complete);
                break;
        case MSU_TASK_SEARCH:
                msu_upnp_search(g_context.upnp, client, task,
-                               g_context.cancellable,
+                               *cancellable,
                                prv_async_task_complete);
                break;
        case MSU_TASK_GET_RESOURCE:
                msu_upnp_get_resource(g_context.upnp, client, task,
-                                     g_context.cancellable,
+                                     *cancellable,
                                      prv_async_task_complete);
                break;
        case MSU_TASK_UPLOAD_TO_ANY:
                msu_upnp_upload_to_any(g_context.upnp, client, task,
-                                      g_context.cancellable,
+                                      *cancellable,
                                       prv_async_task_complete);
                break;
        case MSU_TASK_UPLOAD:
                msu_upnp_upload(g_context.upnp, client, task,
-                               g_context.cancellable,
+                               *cancellable,
                                prv_async_task_complete);
                break;
        case MSU_TASK_DELETE_OBJECT:
                msu_upnp_delete_object(g_context.upnp, client, task,
-                                      g_context.cancellable,
+                                      *cancellable,
                                       prv_async_task_complete);
                break;
        case MSU_TASK_CREATE_CONTAINER:
                msu_upnp_create_container(g_context.upnp, client, task,
-                                         g_context.cancellable,
+                                         *cancellable,
                                          prv_async_task_complete);
                break;
        case MSU_TASK_CREATE_CONTAINER_IN_ANY:
                msu_upnp_create_container_in_any(g_context.upnp, client, task,
-                                                g_context.cancellable,
+                                                *cancellable,
                                                 prv_async_task_complete);
                break;
        case MSU_TASK_UPDATE_OBJECT:
                msu_upnp_update_object(g_context.upnp, client, task,
-                                      g_context.cancellable,
+                                      *cancellable,
                                       prv_async_task_complete);
                break;
        default:
@@ -570,26 +582,24 @@ static void prv_process_async_task(msu_task_t *task)
        MSU_LOG_DEBUG("Exit");
 }
 
-static gboolean prv_process_task(gpointer user_data)
+static void prv_process_task(msu_task_atom_t *task, GCancellable **cancellable)
 {
-       msu_task_t *task;
-       gboolean retval = FALSE;
-
-       if (g_context.tasks->len > 0) {
-               task = g_ptr_array_index(g_context.tasks, 0);
-               if (task->synchronous) {
-                       prv_process_sync_task(task);
-                       retval = TRUE;
-               } else {
-                       prv_process_async_task(task);
-                       g_context.idle_id = 0;
-               }
-               g_ptr_array_remove_index(g_context.tasks, 0);
-       } else {
-               g_context.idle_id = 0;
-       }
+       msu_task_t *client_task = (msu_task_t *)task;
 
-       return retval;
+       if (client_task->synchronous)
+               prv_process_sync_task(client_task);
+       else
+               prv_process_async_task(client_task, cancellable);
+}
+
+static void prv_cancel_task(msu_task_atom_t *task)
+{
+       msu_task_cancel((msu_task_t *)task);
+}
+
+static void prv_delete_task(msu_task_atom_t *task)
+{
+       msu_task_delete((msu_task_t *)task);
 }
 
 static void prv_msu_method_call(GDBusConnection *conn,
@@ -693,6 +703,7 @@ static const GDBusInterfaceVTable *g_server_vtables[MSU_INTERFACE_INFO_MAX] = {
 static void prv_msu_context_init(void)
 {
        memset(&g_context, 0, sizeof(g_context));
+       g_context.processor = msu_task_processor_new(prv_context_quit_cb);
 }
 
 static void prv_msu_context_free(void)
@@ -702,14 +713,7 @@ static void prv_msu_context_free(void)
        if (g_context.watchers)
                g_hash_table_unref(g_context.watchers);
 
-       if (g_context.tasks) {
-               g_ptr_array_foreach(g_context.tasks, prv_free_msu_task_cb,
-                                   NULL);
-               g_ptr_array_unref(g_context.tasks);
-       }
-
-       if (g_context.idle_id)
-               (void) g_source_remove(g_context.idle_id);
+       msu_task_processor_free(g_context.processor);
 
        if (g_context.sig_id)
                (void) g_source_remove(g_context.sig_id);
@@ -740,56 +744,15 @@ static void prv_msu_context_free(void)
                msu_settings_delete(g_context.settings);
 }
 
-static void prv_quit(void)
-{
-       if (g_context.cancellable) {
-               g_cancellable_cancel(g_context.cancellable);
-               g_context.quitting = TRUE;
-       } else {
-               g_main_loop_quit(g_context.main_loop);
-       }
-}
-
 static void prv_remove_client(const gchar *name)
 {
-       const gchar *client_name;
-       msu_task_t *task;
-       guint pos;
-
-       if (g_context.cancellable) {
-               client_name = g_dbus_method_invocation_get_sender(
-                                       g_context.current_task->invocation);
-               if (!strcmp(client_name, name)) {
-                       MSU_LOG_DEBUG("Cancelling current task, type is %d",
-                                     g_context.current_task->type);
-
-                       g_cancellable_cancel(g_context.cancellable);
-               }
-       }
-
-       pos = 0;
-       while (pos < g_context.tasks->len) {
-               task = (msu_task_t *) g_ptr_array_index(g_context.tasks, pos);
-
-               client_name = g_dbus_method_invocation_get_sender(
-                                                       task->invocation);
-
-               if (strcmp(client_name, name)) {
-                       pos++;
-                       continue;
-               }
-
-               MSU_LOG_DEBUG("Removing task type %d from array", task->type);
-
-               (void) g_ptr_array_remove_index(g_context.tasks, pos);
-               msu_task_cancel_and_delete(task);
-       }
+       msu_task_processor_remove_queues_for_source(g_context.processor, name);
 
        (void) g_hash_table_remove(g_context.watchers, name);
 
        if (g_hash_table_size(g_context.watchers) == 0)
                if (!msu_settings_is_never_quit(g_context.settings))
-                       prv_quit();
+                       msu_task_processor_set_quitting(g_context.processor);
 }
 
 static void prv_lost_client(GDBusConnection *connection, const gchar *name,
@@ -800,10 +763,11 @@ static void prv_lost_client(GDBusConnection *connection, const gchar *name,
        prv_remove_client(name);
 }
 
-static void prv_add_task(msu_task_t *task)
+static void prv_add_task(msu_task_t *task, const gchar *sink)
 {
        const gchar *client_name;
        msu_client_t *client;
+       const msu_task_queue_key_t *queue_id;
 
        client_name = g_dbus_method_invocation_get_sender(task->invocation);
 
@@ -818,10 +782,19 @@ static void prv_add_task(msu_task_t *task)
                                    client);
        }
 
-       if (!g_context.cancellable && !g_context.idle_id)
-               g_context.idle_id = g_idle_add(prv_process_task, NULL);
-
-       g_ptr_array_add(g_context.tasks, task);
+       queue_id = msu_task_processor_lookup_queue(g_context.processor,
+                                                  client_name, sink);
+       if (!queue_id)
+               queue_id = msu_task_processor_add_queue(
+                                               g_context.processor,
+                                               client_name,
+                                               sink,
+                                               MSU_TASK_QUEUE_FLAG_AUTO_START,
+                                               prv_process_task,
+                                               prv_cancel_task,
+                                               prv_delete_task);
+
+       msu_task_queue_add_task(queue_id, &task->base);
 }
 
 static void prv_msu_method_call(GDBusConnection *conn,
@@ -840,20 +813,76 @@ static void prv_msu_method_call(GDBusConnection *conn,
                g_dbus_method_invocation_return_value(invocation, NULL);
        } else if (!strcmp(method, MSU_INTERFACE_GET_VERSION)) {
                task = msu_task_get_version_new(invocation);
-               prv_add_task(task);
+               prv_add_task(task, MSU_SINK);
        } else if (!strcmp(method, MSU_INTERFACE_GET_SERVERS)) {
                task = msu_task_get_servers_new(invocation);
-               prv_add_task(task);
+               prv_add_task(task, MSU_SINK);
        } else if (!strcmp(method, MSU_INTERFACE_SET_PROTOCOL_INFO)) {
                task = msu_task_set_protocol_info_new(invocation, parameters);
-               prv_add_task(task);
+               prv_add_task(task, MSU_SINK);
        } else if (!strcmp(method, MSU_INTERFACE_PREFER_LOCAL_ADDRESSES)) {
                task = msu_task_prefer_local_addresses_new(invocation,
                                                           parameters);
-               prv_add_task(task);
+               prv_add_task(task, MSU_SINK);
        }
 }
 
+gboolean msu_media_service_get_object_info(const gchar *object_path,
+                                          gchar **root_path,
+                                          gchar **object_id,
+                                          msu_device_t **device,
+                                          GError **error)
+{
+       if (!msu_path_get_path_and_id(object_path, root_path, object_id,
+                                     error)) {
+               MSU_LOG_WARNING("Bad object %s", object_path);
+
+               goto on_error;
+       }
+
+       *device = msu_device_from_path(*root_path,
+                               msu_upnp_get_server_udn_map(g_context.upnp));
+
+       if (*device == NULL) {
+               MSU_LOG_WARNING("Cannot locate device for %s", *root_path);
+
+               *error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+                                    "Cannot locate device corresponding to"
+                                    " the specified path");
+
+               g_free(*root_path);
+               g_free(*object_id);
+
+               goto on_error;
+       }
+
+       return TRUE;
+
+on_error:
+
+       return FALSE;
+}
+
+static const gchar *prv_get_device_id(const gchar *object, GError **error)
+{
+       msu_device_t *device;
+       gchar *root_path;
+       gchar *id;
+
+       if (!msu_media_service_get_object_info(object, &root_path, &id, &device,
+                                              error))
+               goto on_error;
+
+       g_free(id);
+       g_free(root_path);
+
+       return device->path;
+
+on_error:
+
+       return NULL;
+}
+
 static void prv_object_method_call(GDBusConnection *conn,
                                   const gchar *sender, const gchar *object,
                                   const gchar *interface,
@@ -862,15 +891,24 @@ static void prv_object_method_call(GDBusConnection *conn,
                                   gpointer user_data)
 {
        msu_task_t *task;
+       GError *error = NULL;
 
-       if (!strcmp(method, MSU_INTERFACE_DELETE)) {
-               task = msu_task_delete_new(invocation, object);
-       } else if (!strcmp(method, MSU_INTERFACE_UPDATE))
-               task = msu_task_update_new(invocation, object, parameters);
+       if (!strcmp(method, MSU_INTERFACE_DELETE))
+               task = msu_task_delete_new(invocation, object, &error);
+       else if (!strcmp(method, MSU_INTERFACE_UPDATE))
+               task = msu_task_update_new(invocation, object, parameters,
+                                          &error);
        else
                goto finished;
 
-       prv_add_task(task);
+       if (!task) {
+               g_dbus_method_invocation_return_gerror(invocation, error);
+               g_error_free(error);
+
+               goto finished;
+       }
+
+       prv_add_task(task, task->target.device->path);
 
 finished:
 
@@ -885,12 +923,26 @@ static void prv_item_method_call(GDBusConnection *conn,
                                 gpointer user_data)
 {
        msu_task_t *task;
+       GError *error = NULL;
 
        if (!strcmp(method, MSU_INTERFACE_GET_COMPATIBLE_RESOURCE)) {
                task = msu_task_get_resource_new(invocation, object,
-                                                parameters);
-               prv_add_task(task);
+                                                parameters, &error);
+
+               if (!task) {
+                       g_dbus_method_invocation_return_gerror(invocation,
+                                                              error);
+                       g_error_free(error);
+
+                       goto finished;
+               }
+
+               prv_add_task(task, task->target.device->path);
        }
+
+finished:
+
+       return;
 }
 
 
@@ -904,41 +956,56 @@ static void prv_con_method_call(GDBusConnection *conn,
                                gpointer user_data)
 {
        msu_task_t *task;
+       GError *error = NULL;
 
        if (!strcmp(method, MSU_INTERFACE_LIST_CHILDREN))
                task = msu_task_get_children_new(invocation, object,
-                                                parameters, TRUE, TRUE);
+                                                parameters, TRUE,
+                                                TRUE, &error);
        else if (!strcmp(method, MSU_INTERFACE_LIST_CHILDREN_EX))
                task = msu_task_get_children_ex_new(invocation, object,
-                                                   parameters, TRUE, TRUE);
+                                                   parameters, TRUE,
+                                                   TRUE, &error);
        else if (!strcmp(method, MSU_INTERFACE_LIST_ITEMS))
                task = msu_task_get_children_new(invocation, object,
-                                                parameters, TRUE, FALSE);
+                                                parameters, TRUE,
+                                                FALSE, &error);
        else if (!strcmp(method, MSU_INTERFACE_LIST_ITEMS_EX))
                task = msu_task_get_children_ex_new(invocation, object,
-                                                   parameters, TRUE, FALSE);
+                                                   parameters, TRUE,
+                                                   FALSE, &error);
        else if (!strcmp(method, MSU_INTERFACE_LIST_CONTAINERS))
                task = msu_task_get_children_new(invocation, object,
-                                                parameters, FALSE, TRUE);
+                                                parameters, FALSE,
+                                                TRUE, &error);
        else if (!strcmp(method, MSU_INTERFACE_LIST_CONTAINERS_EX))
                task = msu_task_get_children_ex_new(invocation, object,
-                                                   parameters, FALSE, TRUE);
+                                                   parameters, FALSE,
+                                                   TRUE, &error);
        else if (!strcmp(method, MSU_INTERFACE_SEARCH_OBJECTS))
                task = msu_task_search_new(invocation, object,
-                                          parameters);
+                                          parameters, &error);
        else if (!strcmp(method, MSU_INTERFACE_SEARCH_OBJECTS_EX))
                task = msu_task_search_ex_new(invocation, object,
-                                             parameters);
+                                             parameters, &error);
        else if (!strcmp(method, MSU_INTERFACE_UPLOAD))
-               task = msu_task_upload_new(invocation, object, parameters);
+               task = msu_task_upload_new(invocation, object,
+                                          parameters, &error);
        else if (!strcmp(method, MSU_INTERFACE_CREATE_CONTAINER))
                task = msu_task_create_container_new_generic(invocation,
                                                MSU_TASK_CREATE_CONTAINER,
-                                               object, parameters);
+                                               object, parameters, &error);
        else
                goto finished;
 
-       prv_add_task(task);
+       if (!task) {
+               g_dbus_method_invocation_return_gerror(invocation, error);
+               g_error_free(error);
+
+               goto finished;
+       }
+
+       prv_add_task(task, task->target.device->path);
 
 finished:
 
@@ -955,15 +1022,25 @@ static void prv_props_method_call(GDBusConnection *conn,
                                  gpointer user_data)
 {
        msu_task_t *task;
+       GError *error = NULL;
 
        if (!strcmp(method, MSU_INTERFACE_GET_ALL))
-               task = msu_task_get_props_new(invocation, object, parameters);
+               task = msu_task_get_props_new(invocation, object,
+                                             parameters, &error);
        else if (!strcmp(method, MSU_INTERFACE_GET))
-               task = msu_task_get_prop_new(invocation, object, parameters);
+               task = msu_task_get_prop_new(invocation, object,
+                                            parameters, &error);
        else
                goto finished;
 
-       prv_add_task(task);
+       if (!task) {
+               g_dbus_method_invocation_return_gerror(invocation, error);
+               g_error_free(error);
+
+               goto finished;
+       }
+
+       prv_add_task(task, task->target.device->path);
 
 finished:
 
@@ -978,28 +1055,61 @@ static void prv_device_method_call(GDBusConnection *conn,
                                   gpointer user_data)
 {
        msu_task_t *task;
+       GError *error = NULL;
+       const gchar *client_name;
+       const gchar *device_id;
+       const msu_task_queue_key_t *queue_id;
 
        if (!strcmp(method, MSU_INTERFACE_UPLOAD_TO_ANY)) {
                task = msu_task_upload_to_any_new(invocation, object,
-                                                 parameters);
-               prv_add_task(task);
+                                                 parameters, &error);
        } else if (!strcmp(method, MSU_INTERFACE_CREATE_CONTAINER_IN_ANY)) {
                task = msu_task_create_container_new_generic(invocation,
                                        MSU_TASK_CREATE_CONTAINER_IN_ANY,
-                                       object, parameters);
-               prv_add_task(task);
+                                       object, parameters, &error);
        } else if (!strcmp(method, MSU_INTERFACE_GET_UPLOAD_STATUS)) {
                task = msu_task_get_upload_status_new(invocation, object,
-                                                     parameters);
-               prv_add_task(task);
+                                                     parameters, &error);
        } else if (!strcmp(method, MSU_INTERFACE_GET_UPLOAD_IDS)) {
-               task = msu_task_get_upload_ids_new(invocation, object);
-               prv_add_task(task);
+               task = msu_task_get_upload_ids_new(invocation, object, &error);
        } else if (!strcmp(method, MSU_INTERFACE_CANCEL_UPLOAD)) {
                task = msu_task_cancel_upload_new(invocation, object,
-                                                 parameters);
-               prv_add_task(task);
+                                                 parameters, &error);
+       } else if (!strcmp(method, MSU_INTERFACE_CANCEL)) {
+               task = NULL;
+
+               device_id = prv_get_device_id(object, &error);
+               if (!device_id)
+                       goto on_error;
+
+               client_name = g_dbus_method_invocation_get_sender(invocation);
+
+               queue_id = msu_task_processor_lookup_queue(g_context.processor,
+                                                       client_name, device_id);
+               if (queue_id)
+                       msu_task_processor_cancel_queue(queue_id);
+
+               g_dbus_method_invocation_return_value(invocation, NULL);
+
+               goto finished;
+       } else {
+               goto finished;
        }
+
+on_error:
+
+       if (!task) {
+               g_dbus_method_invocation_return_gerror(invocation, error);
+               g_error_free(error);
+
+               goto finished;
+       }
+
+       prv_add_task(task, task->target.device->path);
+
+finished:
+
+       return;
 }
 
 static void prv_found_media_server(const gchar *path, void *user_data)
@@ -1022,6 +1132,8 @@ static void prv_lost_media_server(const gchar *path, void *user_data)
                                             MSU_INTERFACE_LOST_SERVER,
                                             g_variant_new("(o)", path),
                                             NULL);
+
+       msu_task_processor_remove_queues_for_sink(g_context.processor, path);
 }
 
 static void prv_bus_acquired(GDBusConnection *connection, const gchar *name,
@@ -1061,13 +1173,13 @@ static void prv_name_lost(GDBusConnection *connection, const gchar *name,
 {
        g_context.connection = NULL;
 
-       prv_quit();
+       msu_task_processor_set_quitting(g_context.processor);
 }
 
 static gboolean prv_quit_handler(GIOChannel *source, GIOCondition condition,
                                 gpointer user_data)
 {
-       prv_quit();
+       msu_task_processor_set_quitting(g_context.processor);
        g_context.sig_id = 0;
 
        return FALSE;
@@ -1095,8 +1207,8 @@ static bool prv_init_signal_handler(sigset_t mask)
                goto on_error;
 
        g_context.sig_id = g_io_add_watch(channel, G_IO_IN | G_IO_PRI,
-                                        prv_quit_handler,
-                                        NULL);
+                                         prv_quit_handler,
+                                         NULL);
 
        retval = true;
 
@@ -1156,8 +1268,6 @@ int main(int argc, char *argv[])
                                          prv_bus_acquired, NULL,
                                          prv_name_lost, NULL, NULL);
 
-       g_context.tasks = g_ptr_array_new();
-
        g_context.watchers = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                 g_free, prv_unregister_client);
 
@@ -1178,4 +1288,3 @@ on_error:
 
        return retval;
 }
-
diff --git a/src/media-service-upnp.h b/src/media-service-upnp.h
new file mode 100644 (file)
index 0000000..0372b4d
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * media-service-upnp
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Regis Merlino <regis.merlino@intel.com>
+ *
+ */
+
+#ifndef MSU_MEDIA_SERVICE_UPNP_H__
+#define MSU_MEDIA_SERVICE_UPNP_H__
+
+#include <glib.h>
+
+typedef struct msu_device_t_ msu_device_t;
+
+gboolean msu_media_service_get_object_info(const gchar *object_path,
+                                          gchar **root_path,
+                                          gchar **object_id,
+                                          msu_device_t **device,
+                                          GError **error);
+
+#endif /* MSU_MEDIA_SERVICE_UPNP_H__ */
index ea1369e..4e3c78d 100644 (file)
@@ -135,7 +135,7 @@ static gchar *prv_id_to_object_name(const gchar *id)
        return retval;
 }
 
-gchar *msu_path_from_id(const gchar *root_path, const gcharid)
+gchar *msu_path_from_id(const gchar *root_path, const gchar *id)
 {
        gchar *coded_id;
        gchar *path;
index 11bb1fa..a7c9a09 100644 (file)
@@ -29,6 +29,6 @@ gboolean msu_path_get_non_root_id(const gchar *object_path,
                                  const gchar **slash_before_id);
 gboolean msu_path_get_path_and_id(const gchar *object_path, gchar **root_path,
                                  gchar **id, GError **error);
-gchar *msu_path_from_id(const gchar *root_path, const gcharid);
+gchar *msu_path_from_id(const gchar *root_path, const gchar *id);
 
 #endif
index b7cecdc..b200d2b 100644 (file)
@@ -333,6 +333,41 @@ void msu_prop_maps_new(GHashTable **property_map, GHashTable **filter_map)
        g_hash_table_insert(p_map, "upnp:originalTrackNumber",
                            MSU_INTERFACE_PROP_TRACK_NUMBER);
 
+       /* res@updateCount */
+       prop_t = prv_msu_prop_map_new("res@updateCount",
+                                     MSU_UPNP_MASK_PROP_UPDATE_COUNT,
+                                     TRUE, TRUE, FALSE);
+       g_hash_table_insert(f_map, MSU_INTERFACE_PROP_UPDATE_COUNT,
+                           prop_t);
+       g_hash_table_insert(p_map, "res@updateCount",
+                           MSU_INTERFACE_PROP_UPDATE_COUNT);
+
+       /* upnp:objectUpdateID */
+       prop_t = prv_msu_prop_map_new("upnp:objectUpdateID",
+                                     MSU_UPNP_MASK_PROP_OBJECT_UPDATE_ID,
+                                     TRUE, TRUE, FALSE);
+       g_hash_table_insert(f_map, MSU_INTERFACE_PROP_OBJECT_UPDATE_ID, prop_t);
+       g_hash_table_insert(p_map, "upnp:objectUpdateID",
+                           MSU_INTERFACE_PROP_OBJECT_UPDATE_ID);
+
+       /* upnp:containerUpdateID */
+       prop_t = prv_msu_prop_map_new("upnp:containerUpdateID",
+                                     MSU_UPNP_MASK_PROP_CONTAINER_UPDATE_ID,
+                                     TRUE, TRUE, FALSE);
+       g_hash_table_insert(f_map, MSU_INTERFACE_PROP_CONTAINER_UPDATE_ID,
+                           prop_t);
+       g_hash_table_insert(p_map, "upnp:containerUpdateID",
+                           MSU_INTERFACE_PROP_CONTAINER_UPDATE_ID);
+
+       /* upnp:totalDeletedChildCount */
+       prop_t = prv_msu_prop_map_new("upnp:totalDeletedChildCount",
+                               MSU_UPNP_MASK_PROP_TOTAL_DELETED_CHILD_COUNT,
+                               TRUE, TRUE, FALSE);
+       g_hash_table_insert(f_map, MSU_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT,
+                           prop_t);
+       g_hash_table_insert(p_map, "upnp:totalDeletedChildCount",
+                           MSU_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT);
+
        *filter_map = f_map;
        *property_map = p_map;
 }
@@ -346,24 +381,25 @@ static gchar *prv_compute_upnp_filter(GHashTable *upnp_props)
        str = g_string_new("");
        g_hash_table_iter_init(&iter, upnp_props);
        if (g_hash_table_iter_next(&iter, &key, NULL)) {
-               g_string_append(str, (const gchar *) key);
+               g_string_append(str, (const gchar *)key);
                while (g_hash_table_iter_next(&iter, &key, NULL)) {
                        g_string_append(str, ",");
-                       g_string_append(str, (const gchar *) key);
+                       g_string_append(str, (const gchar *)key);
                }
        }
 
        return g_string_free(str, FALSE);
 }
 
-static guint32 prv_parse_filter_list(GHashTable *filter_map, GVariant *filter,
-                                    gchar **upnp_filter)
+static msu_upnp_prop_mask prv_parse_filter_list(GHashTable *filter_map,
+                                               GVariant *filter,
+                                               gchar **upnp_filter)
 {
        GVariantIter viter;
        const gchar *prop;
        msu_prop_map_t *prop_map;
        GHashTable *upnp_props;
-       guint32 mask = 0;
+       msu_upnp_prop_mask mask = 0;
 
        upnp_props = g_hash_table_new_full(g_str_hash, g_str_equal,
                                           NULL, NULL);
@@ -389,12 +425,13 @@ static guint32 prv_parse_filter_list(GHashTable *filter_map, GVariant *filter,
        return mask;
 }
 
-guint32 msu_props_parse_filter(GHashTable *filter_map, GVariant *filter,
-                              gchar **upnp_filter)
+msu_upnp_prop_mask msu_props_parse_filter(GHashTable *filter_map,
+                                         GVariant *filter,
+                                         gchar **upnp_filter)
 {
        gchar *str;
        gboolean parse_filter = TRUE;
-       guint32 mask;
+       msu_upnp_prop_mask mask;
 
        if (g_variant_n_children(filter) == 1) {
                g_variant_get_child(filter, 0, "&s", &str);
@@ -405,7 +442,7 @@ guint32 msu_props_parse_filter(GHashTable *filter_map, GVariant *filter,
        if (parse_filter) {
                mask = prv_parse_filter_list(filter_map, filter, upnp_filter);
        } else {
-               mask = 0xffffffff;
+               mask = MSU_UPNP_MASK_ALL_PROPS;
                *upnp_filter = g_strdup("*");
        }
 
@@ -414,7 +451,8 @@ guint32 msu_props_parse_filter(GHashTable *filter_map, GVariant *filter,
 
 gboolean msu_props_parse_update_filter(GHashTable *filter_map,
                                       GVariant *to_add_update,
-                                      GVariant *to_delete, guint32 *mask,
+                                      GVariant *to_delete,
+                                      msu_upnp_prop_mask *mask,
                                       gchar **upnp_filter)
 {
        GVariantIter viter;
@@ -558,8 +596,8 @@ static void prv_add_int64_prop(GVariantBuilder *vb, const gchar *key,
 
 static void prv_add_list_dlna_str(gpointer data, gpointer user_data)
 {
-       GVariantBuilder *vb = (GVariantBuilder *) user_data;
-       gchar *cap_str = (gchar *) data;
+       GVariantBuilder *vb = (GVariantBuilder *)user_data;
+       gchar *cap_str = (gchar *)data;
        gchar *str;
        int value = 0;
 
@@ -578,7 +616,7 @@ static void prv_add_list_dlna_str(gpointer data, gpointer user_data)
        prv_add_uint_prop(vb, cap_str, value);
 }
 
-static GVariant *prv_add_list_dlna_prop(GListlist)
+static GVariant *prv_add_list_dlna_prop(GList *list)
 {
        GVariantBuilder vb;
 
@@ -591,7 +629,7 @@ static GVariant *prv_add_list_dlna_prop(GList* list)
 
 static void prv_add_list_artists_str(gpointer data, gpointer user_data)
 {
-       GVariantBuilder *vb = (GVariantBuilder *) user_data;
+       GVariantBuilder *vb = (GVariantBuilder *)user_data;
        GUPnPDIDLLiteContributor *contributor = data;
        const char *str;
 
@@ -610,7 +648,7 @@ static GVariant *prv_get_artists_prop(GList *list)
 }
 
 void msu_props_add_device(GUPnPDeviceInfo *proxy,
-                         msu_device_t *device,
+                         const msu_device_t *device,
                          GVariantBuilder *vb)
 {
        gchar *str;
@@ -668,7 +706,7 @@ void msu_props_add_device(GUPnPDeviceInfo *proxy,
        g_free(str);
 
        list = gupnp_device_info_list_dlna_capabilities(proxy);
-       if (list != NULL){
+       if (list != NULL) {
                dlna_caps = prv_add_list_dlna_prop(list);
                g_variant_builder_add(vb, "{sv}",
                                      MSU_INTERFACE_PROP_SV_DLNA_CAPABILITIES,
@@ -687,7 +725,8 @@ void msu_props_add_device(GUPnPDeviceInfo *proxy,
                                      device->sort_caps);
 
        if (device->sort_ext_caps != NULL)
-               g_variant_builder_add(vb, "{sv}",
+               g_variant_builder_add(
+                               vb, "{sv}",
                                MSU_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES,
                                device->sort_ext_caps);
 
@@ -698,7 +737,7 @@ void msu_props_add_device(GUPnPDeviceInfo *proxy,
 }
 
 GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy,
-                                   msu_device_t *device,
+                                   const msu_device_t *device,
                                    const gchar *prop)
 {
        GVariant *dlna_caps = NULL;
@@ -747,7 +786,7 @@ GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy,
                str = copy;
        } else if (!strcmp(MSU_INTERFACE_PROP_SV_DLNA_CAPABILITIES, prop)) {
                list = gupnp_device_info_list_dlna_capabilities(proxy);
-               if (list != NULL){
+               if (list != NULL) {
                        dlna_caps = prv_add_list_dlna_prop(list);
                        g_list_free_full(list, g_free);
                        retval = g_variant_ref_sink(dlna_caps);
@@ -758,7 +797,7 @@ GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy,
 #endif
                }
        } else if (!strcmp(MSU_INTERFACE_PROP_SV_SEARCH_CAPABILITIES, prop)) {
-               if (device->search_caps != NULL){
+               if (device->search_caps != NULL) {
                        retval = g_variant_ref(device->search_caps);
 
 #if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
@@ -767,7 +806,7 @@ GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy,
 #endif
                }
        } else if (!strcmp(MSU_INTERFACE_PROP_SV_SORT_CAPABILITIES, prop)) {
-               if (device->sort_caps != NULL){
+               if (device->sort_caps != NULL) {
                        retval = g_variant_ref(device->sort_caps);
 
 #if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
@@ -776,7 +815,7 @@ GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy,
 #endif
                }
        } else if (!strcmp(MSU_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES, prop)) {
-               if (device->sort_ext_caps != NULL){
+               if (device->sort_ext_caps != NULL) {
                        retval = g_variant_ref(device->sort_ext_caps);
 
 #if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
@@ -785,7 +824,7 @@ GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy,
 #endif
                }
        } else if (!strcmp(MSU_INTERFACE_PROP_SV_FEATURE_LIST, prop)) {
-               if (device->feature_list != NULL){
+               if (device->feature_list != NULL) {
                        retval = g_variant_ref(device->feature_list);
 
 #if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
@@ -795,7 +834,7 @@ GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy,
                }
        }
 
-       if (!retval){
+       if (!retval) {
                if (str) {
                        MSU_LOG_DEBUG("Prop %s = %s", prop, str);
 
@@ -868,8 +907,10 @@ static GUPnPDIDLLiteResource *prv_get_matching_resource
                        retval = prv_match_resource(res, pi_str_array);
                        if (!retval)
                                g_object_unref(res);
-               } else
+               } else {
                        g_object_unref(res);
+               }
+
                ptr = ptr->next;
        }
 
@@ -882,12 +923,13 @@ static GUPnPDIDLLiteResource *prv_get_matching_resource
 
 static void prv_parse_resources(GVariantBuilder *item_vb,
                                GUPnPDIDLLiteResource *res,
-                               guint32 filter_mask)
+                               msu_upnp_prop_mask filter_mask)
 {
        GUPnPProtocolInfo *protocol_info;
        int int_val;
        gint64 int64_val;
        const char *str_val;
+       guint uint_val;
 
        if (filter_mask & MSU_UPNP_MASK_PROP_SIZE) {
                int64_val = gupnp_didl_lite_resource_get_size64(res);
@@ -932,6 +974,12 @@ static void prv_parse_resources(GVariantBuilder *item_vb,
                                 int_val);
        }
 
+       if (filter_mask & MSU_UPNP_MASK_PROP_UPDATE_COUNT) {
+               uint_val = gupnp_didl_lite_resource_get_update_count(res);
+               prv_add_uint_prop(item_vb, MSU_INTERFACE_PROP_UPDATE_COUNT,
+                                 uint_val);
+       }
+
        protocol_info = gupnp_didl_lite_resource_get_protocol_info(res);
 
        if (filter_mask & MSU_UPNP_MASK_PROP_DLNA_PROFILE) {
@@ -1114,7 +1162,7 @@ gboolean msu_props_add_object(GVariantBuilder *item_vb,
                              GUPnPDIDLLiteObject *object,
                              const char *root_path,
                              const gchar *parent_path,
-                             guint32 filter_mask)
+                             msu_upnp_prop_mask filter_mask)
 {
        gchar *path = NULL;
        const char *id;
@@ -1125,6 +1173,7 @@ gboolean msu_props_add_object(GVariantBuilder *item_vb,
        gboolean retval = FALSE;
        gboolean rest;
        GUPnPOCMFlags flags;
+       guint uint_val;
 
        id = gupnp_didl_lite_object_get_id(object);
        if (!id)
@@ -1170,6 +1219,12 @@ gboolean msu_props_add_object(GVariantBuilder *item_vb,
                                     prv_props_get_dlna_managed_dict(flags));
        }
 
+       if (filter_mask & MSU_UPNP_MASK_PROP_OBJECT_UPDATE_ID) {
+               uint_val = gupnp_didl_lite_object_get_update_id(object);
+               prv_add_uint_prop(item_vb, MSU_INTERFACE_PROP_OBJECT_UPDATE_ID,
+                                 uint_val);
+       }
+
        retval = TRUE;
 
 on_error:
@@ -1181,11 +1236,12 @@ on_error:
 
 void msu_props_add_container(GVariantBuilder *item_vb,
                             GUPnPDIDLLiteContainer *object,
-                            guint32 filter_mask,
+                            msu_upnp_prop_mask filter_mask,
                             gboolean *have_child_count)
 {
        int child_count;
        gboolean searchable;
+       guint uint_val;
 
        *have_child_count = FALSE;
        if (filter_mask & MSU_UPNP_MASK_PROP_CHILD_COUNT) {
@@ -1208,10 +1264,26 @@ void msu_props_add_container(GVariantBuilder *item_vb,
                prv_add_variant_prop(item_vb,
                                     MSU_INTERFACE_PROP_CREATE_CLASSES,
                                     prv_compute_create_classes(object));
+
+       if (filter_mask & MSU_UPNP_MASK_PROP_CONTAINER_UPDATE_ID) {
+               uint_val = gupnp_didl_lite_container_get_container_update_id(
+                                                                       object);
+               prv_add_uint_prop(item_vb,
+                                 MSU_INTERFACE_PROP_CONTAINER_UPDATE_ID,
+                                 uint_val);
+       }
+
+       if (filter_mask & MSU_UPNP_MASK_PROP_TOTAL_DELETED_CHILD_COUNT) {
+               uint_val =
+               gupnp_didl_lite_container_get_total_deleted_child_count(object);
+               prv_add_uint_prop(item_vb,
+                                 MSU_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT,
+                                 uint_val);
+       }
 }
 
 static GVariant *prv_compute_resources(GUPnPDIDLLiteObject *object,
-                                      guint32 filter_mask)
+                                      msu_upnp_prop_mask filter_mask)
 {
        GUPnPDIDLLiteResource *res = NULL;
        GList *resources;
@@ -1257,7 +1329,7 @@ static GVariant *prv_compute_resources(GUPnPDIDLLiteObject *object,
 
 static void prv_add_resources(GVariantBuilder *item_vb,
                              GUPnPDIDLLiteObject *object,
-                             guint32 filter_mask)
+                             msu_upnp_prop_mask filter_mask)
 {
        GVariant *val;
 
@@ -1269,7 +1341,7 @@ static void prv_add_resources(GVariantBuilder *item_vb,
 void msu_props_add_item(GVariantBuilder *item_vb,
                        GUPnPDIDLLiteObject *object,
                        const gchar *root_path,
-                       guint32 filter_mask,
+                       msu_upnp_prop_mask filter_mask,
                        const gchar *protocol_info)
 {
        int track_number;
@@ -1320,7 +1392,7 @@ void msu_props_add_item(GVariantBuilder *item_vb,
                if (str_val != NULL) {
                        path = msu_path_from_id(root_path, str_val);
                        prv_add_path_prop(item_vb, MSU_INTERFACE_PROP_REFPATH,
-                                           path);
+                                         path);
                        g_free(path);
                }
        }
@@ -1344,7 +1416,7 @@ void msu_props_add_item(GVariantBuilder *item_vb,
 
 void msu_props_add_resource(GVariantBuilder *item_vb,
                            GUPnPDIDLLiteObject *object,
-                           guint32 filter_mask,
+                           msu_upnp_prop_mask filter_mask,
                            const gchar *protocol_info)
 {
        GUPnPDIDLLiteResource *res;
@@ -1452,6 +1524,7 @@ GVariant *msu_props_get_object_prop(const gchar *prop, const gchar *root_path,
        gboolean rest;
        GVariant *retval = NULL;
        GUPnPOCMFlags dlna_managed;
+       guint uint_val;
 
        if (!strcmp(prop, MSU_INTERFACE_PROP_PARENT)) {
                id = gupnp_didl_lite_object_get_parent_id(object);
@@ -1520,6 +1593,12 @@ GVariant *msu_props_get_object_prop(const gchar *prop, const gchar *root_path,
 
                retval = g_variant_ref_sink(
                                prv_props_get_dlna_managed_dict(dlna_managed));
+       } else if (!strcmp(prop, MSU_INTERFACE_PROP_OBJECT_UPDATE_ID)) {
+               uint_val = gupnp_didl_lite_object_get_update_id(object);
+
+               MSU_LOG_DEBUG("Prop %s = %u", prop, uint_val);
+
+               retval = g_variant_ref_sink(g_variant_new_uint32(uint_val));
        }
 
 on_error:
@@ -1616,7 +1695,7 @@ GVariant *msu_props_get_item_prop(const gchar *prop, const gchar *root_path,
                g_free(path);
        } else if (!strcmp(prop, MSU_INTERFACE_PROP_RESOURCES)) {
                retval = g_variant_ref_sink(
-                       prv_compute_resources(object, 0xffffffff));
+                       prv_compute_resources(object, MSU_UPNP_MASK_ALL_PROPS));
        } else {
                res = prv_get_matching_resource(object, protocol_info);
                if (!res)
@@ -1639,13 +1718,14 @@ GVariant *msu_props_get_container_prop(const gchar *prop,
        gboolean searchable;
        GUPnPDIDLLiteContainer *container;
        GVariant *retval = NULL;
+       guint uint_val;
 #if MSU_LOG_LEVEL & MSU_LOG_LEVEL_DEBUG
        gchar *create_classes;
 #endif
        if (!GUPNP_IS_DIDL_LITE_CONTAINER(object))
                goto on_error;
 
-       container = (GUPnPDIDLLiteContainer *) object;
+       container = (GUPnPDIDLLiteContainer *)object;
        if (!strcmp(prop, MSU_INTERFACE_PROP_CHILD_COUNT)) {
                child_count =
                        gupnp_didl_lite_container_get_child_count(container);
@@ -1672,6 +1752,22 @@ GVariant *msu_props_get_container_prop(const gchar *prop,
                MSU_LOG_DEBUG("Prop %s = %s", prop, create_classes);
                g_free(create_classes);
 #endif
+       } else if (!strcmp(prop, MSU_INTERFACE_PROP_CONTAINER_UPDATE_ID)) {
+               uint_val = gupnp_didl_lite_container_get_container_update_id(
+                                                               container);
+
+               MSU_LOG_DEBUG("Prop %s = %u", prop, uint_val);
+
+               retval = g_variant_ref_sink(g_variant_new_uint32(uint_val));
+       } else if (!strcmp(prop,
+                               MSU_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT)) {
+               uint_val =
+                       gupnp_didl_lite_container_get_total_deleted_child_count(
+                                                               container);
+
+               MSU_LOG_DEBUG("Prop %s = %u", prop, uint_val);
+
+               retval = g_variant_ref_sink(g_variant_new_uint32(uint_val));
        }
 
 on_error:
index 3e9e063..ecfed34 100644 (file)
 #include <libgupnp-av/gupnp-av.h>
 #include "async.h"
 
-enum msu_upnp_prop_mask_ {
-       MSU_UPNP_MASK_PROP_PARENT = 1,
-       MSU_UPNP_MASK_PROP_TYPE = 1 << 1,
-       MSU_UPNP_MASK_PROP_PATH = 1 << 2,
-       MSU_UPNP_MASK_PROP_DISPLAY_NAME = 1 << 3,
-       MSU_UPNP_MASK_PROP_CHILD_COUNT = 1 << 4,
-       MSU_UPNP_MASK_PROP_SEARCHABLE = 1 << 5,
-       MSU_UPNP_MASK_PROP_URLS = 1 << 6,
-       MSU_UPNP_MASK_PROP_MIME_TYPE = 1 << 7,
-       MSU_UPNP_MASK_PROP_ARTIST = 1 << 8,
-       MSU_UPNP_MASK_PROP_ALBUM = 1 << 9,
-       MSU_UPNP_MASK_PROP_DATE = 1 << 10,
-       MSU_UPNP_MASK_PROP_GENRE = 1 << 11,
-       MSU_UPNP_MASK_PROP_DLNA_PROFILE = 1 << 12,
-       MSU_UPNP_MASK_PROP_TRACK_NUMBER = 1 << 13,
-       MSU_UPNP_MASK_PROP_SIZE = 1 << 14,
-       MSU_UPNP_MASK_PROP_DURATION = 1 << 15,
-       MSU_UPNP_MASK_PROP_BITRATE = 1 << 16,
-       MSU_UPNP_MASK_PROP_SAMPLE_RATE = 1 << 17,
-       MSU_UPNP_MASK_PROP_BITS_PER_SAMPLE = 1 << 18,
-       MSU_UPNP_MASK_PROP_WIDTH = 1 << 19,
-       MSU_UPNP_MASK_PROP_HEIGHT = 1 << 20,
-       MSU_UPNP_MASK_PROP_COLOR_DEPTH = 1 << 21,
-       MSU_UPNP_MASK_PROP_ALBUM_ART_URL = 1 << 22,
-       MSU_UPNP_MASK_PROP_RESOURCES = 1 << 23,
-       MSU_UPNP_MASK_PROP_URL = 1 << 24,
-       MSU_UPNP_MASK_PROP_REFPATH = 1 << 25,
-       MSU_UPNP_MASK_PROP_RESTRICTED = 1 << 26,
-       MSU_UPNP_MASK_PROP_DLNA_MANAGED = 1 << 27,
-       MSU_UPNP_MASK_PROP_CREATOR = 1 << 28,
-       MSU_UPNP_MASK_PROP_ARTISTS = 1 << 29,
-       MSU_UPNP_MASK_PROP_CREATE_CLASSES = 1 << 30
-};
-typedef enum msu_upnp_prop_mask_ msu_upnp_prop_mask;
+#define MSU_UPNP_MASK_PROP_PARENT                      (1LL << 0)
+#define MSU_UPNP_MASK_PROP_TYPE                                (1LL << 1)
+#define MSU_UPNP_MASK_PROP_PATH                                (1LL << 2)
+#define MSU_UPNP_MASK_PROP_DISPLAY_NAME                        (1LL << 3)
+#define MSU_UPNP_MASK_PROP_CHILD_COUNT                 (1LL << 4)
+#define MSU_UPNP_MASK_PROP_SEARCHABLE                  (1LL << 5)
+#define MSU_UPNP_MASK_PROP_URLS                                (1LL << 6)
+#define MSU_UPNP_MASK_PROP_MIME_TYPE                   (1LL << 7)
+#define MSU_UPNP_MASK_PROP_ARTIST                      (1LL << 8)
+#define MSU_UPNP_MASK_PROP_ALBUM                       (1LL << 9)
+#define MSU_UPNP_MASK_PROP_DATE                                (1LL << 10)
+#define MSU_UPNP_MASK_PROP_GENRE                       (1LL << 11)
+#define MSU_UPNP_MASK_PROP_DLNA_PROFILE                        (1LL << 12)
+#define MSU_UPNP_MASK_PROP_TRACK_NUMBER                        (1LL << 13)
+#define MSU_UPNP_MASK_PROP_SIZE                                (1LL << 14)
+#define MSU_UPNP_MASK_PROP_DURATION                    (1LL << 15)
+#define MSU_UPNP_MASK_PROP_BITRATE                     (1LL << 16)
+#define MSU_UPNP_MASK_PROP_SAMPLE_RATE                 (1LL << 17)
+#define MSU_UPNP_MASK_PROP_BITS_PER_SAMPLE             (1LL << 18)
+#define MSU_UPNP_MASK_PROP_WIDTH                       (1LL << 19)
+#define MSU_UPNP_MASK_PROP_HEIGHT                      (1LL << 20)
+#define MSU_UPNP_MASK_PROP_COLOR_DEPTH                 (1LL << 21)
+#define MSU_UPNP_MASK_PROP_ALBUM_ART_URL               (1LL << 22)
+#define MSU_UPNP_MASK_PROP_RESOURCES                   (1LL << 23)
+#define MSU_UPNP_MASK_PROP_URL                         (1LL << 24)
+#define MSU_UPNP_MASK_PROP_REFPATH                     (1LL << 25)
+#define MSU_UPNP_MASK_PROP_RESTRICTED                  (1LL << 26)
+#define MSU_UPNP_MASK_PROP_DLNA_MANAGED                        (1LL << 27)
+#define MSU_UPNP_MASK_PROP_CREATOR                     (1LL << 28)
+#define MSU_UPNP_MASK_PROP_ARTISTS                     (1LL << 29)
+#define MSU_UPNP_MASK_PROP_CREATE_CLASSES              (1LL << 30)
+#define MSU_UPNP_MASK_PROP_OBJECT_UPDATE_ID            (1LL << 31)
+#define MSU_UPNP_MASK_PROP_UPDATE_COUNT                        (1LL << 32)
+#define MSU_UPNP_MASK_PROP_CONTAINER_UPDATE_ID         (1LL << 33)
+#define MSU_UPNP_MASK_PROP_TOTAL_DELETED_CHILD_COUNT   (1LL << 34)
+
+#define MSU_UPNP_MASK_ALL_PROPS 0xffffffffffffffff
 
 typedef struct msu_prop_map_t_ msu_prop_map_t;
 struct msu_prop_map_t_ {
@@ -72,34 +75,36 @@ struct msu_prop_map_t_ {
 
 void msu_prop_maps_new(GHashTable **property_map, GHashTable **filter_map);
 
-guint32 msu_props_parse_filter(GHashTable *filter_map, GVariant *filter,
-                              gchar **upnp_filter);
+msu_upnp_prop_mask msu_props_parse_filter(GHashTable *filter_map,
+                                         GVariant *filter,
+                                         gchar **upnp_filter);
 
 gboolean msu_props_parse_update_filter(GHashTable *filter_map,
                                       GVariant *to_add_update,
-                                      GVariant *to_delete, guint32 *mask,
+                                      GVariant *to_delete,
+                                      msu_upnp_prop_mask *mask,
                                       gchar **upnp_filter);
 
 void msu_props_add_device(GUPnPDeviceInfo *proxy,
-                         msu_device_t *device,
+                         const msu_device_t *device,
                          GVariantBuilder *vb);
 
 GVariant *msu_props_get_device_prop(GUPnPDeviceInfo *proxy,
-                                   msu_device_t *device,
+                                   const msu_device_t *device,
                                    const gchar *prop);
 
 gboolean msu_props_add_object(GVariantBuilder *item_vb,
                              GUPnPDIDLLiteObject *object,
                              const char *root_path,
                              const gchar *parent_path,
-                             guint32 filter_mask);
+                             msu_upnp_prop_mask filter_mask);
 
 GVariant *msu_props_get_object_prop(const gchar *prop, const gchar *root_path,
                                    GUPnPDIDLLiteObject *object);
 
 void msu_props_add_container(GVariantBuilder *item_vb,
                             GUPnPDIDLLiteContainer *object,
-                            guint32 filter_mask,
+                            msu_upnp_prop_mask filter_mask,
                             gboolean *have_child_count);
 
 void msu_props_add_child_count(GVariantBuilder *item_vb, gint value);
@@ -109,13 +114,13 @@ GVariant *msu_props_get_container_prop(const gchar *prop,
 
 void msu_props_add_resource(GVariantBuilder *item_vb,
                            GUPnPDIDLLiteObject *object,
-                           guint32 filter_mask,
+                           msu_upnp_prop_mask filter_mask,
                            const gchar *protocol_info);
 
 void msu_props_add_item(GVariantBuilder *item_vb,
                        GUPnPDIDLLiteObject *object,
                        const gchar *root_path,
-                       guint32 filter_mask,
+                       msu_upnp_prop_mask filter_mask,
                        const gchar *protocol_info);
 
 GVariant *msu_props_get_item_prop(const gchar *prop, const gchar *root_path,
index 0d546bb..069755f 100644 (file)
@@ -47,8 +47,8 @@ gchar *msu_search_translate_search_string(GHashTable *filter_map,
        gchar *root_path;
        gchar *id;
 
-       reg = g_regex_new("(\\w+)\\s+(=|!=|<|<=|>|>|contains|doesNotContain|"
-                         "derivedfrom|exists)\\s+"
+       reg = g_regex_new("(\\w+)\\s+(=|!=|<|<=|>|>|contains|doesNotContain|"\
+                         "derivedfrom|exists)\\s+"\
                          "(\"[^\"]*\"|true|false)",
                          0, 0, NULL);
        str = g_string_new("");
index e0bd20d..c84a4bd 100644 (file)
@@ -133,7 +133,7 @@ static GKeyFile *prv_msu_settings_load_keyfile(const gchar *filepath)
        keyfile = g_key_file_new();
 
        if (!g_key_file_load_from_file(keyfile, filepath, G_KEY_FILE_NONE,
-                                       NULL)) {
+                                      NULL)) {
                g_key_file_free(keyfile);
                keyfile = NULL;
        }
@@ -161,9 +161,9 @@ static int prv_msu_settings_to_log_level(gint *int_list, gsize length)
        for (i = 0; i < length; ++i) {
                level = int_list[i];
 
-               if (level > 0 && level < 7)
+               if (level > 0 && level < 7) {
                        log_level_value |= log_level_array[level];
-               else if ((level == 0) || (level == 7) || (level == 8)) {
+               else if ((level == 0) || (level == 7) || (level == 8)) {
                        log_level_value = log_level_array[level];
                        break;
                }
@@ -202,9 +202,9 @@ static void prv_msu_settings_read_keys(msu_settings_context_t *settings)
                                                MSU_SETTINGS_KEY_NEVER_QUIT,
                                                &error);
 
-       if (error == NULL)
+       if (error == NULL) {
                settings->never_quit = b_val;
-       else {
+       else {
                g_error_free(error);
                error = NULL;
        }
@@ -213,9 +213,9 @@ static void prv_msu_settings_read_keys(msu_settings_context_t *settings)
                                                  MSU_SETTINGS_KEY_LOG_TYPE,
                                                  &error);
 
-       if (error == NULL)
+       if (error == NULL) {
                settings->log_type = prv_msu_settings_to_log_type(int_val);
-       else {
+       else {
                g_error_free(error);
                error = NULL;
        }
@@ -223,13 +223,13 @@ static void prv_msu_settings_read_keys(msu_settings_context_t *settings)
        g_key_file_set_list_separator(keyfile, ',');
 
        int_star = g_key_file_get_integer_list(keyfile, MSU_SETTINGS_GROUP_LOG,
-                                                  MSU_SETTINGS_KEY_LOG_LEVEL,
-                                                  &length,
-                                                  &error);
+                                              MSU_SETTINGS_KEY_LOG_LEVEL,
+                                              &length,
+                                              &error);
 
        if (error == NULL) {
                settings->log_level = prv_msu_settings_to_log_level(int_star,
-                                                                    length);
+                                                                   length);
                g_free(int_star);
        } else {
                g_error_free(error);
@@ -291,7 +291,7 @@ static void prv_msu_settings_reload(msu_settings_context_t *settings)
 
 static gboolean prv_msu_settings_monitor_timout_cb(gpointer user_data)
 {
-       msu_settings_context_t *data = (msu_settings_context_t *) user_data;
+       msu_settings_context_t *data = (msu_settings_context_t *)user_data;
 
        MSU_LOG_INFO("Change in local settings file: Reload");
 
@@ -307,7 +307,7 @@ static void prv_msu_settings_monitor_keyfile_cb(GFileMonitor *monitor,
                                                GFileMonitorEvent event_type,
                                                gpointer user_data)
 {
-       msu_settings_context_t *data = (msu_settings_context_t *) user_data;
+       msu_settings_context_t *data = (msu_settings_context_t *)user_data;
 
        switch (event_type) {
        case G_FILE_MONITOR_EVENT_CHANGED:
diff --git a/src/task-atom.h b/src/task-atom.h
new file mode 100644 (file)
index 0000000..dcfb577
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * media-service-upnp
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Regis Merlino <regis.merlino@intel.com>
+ *
+ */
+
+#ifndef MSU_TASK_ATOM_H__
+#define MSU_TASK_ATOM_H__
+
+typedef struct msu_task_queue_key_t_ msu_task_queue_key_t;
+
+typedef struct msu_task_atom_t_ msu_task_atom_t;
+struct msu_task_atom_t_ {
+       const msu_task_queue_key_t *queue_id;
+};
+
+#endif /* MSU_TASK_ATOM_H__ */
diff --git a/src/task-processor.c b/src/task-processor.c
new file mode 100644 (file)
index 0000000..24ac26c
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * media-service-upnp
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Regis Merlino <regis.merlino@intel.com>
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "task-processor.h"
+#include "log.h"
+
+struct msu_task_processor_t_ {
+       GHashTable *task_queues;
+       guint running_tasks;
+       gboolean quitting;
+       GSourceFunc on_quit_cb;
+};
+
+typedef struct msu_task_queue_t_ msu_task_queue_t;
+struct msu_task_queue_t_ {
+       GPtrArray *tasks;
+       msu_task_process_cb_t task_process_cb;
+       msu_task_cancel_cb_t task_cancel_cb;
+       msu_task_delete_cb_t task_delete_cb;
+       GCancellable *cancellable;
+       msu_task_atom_t *current_task;
+       guint idle_id;
+       gboolean defer_remove;
+       guint32 flags;
+};
+
+struct msu_task_queue_key_t_ {
+       msu_task_processor_t *processor;
+       gchar *source;
+       gchar *sink;
+};
+
+static guint prv_task_queue_key_hash_cb(gconstpointer ptr)
+{
+       const msu_task_queue_key_t *queue_key = ptr;
+       guint hash;
+
+       hash = g_str_hash(queue_key->source);
+       hash ^= g_str_hash(queue_key->sink);
+
+       return hash;
+}
+
+static gboolean prv_task_queue_key_equal_cb(gconstpointer ptr1,
+                                           gconstpointer ptr2)
+{
+       const msu_task_queue_key_t *queue_key1 = ptr1;
+       const msu_task_queue_key_t *queue_key2 = ptr2;
+
+       return !strcmp(queue_key1->source, queue_key2->source) &&
+               !strcmp(queue_key1->sink, queue_key2->sink);
+}
+
+static void prv_task_queue_key_free_cb(gpointer ptr)
+{
+       msu_task_queue_key_t *queue_key = ptr;
+
+       g_free(queue_key->source);
+       g_free(queue_key->sink);
+       g_free(queue_key);
+}
+
+static void prv_task_free_cb(gpointer data, gpointer user_data)
+{
+       msu_task_queue_t *task_queue = user_data;
+
+       task_queue->task_delete_cb(data);
+}
+
+static void prv_task_queue_free_cb(gpointer data)
+{
+       msu_task_queue_t *task_queue = data;
+
+       MSU_LOG_DEBUG("Enter");
+
+       g_ptr_array_foreach(task_queue->tasks, prv_task_free_cb, task_queue);
+       g_ptr_array_unref(task_queue->tasks);
+       if (task_queue->cancellable)
+               g_object_unref(task_queue->cancellable);
+       g_free(task_queue);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+msu_task_processor_t *msu_task_processor_new(GSourceFunc on_quit_cb)
+{
+       msu_task_processor_t *processor;
+
+       MSU_LOG_DEBUG("Enter");
+
+       processor = g_malloc(sizeof(*processor));
+
+       processor->task_queues = g_hash_table_new_full(
+                                               prv_task_queue_key_hash_cb,
+                                               prv_task_queue_key_equal_cb,
+                                               prv_task_queue_key_free_cb,
+                                               prv_task_queue_free_cb);
+       processor->running_tasks = 0;
+       processor->quitting = FALSE;
+       processor->on_quit_cb = on_quit_cb;
+
+       MSU_LOG_DEBUG("Exit");
+
+       return processor;
+}
+
+void msu_task_processor_free(msu_task_processor_t *processor)
+{
+       MSU_LOG_DEBUG("Enter");
+
+       g_hash_table_unref(processor->task_queues);
+       g_free(processor);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+const msu_task_queue_key_t *msu_task_processor_add_queue(
+                                       msu_task_processor_t *processor,
+                                       const gchar *source,
+                                       const gchar *sink,
+                                       guint32 flags,
+                                       msu_task_process_cb_t task_process_cb,
+                                       msu_task_cancel_cb_t task_cancel_cb,
+                                       msu_task_delete_cb_t task_delete_cb)
+{
+       msu_task_queue_t *queue;
+       msu_task_queue_key_t *key;
+
+       MSU_LOG_DEBUG("Enter - queue <%s,%s>", source, sink);
+
+       key = g_malloc(sizeof(*key));
+       key->processor = processor;
+       key->source = g_strdup(source);
+       key->sink = g_strdup(sink);
+
+       queue = g_malloc(sizeof(*queue));
+       queue->task_process_cb = task_process_cb;
+       queue->task_cancel_cb = task_cancel_cb;
+       queue->task_delete_cb = task_delete_cb;
+       queue->cancellable = NULL;
+       queue->current_task = NULL;
+       queue->idle_id = 0;
+       queue->tasks = g_ptr_array_new();
+       queue->flags = flags;
+       queue->defer_remove = FALSE;
+
+       g_hash_table_insert(processor->task_queues, key, queue);
+
+       MSU_LOG_DEBUG("Exit");
+
+       return key;
+}
+
+static void prv_task_cancel_and_free_cb(gpointer data, gpointer user_data)
+{
+       msu_task_queue_t *task_queue = user_data;
+
+       task_queue->task_cancel_cb(data);
+       task_queue->task_delete_cb(data);
+}
+
+static void prv_task_queue_cancel(msu_task_queue_t *task_queue)
+{
+       if (task_queue->current_task && task_queue->cancellable) {
+               g_cancellable_cancel(task_queue->cancellable);
+               g_object_unref(task_queue->cancellable);
+               task_queue->cancellable = NULL;
+
+               g_ptr_array_remove(task_queue->tasks, task_queue->current_task);
+
+               task_queue->task_cancel_cb(task_queue->current_task);
+       }
+
+       if (task_queue->idle_id) {
+               (void) g_source_remove(task_queue->idle_id);
+               task_queue->idle_id = 0;
+       }
+
+       g_ptr_array_foreach(task_queue->tasks, prv_task_cancel_and_free_cb,
+                           task_queue);
+       g_ptr_array_set_size(task_queue->tasks, 0);
+}
+
+static void prv_task_queue_cancel_cb(gpointer key, gpointer value,
+                                    gpointer user_data)
+{
+       msu_task_queue_t *task_queue = value;
+
+       prv_task_queue_cancel(task_queue);
+}
+
+static void prv_cancel_all_queues(msu_task_processor_t *processor)
+{
+       MSU_LOG_DEBUG("Enter");
+
+       g_hash_table_foreach(processor->task_queues, prv_task_queue_cancel_cb,
+                            NULL);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+void msu_task_processor_set_quitting(msu_task_processor_t *processor)
+{
+       MSU_LOG_DEBUG("Enter");
+
+       processor->quitting = TRUE;
+
+       if (processor->running_tasks > 0)
+               prv_cancel_all_queues(processor);
+       else
+               g_idle_add(processor->on_quit_cb, NULL);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+void msu_task_processor_cancel_queue(const msu_task_queue_key_t *queue_id)
+{
+       msu_task_queue_t *queue;
+
+       MSU_LOG_DEBUG("Cancel queue <%s,%s>", queue_id->source, queue_id->sink);
+
+       queue = g_hash_table_lookup(queue_id->processor->task_queues,
+                                   queue_id);
+       prv_task_queue_cancel(queue);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+static void prv_free_queue_for_source(gpointer key, gpointer value,
+                                     gpointer user_data)
+{
+       msu_task_queue_key_t *queue_key = key;
+       msu_task_queue_t *queue = value;
+       const gchar *source = user_data;
+
+       if (!strcmp(source, queue_key->source) && !queue->defer_remove) {
+               queue->defer_remove = (queue->cancellable != NULL);
+
+               prv_task_queue_cancel(queue);
+
+               if (!queue->defer_remove)
+                       g_hash_table_remove(queue_key->processor->task_queues,
+                                           queue_key);
+       }
+}
+
+void msu_task_processor_remove_queues_for_source(
+                                               msu_task_processor_t *processor,
+                                               const gchar *source)
+{
+       MSU_LOG_DEBUG("Enter - Source <%s>", source);
+
+       g_hash_table_foreach(processor->task_queues, prv_free_queue_for_source,
+                            (gpointer)source);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+static void prv_free_queue_for_sink(gpointer key, gpointer value,
+                                   gpointer user_data)
+{
+       msu_task_queue_key_t *queue_key = key;
+       msu_task_queue_t *queue = value;
+       const gchar *sink = user_data;
+
+       if (!strcmp(sink, queue_key->sink) && !queue->defer_remove) {
+               queue->defer_remove = (queue->cancellable != NULL);
+
+               prv_task_queue_cancel(queue);
+
+               if (!queue->defer_remove)
+                       g_hash_table_remove(queue_key->processor->task_queues,
+                                           queue_key);
+       }
+}
+
+void msu_task_processor_remove_queues_for_sink(msu_task_processor_t *processor,
+                                              const gchar *sink)
+{
+       MSU_LOG_DEBUG("Enter - Sink <%s>", sink);
+
+       g_hash_table_foreach(processor->task_queues, prv_free_queue_for_sink,
+                            (gpointer)sink);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+const msu_task_queue_key_t *msu_task_processor_lookup_queue(
+                                       const msu_task_processor_t *processor,
+                                       const gchar *source,
+                                       const gchar *sink)
+{
+       msu_task_queue_key_t key;
+       msu_task_queue_key_t *orig_key = NULL;
+       msu_task_queue_t *queue;
+
+       key.source = (gchar *)source;
+       key.sink = (gchar *)sink;
+
+       g_hash_table_lookup_extended(processor->task_queues,
+                                    &key,
+                                    (gpointer *)&orig_key,
+                                    (gpointer *)&queue);
+
+       return orig_key;
+}
+
+static gboolean prv_task_queue_process_task(gpointer user_data)
+{
+       msu_task_queue_key_t *queue_id = user_data;
+       msu_task_queue_t *queue;
+
+       MSU_LOG_DEBUG("Enter - Start task processing for queue <%s,%s>",
+                     queue_id->source, queue_id->sink);
+
+       queue = g_hash_table_lookup(queue_id->processor->task_queues,
+                                   queue_id);
+
+       queue->idle_id = 0;
+       queue->current_task = g_ptr_array_index(queue->tasks, 0);
+       g_ptr_array_remove_index(queue->tasks, 0);
+       queue_id->processor->running_tasks++;
+       queue->task_process_cb(queue->current_task, &queue->cancellable);
+
+       MSU_LOG_DEBUG("Exit");
+
+       return FALSE;
+}
+
+void msu_task_queue_start(const msu_task_queue_key_t *queue_id)
+{
+       msu_task_queue_t *queue;
+
+       MSU_LOG_DEBUG("Enter - Starting queue <%s,%s>", queue_id->source,
+                     queue_id->sink);
+
+       queue = g_hash_table_lookup(queue_id->processor->task_queues,
+                                   queue_id);
+
+       if (queue->defer_remove)
+               goto exit;
+
+       if (!queue->cancellable && !queue->idle_id)
+               queue->idle_id = g_idle_add(prv_task_queue_process_task,
+                                           (gpointer)queue_id);
+
+exit:
+       MSU_LOG_DEBUG("Exit");
+}
+
+void msu_task_queue_add_task(const msu_task_queue_key_t *queue_id,
+                            msu_task_atom_t *task)
+{
+       msu_task_queue_t *queue;
+
+       MSU_LOG_DEBUG("Enter - Task added to queue <%s,%s>", queue_id->source,
+                     queue_id->sink);
+
+       queue = g_hash_table_lookup(queue_id->processor->task_queues,
+                                   queue_id);
+
+       task->queue_id = queue_id;
+       g_ptr_array_add(queue->tasks, task);
+
+       if (queue->defer_remove)
+               goto exit;
+
+       if (queue->flags & MSU_TASK_QUEUE_FLAG_AUTO_START) {
+               if (!queue->cancellable && !queue->idle_id)
+                       queue->idle_id = g_idle_add(prv_task_queue_process_task,
+                                                   (gpointer)queue_id);
+       }
+
+exit:
+       MSU_LOG_DEBUG("Exit");
+}
+
+void msu_task_queue_task_completed(const msu_task_queue_key_t *queue_id)
+{
+       msu_task_queue_t *queue;
+       msu_task_processor_t *processor = queue_id->processor;
+
+       MSU_LOG_DEBUG("Enter - Task completed for queue <%s,%s>",
+                     queue_id->source, queue_id->sink);
+
+       queue = g_hash_table_lookup(processor->task_queues, queue_id);
+
+       if (queue->cancellable) {
+               g_object_unref(queue->cancellable);
+               queue->cancellable = NULL;
+       }
+
+       if (queue->current_task) {
+               queue->task_delete_cb(queue->current_task);
+               queue->current_task = NULL;
+       }
+
+       processor->running_tasks--;
+
+       if (processor->quitting && !processor->running_tasks)
+               g_idle_add(processor->on_quit_cb, NULL);
+       else if (queue->defer_remove)
+               g_hash_table_remove(processor->task_queues, queue_id);
+       else if (queue->tasks->len > 0)
+               queue->idle_id = g_idle_add(prv_task_queue_process_task,
+                                           (gpointer)queue_id);
+       else if (queue->flags & MSU_TASK_QUEUE_FLAG_AUTO_REMOVE)
+               g_hash_table_remove(processor->task_queues, queue_id);
+
+       MSU_LOG_DEBUG("Exit");
+}
diff --git a/src/task-processor.h b/src/task-processor.h
new file mode 100644 (file)
index 0000000..cff8e02
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * media-service-upnp
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Regis Merlino <regis.merlino@intel.com>
+ *
+ */
+
+#ifndef MSU_TASK_PROCESSOR_H__
+#define MSU_TASK_PROCESSOR_H__
+
+#include <gio/gio.h>
+#include <glib.h>
+
+#include "task-atom.h"
+
+enum msu_task_queue_flag_mask_ {
+       MSU_TASK_QUEUE_FLAG_NONE = 0,
+       MSU_TASK_QUEUE_FLAG_AUTO_START = 1,
+       MSU_TASK_QUEUE_FLAG_AUTO_REMOVE = 1 << 1,
+};
+typedef enum msu_task_queue_flag_mask_ msu_task_queue_flag_mask;
+
+typedef struct msu_task_processor_t_ msu_task_processor_t;
+
+typedef void (*msu_task_process_cb_t)(msu_task_atom_t *task,
+                                     GCancellable **cancellable);
+typedef void (*msu_task_cancel_cb_t)(msu_task_atom_t *task);
+typedef void (*msu_task_delete_cb_t)(msu_task_atom_t *task);
+
+msu_task_processor_t *msu_task_processor_new(GSourceFunc on_quit_cb);
+void msu_task_processor_free(msu_task_processor_t *processor);
+void msu_task_processor_set_quitting(msu_task_processor_t *processor);
+const msu_task_queue_key_t *msu_task_processor_add_queue(
+                                       msu_task_processor_t *processor,
+                                       const gchar *source,
+                                       const gchar *sink,
+                                       guint32 flags,
+                                       msu_task_process_cb_t task_process_cb,
+                                       msu_task_cancel_cb_t task_cancel_cb,
+                                       msu_task_delete_cb_t task_delete_cb);
+const msu_task_queue_key_t *msu_task_processor_lookup_queue(
+                                       const msu_task_processor_t *processor,
+                                       const gchar *source,
+                                       const gchar *sink);
+void msu_task_processor_cancel_queue(const msu_task_queue_key_t *queue_id);
+void msu_task_processor_remove_queues_for_source(
+                                               msu_task_processor_t *processor,
+                                               const gchar *source);
+void msu_task_processor_remove_queues_for_sink(msu_task_processor_t *processor,
+                                              const gchar *sink);
+
+void msu_task_queue_start(const msu_task_queue_key_t *queue_id);
+void msu_task_queue_add_task(const msu_task_queue_key_t *queue_id,
+                            msu_task_atom_t *task);
+void msu_task_queue_task_completed(const msu_task_queue_key_t *queue_id);
+
+#endif /* MSU_TASK_PROCESSOR_H__ */
index 17e9e9a..7a3aec6 100644 (file)
 #include "error.h"
 #include "task.h"
 
-static msu_task_t *prv_upload_new_generic(msu_task_type_t type,
-                                         GDBusMethodInvocation *invocation,
-                                         const gchar *path,
-                                         GVariant *parameters);
-
 msu_task_t *msu_task_get_version_new(GDBusMethodInvocation *invocation)
 {
        msu_task_t *task = g_new0(msu_task_t, 1);
@@ -53,71 +48,166 @@ msu_task_t *msu_task_get_servers_new(GDBusMethodInvocation *invocation)
        return task;
 }
 
+static void prv_msu_task_delete(msu_task_t *task)
+{
+       switch (task->type) {
+       case MSU_TASK_GET_CHILDREN:
+               if (task->ut.get_children.filter)
+                       g_variant_unref(task->ut.get_children.filter);
+               g_free(task->ut.get_children.sort_by);
+               break;
+       case MSU_TASK_GET_ALL_PROPS:
+               g_free(task->ut.get_props.interface_name);
+               break;
+       case MSU_TASK_GET_PROP:
+               g_free(task->ut.get_prop.interface_name);
+               g_free(task->ut.get_prop.prop_name);
+               break;
+       case MSU_TASK_SEARCH:
+               g_free(task->ut.search.query);
+               if (task->ut.search.filter)
+                       g_variant_unref(task->ut.search.filter);
+               g_free(task->ut.search.sort_by);
+               break;
+       case MSU_TASK_GET_RESOURCE:
+               if (task->ut.resource.filter)
+                       g_variant_unref(task->ut.resource.filter);
+               g_free(task->ut.resource.protocol_info);
+               break;
+       case MSU_TASK_SET_PROTOCOL_INFO:
+               if (task->ut.protocol_info.protocol_info)
+                       g_free(task->ut.protocol_info.protocol_info);
+               break;
+       case MSU_TASK_UPLOAD_TO_ANY:
+       case MSU_TASK_UPLOAD:
+               g_free(task->ut.upload.display_name);
+               g_free(task->ut.upload.file_path);
+               break;
+       case MSU_TASK_CREATE_CONTAINER:
+       case MSU_TASK_CREATE_CONTAINER_IN_ANY:
+               g_free(task->ut.create_container.display_name);
+               g_free(task->ut.create_container.type);
+               g_variant_unref(task->ut.create_container.child_types);
+               break;
+       case MSU_TASK_UPDATE_OBJECT:
+               if (task->ut.update.to_add_update)
+                       g_variant_unref(task->ut.update.to_add_update);
+               if (task->ut.update.to_delete)
+                       g_variant_unref(task->ut.update.to_delete);
+               break;
+       default:
+               break;
+       }
+
+       g_free(task->target.path);
+       g_free(task->target.root_path);
+       g_free(task->target.id);
+
+       if (task->result)
+               g_variant_unref(task->result);
+
+       g_free(task);
+}
+
+static gboolean prv_set_task_target_info(msu_task_t *task, const gchar *path,
+                                        GError **error)
+{
+       task->target.path = g_strdup(path);
+       g_strstrip(task->target.path);
+
+       return msu_media_service_get_object_info(path, &task->target.root_path,
+                                              &task->target.id,
+                                              &task->target.device, error);
+}
+
 static msu_task_t *prv_m2spec_task_new(msu_task_type_t type,
                                       GDBusMethodInvocation *invocation,
                                       const gchar *path,
-                                      const gchar *result_format)
+                                      const gchar *result_format,
+                                      GError **error)
 {
        msu_task_t *task = g_new0(msu_task_t, 1);
 
+       if (!prv_set_task_target_info(task, path, error)) {
+               prv_msu_task_delete(task);
+               task = NULL;
+
+               goto finished;
+       }
+
        task->type = type;
        task->invocation = invocation;
        task->result_format = result_format;
 
-       task->path = g_strdup(path);
-       g_strstrip(task->path);
+finished:
 
        return task;
 }
 
 msu_task_t *msu_task_get_children_new(GDBusMethodInvocation *invocation,
                                      const gchar *path, GVariant *parameters,
-                                     gboolean items, gboolean containers)
+                                     gboolean items, gboolean containers,
+                                     GError **error)
 {
        msu_task_t *task;
 
        task = prv_m2spec_task_new(MSU_TASK_GET_CHILDREN, invocation, path,
-                                  "(@aa{sv})");
+                                  "(@aa{sv})", error);
+       if (!task)
+               goto finished;
 
        task->ut.get_children.containers = containers;
        task->ut.get_children.items = items;
 
-       g_variant_get(parameters, "(uu@as)", &task->ut.get_children.start,
-                                            &task->ut.get_children.count,
-                                            &task->ut.get_children.filter);
+       g_variant_get(parameters, "(uu@as)",
+                     &task->ut.get_children.start,
+                     &task->ut.get_children.count,
+                     &task->ut.get_children.filter);
 
        task->ut.get_children.sort_by = g_strdup("");
 
+finished:
+
        return task;
 }
 
 msu_task_t *msu_task_get_children_ex_new(GDBusMethodInvocation *invocation,
                                         const gchar *path,
                                         GVariant *parameters, gboolean items,
-                                        gboolean containers)
+                                        gboolean containers,
+                                        GError **error)
 {
        msu_task_t *task;
 
        task = prv_m2spec_task_new(MSU_TASK_GET_CHILDREN, invocation, path,
-                                  "(@aa{sv})");
+                                  "(@aa{sv})", error);
+       if (!task)
+               goto finished;
 
        task->ut.get_children.containers = containers;
        task->ut.get_children.items = items;
 
-       g_variant_get(parameters, "(uu@ass)", &task->ut.get_children.start,
-                                             &task->ut.get_children.count,
-                                             &task->ut.get_children.filter,
-                                             &task->ut.get_children.sort_by);
+       g_variant_get(parameters, "(uu@ass)",
+                     &task->ut.get_children.start,
+                     &task->ut.get_children.count,
+                     &task->ut.get_children.filter,
+                     &task->ut.get_children.sort_by);
+
+finished:
 
        return task;
 }
 
 msu_task_t *msu_task_get_prop_new(GDBusMethodInvocation *invocation,
-                                 const gchar *path, GVariant *parameters)
+                                 const gchar *path, GVariant *parameters,
+                                 GError **error)
 {
        msu_task_t *task;
 
-       task = prv_m2spec_task_new(MSU_TASK_GET_PROP, invocation, path, "(v)");
+       task = prv_m2spec_task_new(MSU_TASK_GET_PROP, invocation, path, "(v)",
+                                  error);
+       if (!task)
+               goto finished;
 
        g_variant_get(parameters, "(ss)", &task->ut.get_prop.interface_name,
                      &task->ut.get_prop.prop_name);
@@ -125,30 +215,40 @@ msu_task_t *msu_task_get_prop_new(GDBusMethodInvocation *invocation,
        g_strstrip(task->ut.get_prop.interface_name);
        g_strstrip(task->ut.get_prop.prop_name);
 
+finished:
+
        return task;
 }
 
 msu_task_t *msu_task_get_props_new(GDBusMethodInvocation *invocation,
-                                  const gchar *path, GVariant *parameters)
+                                  const gchar *path, GVariant *parameters,
+                                  GError **error)
 {
        msu_task_t *task;
 
        task = prv_m2spec_task_new(MSU_TASK_GET_ALL_PROPS, invocation, path,
-                                  "(@a{sv})");
+                                  "(@a{sv})", error);
+       if (!task)
+               goto finished;
 
        g_variant_get(parameters, "(s)", &task->ut.get_props.interface_name);
        g_strstrip(task->ut.get_props.interface_name);
 
+finished:
+
        return task;
 }
 
 msu_task_t *msu_task_search_new(GDBusMethodInvocation *invocation,
-                               const gchar *path, GVariant *parameters)
+                               const gchar *path, GVariant *parameters,
+                               GError **error)
 {
        msu_task_t *task;
 
        task = prv_m2spec_task_new(MSU_TASK_SEARCH, invocation, path,
-                                  "(@aa{sv})");
+                                  "(@aa{sv})", error);
+       if (!task)
+               goto finished;
 
        g_variant_get(parameters, "(suu@as)", &task->ut.search.query,
                      &task->ut.search.start, &task->ut.search.count,
@@ -156,16 +256,20 @@ msu_task_t *msu_task_search_new(GDBusMethodInvocation *invocation,
 
        task->ut.search.sort_by = g_strdup("");
 
+finished:
        return task;
 }
 
 msu_task_t *msu_task_search_ex_new(GDBusMethodInvocation *invocation,
-                                  const gchar *path, GVariant *parameters)
+                                  const gchar *path, GVariant *parameters,
+                                  GError **error)
 {
        msu_task_t *task;
 
        task = prv_m2spec_task_new(MSU_TASK_SEARCH, invocation, path,
-                                  "(@aa{sv}u)");
+                                  "(@aa{sv}u)", error);
+       if (!task)
+               goto finished;
 
        g_variant_get(parameters, "(suu@ass)", &task->ut.search.query,
                      &task->ut.search.start, &task->ut.search.count,
@@ -173,19 +277,27 @@ msu_task_t *msu_task_search_ex_new(GDBusMethodInvocation *invocation,
 
        task->multiple_retvals = TRUE;
 
+finished:
+
        return task;
 }
 
 msu_task_t *msu_task_get_resource_new(GDBusMethodInvocation *invocation,
-                                     const gchar *path, GVariant *parameters)
+                                     const gchar *path, GVariant *parameters,
+                                     GError **error)
 {
        msu_task_t *task;
 
        task = prv_m2spec_task_new(MSU_TASK_GET_RESOURCE, invocation, path,
-                                  "(@a{sv})");
+                                  "(@a{sv})", error);
+       if (!task)
+               goto finished;
+
+       g_variant_get(parameters, "(s@as)",
+                     &task->ut.resource.protocol_info,
+                     &task->ut.resource.filter);
 
-       g_variant_get(parameters, "(s@as)", &task->ut.resource.protocol_info,
-                                           &task->ut.resource.filter);
+finished:
 
        return task;
 }
@@ -206,17 +318,22 @@ msu_task_t *msu_task_set_protocol_info_new(GDBusMethodInvocation *invocation,
 static msu_task_t *prv_upload_new_generic(msu_task_type_t type,
                                          GDBusMethodInvocation *invocation,
                                          const gchar *path,
-                                         GVariant *parameters)
+                                         GVariant *parameters,
+                                         GError **error)
 {
        msu_task_t *task;
 
-       task = prv_m2spec_task_new(type, invocation, path, "(uo)");
+       task = prv_m2spec_task_new(type, invocation, path, "(uo)", error);
+       if (!task)
+               goto finished;
 
        g_variant_get(parameters, "(ss)", &task->ut.upload.display_name,
                      &task->ut.upload.file_path);
        g_strstrip(task->ut.upload.file_path);
        task->multiple_retvals = TRUE;
 
+finished:
+
        return task;
 }
 
@@ -236,72 +353,90 @@ msu_task_t *msu_task_prefer_local_addresses_new(
 }
 
 msu_task_t *msu_task_upload_to_any_new(GDBusMethodInvocation *invocation,
-                                      const gchar *path, GVariant *parameters)
+                                      const gchar *path, GVariant *parameters,
+                                      GError **error)
 {
        return prv_upload_new_generic(MSU_TASK_UPLOAD_TO_ANY, invocation,
-                                     path, parameters);
+                                     path, parameters, error);
 }
 
 msu_task_t *msu_task_upload_new(GDBusMethodInvocation *invocation,
-                               const gchar *path, GVariant *parameters)
+                               const gchar *path, GVariant *parameters,
+                               GError **error)
 {
        return prv_upload_new_generic(MSU_TASK_UPLOAD, invocation,
-                                     path, parameters);
+                                     path, parameters, error);
 }
 
 msu_task_t *msu_task_get_upload_status_new(GDBusMethodInvocation *invocation,
                                           const gchar *path,
-                                          GVariant *parameters)
+                                          GVariant *parameters,
+                                          GError **error)
 {
        msu_task_t *task;
 
        task = prv_m2spec_task_new(MSU_TASK_GET_UPLOAD_STATUS, invocation, path,
-                                  "(stt)");
+                                  "(stt)", error);
+       if (!task)
+               goto finished;
 
        g_variant_get(parameters, "(u)",
                      &task->ut.upload_action.upload_id);
        task->synchronous = TRUE;
        task->multiple_retvals = TRUE;
 
+finished:
+
        return task;
 }
 
 msu_task_t *msu_task_get_upload_ids_new(GDBusMethodInvocation *invocation,
-                                       const gchar *path)
+                                       const gchar *path,
+                                       GError **error)
 {
        msu_task_t *task;
 
        task = prv_m2spec_task_new(MSU_TASK_GET_UPLOAD_IDS, invocation, path,
-                                  "(@au)");
+                                  "(@au)", error);
+       if (!task)
+               goto finished;
 
        task->synchronous = TRUE;
 
+finished:
+
        return task;
 }
 
 msu_task_t *msu_task_cancel_upload_new(GDBusMethodInvocation *invocation,
                                       const gchar *path,
-                                      GVariant *parameters)
+                                      GVariant *parameters,
+                                      GError **error)
 {
        msu_task_t *task;
 
        task = prv_m2spec_task_new(MSU_TASK_CANCEL_UPLOAD, invocation, path,
-                                  NULL);
+                                  NULL, error);
+       if (!task)
+               goto finished;
 
        g_variant_get(parameters, "(u)",
                      &task->ut.upload_action.upload_id);
        task->synchronous = TRUE;
 
+finished:
+
        return task;
 }
 
 msu_task_t *msu_task_delete_new(GDBusMethodInvocation *invocation,
-                               const gchar *path)
+                               const gchar *path,
+                               GError **error)
 {
        msu_task_t *task;
 
        task = prv_m2spec_task_new(MSU_TASK_DELETE_OBJECT, invocation,
-                                  path, NULL);
+                                  path, NULL, error);
        return task;
 }
 
@@ -309,94 +444,46 @@ msu_task_t *msu_task_create_container_new_generic(
                                        GDBusMethodInvocation *invocation,
                                        msu_task_type_t type,
                                        const gchar *path,
-                                       GVariant *parameters)
+                                       GVariant *parameters,
+                                       GError **error)
 {
        msu_task_t *task;
 
-       task = prv_m2spec_task_new(type, invocation, path, "(@o)");
+       task = prv_m2spec_task_new(type, invocation, path, "(@o)", error);
+       if (!task)
+               goto finished;
 
        g_variant_get(parameters, "(ss@as)",
-                                       &task->ut.create_container.display_name,
-                                       &task->ut.create_container.type,
-                                       &task->ut.create_container.child_types);
+                     &task->ut.create_container.display_name,
+                     &task->ut.create_container.type,
+                     &task->ut.create_container.child_types);
+
+finished:
 
        return task;
 }
 
 msu_task_t *msu_task_update_new(GDBusMethodInvocation *invocation,
-                               const gchar *path, GVariant *parameters)
+                               const gchar *path, GVariant *parameters,
+                               GError **error)
 {
        msu_task_t *task;
 
        task = prv_m2spec_task_new(MSU_TASK_UPDATE_OBJECT, invocation, path,
-                                  NULL);
+                                  NULL, error);
+       if (!task)
+               goto finished;
 
        g_variant_get(parameters, "(@a{sv}@as)",
                      &task->ut.update.to_add_update,
                      &task->ut.update.to_delete);
 
-       return task;
-}
-
-static void prv_msu_task_delete(msu_task_t *task)
-{
-       switch (task->type) {
-       case MSU_TASK_GET_CHILDREN:
-               if (task->ut.get_children.filter)
-                       g_variant_unref(task->ut.get_children.filter);
-               g_free(task->ut.get_children.sort_by);
-               break;
-       case MSU_TASK_GET_ALL_PROPS:
-               g_free(task->ut.get_props.interface_name);
-               break;
-       case MSU_TASK_GET_PROP:
-               g_free(task->ut.get_prop.interface_name);
-               g_free(task->ut.get_prop.prop_name);
-               break;
-       case MSU_TASK_SEARCH:
-               g_free(task->ut.search.query);
-               if (task->ut.search.filter)
-                       g_variant_unref(task->ut.search.filter);
-               g_free(task->ut.search.sort_by);
-               break;
-       case MSU_TASK_GET_RESOURCE:
-               if (task->ut.resource.filter)
-                       g_variant_unref(task->ut.resource.filter);
-               g_free(task->ut.resource.protocol_info);
-               break;
-       case MSU_TASK_SET_PROTOCOL_INFO:
-               if (task->ut.protocol_info.protocol_info)
-                       g_free(task->ut.protocol_info.protocol_info);
-               break;
-       case MSU_TASK_UPLOAD_TO_ANY:
-       case MSU_TASK_UPLOAD:
-               g_free(task->ut.upload.display_name);
-               g_free(task->ut.upload.file_path);
-               break;
-       case MSU_TASK_CREATE_CONTAINER:
-       case MSU_TASK_CREATE_CONTAINER_IN_ANY:
-               g_free(task->ut.create_container.display_name);
-               g_free(task->ut.create_container.type);
-               g_variant_unref(task->ut.create_container.child_types);
-               break;
-       case MSU_TASK_UPDATE_OBJECT:
-               if (task->ut.update.to_add_update)
-                       g_variant_unref(task->ut.update.to_add_update);
-               if (task->ut.update.to_delete)
-                       g_variant_unref(task->ut.update.to_delete);
-               break;
-       default:
-               break;
-       }
-
-       g_free(task->path);
-       if (task->result)
-               g_variant_unref(task->result);
+finished:
 
-       g_free(task);
+       return task;
 }
 
-void msu_task_complete_and_delete(msu_task_t *task)
+void msu_task_complete(msu_task_t *task)
 {
        GVariant *variant = NULL;
 
@@ -414,29 +501,28 @@ void msu_task_complete_and_delete(msu_task_t *task)
                g_dbus_method_invocation_return_value(task->invocation,
                                                      variant);
        }
-       prv_msu_task_delete(task);
 
 finished:
 
        return;
 }
 
-void msu_task_fail_and_delete(msu_task_t *task, GError *error)
+void msu_task_fail(msu_task_t *task, GError *error)
 {
        if (!task)
                goto finished;
 
-       if (task->invocation)
+       if (task->invocation) {
                g_dbus_method_invocation_return_gerror(task->invocation, error);
-
-       prv_msu_task_delete(task);
+               task->invocation = NULL;
+       }
 
 finished:
 
        return;
 }
 
-void msu_task_cancel_and_delete(msu_task_t *task)
+void msu_task_cancel(msu_task_t *task)
 {
        GError *error;
 
@@ -447,11 +533,10 @@ void msu_task_cancel_and_delete(msu_task_t *task)
                error = g_error_new(MSU_ERROR, MSU_ERROR_CANCELLED,
                                    "Operation cancelled.");
                g_dbus_method_invocation_return_gerror(task->invocation, error);
+               task->invocation = NULL;
                g_error_free(error);
        }
 
-       prv_msu_task_delete(task);
-
 finished:
 
        return;
index 4eb656d..2242351 100644 (file)
@@ -26,6 +26,9 @@
 #include <gio/gio.h>
 #include <glib.h>
 
+#include "media-service-upnp.h"
+#include "task-atom.h"
+
 enum msu_task_type_t_ {
        MSU_TASK_GET_VERSION,
        MSU_TASK_GET_SERVERS,
@@ -121,10 +124,19 @@ struct msu_task_update_t_ {
        GVariant *to_delete;
 };
 
+typedef struct msu_task_target_info_t_ msu_task_target_info_t;
+struct msu_task_target_info_t_ {
+       gchar *path;
+       gchar *root_path;
+       gchar *id;
+       msu_device_t *device;
+};
+
 typedef struct msu_task_t_ msu_task_t;
 struct msu_task_t_ {
+       msu_task_atom_t base; /* pseudo inheritance - MUST be first field */
        msu_task_type_t type;
-       gchar *path;
+       msu_task_target_info_t target;
        const gchar *result_format;
        GVariant *result;
        GDBusMethodInvocation *invocation;
@@ -149,50 +161,66 @@ msu_task_t *msu_task_get_version_new(GDBusMethodInvocation *invocation);
 msu_task_t *msu_task_get_servers_new(GDBusMethodInvocation *invocation);
 msu_task_t *msu_task_get_children_new(GDBusMethodInvocation *invocation,
                                      const gchar *path, GVariant *parameters,
-                                     gboolean items, gboolean containers);
+                                     gboolean items, gboolean containers,
+                                     GError **error);
 msu_task_t *msu_task_get_children_ex_new(GDBusMethodInvocation *invocation,
                                         const gchar *path,
                                         GVariant *parameters, gboolean items,
-                                        gboolean containers);
+                                        gboolean containers,
+                                        GError **error);
 msu_task_t *msu_task_get_prop_new(GDBusMethodInvocation *invocation,
-                                 const gchar *path, GVariant *parameters);
+                                 const gchar *path, GVariant *parameters,
+                                 GError **error);
 msu_task_t *msu_task_get_props_new(GDBusMethodInvocation *invocation,
-                                  const gchar *path, GVariant *parameters);
+                                  const gchar *path, GVariant *parameters,
+                                  GError **error);
 msu_task_t *msu_task_search_new(GDBusMethodInvocation *invocation,
-                               const gchar *path, GVariant *parameters);
+                               const gchar *path, GVariant *parameters,
+                               GError **error);
 msu_task_t *msu_task_search_ex_new(GDBusMethodInvocation *invocation,
-                                  const gchar *path, GVariant *parameters);
+                                  const gchar *path, GVariant *parameters,
+                                  GError **error);
 msu_task_t *msu_task_get_resource_new(GDBusMethodInvocation *invocation,
-                                     const gchar *path, GVariant *parameters);
+                                     const gchar *path, GVariant *parameters,
+                                     GError **error);
 msu_task_t *msu_task_set_protocol_info_new(GDBusMethodInvocation *invocation,
                                           GVariant *parameters);
 msu_task_t *msu_task_prefer_local_addresses_new(
                                        GDBusMethodInvocation *invocation,
                                        GVariant *parameters);
 msu_task_t *msu_task_upload_to_any_new(GDBusMethodInvocation *invocation,
-                                      const gchar *path, GVariant *parameters);
+                                      const gchar *path, GVariant *parameters,
+                                      GError **error);
 msu_task_t *msu_task_upload_new(GDBusMethodInvocation *invocation,
-                               const gchar *path, GVariant *parameters);
+                               const gchar *path, GVariant *parameters,
+                               GError **error);
 msu_task_t *msu_task_get_upload_status_new(GDBusMethodInvocation *invocation,
                                           const gchar *path,
-                                          GVariant *parameters);
+                                          GVariant *parameters,
+                                          GError **error);
 msu_task_t *msu_task_get_upload_ids_new(GDBusMethodInvocation *invocation,
-                                       const gchar *path);
+                                       const gchar *path,
+                                       GError **error);
 msu_task_t *msu_task_cancel_upload_new(GDBusMethodInvocation *invocation,
                                       const gchar *path,
-                                      GVariant *parameters);
+                                      GVariant *parameters,
+                                      GError **error);
 msu_task_t *msu_task_delete_new(GDBusMethodInvocation *invocation,
-                               const gchar *path);
+                               const gchar *path,
+                               GError **error);
 msu_task_t *msu_task_create_container_new_generic(
                                        GDBusMethodInvocation *invocation,
                                        msu_task_type_t type,
                                        const gchar *path,
-                                       GVariant *parameters);
+                                       GVariant *parameters,
+                                       GError **error);
 msu_task_t *msu_task_update_new(GDBusMethodInvocation *invocation,
-                                  const gchar *path, GVariant *parameters);
-void msu_task_complete_and_delete(msu_task_t *task);
-void msu_task_fail_and_delete(msu_task_t *task, GError *error);
-void msu_task_cancel_and_delete(msu_task_t *task);
+                               const gchar *path, GVariant *parameters,
+                               GError **error);
+
+void msu_task_cancel(msu_task_t *task);
+void msu_task_complete(msu_task_t *task);
+void msu_task_fail(msu_task_t *task, GError *error);
 void msu_task_delete(msu_task_t *task);
 
 #endif
index a93a303..40061e5 100644 (file)
@@ -191,7 +191,7 @@ static void prv_device_chain_end(msu_chain_task_t *chain, gpointer data)
 {
        msu_device_t *device;
        gboolean canceled;
-       prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *) data;
+       prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *)data;
 
        device = msu_chain_task_get_device(chain);
        canceled = msu_chain_task_is_canceled(chain);
@@ -228,7 +228,7 @@ static void prv_server_available_cb(GUPnPControlPoint *cp,
        unsigned int i;
        prv_device_new_ct_t *priv_t;
 
-       udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *) proxy);
+       udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy);
        if (!udn)
                goto on_error;
 
@@ -315,7 +315,7 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
 
        MSU_LOG_DEBUG("Enter");
 
-       udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *) proxy);
+       udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy);
        if (!udn)
                goto on_error;
 
@@ -353,15 +353,15 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
                (void) g_ptr_array_remove_index(device->contexts, i);
                if (device->contexts->len == 0) {
                        if (!under_construction) {
-                               MSU_LOG_DEBUG("Last Context lost. " \
-                                              "Delete device");
+                               MSU_LOG_DEBUG(
+                                       "Last Context lost. Delete device");
 
                                upnp->lost_server(device->path,
                                                  upnp->user_data);
                                g_hash_table_remove(upnp->server_udn_map, udn);
                        } else {
-                               MSU_LOG_WARNING("Device under construction. "\
-                                                "Cancelling");
+                               MSU_LOG_WARNING(
+                                       "Device under construction. Cancelling");
 
                                msu_chain_task_cancel(priv_t->chain);
                                prv_device_chain_end(priv_t->chain, priv_t);
@@ -477,6 +477,11 @@ GVariant *msu_upnp_get_server_ids(msu_upnp_t *upnp)
        return retval;
 }
 
+GHashTable *msu_upnp_get_server_udn_map(msu_upnp_t *upnp)
+{
+       return upnp->server_udn_map;
+}
+
 void msu_upnp_get_children(msu_upnp_t *upnp, msu_client_t *client,
                           msu_task_t *task,
                           GCancellable *cancellable,
@@ -484,45 +489,25 @@ void msu_upnp_get_children(msu_upnp_t *upnp, msu_client_t *client,
 {
        msu_async_cb_data_t *cb_data;
        msu_async_bas_t *cb_task_data;
-       msu_device_t *device;
        gchar *upnp_filter = NULL;
        gchar *sort_by = NULL;
 
        MSU_LOG_DEBUG("Enter");
 
-       MSU_LOG_DEBUG("Path: %s", task->path);
+       MSU_LOG_DEBUG("Path: %s", task->target.path);
        MSU_LOG_DEBUG("Start: %u", task->ut.get_children.start);
        MSU_LOG_DEBUG("Count: %u", task->ut.get_children.count);
 
        cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.bas;
 
-       if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
-                                     &cb_data->id, &cb_data->error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       device = msu_device_from_path(cb_task_data->root_path,
-                                     upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                             cb_task_data->root_path);
-
-               cb_data->error =
-                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
-
        cb_task_data->filter_mask =
                msu_props_parse_filter(upnp->filter_map,
-                                       task->ut.get_children.filter,
-                                       &upnp_filter);
+                                      task->ut.get_children.filter,
+                                      &upnp_filter);
 
-       MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
+       MSU_LOG_DEBUG("Filter Mask 0x%"G_GUINT64_FORMAT"x",
+                     cb_task_data->filter_mask);
 
        sort_by = msu_sort_translate_sort_string(upnp->filter_map,
                                                 task->ut.get_children.sort_by);
@@ -538,7 +523,7 @@ void msu_upnp_get_children(msu_upnp_t *upnp, msu_client_t *client,
 
        cb_task_data->protocol_info = client->protocol_info;
 
-       msu_device_get_children(device, client, task, cb_data,
+       msu_device_get_children(client, task, cb_data,
                                upnp_filter, sort_by, cancellable);
 
 on_error:
@@ -560,54 +545,25 @@ void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_client_t *client,
        gboolean root_object;
        msu_async_cb_data_t *cb_data;
        msu_async_get_all_t *cb_task_data;
-       msu_device_t *device;
 
        MSU_LOG_DEBUG("Enter");
 
-       MSU_LOG_DEBUG("Path: %s", task->path);
+       MSU_LOG_DEBUG("Path: %s", task->target.path);
        MSU_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
 
        cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.get_all;
 
-       if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
-                                     &cb_data->id, &cb_data->error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       root_object = cb_data->id[0] == '0' && cb_data->id[1] == 0;
+       root_object = task->target.id[0] == '0' && task->target.id[1] == 0;
 
        MSU_LOG_DEBUG("Root Object = %d", root_object);
 
-       device = msu_device_from_path(cb_task_data->root_path,
-                                     upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                             cb_task_data->root_path);
-
-               cb_data->error =
-                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
-
        cb_task_data->protocol_info = client->protocol_info;
 
-       msu_device_get_all_props(device, client, task, cb_data, root_object,
+       msu_device_get_all_props(client, task, cb_data, root_object,
                                 cancellable);
 
        MSU_LOG_DEBUG("Exit with SUCCESS");
-
-       return;
-
-on_error:
-
-       (void) g_idle_add(msu_async_complete_task, cb_data);
-
-       MSU_LOG_DEBUG("Exit with FAIL");
 }
 
 void msu_upnp_get_prop(msu_upnp_t *upnp, msu_client_t *client,
@@ -618,13 +574,12 @@ void msu_upnp_get_prop(msu_upnp_t *upnp, msu_client_t *client,
        gboolean root_object;
        msu_async_cb_data_t *cb_data;
        msu_async_get_prop_t *cb_task_data;
-       msu_device_t *device;
        msu_prop_map_t *prop_map;
        msu_task_get_prop_t *task_data;
 
        MSU_LOG_DEBUG("Enter");
 
-       MSU_LOG_DEBUG("Path: %s", task->path);
+       MSU_LOG_DEBUG("Path: %s", task->target.path);
        MSU_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
        MSU_LOG_DEBUG("Prop.%s", task->ut.get_prop.prop_name);
 
@@ -632,46 +587,17 @@ void msu_upnp_get_prop(msu_upnp_t *upnp, msu_client_t *client,
        cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.get_prop;
 
-       if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
-                                     &cb_data->id,
-                                     &cb_data->error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       root_object = cb_data->id[0] == '0' && cb_data->id[1] == 0;
+       root_object = task->target.id[0] == '0' && task->target.id[1] == 0;
 
        MSU_LOG_DEBUG("Root Object = %d", root_object);
 
-       device = msu_device_from_path(cb_task_data->root_path,
-                                     upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                             cb_task_data->root_path);
-
-               cb_data->error =
-                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
-
        cb_task_data->protocol_info = client->protocol_info;
        prop_map = g_hash_table_lookup(upnp->filter_map, task_data->prop_name);
 
-       msu_device_get_prop(device, client, task, cb_data, prop_map,
+       msu_device_get_prop(client, task, cb_data, prop_map,
                            root_object, cancellable);
 
        MSU_LOG_DEBUG("Exit with SUCCESS");
-
-       return;
-
-on_error:
-
-       (void) g_idle_add(msu_async_complete_task, cb_data);
-
-       MSU_LOG_DEBUG("Exit with FAIL");
 }
 
 void msu_upnp_search(msu_upnp_t *upnp, msu_client_t *client,
@@ -684,11 +610,10 @@ void msu_upnp_search(msu_upnp_t *upnp, msu_client_t *client,
        gchar *sort_by = NULL;
        msu_async_cb_data_t *cb_data;
        msu_async_bas_t *cb_task_data;
-       msu_device_t *device;
 
        MSU_LOG_DEBUG("Enter");
 
-       MSU_LOG_DEBUG("Path: %s", task->path);
+       MSU_LOG_DEBUG("Path: %s", task->target.path);
        MSU_LOG_DEBUG("Query: %s", task->ut.search.query);
        MSU_LOG_DEBUG("Start: %u", task->ut.search.start);
        MSU_LOG_DEBUG("Count: %u", task->ut.search.count);
@@ -696,37 +621,18 @@ void msu_upnp_search(msu_upnp_t *upnp, msu_client_t *client,
        cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.bas;
 
-       if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
-                                     &cb_data->id, &cb_data->error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       device = msu_device_from_path(cb_task_data->root_path,
-                                     upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                             cb_task_data->root_path);
-
-               cb_data->error =
-                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
-
        cb_task_data->filter_mask =
                msu_props_parse_filter(upnp->filter_map,
                                       task->ut.search.filter, &upnp_filter);
 
-       MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
+       MSU_LOG_DEBUG("Filter Mask 0x%"G_GUINT64_FORMAT"x",
+                     cb_task_data->filter_mask);
 
        upnp_query = msu_search_translate_search_string(upnp->filter_map,
                                                        task->ut.search.query);
        if (!upnp_query) {
                MSU_LOG_WARNING("Query string is not valid:%s",
-                             task->ut.search.query);
+                               task->ut.search.query);
 
                cb_data->error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_QUERY,
                                             "Query string is not valid.");
@@ -749,7 +655,7 @@ void msu_upnp_search(msu_upnp_t *upnp, msu_client_t *client,
 
        cb_task_data->protocol_info = client->protocol_info;
 
-       msu_device_search(device, client, task, cb_data, upnp_filter,
+       msu_device_search(client, task, cb_data, upnp_filter,
                          upnp_query, sort_by, cancellable);
 on_error:
 
@@ -770,9 +676,7 @@ void msu_upnp_get_resource(msu_upnp_t *upnp, msu_client_t *client,
 {
        msu_async_cb_data_t *cb_data;
        msu_async_get_all_t *cb_task_data;
-       msu_device_t *device;
        gchar *upnp_filter = NULL;
-       gchar *root_path = NULL;
 
        MSU_LOG_DEBUG("Enter");
 
@@ -781,44 +685,20 @@ void msu_upnp_get_resource(msu_upnp_t *upnp, msu_client_t *client,
        cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.get_all;
 
-       if (!msu_path_get_path_and_id(task->path, &root_path, &cb_data->id,
-                                     &cb_data->error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       MSU_LOG_DEBUG("Root Path %s Id %s", root_path, cb_data->id);
-
-       device = msu_device_from_path(root_path, upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s", root_path);
-
-               cb_data->error =
-                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
+       MSU_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
+                     task->target.id);
 
        cb_task_data->filter_mask =
                msu_props_parse_filter(upnp->filter_map,
                                       task->ut.resource.filter, &upnp_filter);
 
-       MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
+       MSU_LOG_DEBUG("Filter Mask 0x%"G_GUINT64_FORMAT"x",
+                     cb_task_data->filter_mask);
 
-       msu_device_get_resource(device, client, task, cb_data, upnp_filter,
+       msu_device_get_resource(client, task, cb_data, upnp_filter,
                                cancellable);
 
-on_error:
-
-       if (!cb_data->action)
-               (void) g_idle_add(msu_async_complete_task, cb_data);
-
-       g_free(upnp_filter);
-       g_free(root_path);
-
-       MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
+       MSU_LOG_DEBUG("Exit");
 }
 
 static gboolean prv_compute_mime_and_class(msu_task_t *task,
@@ -830,12 +710,12 @@ static gboolean prv_compute_mime_and_class(msu_task_t *task,
        if (!g_file_test(task->ut.upload.file_path,
                         G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS)) {
 
-               MSU_LOG_WARNING("File %s does not exist or is not"
-                               " a regular file", task->ut.upload.file_path);
+               MSU_LOG_WARNING(
+                       "File %s does not exist or is not a regular file",
+                       task->ut.upload.file_path);
 
                *error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                    "File %s does not exist or is not"
-                                    " a regular file",
+                                    "File %s does not exist or is not a regular file",
                                     task->ut.upload.file_path);
                goto on_error;
        }
@@ -845,12 +725,12 @@ static gboolean prv_compute_mime_and_class(msu_task_t *task,
 
        if (!content_type) {
 
-               MSU_LOG_WARNING("Unable to determine Content Type "
-                               "for %s", task->ut.upload.file_path);
+               MSU_LOG_WARNING("Unable to determine Content Type for %s",
+                               task->ut.upload.file_path);
 
                *error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_MIME,
-                                    "Unable to determine Content Type "
-                                    "for %s", task->ut.upload.file_path);
+                                    "Unable to determine Content Type for %s",
+                                    task->ut.upload.file_path);
                goto on_error;
        }
 
@@ -859,12 +739,12 @@ static gboolean prv_compute_mime_and_class(msu_task_t *task,
 
        if (!cb_task_data->mime_type) {
 
-               MSU_LOG_WARNING("Unable to determine MIME Type for"
-                               " %s", task->ut.upload.file_path);
+               MSU_LOG_WARNING("Unable to determine MIME Type for %s",
+                               task->ut.upload.file_path);
 
                *error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_MIME,
-                                    "Unable to determine MIME Type for"
-                                    " %s", task->ut.upload.file_path);
+                                    "Unable to determine MIME Type for %s",
+                                    task->ut.upload.file_path);
                goto on_error;
        }
 
@@ -876,12 +756,12 @@ static gboolean prv_compute_mime_and_class(msu_task_t *task,
                cb_task_data->object_class = "object.item.videoItem";
        } else {
 
-               MSU_LOG_WARNING("Unsupported MIME Type"
-                               " %s", cb_task_data->mime_type);
+               MSU_LOG_WARNING("Unsupported MIME Type %s",
+                               cb_task_data->mime_type);
 
                *error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_MIME,
-                                    "Unsupported MIME Type"
-                                    " %s", cb_task_data->mime_type);
+                                    "Unsupported MIME Type %s",
+                                    cb_task_data->mime_type);
                goto on_error;
        }
 
@@ -899,43 +779,21 @@ void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_client_t *client,
 {
        msu_async_cb_data_t *cb_data;
        msu_async_upload_t *cb_task_data;
-       msu_device_t *device;
 
        MSU_LOG_DEBUG("Enter");
 
        cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.upload;
 
-       if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
-                                     &cb_data->id, &cb_data->error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
-                     cb_data->id);
-
-       device = msu_device_from_path(cb_task_data->root_path,
-                                     upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                               cb_task_data->root_path);
-
-               cb_data->error =
-                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
+       MSU_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
+                     task->target.id);
 
-       if (strcmp(cb_data->id, "0")) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
+       if (strcmp(task->target.id, "0")) {
+               MSU_LOG_WARNING("Bad path %s", task->target.path);
 
                cb_data->error =
                        g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
-                                   "UploadToAnyContainer must be executed "
-                                   " on a root path");
+                                   "UploadToAnyContainer must be executed on a root path");
                goto on_error;
        }
 
@@ -945,7 +803,7 @@ void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_client_t *client,
        MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
        MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
 
-       msu_device_upload(device, client, task, "DLNA.ORG_AnyContainer",
+       msu_device_upload(client, task, "DLNA.ORG_AnyContainer",
                          cb_data, cancellable);
 
 on_error:
@@ -962,40 +820,19 @@ void msu_upnp_upload(msu_upnp_t *upnp, msu_client_t *client, msu_task_t *task,
 {
        msu_async_cb_data_t *cb_data;
        msu_async_upload_t *cb_task_data;
-       msu_device_t *device;
 
        MSU_LOG_DEBUG("Enter");
 
        cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.upload;
 
-       if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
-                                     &cb_data->id, &cb_data->error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       device = msu_device_from_path(cb_task_data->root_path,
-                                     upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                               cb_task_data->root_path);
-
-               cb_data->error =
-                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
-
        if (!prv_compute_mime_and_class(task, cb_task_data, &cb_data->error))
                goto on_error;
 
        MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
        MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
 
-       msu_device_upload(device, client, task, cb_data->id, cb_data,
+       msu_device_upload(client, task, task->target.id, cb_data,
                          cancellable);
 
 on_error:
@@ -1008,163 +845,94 @@ on_error:
 
 void msu_upnp_get_upload_status(msu_upnp_t *upnp, msu_task_t *task)
 {
-       gchar *root_path = NULL;
-       gchar *id = NULL;
        GError *error = NULL;
-       msu_device_t *device;
 
        MSU_LOG_DEBUG("Enter");
 
-       if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
+       MSU_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
+                     task->target.id);
 
-       device = msu_device_from_path(root_path, upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                               root_path);
-
-               error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
-
-       if (strcmp(id, "0")) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
+       if (strcmp(task->target.id, "0")) {
+               MSU_LOG_WARNING("Bad path %s", task->target.path);
 
                error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
-                                   "GetUploadStatus must be executed "
-                                   " on a root path");
+                                   "GetUploadStatus must be executed on a root path");
                goto on_error;
        }
 
-       (void) msu_device_get_upload_status(device, task, &error);
+       (void) msu_device_get_upload_status(task, &error);
 
 on_error:
 
        if (error) {
-               msu_task_fail_and_delete(task, error);
+               msu_task_fail(task, error);
                g_error_free(error);
        } else {
-               msu_task_complete_and_delete(task);
+               msu_task_complete(task);
        }
 
-       g_free(id);
-       g_free(root_path);
-
        MSU_LOG_DEBUG("Exit");
 }
 
 void msu_upnp_get_upload_ids(msu_upnp_t *upnp, msu_task_t *task)
 {
-       gchar *root_path = NULL;
-       gchar *id = NULL;
        GError *error = NULL;
-       msu_device_t *device;
 
        MSU_LOG_DEBUG("Enter");
 
-       if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
-
-       device = msu_device_from_path(root_path, upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                               root_path);
-
-               error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
+       MSU_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
+                     task->target.id);
 
-       if (strcmp(id, "0")) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
+       if (strcmp(task->target.id, "0")) {
+               MSU_LOG_WARNING("Bad path %s", task->target.path);
 
                error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
-                                   "GetUploadIDs must be executed "
-                                   " on a root path");
+                                   "GetUploadIDs must be executed on a root path");
                goto on_error;
        }
 
-        msu_device_get_upload_ids(device, task);
+        msu_device_get_upload_ids(task);
 
 on_error:
 
        if (error) {
-               msu_task_fail_and_delete(task, error);
+               msu_task_fail(task, error);
                g_error_free(error);
        } else {
-               msu_task_complete_and_delete(task);
+               msu_task_complete(task);
        }
 
-       g_free(id);
-       g_free(root_path);
-
        MSU_LOG_DEBUG("Exit");
 }
 
 void msu_upnp_cancel_upload(msu_upnp_t *upnp, msu_task_t *task)
 {
-       gchar *root_path = NULL;
-       gchar *id = NULL;
        GError *error = NULL;
-       msu_device_t *device;
 
        MSU_LOG_DEBUG("Enter");
 
-       if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
-
-       device = msu_device_from_path(root_path, upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                               root_path);
-
-               error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
+       MSU_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
+                     task->target.id);
 
-       if (strcmp(id, "0")) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
+       if (strcmp(task->target.id, "0")) {
+               MSU_LOG_WARNING("Bad path %s", task->target.path);
 
                error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
-                                   "CancelUpload must be executed "
-                                   " on a root path");
+                                   "CancelUpload must be executed on a root path");
                goto on_error;
        }
 
-       (void) msu_device_cancel_upload(device, task, &error);
+       (void) msu_device_cancel_upload(task, &error);
 
 on_error:
 
        if (error) {
-               msu_task_fail_and_delete(task, error);
+               msu_task_fail(task, error);
                g_error_free(error);
        } else {
-               msu_task_complete_and_delete(task);
+               msu_task_complete(task);
        }
 
-       g_free(id);
-       g_free(root_path);
-
        MSU_LOG_DEBUG("Exit");
 }
 
@@ -1174,43 +942,15 @@ void msu_upnp_delete_object(msu_upnp_t *upnp, msu_client_t *client,
                            msu_upnp_task_complete_t cb)
 {
        msu_async_cb_data_t *cb_data;
-       msu_device_t *device;
-       gchar *root_path = NULL;
 
        MSU_LOG_DEBUG("Enter");
 
        cb_data = msu_async_cb_data_new(task, cb);
 
-       if (!msu_path_get_path_and_id(task->path, &root_path,
-                                     &cb_data->id, &cb_data->error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       MSU_LOG_DEBUG("Root Path %s Id %s", root_path,
-                     cb_data->id);
+       MSU_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
+                     task->target.id);
 
-       device = msu_device_from_path(root_path, upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                               root_path);
-
-               cb_data->error =
-                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
-
-       msu_device_delete_object(device, client, task, cb_data, cancellable);
-
-on_error:
-
-       if (root_path)
-               g_free(root_path);
-       if (!cb_data->action)
-               (void) g_idle_add(msu_async_complete_task, cb_data);
+       msu_device_delete_object(client, task, cb_data, cancellable);
 
        MSU_LOG_DEBUG("Exit");
 }
@@ -1221,45 +961,17 @@ void msu_upnp_create_container(msu_upnp_t *upnp, msu_client_t *client,
                               msu_upnp_task_complete_t cb)
 {
        msu_async_cb_data_t *cb_data;
-       msu_async_create_container_t *cb_task_data;
-       msu_device_t *device;
 
        MSU_LOG_DEBUG("Enter");
 
        cb_data = msu_async_cb_data_new(task, cb);
-       cb_task_data = &cb_data->ut.create_container;
-
-       if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
-                                     &cb_data->id, &cb_data->error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
-                     cb_data->id);
-
-       device = msu_device_from_path(cb_task_data->root_path,
-                                                       upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                                               cb_task_data->root_path);
 
-               cb_data->error =
-                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
+       MSU_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
+                     task->target.id);
 
-       msu_device_create_container(device, client, task, cb_data->id,
+       msu_device_create_container(client, task, task->target.id,
                                    cb_data, cancellable);
 
-on_error:
-
-       if (!cb_data->action)
-               (void) g_idle_add(msu_async_complete_task, cb_data);
-
        MSU_LOG_DEBUG("Exit");
 }
 
@@ -1269,48 +981,24 @@ void msu_upnp_create_container_in_any(msu_upnp_t *upnp, msu_client_t *client,
                                      msu_upnp_task_complete_t cb)
 {
        msu_async_cb_data_t *cb_data;
-       msu_async_create_container_t *cb_task_data;
-       msu_device_t *device;
 
        MSU_LOG_DEBUG("Enter");
 
        cb_data = msu_async_cb_data_new(task, cb);
-       cb_task_data = &cb_data->ut.create_container;
-
-       if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
-                                     &cb_data->id, &cb_data->error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
 
-       MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
-                     cb_data->id);
+       MSU_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
+                     task->target.id);
 
-       if (strcmp(cb_data->id, "0")) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
+       if (strcmp(task->target.id, "0")) {
+               MSU_LOG_WARNING("Bad path %s", task->target.path);
 
                cb_data->error =
                        g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
-                                   "CreateContainerInAnyContainer must be "
-                                   "executed on a root path");
-               goto on_error;
-       }
-
-       device = msu_device_from_path(cb_task_data->root_path,
-                                                       upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s",
-                                               cb_task_data->root_path);
-
-               cb_data->error =
-                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
+                                   "CreateContainerInAnyContainer must be executed on a root path");
                goto on_error;
        }
 
-       msu_device_create_container(device, client, task,
+       msu_device_create_container(client, task,
                                    "DLNA.ORG_AnyContainer",
                                    cb_data, cancellable);
 
@@ -1329,9 +1017,7 @@ void msu_upnp_update_object(msu_upnp_t *upnp, msu_client_t *client,
 {
        msu_async_cb_data_t *cb_data;
        msu_async_update_t *cb_task_data;
-       msu_device_t *device;
-       guint32 mask;
-       gchar *root_path = NULL;
+       msu_upnp_prop_mask mask;
        gchar *upnp_filter = NULL;
        msu_task_update_t *task_data;
 
@@ -1341,25 +1027,8 @@ void msu_upnp_update_object(msu_upnp_t *upnp, msu_client_t *client,
        cb_task_data = &cb_data->ut.update;
        task_data = &task->ut.update;
 
-       if (!msu_path_get_path_and_id(task->path, &root_path,
-                                     &cb_data->id, &cb_data->error)) {
-               MSU_LOG_WARNING("Bad path %s", task->path);
-
-               goto on_error;
-       }
-
-       MSU_LOG_DEBUG("Root Path = %s, Id = %s", root_path, cb_data->id);
-
-       device = msu_device_from_path(root_path, upnp->server_udn_map);
-       if (!device) {
-               MSU_LOG_WARNING("Cannot locate device for %s", root_path);
-
-               cb_data->error =
-                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
-                                   "Cannot locate device corresponding to"
-                                   " the specified path");
-               goto on_error;
-       }
+       MSU_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
+                     task->target.id);
 
        if (!msu_props_parse_update_filter(upnp->filter_map,
                                           task_data->to_add_update,
@@ -1376,7 +1045,7 @@ void msu_upnp_update_object(msu_upnp_t *upnp, msu_client_t *client,
        cb_task_data->map = upnp->filter_map;
 
        MSU_LOG_DEBUG("Filter = %s", upnp_filter);
-       MSU_LOG_DEBUG("Mask = 0x%x", mask);
+       MSU_LOG_DEBUG("Mask = 0x%"G_GUINT64_FORMAT"x", mask);
 
        if (mask == 0) {
                MSU_LOG_WARNING("Empty Parameters");
@@ -1388,14 +1057,11 @@ void msu_upnp_update_object(msu_upnp_t *upnp, msu_client_t *client,
                goto on_error;
        }
 
-       msu_device_update_object(device, client, task, cb_data, upnp_filter,
+       msu_device_update_object(client, task, cb_data, upnp_filter,
                                 cancellable);
 
 on_error:
 
-       if (root_path)
-               g_free(root_path);
-
        g_free(upnp_filter);
 
        if (!cb_data->action)
index 7e8ae08..74808eb 100644 (file)
@@ -54,6 +54,7 @@ msu_upnp_t *msu_upnp_new(GDBusConnection *connection,
                         void *user_data);
 void msu_upnp_delete(msu_upnp_t *upnp);
 GVariant *msu_upnp_get_server_ids(msu_upnp_t *upnp);
+GHashTable *msu_upnp_get_server_udn_map(msu_upnp_t *upnp);
 void msu_upnp_get_children(msu_upnp_t *upnp, msu_client_t *client,
                           msu_task_t *task,
                           GCancellable *cancellable,
index cd05e6d..1695cbc 100644 (file)
@@ -162,6 +162,9 @@ class Device(Container):
     def cancel_upload(self, id):
         self.__deviceIF.CancelUpload(id)
 
+    def cancel(self):
+        return self.__deviceIF.Cancel()
+
 class UPNP(object):
 
     def __init__(self):