Update media-service-upnp to version 0.3.0 ( ca17a69 )
[profile/ivi/media-service-upnp.git] / src / media-service-upnp.c
index db09283..963ab38 100644 (file)
 #include <syslog.h>
 #include <sys/signalfd.h>
 
+#include "client.h"
 #include "interface.h"
 #include "log.h"
 #include "settings.h"
 #include "task.h"
 #include "upnp.h"
 
-typedef struct msu_client_t_ msu_client_t;
-struct msu_client_t_ {
-       guint id;
-       gchar *protocol_info;
-};
-
 typedef struct msu_context_t_ msu_context_t;
 struct msu_context_t_ {
        bool error;
@@ -61,6 +56,8 @@ struct msu_context_t_ {
        msu_settings_context_t *settings;
 };
 
+static msu_context_t g_context;
+
 static const gchar g_msu_root_introspection[] =
        "<node>"
        "  <interface name='"MSU_INTERFACE_MANAGER"'>"
@@ -78,6 +75,10 @@ static const gchar g_msu_root_introspection[] =
        "      <arg type='s' name='"MSU_INTERFACE_PROTOCOL_INFO"'"
        "           direction='in'/>"
        "    </method>"
+       "    <method name='"MSU_INTERFACE_PREFER_LOCAL_ADDRESSES"'>"
+       "      <arg type='b' name='"MSU_INTERFACE_PREFER"'"
+       "           direction='in'/>"
+       "    </method>"
        "    <signal name='"MSU_INTERFACE_FOUND_SERVER"'>"
        "      <arg type='o' name='"MSU_INTERFACE_PATH"'/>"
        "    </signal>"
@@ -104,6 +105,11 @@ static const gchar g_msu_server_introspection[] =
        "      <arg type='a{sv}' name='"MSU_INTERFACE_PROPERTIES_VALUE"'"
        "           direction='out'/>"
        "    </method>"
+       "    <signal name='"MSU_INTERFACE_PROPERTIES_CHANGED"'>"
+       "      <arg type='s' name='"MSU_INTERFACE_INTERFACE_NAME"'/>"
+       "      <arg type='a{sv}' name='"MSU_INTERFACE_CHANGED_PROPERTIES"'/>"
+       "      <arg type='as' name='"MSU_INTERFACE_INVALIDATED_PROPERTIES"'/>"
+       "    </signal>"
        "  </interface>"
        "  <interface name='"MSU_INTERFACE_MEDIA_OBJECT"'>"
        "    <property type='o' name='"MSU_INTERFACE_PROP_PARENT"'"
@@ -114,8 +120,20 @@ static const gchar g_msu_server_introspection[] =
        "       access='read'/>"
        "    <property type='s' name='"MSU_INTERFACE_PROP_DISPLAY_NAME"'"
        "       access='read'/>"
+       "    <property type='s' name='"MSU_INTERFACE_PROP_CREATOR"'"
+       "       access='read'/>"
        "    <property type='b' name='"MSU_INTERFACE_PROP_RESTRICTED"'"
        "       access='read'/>"
+       "    <property type='a{sb}' name='"MSU_INTERFACE_PROP_DLNA_MANAGED"'"
+       "       access='read'/>"
+       "    <method name='"MSU_INTERFACE_DELETE"'>"
+       "    </method>"
+       "    <method name='"MSU_INTERFACE_UPDATE"'>"
+       "      <arg type='a{sv}' name='"MSU_INTERFACE_TO_ADD_UPDATE"'"
+       "           direction='in'/>"
+       "      <arg type='as' name='"MSU_INTERFACE_TO_DELETE"'"
+       "           direction='in'/>"
+       "    </method>"
        "  </interface>"
        "  <interface name='"MSU_INTERFACE_MEDIA_CONTAINER"'>"
        "    <method name='"MSU_INTERFACE_LIST_CHILDREN"'>"
@@ -222,10 +240,22 @@ static const gchar g_msu_server_introspection[] =
        "      <arg type='o' name='"MSU_INTERFACE_PATH"'"
        "           direction='out'/>"
        "    </method>"
+       "    <method name='"MSU_INTERFACE_CREATE_CONTAINER"'>"
+       "      <arg type='s' name='"MSU_INTERFACE_PROP_DISPLAY_NAME"'"
+       "           direction='in'/>"
+       "      <arg type='s' name='"MSU_INTERFACE_PROP_TYPE"'"
+       "           direction='in'/>"
+       "      <arg type='as' name='"MSU_INTERFACE_CHILD_TYPES"'"
+       "           direction='in'/>"
+       "      <arg type='o' name='"MSU_INTERFACE_PATH"'"
+       "           direction='out'/>"
+       "    </method>"
        "    <property type='u' name='"MSU_INTERFACE_PROP_CHILD_COUNT"'"
        "       access='read'/>"
        "    <property type='b' name='"MSU_INTERFACE_PROP_SEARCHABLE"'"
        "       access='read'/>"
+       "    <property type='a(sb)' name='"MSU_INTERFACE_PROP_CREATE_CLASSES"'"
+       "       access='read'/>"
        "  </interface>"
        "  <interface name='"MSU_INTERFACE_MEDIA_ITEM"'>"
        "    <method name='"MSU_INTERFACE_GET_COMPATIBLE_RESOURCE"'>"
@@ -242,6 +272,8 @@ static const gchar g_msu_server_introspection[] =
        "       access='read'/>"
        "    <property type='s' name='"MSU_INTERFACE_PROP_ARTIST"'"
        "       access='read'/>"
+       "    <property type='as' name='"MSU_INTERFACE_PROP_ARTISTS"'"
+       "       access='read'/>"
        "    <property type='s' name='"MSU_INTERFACE_PROP_ALBUM"'"
        "       access='read'/>"
        "    <property type='s' name='"MSU_INTERFACE_PROP_DATE"'"
@@ -286,6 +318,34 @@ static const gchar g_msu_server_introspection[] =
        "      <arg type='o' name='"MSU_INTERFACE_PATH"'"
        "           direction='out'/>"
        "    </method>"
+       "    <method name='"MSU_INTERFACE_GET_UPLOAD_STATUS"'>"
+       "      <arg type='u' name='"MSU_INTERFACE_UPLOAD_ID"'"
+       "           direction='in'/>"
+       "      <arg type='s' name='"MSU_INTERFACE_UPLOAD_STATUS"'"
+       "           direction='out'/>"
+       "      <arg type='t' name='"MSU_INTERFACE_LENGTH"'"
+       "           direction='out'/>"
+       "      <arg type='t' name='"MSU_INTERFACE_TOTAL"'"
+       "           direction='out'/>"
+       "    </method>"
+       "    <method name='"MSU_INTERFACE_GET_UPLOAD_IDS"'>"
+       "      <arg type='au' name='"MSU_INTERFACE_TOTAL"'"
+       "           direction='out'/>"
+       "    </method>"
+       "    <method name='"MSU_INTERFACE_CANCEL_UPLOAD"'>"
+       "      <arg type='u' name='"MSU_INTERFACE_UPLOAD_ID"'"
+       "           direction='in'/>"
+       "    </method>"
+       "    <method name='"MSU_INTERFACE_CREATE_CONTAINER_IN_ANY"'>"
+       "      <arg type='s' name='"MSU_INTERFACE_PROP_DISPLAY_NAME"'"
+       "           direction='in'/>"
+       "      <arg type='s' name='"MSU_INTERFACE_PROP_TYPE"'"
+       "           direction='in'/>"
+       "      <arg type='as' name='"MSU_INTERFACE_CHILD_TYPES"'"
+       "           direction='in'/>"
+       "      <arg type='o' name='"MSU_INTERFACE_PATH"'"
+       "           direction='out'/>"
+       "    </method>"
        "    <property type='s' name='"MSU_INTERFACE_PROP_LOCATION"'"
        "       access='read'/>"
        "    <property type='s' name='"MSU_INTERFACE_PROP_UDN"'"
@@ -312,12 +372,36 @@ static const gchar g_msu_server_introspection[] =
        "       access='read'/>"
        "    <property type='s' name='"MSU_INTERFACE_PROP_ICON_URL"'"
        "       access='read'/>"
-       "    <signal name='"MSU_INTERFACE_SYSTEM_UPDATE"'>"
-       "      <arg type='u' name='"MSU_INTERFACE_SYSTEM_UPDATE_ID"'/>"
-       "    </signal>"
+       "    <property type='a{sv}'name='"
+       MSU_INTERFACE_PROP_SV_DLNA_CAPABILITIES"'"
+       "       access='read'/>"
+       "    <property type='as' name='"
+       MSU_INTERFACE_PROP_SV_SEARCH_CAPABILITIES"'"
+       "       access='read'/>"
+       "    <property type='as' name='"
+       MSU_INTERFACE_PROP_SV_SORT_CAPABILITIES"'"
+       "       access='read'/>"
+       "    <property type='as' name='"
+       MSU_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES"'"
+       "       access='read'/>"
+       "    <property type='a(ssao)' name='"
+       MSU_INTERFACE_PROP_SV_FEATURE_LIST"'"
+       "       access='read'/>"
+       "    <property type='u' name='"
+       MSU_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID"'"
+       "       access='read'/>"
+       "    <property type='s' name='"
+       MSU_INTERFACE_PROP_ESV_SERVICE_RESET_TOKEN"'"
+       "       access='read'/>"
        "    <signal name='"MSU_INTERFACE_CONTAINER_UPDATE"'>"
        "      <arg type='ao' name='"MSU_INTERFACE_CONTAINER_PATHS"'/>"
        "    </signal>"
+       "    <signal name='"MSU_INTERFACE_UPLOAD_UPDATE"'>"
+       "      <arg type='u' name='"MSU_INTERFACE_UPLOAD_ID"'/>"
+       "      <arg type='s' name='"MSU_INTERFACE_UPLOAD_STATUS"'/>"
+       "      <arg type='t' name='"MSU_INTERFACE_LENGTH"'/>"
+       "      <arg type='t' name='"MSU_INTERFACE_TOTAL"'/>"
+       "    </signal>"
        "  </interface>"
        "</node>";
 
@@ -328,25 +412,25 @@ static void prv_free_msu_task_cb(gpointer data, gpointer user_data)
        msu_task_delete(data);
 }
 
-static void prv_process_sync_task(msu_context_t *context, msu_task_t *task)
+static void prv_process_sync_task(msu_task_t *task)
 {
        const gchar *client_name;
        msu_client_t *client;
 
-       context->current_task = task;
+       g_context.current_task = task;
 
        switch (task->type) {
        case MSU_TASK_GET_VERSION:
                msu_task_complete_and_delete(task);
                break;
        case MSU_TASK_GET_SERVERS:
-               task->result = msu_upnp_get_server_ids(context->upnp);
+               task->result = msu_upnp_get_server_ids(g_context.upnp);
                msu_task_complete_and_delete(task);
                break;
        case MSU_TASK_SET_PROTOCOL_INFO:
                client_name =
                        g_dbus_method_invocation_get_sender(task->invocation);
-               client = g_hash_table_lookup(context->watchers, client_name);
+               client = g_hash_table_lookup(g_context.watchers, client_name);
                if (client) {
                        g_free(client->protocol_info);
                        if (task->ut.protocol_info.protocol_info[0]) {
@@ -359,24 +443,40 @@ static void prv_process_sync_task(msu_context_t *context, msu_task_t *task)
                }
                msu_task_complete_and_delete(task);
                break;
-
+       case MSU_TASK_SET_PREFER_LOCAL_ADDRESSES:
+               client_name =
+                       g_dbus_method_invocation_get_sender(task->invocation);
+               client = g_hash_table_lookup(g_context.watchers, client_name);
+               if (client) {
+                       client->prefer_local_addresses =
+                                       task->ut.prefer_local_addresses.prefer;
+               }
+               msu_task_complete_and_delete(task);
+               break;
+       case MSU_TASK_GET_UPLOAD_STATUS:
+               msu_upnp_get_upload_status(g_context.upnp, task);
+               break;
+       case MSU_TASK_GET_UPLOAD_IDS:
+               msu_upnp_get_upload_ids(g_context.upnp, task);
+               break;
+       case MSU_TASK_CANCEL_UPLOAD:
+               msu_upnp_cancel_upload(g_context.upnp, task);
+               break;
        default:
                break;
        }
 
-       context->current_task = NULL;
+       g_context.current_task = NULL;
 }
 
 static void prv_async_task_complete(msu_task_t *task, GVariant *result,
-                                   GError *error, void *user_data)
+                                   GError *error)
 {
-       msu_context_t *context = user_data;
-
        MSU_LOG_DEBUG("Enter");
 
-       g_object_unref(context->cancellable);
-       context->cancellable = NULL;
-       context->current_task = NULL;
+       g_object_unref(g_context.cancellable);
+       g_context.cancellable = NULL;
+       g_context.current_task = NULL;
 
        if (error) {
                msu_task_fail_and_delete(task, error);
@@ -386,64 +486,82 @@ static void prv_async_task_complete(msu_task_t *task, GVariant *result,
                msu_task_complete_and_delete(task);
        }
 
-       if (context->quitting)
-               g_main_loop_quit(context->main_loop);
-       else if (context->tasks->len > 0)
-               context->idle_id = g_idle_add(prv_process_task, context);
+       if (g_context.quitting)
+               g_main_loop_quit(g_context.main_loop);
+       else if (g_context.tasks->len > 0)
+               g_context.idle_id = g_idle_add(prv_process_task, NULL);
 
        MSU_LOG_DEBUG("Exit");
 }
 
-static void prv_process_async_task(msu_context_t *context, msu_task_t *task)
+static void prv_process_async_task(msu_task_t *task)
 {
        const gchar *client_name;
        msu_client_t *client;
-       const gchar *protocol_info = NULL;
 
        MSU_LOG_DEBUG("Enter");
 
-       context->cancellable = g_cancellable_new();
-       context->current_task = task;
+       g_context.cancellable = g_cancellable_new();
+       g_context.current_task = task;
        client_name =
                g_dbus_method_invocation_get_sender(task->invocation);
-       client = g_hash_table_lookup(context->watchers, client_name);
-       if (client)
-               protocol_info = client->protocol_info;
+       client = g_hash_table_lookup(g_context.watchers, client_name);
 
        switch (task->type) {
        case MSU_TASK_GET_CHILDREN:
-               msu_upnp_get_children(context->upnp, task, protocol_info,
-                                     context->cancellable,
-                                     prv_async_task_complete, context);
+               msu_upnp_get_children(g_context.upnp, client, task,
+                                     g_context.cancellable,
+                                     prv_async_task_complete);
                break;
        case MSU_TASK_GET_PROP:
-               msu_upnp_get_prop(context->upnp, task, protocol_info,
-                                 context->cancellable,
-                                 prv_async_task_complete, context);
+               msu_upnp_get_prop(g_context.upnp, client, task,
+                                 g_context.cancellable,
+                                 prv_async_task_complete);
                break;
        case MSU_TASK_GET_ALL_PROPS:
-               msu_upnp_get_all_props(context->upnp, task, protocol_info,
-                                      context->cancellable,
-                                      prv_async_task_complete, context);
+               msu_upnp_get_all_props(g_context.upnp, client, task,
+                                      g_context.cancellable,
+                                      prv_async_task_complete);
                break;
        case MSU_TASK_SEARCH:
-               msu_upnp_search(context->upnp, task, protocol_info,
-                               context->cancellable,
-                               prv_async_task_complete, context);
+               msu_upnp_search(g_context.upnp, client, task,
+                               g_context.cancellable,
+                               prv_async_task_complete);
                break;
        case MSU_TASK_GET_RESOURCE:
-               msu_upnp_get_resource(context->upnp, task,
-                                     context->cancellable,
-                                     prv_async_task_complete, context);
+               msu_upnp_get_resource(g_context.upnp, client, task,
+                                     g_context.cancellable,
+                                     prv_async_task_complete);
                break;
        case MSU_TASK_UPLOAD_TO_ANY:
-               msu_upnp_upload_to_any(context->upnp, task,
-                                      context->cancellable,
-                                      prv_async_task_complete, context);
+               msu_upnp_upload_to_any(g_context.upnp, client, task,
+                                      g_context.cancellable,
+                                      prv_async_task_complete);
                break;
        case MSU_TASK_UPLOAD:
-               msu_upnp_upload(context->upnp, task, context->cancellable,
-                               prv_async_task_complete, context);
+               msu_upnp_upload(g_context.upnp, client, task,
+                               g_context.cancellable,
+                               prv_async_task_complete);
+               break;
+       case MSU_TASK_DELETE_OBJECT:
+               msu_upnp_delete_object(g_context.upnp, client, task,
+                                      g_context.cancellable,
+                                      prv_async_task_complete);
+               break;
+       case MSU_TASK_CREATE_CONTAINER:
+               msu_upnp_create_container(g_context.upnp, client, task,
+                                         g_context.cancellable,
+                                         prv_async_task_complete);
+               break;
+       case MSU_TASK_CREATE_CONTAINER_IN_ANY:
+               msu_upnp_create_container_in_any(g_context.upnp, client, task,
+                                                g_context.cancellable,
+                                                prv_async_task_complete);
+               break;
+       case MSU_TASK_UPDATE_OBJECT:
+               msu_upnp_update_object(g_context.upnp, client, task,
+                                      g_context.cancellable,
+                                      prv_async_task_complete);
                break;
        default:
                break;
@@ -454,22 +572,21 @@ static void prv_process_async_task(msu_context_t *context, msu_task_t *task)
 
 static gboolean prv_process_task(gpointer user_data)
 {
-       msu_context_t *context = user_data;
        msu_task_t *task;
        gboolean retval = FALSE;
 
-       if (context->tasks->len > 0) {
-               task = g_ptr_array_index(context->tasks, 0);
+       if (g_context.tasks->len > 0) {
+               task = g_ptr_array_index(g_context.tasks, 0);
                if (task->synchronous) {
-                       prv_process_sync_task(context, task);
+                       prv_process_sync_task(task);
                        retval = TRUE;
                } else {
-                       prv_process_async_task(context, task);
-                       context->idle_id = 0;
+                       prv_process_async_task(task);
+                       g_context.idle_id = 0;
                }
-               g_ptr_array_remove_index(context->tasks, 0);
+               g_ptr_array_remove_index(g_context.tasks, 0);
        } else {
-               context->idle_id = 0;
+               g_context.idle_id = 0;
        }
 
        return retval;
@@ -484,6 +601,15 @@ static void prv_msu_method_call(GDBusConnection *conn,
                                GDBusMethodInvocation *invocation,
                                gpointer user_data);
 
+static void prv_object_method_call(GDBusConnection *conn,
+                                  const gchar *sender,
+                                  const gchar *object,
+                                  const gchar *interface,
+                                  const gchar *method,
+                                  GVariant *parameters,
+                                  GDBusMethodInvocation *invocation,
+                                  gpointer user_data);
+
 static void prv_item_method_call(GDBusConnection *conn,
                                 const gchar *sender,
                                 const gchar *object,
@@ -526,6 +652,12 @@ static const GDBusInterfaceVTable g_msu_vtable = {
        NULL
 };
 
+static const GDBusInterfaceVTable g_object_vtable = {
+       prv_object_method_call,
+       NULL,
+       NULL
+};
+
 static const GDBusInterfaceVTable g_item_vtable = {
        prv_item_method_call,
        NULL,
@@ -552,91 +684,92 @@ static const GDBusInterfaceVTable g_device_vtable = {
 
 static const GDBusInterfaceVTable *g_server_vtables[MSU_INTERFACE_INFO_MAX] = {
        &g_props_vtable,
-       NULL,
+       &g_object_vtable,
        &g_ms_vtable,
        &g_item_vtable,
        &g_device_vtable
 };
 
-static void prv_msu_context_init(msu_context_t *context)
+static void prv_msu_context_init(void)
 {
-       memset(context, 0, sizeof(*context));
+       memset(&g_context, 0, sizeof(g_context));
 }
 
-static void prv_msu_context_free(msu_context_t *context)
+static void prv_msu_context_free(void)
 {
-       msu_upnp_delete(context->upnp);
+       msu_upnp_delete(g_context.upnp);
 
-       if (context->watchers)
-               g_hash_table_unref(context->watchers);
+       if (g_context.watchers)
+               g_hash_table_unref(g_context.watchers);
 
-       if (context->tasks) {
-               g_ptr_array_foreach(context->tasks, prv_free_msu_task_cb, NULL);
-               g_ptr_array_unref(context->tasks);
+       if (g_context.tasks) {
+               g_ptr_array_foreach(g_context.tasks, prv_free_msu_task_cb,
+                                   NULL);
+               g_ptr_array_unref(g_context.tasks);
        }
 
-       if (context->idle_id)
-               (void) g_source_remove(context->idle_id);
+       if (g_context.idle_id)
+               (void) g_source_remove(g_context.idle_id);
 
-       if (context->sig_id)
-               (void) g_source_remove(context->sig_id);
+       if (g_context.sig_id)
+               (void) g_source_remove(g_context.sig_id);
 
-       if (context->connection) {
-               if (context->msu_id)
+       if (g_context.connection) {
+               if (g_context.msu_id)
                        g_dbus_connection_unregister_object(
-                               context->connection,
-                               context->msu_id);
+                                                       g_context.connection,
+                                                       g_context.msu_id);
        }
 
-       if (context->owner_id)
-               g_bus_unown_name(context->owner_id);
+       if (g_context.owner_id)
+               g_bus_unown_name(g_context.owner_id);
 
-       if (context->connection)
-               g_object_unref(context->connection);
+       if (g_context.connection)
+               g_object_unref(g_context.connection);
 
-       if (context->main_loop)
-               g_main_loop_unref(context->main_loop);
+       if (g_context.main_loop)
+               g_main_loop_unref(g_context.main_loop);
 
-       if (context->server_node_info)
-               g_dbus_node_info_unref(context->server_node_info);
+       if (g_context.server_node_info)
+               g_dbus_node_info_unref(g_context.server_node_info);
 
-       if (context->root_node_info)
-               g_dbus_node_info_unref(context->root_node_info);
+       if (g_context.root_node_info)
+               g_dbus_node_info_unref(g_context.root_node_info);
 
-       if (context->settings)
-               msu_settings_delete(context->settings);
+       if (g_context.settings)
+               msu_settings_delete(g_context.settings);
 }
 
-static void prv_quit(msu_context_t *context)
+static void prv_quit(void)
 {
-       if (context->cancellable) {
-               g_cancellable_cancel(context->cancellable);
-               context->quitting = TRUE;
+       if (g_context.cancellable) {
+               g_cancellable_cancel(g_context.cancellable);
+               g_context.quitting = TRUE;
        } else {
-               g_main_loop_quit(context->main_loop);
+               g_main_loop_quit(g_context.main_loop);
        }
 }
 
-static void prv_remove_client(msu_context_t *context, const gchar *name)
+static void prv_remove_client(const gchar *name)
 {
        const gchar *client_name;
        msu_task_t *task;
        guint pos;
 
-       if (context->cancellable) {
+       if (g_context.cancellable) {
                client_name = g_dbus_method_invocation_get_sender(
-                                       context->current_task->invocation);
+                                       g_context.current_task->invocation);
                if (!strcmp(client_name, name)) {
                        MSU_LOG_DEBUG("Cancelling current task, type is %d",
-                                               context->current_task->type);
+                                     g_context.current_task->type);
 
-                       g_cancellable_cancel(context->cancellable);
+                       g_cancellable_cancel(g_context.cancellable);
                }
        }
 
        pos = 0;
-       while (pos < context->tasks->len) {
-               task = (msu_task_t *) g_ptr_array_index(context->tasks, pos);
+       while (pos < g_context.tasks->len) {
+               task = (msu_task_t *) g_ptr_array_index(g_context.tasks, pos);
 
                client_name = g_dbus_method_invocation_get_sender(
                                                        task->invocation);
@@ -648,15 +781,15 @@ static void prv_remove_client(msu_context_t *context, const gchar *name)
 
                MSU_LOG_DEBUG("Removing task type %d from array", task->type);
 
-               (void) g_ptr_array_remove_index(context->tasks, pos);
+               (void) g_ptr_array_remove_index(g_context.tasks, pos);
                msu_task_cancel_and_delete(task);
        }
 
-       (void) g_hash_table_remove(context->watchers, name);
+       (void) g_hash_table_remove(g_context.watchers, name);
 
-       if (g_hash_table_size(context->watchers) == 0)
-               if (!msu_settings_is_never_quit(context->settings))
-                       prv_quit(context);
+       if (g_hash_table_size(g_context.watchers) == 0)
+               if (!msu_settings_is_never_quit(g_context.settings))
+                       prv_quit();
 }
 
 static void prv_lost_client(GDBusConnection *connection, const gchar *name,
@@ -664,30 +797,31 @@ static void prv_lost_client(GDBusConnection *connection, const gchar *name,
 {
        MSU_LOG_DEBUG("Lost Client %s", name);
 
-       prv_remove_client(user_data, name);
+       prv_remove_client(name);
 }
 
-static void prv_add_task(msu_context_t *context, msu_task_t *task)
+static void prv_add_task(msu_task_t *task)
 {
        const gchar *client_name;
        msu_client_t *client;
 
        client_name = g_dbus_method_invocation_get_sender(task->invocation);
 
-       if (!g_hash_table_lookup(context->watchers, client_name)) {
+       if (!g_hash_table_lookup(g_context.watchers, client_name)) {
                client = g_new0(msu_client_t, 1);
+               client->prefer_local_addresses = TRUE;
                client->id = g_bus_watch_name(G_BUS_TYPE_SESSION, client_name,
                                              G_BUS_NAME_WATCHER_FLAGS_NONE,
-                                             NULL, prv_lost_client, context,
+                                             NULL, prv_lost_client, NULL,
                                              NULL);
-               g_hash_table_insert(context->watchers, g_strdup(client_name),
+               g_hash_table_insert(g_context.watchers, g_strdup(client_name),
                                    client);
        }
 
-       if (!context->cancellable && !context->idle_id)
-               context->idle_id = g_idle_add(prv_process_task, context);
+       if (!g_context.cancellable && !g_context.idle_id)
+               g_context.idle_id = g_idle_add(prv_process_task, NULL);
 
-       g_ptr_array_add(context->tasks, task);
+       g_ptr_array_add(g_context.tasks, task);
 }
 
 static void prv_msu_method_call(GDBusConnection *conn,
@@ -697,26 +831,52 @@ static void prv_msu_method_call(GDBusConnection *conn,
                                GDBusMethodInvocation *invocation,
                                gpointer user_data)
 {
-       msu_context_t *context = user_data;
        const gchar *client_name;
        msu_task_t *task;
 
        if (!strcmp(method, MSU_INTERFACE_RELEASE)) {
                client_name = g_dbus_method_invocation_get_sender(invocation);
-               prv_remove_client(context, client_name);
+               prv_remove_client(client_name);
                g_dbus_method_invocation_return_value(invocation, NULL);
        } else if (!strcmp(method, MSU_INTERFACE_GET_VERSION)) {
                task = msu_task_get_version_new(invocation);
-               prv_add_task(context, task);
+               prv_add_task(task);
        } else if (!strcmp(method, MSU_INTERFACE_GET_SERVERS)) {
                task = msu_task_get_servers_new(invocation);
-               prv_add_task(context, task);
+               prv_add_task(task);
        } else if (!strcmp(method, MSU_INTERFACE_SET_PROTOCOL_INFO)) {
                task = msu_task_set_protocol_info_new(invocation, parameters);
-               prv_add_task(context, task);
+               prv_add_task(task);
+       } else if (!strcmp(method, MSU_INTERFACE_PREFER_LOCAL_ADDRESSES)) {
+               task = msu_task_prefer_local_addresses_new(invocation,
+                                                          parameters);
+               prv_add_task(task);
        }
 }
 
+static void prv_object_method_call(GDBusConnection *conn,
+                                  const gchar *sender, const gchar *object,
+                                  const gchar *interface,
+                                  const gchar *method, GVariant *parameters,
+                                  GDBusMethodInvocation *invocation,
+                                  gpointer user_data)
+{
+       msu_task_t *task;
+
+       if (!strcmp(method, MSU_INTERFACE_DELETE)) {
+               task = msu_task_delete_new(invocation, object);
+       } else if (!strcmp(method, MSU_INTERFACE_UPDATE))
+               task = msu_task_update_new(invocation, object, parameters);
+       else
+               goto finished;
+
+       prv_add_task(task);
+
+finished:
+
+       return;
+}
+
 static void prv_item_method_call(GDBusConnection *conn,
                                 const gchar *sender, const gchar *object,
                                 const gchar *interface,
@@ -724,13 +884,12 @@ static void prv_item_method_call(GDBusConnection *conn,
                                 GDBusMethodInvocation *invocation,
                                 gpointer user_data)
 {
-       msu_context_t *context = user_data;
        msu_task_t *task;
 
        if (!strcmp(method, MSU_INTERFACE_GET_COMPATIBLE_RESOURCE)) {
                task = msu_task_get_resource_new(invocation, object,
                                                 parameters);
-               prv_add_task(context, task);
+               prv_add_task(task);
        }
 }
 
@@ -744,7 +903,6 @@ static void prv_con_method_call(GDBusConnection *conn,
                                GDBusMethodInvocation *invocation,
                                gpointer user_data)
 {
-       msu_context_t *context = user_data;
        msu_task_t *task;
 
        if (!strcmp(method, MSU_INTERFACE_LIST_CHILDREN))
@@ -773,10 +931,14 @@ static void prv_con_method_call(GDBusConnection *conn,
                                              parameters);
        else if (!strcmp(method, MSU_INTERFACE_UPLOAD))
                task = msu_task_upload_new(invocation, object, parameters);
+       else if (!strcmp(method, MSU_INTERFACE_CREATE_CONTAINER))
+               task = msu_task_create_container_new_generic(invocation,
+                                               MSU_TASK_CREATE_CONTAINER,
+                                               object, parameters);
        else
                goto finished;
 
-       prv_add_task(context, task);
+       prv_add_task(task);
 
 finished:
 
@@ -792,7 +954,6 @@ static void prv_props_method_call(GDBusConnection *conn,
                                  GDBusMethodInvocation *invocation,
                                  gpointer user_data)
 {
-       msu_context_t *context = user_data;
        msu_task_t *task;
 
        if (!strcmp(method, MSU_INTERFACE_GET_ALL))
@@ -802,7 +963,7 @@ static void prv_props_method_call(GDBusConnection *conn,
        else
                goto finished;
 
-       prv_add_task(context, task);
+       prv_add_task(task);
 
 finished:
 
@@ -816,21 +977,34 @@ static void prv_device_method_call(GDBusConnection *conn,
                                   GDBusMethodInvocation *invocation,
                                   gpointer user_data)
 {
-       msu_context_t *context = user_data;
        msu_task_t *task;
 
        if (!strcmp(method, MSU_INTERFACE_UPLOAD_TO_ANY)) {
                task = msu_task_upload_to_any_new(invocation, object,
                                                  parameters);
-               prv_add_task(context, task);
+               prv_add_task(task);
+       } else if (!strcmp(method, MSU_INTERFACE_CREATE_CONTAINER_IN_ANY)) {
+               task = msu_task_create_container_new_generic(invocation,
+                                       MSU_TASK_CREATE_CONTAINER_IN_ANY,
+                                       object, parameters);
+               prv_add_task(task);
+       } else if (!strcmp(method, MSU_INTERFACE_GET_UPLOAD_STATUS)) {
+               task = msu_task_get_upload_status_new(invocation, object,
+                                                     parameters);
+               prv_add_task(task);
+       } else if (!strcmp(method, MSU_INTERFACE_GET_UPLOAD_IDS)) {
+               task = msu_task_get_upload_ids_new(invocation, object);
+               prv_add_task(task);
+       } else if (!strcmp(method, MSU_INTERFACE_CANCEL_UPLOAD)) {
+               task = msu_task_cancel_upload_new(invocation, object,
+                                                 parameters);
+               prv_add_task(task);
        }
 }
 
 static void prv_found_media_server(const gchar *path, void *user_data)
 {
-       msu_context_t *context = user_data;
-
-       (void) g_dbus_connection_emit_signal(context->connection,
+       (void) g_dbus_connection_emit_signal(g_context.connection,
                                             NULL,
                                             MSU_OBJECT,
                                             MSU_INTERFACE_MANAGER,
@@ -841,9 +1015,7 @@ static void prv_found_media_server(const gchar *path, void *user_data)
 
 static void prv_lost_media_server(const gchar *path, void *user_data)
 {
-       msu_context_t *context = user_data;
-
-       (void) g_dbus_connection_emit_signal(context->connection,
+       (void) g_dbus_connection_emit_signal(g_context.connection,
                                             NULL,
                                             MSU_OBJECT,
                                             MSU_INTERFACE_MANAGER,
@@ -855,30 +1027,29 @@ static void prv_lost_media_server(const gchar *path, void *user_data)
 static void prv_bus_acquired(GDBusConnection *connection, const gchar *name,
                             gpointer user_data)
 {
-       msu_context_t *context = user_data;
        msu_interface_info_t *info;
        unsigned int i;
 
-       context->connection = connection;
+       g_context.connection = connection;
 
-       context->msu_id =
+       g_context.msu_id =
                g_dbus_connection_register_object(connection, MSU_OBJECT,
-                                                 context->root_node_info->
+                                                 g_context.root_node_info->
                                                  interfaces[0],
                                                  &g_msu_vtable,
                                                  user_data, NULL, NULL);
 
-       if (!context->msu_id) {
-               context->error = true;
-               g_main_loop_quit(context->main_loop);
+       if (!g_context.msu_id) {
+               g_context.error = true;
+               g_main_loop_quit(g_context.main_loop);
        } else {
                info = g_new(msu_interface_info_t, MSU_INTERFACE_INFO_MAX);
                for (i = 0; i < MSU_INTERFACE_INFO_MAX; ++i) {
                        info[i].interface =
-                               context->server_node_info->interfaces[i];
+                               g_context.server_node_info->interfaces[i];
                        info[i].vtable = g_server_vtables[i];
                }
-               context->upnp = msu_upnp_new(connection, info,
+               g_context.upnp = msu_upnp_new(connection, info,
                                            prv_found_media_server,
                                            prv_lost_media_server,
                                            user_data);
@@ -888,25 +1059,21 @@ static void prv_bus_acquired(GDBusConnection *connection, const gchar *name,
 static void prv_name_lost(GDBusConnection *connection, const gchar *name,
                          gpointer user_data)
 {
-       msu_context_t *context = user_data;
-
-       context->connection = NULL;
+       g_context.connection = NULL;
 
-       prv_quit(context);
+       prv_quit();
 }
 
 static gboolean prv_quit_handler(GIOChannel *source, GIOCondition condition,
                                 gpointer user_data)
 {
-       msu_context_t *context = user_data;
-
-       prv_quit(context);
-       context->sig_id = 0;
+       prv_quit();
+       g_context.sig_id = 0;
 
        return FALSE;
 }
 
-static bool prv_init_signal_handler(sigset_t mask, msu_context_t *context)
+static bool prv_init_signal_handler(sigset_t mask)
 {
        bool retval = false;
        int fd = -1;
@@ -927,9 +1094,9 @@ static bool prv_init_signal_handler(sigset_t mask, msu_context_t *context)
            G_IO_STATUS_NORMAL)
                goto on_error;
 
-       context->sig_id = g_io_add_watch(channel, G_IO_IN | G_IO_PRI,
+       g_context.sig_id = g_io_add_watch(channel, G_IO_IN | G_IO_PRI,
                                         prv_quit_handler,
-                                        context);
+                                        NULL);
 
        retval = true;
 
@@ -954,12 +1121,10 @@ static void prv_unregister_client(gpointer user_data)
 
 int main(int argc, char *argv[])
 {
-       msu_context_t context;
-
        sigset_t mask;
        int retval = 1;
 
-       prv_msu_context_init(&context);
+       prv_msu_context_init();
 
        sigemptyset(&mask);
        sigaddset(&mask, SIGTERM);
@@ -971,45 +1136,46 @@ int main(int argc, char *argv[])
        g_type_init();
 
        msu_log_init(argv[0]);
-       msu_settings_new(&context.settings);
+       msu_settings_new(&g_context.settings);
 
-       context.root_node_info =
+       g_context.root_node_info =
                g_dbus_node_info_new_for_xml(g_msu_root_introspection, NULL);
-       if (!context.root_node_info)
+       if (!g_context.root_node_info)
                goto on_error;
 
-       context.server_node_info =
+       g_context.server_node_info =
                g_dbus_node_info_new_for_xml(g_msu_server_introspection, NULL);
-       if (!context.server_node_info)
+       if (!g_context.server_node_info)
                goto on_error;
 
-       context.main_loop = g_main_loop_new(NULL, FALSE);
+       g_context.main_loop = g_main_loop_new(NULL, FALSE);
 
-       context.owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
+       g_context.owner_id = g_bus_own_name(G_BUS_TYPE_SESSION,
                                          MSU_SERVER_NAME,
                                          G_BUS_NAME_OWNER_FLAGS_NONE,
                                          prv_bus_acquired, NULL,
-                                         prv_name_lost, &context, NULL);
+                                         prv_name_lost, NULL, NULL);
 
-       context.tasks = g_ptr_array_new();
+       g_context.tasks = g_ptr_array_new();
 
-       context.watchers = g_hash_table_new_full(g_str_hash, g_str_equal,
+       g_context.watchers = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                 g_free, prv_unregister_client);
 
-       if (!prv_init_signal_handler(mask, &context))
+       if (!prv_init_signal_handler(mask))
                goto on_error;
 
-       g_main_loop_run(context.main_loop);
-       if (context.error)
+       g_main_loop_run(g_context.main_loop);
+       if (g_context.error)
                goto on_error;
 
        retval = 0;
 
 on_error:
 
-       prv_msu_context_free(&context);
+       prv_msu_context_free();
 
        msu_log_finalize();
 
        return retval;
 }
+