Update media-service-upnp to version 0.3.0 ( ca17a69 )
[profile/ivi/media-service-upnp.git] / src / upnp.c
index 3f2d38f..a93a303 100644 (file)
 
 #include <string.h>
 
+#include <libgssdp/gssdp-resource-browser.h>
 #include <libgupnp/gupnp-control-point.h>
 #include <libgupnp/gupnp-error.h>
 
 #include "async.h"
+#include "chain-task.h"
 #include "device.h"
 #include "error.h"
 #include "interface.h"
@@ -39,14 +41,25 @@ struct msu_upnp_t_ {
        GDBusConnection *connection;
        msu_interface_info_t *interface_info;
        GHashTable *filter_map;
+       GHashTable *property_map;
        msu_upnp_callback_t found_server;
        msu_upnp_callback_t lost_server;
        GUPnPContextManager *context_manager;
        void *user_data;
        GHashTable *server_udn_map;
+       GHashTable *server_uc_map;
        guint counter;
 };
 
+/* Private structure used in chain task */
+typedef struct prv_device_new_ct_t_ prv_device_new_ct_t;
+struct prv_device_new_ct_t_ {
+       msu_upnp_t *upnp;
+       const char *udn;
+       msu_device_t *device;
+       msu_chain_task_t *chain;
+};
+
 static gchar **prv_subtree_enumerate(GDBusConnection *connection,
                                     const gchar *sender,
                                     const gchar *object_path,
@@ -157,6 +170,9 @@ static const GDBusInterfaceVTable *prv_subtree_dispatch(
        if (!strcmp(MSU_INTERFACE_MEDIA_CONTAINER, interface_name))
                retval = upnp->interface_info[
                        MSU_INTERFACE_INFO_CONTAINER].vtable;
+       else if (!strcmp(MSU_INTERFACE_MEDIA_OBJECT, interface_name))
+               retval = upnp->interface_info[
+                       MSU_INTERFACE_INFO_OBJECT].vtable;
        else if (!strcmp(MSU_INTERFACE_PROPERTIES, interface_name))
                retval = upnp->interface_info[
                        MSU_INTERFACE_INFO_PROPERTIES].vtable;
@@ -171,6 +187,34 @@ static const GDBusInterfaceVTable *prv_subtree_dispatch(
        return retval;
 }
 
+static void prv_device_chain_end(msu_chain_task_t *chain, gpointer data)
+{
+       msu_device_t *device;
+       gboolean canceled;
+       prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *) data;
+
+       device = msu_chain_task_get_device(chain);
+       canceled = msu_chain_task_is_canceled(chain);
+       if (canceled)
+               goto on_clear;
+
+       MSU_LOG_DEBUG("Notify new server available: %s", device->path);
+       g_hash_table_insert(priv_t->upnp->server_udn_map, g_strdup(priv_t->udn),
+                           device);
+       priv_t->upnp->found_server(device->path, priv_t->upnp->user_data);
+
+on_clear:
+
+       g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
+       msu_chain_task_delete(chain);
+       g_free(priv_t);
+
+       if (canceled)
+               msu_device_delete(device);
+
+       MSU_LOG_DEBUG_NL();
+}
+
 static void prv_server_available_cb(GUPnPControlPoint *cp,
                                    GUPnPDeviceProxy *proxy,
                                    gpointer user_data)
@@ -180,9 +224,9 @@ static void prv_server_available_cb(GUPnPControlPoint *cp,
        msu_device_t *device;
        const gchar *ip_address;
        msu_device_context_t *context;
+       msu_chain_task_t *chain;
        unsigned int i;
-
-       MSU_LOG_DEBUG("Enter");
+       prv_device_new_ct_t *priv_t;
 
        udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *) proxy);
        if (!udn)
@@ -197,16 +241,31 @@ static void prv_server_available_cb(GUPnPControlPoint *cp,
        device = g_hash_table_lookup(upnp->server_udn_map, udn);
 
        if (!device) {
+               priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
+
+               if (priv_t)
+                       device = priv_t->device;
+       }
+
+       if (!device) {
                MSU_LOG_DEBUG("Device not found. Adding");
+               MSU_LOG_DEBUG_NL();
 
-               if (msu_device_new(upnp->connection, proxy,
-                                  ip_address, &gSubtreeVtable, upnp,
-                                  upnp->counter, &device)) {
-                       upnp->counter++;
-                       g_hash_table_insert(upnp->server_udn_map, g_strdup(udn),
-                                           device);
-                       upnp->found_server(device->path, upnp->user_data);
-               }
+               priv_t = g_new0(prv_device_new_ct_t, 1);
+               chain = msu_chain_task_new(prv_device_chain_end, priv_t);
+               device = msu_device_new(upnp->connection, proxy, ip_address,
+                                       &gSubtreeVtable, upnp,
+                                       upnp->property_map, upnp->counter,
+                                       chain);
+
+               upnp->counter++;
+
+               priv_t->upnp = upnp;
+               priv_t->udn = udn;
+               priv_t->chain = chain;
+               priv_t->device = device;
+
+               g_hash_table_insert(upnp->server_uc_map, g_strdup(udn), priv_t);
        } else {
                MSU_LOG_DEBUG("Device Found");
 
@@ -221,13 +280,12 @@ static void prv_server_available_cb(GUPnPControlPoint *cp,
                        msu_device_append_new_context(device, ip_address,
                                                      proxy);
                }
+
+               MSU_LOG_DEBUG_NL();
        }
 
 on_error:
 
-       MSU_LOG_DEBUG("Exit");
-       MSU_LOG_DEBUG_NL();
-
        return;
 }
 
@@ -252,6 +310,8 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
        unsigned int i;
        msu_device_context_t *context;
        gboolean subscribed;
+       gboolean under_construction = FALSE;
+       prv_device_new_ct_t *priv_t;
 
        MSU_LOG_DEBUG("Enter");
 
@@ -266,6 +326,16 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
        MSU_LOG_DEBUG("IP Address %s", ip_address);
 
        device = g_hash_table_lookup(upnp->server_udn_map, udn);
+
+       if (!device) {
+               priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
+
+               if (priv_t) {
+                       device = priv_t->device;
+                       under_construction = TRUE;
+               }
+       }
+
        if (!device) {
                MSU_LOG_WARNING("Device not found. Ignoring");
                goto on_error;
@@ -282,9 +352,20 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
 
                (void) g_ptr_array_remove_index(device->contexts, i);
                if (device->contexts->len == 0) {
-                       MSU_LOG_DEBUG("Last Context lost. Delete device");
-                       upnp->lost_server(device->path, upnp->user_data);
-                       g_hash_table_remove(upnp->server_udn_map, udn);
+                       if (!under_construction) {
+                               MSU_LOG_DEBUG("Last Context lost. " \
+                                              "Delete device");
+
+                               upnp->lost_server(device->path,
+                                                 upnp->user_data);
+                               g_hash_table_remove(upnp->server_udn_map, udn);
+                       } else {
+                               MSU_LOG_WARNING("Device under construction. "\
+                                                "Cancelling");
+
+                               msu_chain_task_cancel(priv_t->chain);
+                               prv_device_chain_end(priv_t->chain, priv_t);
+                       }
                } else if (subscribed && !device->timeout_id) {
 
                        MSU_LOG_DEBUG("Subscribe on new context");
@@ -342,7 +423,12 @@ msu_upnp_t *msu_upnp_new(GDBusConnection *connection,
        upnp->server_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                     g_free,
                                                     msu_device_delete);
-       upnp->filter_map = msu_prop_maps_new();
+
+       upnp->server_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                    g_free, NULL);
+
+       msu_prop_maps_new(&upnp->property_map, &upnp->filter_map);
+
        upnp->context_manager = gupnp_context_manager_create(0);
 
        g_signal_connect(upnp->context_manager, "context-available",
@@ -356,8 +442,10 @@ void msu_upnp_delete(msu_upnp_t *upnp)
 {
        if (upnp) {
                g_object_unref(upnp->context_manager);
+               g_hash_table_unref(upnp->property_map);
                g_hash_table_unref(upnp->filter_map);
                g_hash_table_unref(upnp->server_udn_map);
+               g_hash_table_unref(upnp->server_uc_map);
                g_free(upnp->interface_info);
                g_free(upnp);
        }
@@ -389,11 +477,10 @@ GVariant *msu_upnp_get_server_ids(msu_upnp_t *upnp)
        return retval;
 }
 
-void msu_upnp_get_children(msu_upnp_t *upnp, msu_task_t *task,
-                          const gchar *protocol_info,
+void msu_upnp_get_children(msu_upnp_t *upnp, msu_client_t *client,
+                          msu_task_t *task,
                           GCancellable *cancellable,
-                          msu_upnp_task_complete_t cb,
-                          void *user_data)
+                          msu_upnp_task_complete_t cb)
 {
        msu_async_cb_data_t *cb_data;
        msu_async_bas_t *cb_task_data;
@@ -407,7 +494,7 @@ void msu_upnp_get_children(msu_upnp_t *upnp, msu_task_t *task,
        MSU_LOG_DEBUG("Start: %u", task->ut.get_children.start);
        MSU_LOG_DEBUG("Count: %u", task->ut.get_children.count);
 
-       cb_data = msu_async_cb_data_new(task, cb, user_data);
+       cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.bas;
 
        if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
@@ -449,9 +536,9 @@ void msu_upnp_get_children(msu_upnp_t *upnp, msu_task_t *task,
 
        MSU_LOG_DEBUG("Sort By %s", sort_by);
 
-       cb_task_data->protocol_info = protocol_info;
+       cb_task_data->protocol_info = client->protocol_info;
 
-       msu_device_get_children(device, task, cb_data,
+       msu_device_get_children(device, client, task, cb_data,
                                upnp_filter, sort_by, cancellable);
 
 on_error:
@@ -465,11 +552,10 @@ on_error:
        MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
 }
 
-void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_task_t *task,
-                           const gchar *protocol_info,
+void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_client_t *client,
+                           msu_task_t *task,
                            GCancellable *cancellable,
-                           msu_upnp_task_complete_t cb,
-                           void *user_data)
+                           msu_upnp_task_complete_t cb)
 {
        gboolean root_object;
        msu_async_cb_data_t *cb_data;
@@ -481,7 +567,7 @@ void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_task_t *task,
        MSU_LOG_DEBUG("Path: %s", task->path);
        MSU_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
 
-       cb_data = msu_async_cb_data_new(task, cb, user_data);
+       cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.get_all;
 
        if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
@@ -508,9 +594,9 @@ void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_task_t *task,
                goto on_error;
        }
 
-       cb_task_data->protocol_info = protocol_info;
+       cb_task_data->protocol_info = client->protocol_info;
 
-       msu_device_get_all_props(device, task, cb_data, root_object,
+       msu_device_get_all_props(device, client, task, cb_data, root_object,
                                 cancellable);
 
        MSU_LOG_DEBUG("Exit with SUCCESS");
@@ -524,11 +610,10 @@ on_error:
        MSU_LOG_DEBUG("Exit with FAIL");
 }
 
-void msu_upnp_get_prop(msu_upnp_t *upnp, msu_task_t *task,
-                      const gchar *protocol_info,
+void msu_upnp_get_prop(msu_upnp_t *upnp, msu_client_t *client,
+                      msu_task_t *task,
                       GCancellable *cancellable,
-                      msu_upnp_task_complete_t cb,
-                      void *user_data)
+                      msu_upnp_task_complete_t cb)
 {
        gboolean root_object;
        msu_async_cb_data_t *cb_data;
@@ -544,7 +629,7 @@ void msu_upnp_get_prop(msu_upnp_t *upnp, msu_task_t *task,
        MSU_LOG_DEBUG("Prop.%s", task->ut.get_prop.prop_name);
 
        task_data = &task->ut.get_prop;
-       cb_data = msu_async_cb_data_new(task, cb, user_data);
+       cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.get_prop;
 
        if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
@@ -572,10 +657,10 @@ void msu_upnp_get_prop(msu_upnp_t *upnp, msu_task_t *task,
                goto on_error;
        }
 
-       cb_task_data->protocol_info = protocol_info;
+       cb_task_data->protocol_info = client->protocol_info;
        prop_map = g_hash_table_lookup(upnp->filter_map, task_data->prop_name);
 
-       msu_device_get_prop(device, task, cb_data, prop_map,
+       msu_device_get_prop(device, client, task, cb_data, prop_map,
                            root_object, cancellable);
 
        MSU_LOG_DEBUG("Exit with SUCCESS");
@@ -589,11 +674,10 @@ on_error:
        MSU_LOG_DEBUG("Exit with FAIL");
 }
 
-void msu_upnp_search(msu_upnp_t *upnp, msu_task_t *task,
-                    const gchar *protocol_info,
+void msu_upnp_search(msu_upnp_t *upnp, msu_client_t *client,
+                    msu_task_t *task,
                     GCancellable *cancellable,
-                    msu_upnp_task_complete_t cb,
-                    void *user_data)
+                    msu_upnp_task_complete_t cb)
 {
        gchar *upnp_filter = NULL;
        gchar *upnp_query = NULL;
@@ -609,7 +693,7 @@ void msu_upnp_search(msu_upnp_t *upnp, msu_task_t *task,
        MSU_LOG_DEBUG("Start: %u", task->ut.search.start);
        MSU_LOG_DEBUG("Count: %u", task->ut.search.count);
 
-       cb_data = msu_async_cb_data_new(task, cb, user_data);
+       cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.bas;
 
        if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
@@ -663,9 +747,9 @@ void msu_upnp_search(msu_upnp_t *upnp, msu_task_t *task,
 
        MSU_LOG_DEBUG("Sort By %s", sort_by);
 
-       cb_task_data->protocol_info = protocol_info;
+       cb_task_data->protocol_info = client->protocol_info;
 
-       msu_device_search(device, task, cb_data, upnp_filter,
+       msu_device_search(device, client, task, cb_data, upnp_filter,
                          upnp_query, sort_by, cancellable);
 on_error:
 
@@ -679,10 +763,10 @@ on_error:
        MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
 }
 
-void msu_upnp_get_resource(msu_upnp_t *upnp, msu_task_t *task,
+void msu_upnp_get_resource(msu_upnp_t *upnp, msu_client_t *client,
+                          msu_task_t *task,
                           GCancellable *cancellable,
-                          msu_upnp_task_complete_t cb,
-                          void *user_data)
+                          msu_upnp_task_complete_t cb)
 {
        msu_async_cb_data_t *cb_data;
        msu_async_get_all_t *cb_task_data;
@@ -694,7 +778,7 @@ void msu_upnp_get_resource(msu_upnp_t *upnp, msu_task_t *task,
 
        MSU_LOG_DEBUG("Protocol Info: %s ", task->ut.resource.protocol_info);
 
-       cb_data = msu_async_cb_data_new(task, cb, user_data);
+       cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.get_all;
 
        if (!msu_path_get_path_and_id(task->path, &root_path, &cb_data->id,
@@ -723,7 +807,7 @@ void msu_upnp_get_resource(msu_upnp_t *upnp, msu_task_t *task,
 
        MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
 
-       msu_device_get_resource(device, task, cb_data, upnp_filter,
+       msu_device_get_resource(device, client, task, cb_data, upnp_filter,
                                cancellable);
 
 on_error:
@@ -808,10 +892,10 @@ on_error:
        return FALSE;
 }
 
-void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_task_t *task,
+void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_client_t *client,
+                           msu_task_t *task,
                            GCancellable *cancellable,
-                           msu_upnp_task_complete_t cb,
-                           void *user_data)
+                           msu_upnp_task_complete_t cb)
 {
        msu_async_cb_data_t *cb_data;
        msu_async_upload_t *cb_task_data;
@@ -819,7 +903,7 @@ void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_task_t *task,
 
        MSU_LOG_DEBUG("Enter");
 
-       cb_data = msu_async_cb_data_new(task, cb, user_data);
+       cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.upload;
 
        if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
@@ -861,8 +945,8 @@ void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_task_t *task,
        MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
        MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
 
-       msu_device_upload(device, task, "DLNA.ORG_AnyContainer", cb_data,
-                         cancellable);
+       msu_device_upload(device, client, task, "DLNA.ORG_AnyContainer",
+                         cb_data, cancellable);
 
 on_error:
 
@@ -872,10 +956,9 @@ on_error:
        MSU_LOG_DEBUG("Exit");
 }
 
-void msu_upnp_upload(msu_upnp_t *upnp, msu_task_t *task,
+void msu_upnp_upload(msu_upnp_t *upnp, msu_client_t *client, msu_task_t *task,
                     GCancellable *cancellable,
-                    msu_upnp_task_complete_t cb,
-                    void *user_data)
+                    msu_upnp_task_complete_t cb)
 {
        msu_async_cb_data_t *cb_data;
        msu_async_upload_t *cb_task_data;
@@ -883,7 +966,7 @@ void msu_upnp_upload(msu_upnp_t *upnp, msu_task_t *task,
 
        MSU_LOG_DEBUG("Enter");
 
-       cb_data = msu_async_cb_data_new(task, cb, user_data);
+       cb_data = msu_async_cb_data_new(task, cb);
        cb_task_data = &cb_data->ut.upload;
 
        if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
@@ -912,7 +995,265 @@ void msu_upnp_upload(msu_upnp_t *upnp, msu_task_t *task,
        MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
        MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
 
-       msu_device_upload(device, task, cb_data->id, cb_data, cancellable);
+       msu_device_upload(device, client, task, cb_data->id, cb_data,
+                         cancellable);
+
+on_error:
+
+       if (!cb_data->action)
+               (void) g_idle_add(msu_async_complete_task, cb_data);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_get_upload_status(msu_upnp_t *upnp, msu_task_t *task)
+{
+       gchar *root_path = NULL;
+       gchar *id = NULL;
+       GError *error = NULL;
+       msu_device_t *device;
+
+       MSU_LOG_DEBUG("Enter");
+
+       if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
+               MSU_LOG_WARNING("Bad path %s", task->path);
+
+               goto on_error;
+       }
+
+       MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
+
+       device = msu_device_from_path(root_path, upnp->server_udn_map);
+       if (!device) {
+               MSU_LOG_WARNING("Cannot locate device for %s",
+                               root_path);
+
+               error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+                                   "Cannot locate device corresponding to"
+                                   " the specified path");
+               goto on_error;
+       }
+
+       if (strcmp(id, "0")) {
+               MSU_LOG_WARNING("Bad path %s", task->path);
+
+               error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+                                   "GetUploadStatus must be executed "
+                                   " on a root path");
+               goto on_error;
+       }
+
+       (void) msu_device_get_upload_status(device, task, &error);
+
+on_error:
+
+       if (error) {
+               msu_task_fail_and_delete(task, error);
+               g_error_free(error);
+       } else {
+               msu_task_complete_and_delete(task);
+       }
+
+       g_free(id);
+       g_free(root_path);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_get_upload_ids(msu_upnp_t *upnp, msu_task_t *task)
+{
+       gchar *root_path = NULL;
+       gchar *id = NULL;
+       GError *error = NULL;
+       msu_device_t *device;
+
+       MSU_LOG_DEBUG("Enter");
+
+       if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
+               MSU_LOG_WARNING("Bad path %s", task->path);
+
+               goto on_error;
+       }
+
+       MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
+
+       device = msu_device_from_path(root_path, upnp->server_udn_map);
+       if (!device) {
+               MSU_LOG_WARNING("Cannot locate device for %s",
+                               root_path);
+
+               error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+                                   "Cannot locate device corresponding to"
+                                   " the specified path");
+               goto on_error;
+       }
+
+       if (strcmp(id, "0")) {
+               MSU_LOG_WARNING("Bad path %s", task->path);
+
+               error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+                                   "GetUploadIDs must be executed "
+                                   " on a root path");
+               goto on_error;
+       }
+
+        msu_device_get_upload_ids(device, task);
+
+on_error:
+
+       if (error) {
+               msu_task_fail_and_delete(task, error);
+               g_error_free(error);
+       } else {
+               msu_task_complete_and_delete(task);
+       }
+
+       g_free(id);
+       g_free(root_path);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_cancel_upload(msu_upnp_t *upnp, msu_task_t *task)
+{
+       gchar *root_path = NULL;
+       gchar *id = NULL;
+       GError *error = NULL;
+       msu_device_t *device;
+
+       MSU_LOG_DEBUG("Enter");
+
+       if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
+               MSU_LOG_WARNING("Bad path %s", task->path);
+
+               goto on_error;
+       }
+
+       MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
+
+       device = msu_device_from_path(root_path, upnp->server_udn_map);
+       if (!device) {
+               MSU_LOG_WARNING("Cannot locate device for %s",
+                               root_path);
+
+               error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+                                   "Cannot locate device corresponding to"
+                                   " the specified path");
+               goto on_error;
+       }
+
+       if (strcmp(id, "0")) {
+               MSU_LOG_WARNING("Bad path %s", task->path);
+
+               error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+                                   "CancelUpload must be executed "
+                                   " on a root path");
+               goto on_error;
+       }
+
+       (void) msu_device_cancel_upload(device, task, &error);
+
+on_error:
+
+       if (error) {
+               msu_task_fail_and_delete(task, error);
+               g_error_free(error);
+       } else {
+               msu_task_complete_and_delete(task);
+       }
+
+       g_free(id);
+       g_free(root_path);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_delete_object(msu_upnp_t *upnp, msu_client_t *client,
+                           msu_task_t *task,
+                           GCancellable *cancellable,
+                           msu_upnp_task_complete_t cb)
+{
+       msu_async_cb_data_t *cb_data;
+       msu_device_t *device;
+       gchar *root_path = NULL;
+
+       MSU_LOG_DEBUG("Enter");
+
+       cb_data = msu_async_cb_data_new(task, cb);
+
+       if (!msu_path_get_path_and_id(task->path, &root_path,
+                                     &cb_data->id, &cb_data->error)) {
+               MSU_LOG_WARNING("Bad path %s", task->path);
+
+               goto on_error;
+       }
+
+       MSU_LOG_DEBUG("Root Path %s Id %s", root_path,
+                     cb_data->id);
+
+       device = msu_device_from_path(root_path, upnp->server_udn_map);
+       if (!device) {
+               MSU_LOG_WARNING("Cannot locate device for %s",
+                               root_path);
+
+               cb_data->error =
+                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+                                   "Cannot locate device corresponding to"
+                                   " the specified path");
+               goto on_error;
+       }
+
+       msu_device_delete_object(device, client, task, cb_data, cancellable);
+
+on_error:
+
+       if (root_path)
+               g_free(root_path);
+       if (!cb_data->action)
+               (void) g_idle_add(msu_async_complete_task, cb_data);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_create_container(msu_upnp_t *upnp, msu_client_t *client,
+                              msu_task_t *task,
+                              GCancellable *cancellable,
+                              msu_upnp_task_complete_t cb)
+{
+       msu_async_cb_data_t *cb_data;
+       msu_async_create_container_t *cb_task_data;
+       msu_device_t *device;
+
+       MSU_LOG_DEBUG("Enter");
+
+       cb_data = msu_async_cb_data_new(task, cb);
+       cb_task_data = &cb_data->ut.create_container;
+
+       if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
+                                     &cb_data->id, &cb_data->error)) {
+               MSU_LOG_WARNING("Bad path %s", task->path);
+
+               goto on_error;
+       }
+
+       MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
+                     cb_data->id);
+
+       device = msu_device_from_path(cb_task_data->root_path,
+                                                       upnp->server_udn_map);
+       if (!device) {
+               MSU_LOG_WARNING("Cannot locate device for %s",
+                                               cb_task_data->root_path);
+
+               cb_data->error =
+                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+                                   "Cannot locate device corresponding to"
+                                   " the specified path");
+               goto on_error;
+       }
+
+       msu_device_create_container(device, client, task, cb_data->id,
+                                   cb_data, cancellable);
 
 on_error:
 
@@ -921,3 +1262,144 @@ on_error:
 
        MSU_LOG_DEBUG("Exit");
 }
+
+void msu_upnp_create_container_in_any(msu_upnp_t *upnp, msu_client_t *client,
+                                     msu_task_t *task,
+                                     GCancellable *cancellable,
+                                     msu_upnp_task_complete_t cb)
+{
+       msu_async_cb_data_t *cb_data;
+       msu_async_create_container_t *cb_task_data;
+       msu_device_t *device;
+
+       MSU_LOG_DEBUG("Enter");
+
+       cb_data = msu_async_cb_data_new(task, cb);
+       cb_task_data = &cb_data->ut.create_container;
+
+       if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
+                                     &cb_data->id, &cb_data->error)) {
+               MSU_LOG_WARNING("Bad path %s", task->path);
+
+               goto on_error;
+       }
+
+       MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
+                     cb_data->id);
+
+       if (strcmp(cb_data->id, "0")) {
+               MSU_LOG_WARNING("Bad path %s", task->path);
+
+               cb_data->error =
+                       g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
+                                   "CreateContainerInAnyContainer must be "
+                                   "executed on a root path");
+               goto on_error;
+       }
+
+       device = msu_device_from_path(cb_task_data->root_path,
+                                                       upnp->server_udn_map);
+       if (!device) {
+               MSU_LOG_WARNING("Cannot locate device for %s",
+                                               cb_task_data->root_path);
+
+               cb_data->error =
+                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+                                   "Cannot locate device corresponding to"
+                                   " the specified path");
+               goto on_error;
+       }
+
+       msu_device_create_container(device, client, task,
+                                   "DLNA.ORG_AnyContainer",
+                                   cb_data, cancellable);
+
+on_error:
+
+       if (!cb_data->action)
+               (void) g_idle_add(msu_async_complete_task, cb_data);
+
+       MSU_LOG_DEBUG("Exit");
+}
+
+void msu_upnp_update_object(msu_upnp_t *upnp, msu_client_t *client,
+                           msu_task_t *task,
+                           GCancellable *cancellable,
+                           msu_upnp_task_complete_t cb)
+{
+       msu_async_cb_data_t *cb_data;
+       msu_async_update_t *cb_task_data;
+       msu_device_t *device;
+       guint32 mask;
+       gchar *root_path = NULL;
+       gchar *upnp_filter = NULL;
+       msu_task_update_t *task_data;
+
+       MSU_LOG_DEBUG("Enter");
+
+       cb_data = msu_async_cb_data_new(task, cb);
+       cb_task_data = &cb_data->ut.update;
+       task_data = &task->ut.update;
+
+       if (!msu_path_get_path_and_id(task->path, &root_path,
+                                     &cb_data->id, &cb_data->error)) {
+               MSU_LOG_WARNING("Bad path %s", task->path);
+
+               goto on_error;
+       }
+
+       MSU_LOG_DEBUG("Root Path = %s, Id = %s", root_path, cb_data->id);
+
+       device = msu_device_from_path(root_path, upnp->server_udn_map);
+       if (!device) {
+               MSU_LOG_WARNING("Cannot locate device for %s", root_path);
+
+               cb_data->error =
+                       g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
+                                   "Cannot locate device corresponding to"
+                                   " the specified path");
+               goto on_error;
+       }
+
+       if (!msu_props_parse_update_filter(upnp->filter_map,
+                                          task_data->to_add_update,
+                                          task_data->to_delete,
+                                          &mask, &upnp_filter)) {
+               MSU_LOG_WARNING("Invalid Parameter");
+
+               cb_data->error = g_error_new(MSU_ERROR,
+                                            MSU_ERROR_OPERATION_FAILED,
+                                            "Invalid Parameter");
+               goto on_error;
+       }
+
+       cb_task_data->map = upnp->filter_map;
+
+       MSU_LOG_DEBUG("Filter = %s", upnp_filter);
+       MSU_LOG_DEBUG("Mask = 0x%x", mask);
+
+       if (mask == 0) {
+               MSU_LOG_WARNING("Empty Parameters");
+
+               cb_data->error = g_error_new(MSU_ERROR,
+                                            MSU_ERROR_OPERATION_FAILED,
+                                            "Empty Parameters");
+
+               goto on_error;
+       }
+
+       msu_device_update_object(device, client, task, cb_data, upnp_filter,
+                                cancellable);
+
+on_error:
+
+       if (root_path)
+               g_free(root_path);
+
+       g_free(upnp_filter);
+
+       if (!cb_data->action)
+               (void) g_idle_add(msu_async_complete_task, cb_data);
+
+       MSU_LOG_DEBUG("Exit");
+}