4 * Copyright (C) 2012 Intel Corporation. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU Lesser General Public License,
8 * version 2.1, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
19 * Mark Ryan <mark.d.ryan@intel.com>
25 #include <libgssdp/gssdp-resource-browser.h>
26 #include <libgupnp/gupnp-control-point.h>
27 #include <libgupnp/gupnp-error.h>
30 #include "chain-task.h"
33 #include "interface.h"
41 GDBusConnection *connection;
42 msu_interface_info_t *interface_info;
43 GHashTable *filter_map;
44 GHashTable *property_map;
45 msu_upnp_callback_t found_server;
46 msu_upnp_callback_t lost_server;
47 GUPnPContextManager *context_manager;
49 GHashTable *server_udn_map;
50 GHashTable *server_uc_map;
54 /* Private structure used in chain task */
55 typedef struct prv_device_new_ct_t_ prv_device_new_ct_t;
56 struct prv_device_new_ct_t_ {
60 msu_chain_task_t *chain;
63 static gchar **prv_subtree_enumerate(GDBusConnection *connection,
65 const gchar *object_path,
68 static GDBusInterfaceInfo **prv_subtree_introspect(
69 GDBusConnection *connection,
71 const gchar *object_path,
75 static const GDBusInterfaceVTable *prv_subtree_dispatch(
76 GDBusConnection *connection,
78 const gchar *object_path,
79 const gchar *interface_name,
81 gpointer *out_user_data,
85 static const GDBusSubtreeVTable gSubtreeVtable = {
86 prv_subtree_enumerate,
87 prv_subtree_introspect,
91 static gchar **prv_subtree_enumerate(GDBusConnection *connection,
93 const gchar *object_path,
96 return g_malloc0(sizeof(gchar *));
99 static GDBusInterfaceInfo **prv_subtree_introspect(
100 GDBusConnection *connection,
102 const gchar *object_path,
106 msu_upnp_t *upnp = user_data;
107 GDBusInterfaceInfo **retval = g_new(GDBusInterfaceInfo *,
108 MSU_INTERFACE_INFO_MAX + 1);
109 GDBusInterfaceInfo *info;
111 gboolean root_object = FALSE;
114 /* All objects in the hierarchy support the same interface. Strictly
115 speaking this is not correct as it will allow ListChildren to be
116 executed on a mediaitem object. However, returning the correct
117 interface here would be too inefficient. We would need to either
118 cache the type of all objects encountered so far or issue a UPnP
119 request here to determine the objects type. Best to let the client
120 call ListChildren on a item. This will lead to an error when we
121 execute the UPnP command and we can return an error then.
123 We do know however that the root objects are containers. Therefore
124 we can remove the MediaItem2 interface from the root containers. We
125 also know that only the root objects suport the MediaDevice
129 if (msu_path_get_non_root_id(object_path, &slash))
130 root_object = !slash;
133 info = upnp->interface_info[MSU_INTERFACE_INFO_PROPERTIES].interface;
134 retval[i++] = g_dbus_interface_info_ref(info);
136 info = upnp->interface_info[MSU_INTERFACE_INFO_OBJECT].interface;
137 retval[i++] = g_dbus_interface_info_ref(info);
139 info = upnp->interface_info[MSU_INTERFACE_INFO_CONTAINER].interface;
140 retval[i++] = g_dbus_interface_info_ref(info);
143 info = upnp->interface_info[MSU_INTERFACE_INFO_ITEM].interface;
144 retval[i++] = g_dbus_interface_info_ref(info);
146 info = upnp->interface_info[
147 MSU_INTERFACE_INFO_DEVICE].interface;
148 retval[i++] = g_dbus_interface_info_ref(info);
156 static const GDBusInterfaceVTable *prv_subtree_dispatch(
157 GDBusConnection *connection,
159 const gchar *object_path,
160 const gchar *interface_name,
162 gpointer *out_user_data,
165 msu_upnp_t *upnp = user_data;
166 const GDBusInterfaceVTable *retval = NULL;
168 *out_user_data = upnp->user_data;
170 if (!strcmp(MSU_INTERFACE_MEDIA_CONTAINER, interface_name))
171 retval = upnp->interface_info[
172 MSU_INTERFACE_INFO_CONTAINER].vtable;
173 else if (!strcmp(MSU_INTERFACE_MEDIA_OBJECT, interface_name))
174 retval = upnp->interface_info[
175 MSU_INTERFACE_INFO_OBJECT].vtable;
176 else if (!strcmp(MSU_INTERFACE_PROPERTIES, interface_name))
177 retval = upnp->interface_info[
178 MSU_INTERFACE_INFO_PROPERTIES].vtable;
179 else if (!strcmp(MSU_INTERFACE_MEDIA_ITEM, interface_name))
180 retval = upnp->interface_info[
181 MSU_INTERFACE_INFO_ITEM].vtable;
182 else if (!strcmp(MSU_INTERFACE_MEDIA_DEVICE, interface_name))
183 retval = upnp->interface_info[
184 MSU_INTERFACE_INFO_DEVICE].vtable;
190 static void prv_device_chain_end(msu_chain_task_t *chain, gpointer data)
192 msu_device_t *device;
194 prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *) data;
196 device = msu_chain_task_get_device(chain);
197 canceled = msu_chain_task_is_canceled(chain);
201 MSU_LOG_DEBUG("Notify new server available: %s", device->path);
202 g_hash_table_insert(priv_t->upnp->server_udn_map, g_strdup(priv_t->udn),
204 priv_t->upnp->found_server(device->path, priv_t->upnp->user_data);
208 g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
209 msu_chain_task_delete(chain);
213 msu_device_delete(device);
218 static void prv_server_available_cb(GUPnPControlPoint *cp,
219 GUPnPDeviceProxy *proxy,
222 msu_upnp_t *upnp = user_data;
224 msu_device_t *device;
225 const gchar *ip_address;
226 msu_device_context_t *context;
227 msu_chain_task_t *chain;
229 prv_device_new_ct_t *priv_t;
231 udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *) proxy);
235 ip_address = gupnp_context_get_host_ip(
236 gupnp_control_point_get_context(cp));
238 MSU_LOG_DEBUG("UDN %s", udn);
239 MSU_LOG_DEBUG("IP Address %s", ip_address);
241 device = g_hash_table_lookup(upnp->server_udn_map, udn);
244 priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
247 device = priv_t->device;
251 MSU_LOG_DEBUG("Device not found. Adding");
254 priv_t = g_new0(prv_device_new_ct_t, 1);
255 chain = msu_chain_task_new(prv_device_chain_end, priv_t);
256 device = msu_device_new(upnp->connection, proxy, ip_address,
257 &gSubtreeVtable, upnp,
258 upnp->property_map, upnp->counter,
265 priv_t->chain = chain;
266 priv_t->device = device;
268 g_hash_table_insert(upnp->server_uc_map, g_strdup(udn), priv_t);
270 MSU_LOG_DEBUG("Device Found");
272 for (i = 0; i < device->contexts->len; ++i) {
273 context = g_ptr_array_index(device->contexts, i);
274 if (!strcmp(context->ip_address, ip_address))
278 if (i == device->contexts->len) {
279 MSU_LOG_DEBUG("Adding Context");
280 msu_device_append_new_context(device, ip_address,
292 static gboolean prv_subscribe_to_contents_change(gpointer user_data)
294 msu_device_t *device = user_data;
296 device->timeout_id = 0;
297 msu_device_subscribe_to_contents_change(device);
302 static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
303 GUPnPDeviceProxy *proxy,
306 msu_upnp_t *upnp = user_data;
308 msu_device_t *device;
309 const gchar *ip_address;
311 msu_device_context_t *context;
313 gboolean under_construction = FALSE;
314 prv_device_new_ct_t *priv_t;
316 MSU_LOG_DEBUG("Enter");
318 udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *) proxy);
322 ip_address = gupnp_context_get_host_ip(
323 gupnp_control_point_get_context(cp));
325 MSU_LOG_DEBUG("UDN %s", udn);
326 MSU_LOG_DEBUG("IP Address %s", ip_address);
328 device = g_hash_table_lookup(upnp->server_udn_map, udn);
331 priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
334 device = priv_t->device;
335 under_construction = TRUE;
340 MSU_LOG_WARNING("Device not found. Ignoring");
344 for (i = 0; i < device->contexts->len; ++i) {
345 context = g_ptr_array_index(device->contexts, i);
346 if (!strcmp(context->ip_address, ip_address))
350 if (i < device->contexts->len) {
351 subscribed = context->subscribed;
353 (void) g_ptr_array_remove_index(device->contexts, i);
354 if (device->contexts->len == 0) {
355 if (!under_construction) {
356 MSU_LOG_DEBUG("Last Context lost. " \
359 upnp->lost_server(device->path,
361 g_hash_table_remove(upnp->server_udn_map, udn);
363 MSU_LOG_WARNING("Device under construction. "\
366 msu_chain_task_cancel(priv_t->chain);
367 prv_device_chain_end(priv_t->chain, priv_t);
369 } else if (subscribed && !device->timeout_id) {
371 MSU_LOG_DEBUG("Subscribe on new context");
373 device->timeout_id = g_timeout_add_seconds(1,
374 prv_subscribe_to_contents_change,
381 MSU_LOG_DEBUG("Exit");
387 static void prv_on_context_available(GUPnPContextManager *context_manager,
388 GUPnPContext *context,
391 msu_upnp_t *upnp = user_data;
392 GUPnPControlPoint *cp;
394 cp = gupnp_control_point_new(
396 "urn:schemas-upnp-org:device:MediaServer:1");
398 g_signal_connect(cp, "device-proxy-available",
399 G_CALLBACK(prv_server_available_cb), upnp);
401 g_signal_connect(cp, "device-proxy-unavailable",
402 G_CALLBACK(prv_server_unavailable_cb), upnp);
404 gssdp_resource_browser_set_active(GSSDP_RESOURCE_BROWSER(cp), TRUE);
405 gupnp_context_manager_manage_control_point(upnp->context_manager, cp);
409 msu_upnp_t *msu_upnp_new(GDBusConnection *connection,
410 msu_interface_info_t *interface_info,
411 msu_upnp_callback_t found_server,
412 msu_upnp_callback_t lost_server,
415 msu_upnp_t *upnp = g_new0(msu_upnp_t, 1);
417 upnp->connection = connection;
418 upnp->interface_info = interface_info;
419 upnp->user_data = user_data;
420 upnp->found_server = found_server;
421 upnp->lost_server = lost_server;
423 upnp->server_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal,
427 upnp->server_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal,
430 msu_prop_maps_new(&upnp->property_map, &upnp->filter_map);
432 upnp->context_manager = gupnp_context_manager_create(0);
434 g_signal_connect(upnp->context_manager, "context-available",
435 G_CALLBACK(prv_on_context_available),
441 void msu_upnp_delete(msu_upnp_t *upnp)
444 g_object_unref(upnp->context_manager);
445 g_hash_table_unref(upnp->property_map);
446 g_hash_table_unref(upnp->filter_map);
447 g_hash_table_unref(upnp->server_udn_map);
448 g_hash_table_unref(upnp->server_uc_map);
449 g_free(upnp->interface_info);
454 GVariant *msu_upnp_get_server_ids(msu_upnp_t *upnp)
459 msu_device_t *device;
462 MSU_LOG_DEBUG("Enter");
464 g_variant_builder_init(&vb, G_VARIANT_TYPE("ao"));
466 g_hash_table_iter_init(&iter, upnp->server_udn_map);
467 while (g_hash_table_iter_next(&iter, NULL, &value)) {
469 MSU_LOG_DEBUG("Have device %s", device->path);
470 g_variant_builder_add(&vb, "o", device->path);
473 retval = g_variant_ref_sink(g_variant_builder_end(&vb));
475 MSU_LOG_DEBUG("Exit");
480 void msu_upnp_get_children(msu_upnp_t *upnp, msu_client_t *client,
482 GCancellable *cancellable,
483 msu_upnp_task_complete_t cb)
485 msu_async_cb_data_t *cb_data;
486 msu_async_bas_t *cb_task_data;
487 msu_device_t *device;
488 gchar *upnp_filter = NULL;
489 gchar *sort_by = NULL;
491 MSU_LOG_DEBUG("Enter");
493 MSU_LOG_DEBUG("Path: %s", task->path);
494 MSU_LOG_DEBUG("Start: %u", task->ut.get_children.start);
495 MSU_LOG_DEBUG("Count: %u", task->ut.get_children.count);
497 cb_data = msu_async_cb_data_new(task, cb);
498 cb_task_data = &cb_data->ut.bas;
500 if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
501 &cb_data->id, &cb_data->error)) {
502 MSU_LOG_WARNING("Bad path %s", task->path);
507 device = msu_device_from_path(cb_task_data->root_path,
508 upnp->server_udn_map);
510 MSU_LOG_WARNING("Cannot locate device for %s",
511 cb_task_data->root_path);
514 g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
515 "Cannot locate device corresponding to"
516 " the specified path");
520 cb_task_data->filter_mask =
521 msu_props_parse_filter(upnp->filter_map,
522 task->ut.get_children.filter,
525 MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
527 sort_by = msu_sort_translate_sort_string(upnp->filter_map,
528 task->ut.get_children.sort_by);
530 MSU_LOG_WARNING("Invalid Sort Criteria");
532 cb_data->error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_QUERY,
533 "Sort Criteria are not valid");
537 MSU_LOG_DEBUG("Sort By %s", sort_by);
539 cb_task_data->protocol_info = client->protocol_info;
541 msu_device_get_children(device, client, task, cb_data,
542 upnp_filter, sort_by, cancellable);
546 if (!cb_data->action)
547 (void) g_idle_add(msu_async_complete_task, cb_data);
552 MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
555 void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_client_t *client,
557 GCancellable *cancellable,
558 msu_upnp_task_complete_t cb)
560 gboolean root_object;
561 msu_async_cb_data_t *cb_data;
562 msu_async_get_all_t *cb_task_data;
563 msu_device_t *device;
565 MSU_LOG_DEBUG("Enter");
567 MSU_LOG_DEBUG("Path: %s", task->path);
568 MSU_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
570 cb_data = msu_async_cb_data_new(task, cb);
571 cb_task_data = &cb_data->ut.get_all;
573 if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
574 &cb_data->id, &cb_data->error)) {
575 MSU_LOG_WARNING("Bad path %s", task->path);
580 root_object = cb_data->id[0] == '0' && cb_data->id[1] == 0;
582 MSU_LOG_DEBUG("Root Object = %d", root_object);
584 device = msu_device_from_path(cb_task_data->root_path,
585 upnp->server_udn_map);
587 MSU_LOG_WARNING("Cannot locate device for %s",
588 cb_task_data->root_path);
591 g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
592 "Cannot locate device corresponding to"
593 " the specified path");
597 cb_task_data->protocol_info = client->protocol_info;
599 msu_device_get_all_props(device, client, task, cb_data, root_object,
602 MSU_LOG_DEBUG("Exit with SUCCESS");
608 (void) g_idle_add(msu_async_complete_task, cb_data);
610 MSU_LOG_DEBUG("Exit with FAIL");
613 void msu_upnp_get_prop(msu_upnp_t *upnp, msu_client_t *client,
615 GCancellable *cancellable,
616 msu_upnp_task_complete_t cb)
618 gboolean root_object;
619 msu_async_cb_data_t *cb_data;
620 msu_async_get_prop_t *cb_task_data;
621 msu_device_t *device;
622 msu_prop_map_t *prop_map;
623 msu_task_get_prop_t *task_data;
625 MSU_LOG_DEBUG("Enter");
627 MSU_LOG_DEBUG("Path: %s", task->path);
628 MSU_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
629 MSU_LOG_DEBUG("Prop.%s", task->ut.get_prop.prop_name);
631 task_data = &task->ut.get_prop;
632 cb_data = msu_async_cb_data_new(task, cb);
633 cb_task_data = &cb_data->ut.get_prop;
635 if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
638 MSU_LOG_WARNING("Bad path %s", task->path);
643 root_object = cb_data->id[0] == '0' && cb_data->id[1] == 0;
645 MSU_LOG_DEBUG("Root Object = %d", root_object);
647 device = msu_device_from_path(cb_task_data->root_path,
648 upnp->server_udn_map);
650 MSU_LOG_WARNING("Cannot locate device for %s",
651 cb_task_data->root_path);
654 g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
655 "Cannot locate device corresponding to"
656 " the specified path");
660 cb_task_data->protocol_info = client->protocol_info;
661 prop_map = g_hash_table_lookup(upnp->filter_map, task_data->prop_name);
663 msu_device_get_prop(device, client, task, cb_data, prop_map,
664 root_object, cancellable);
666 MSU_LOG_DEBUG("Exit with SUCCESS");
672 (void) g_idle_add(msu_async_complete_task, cb_data);
674 MSU_LOG_DEBUG("Exit with FAIL");
677 void msu_upnp_search(msu_upnp_t *upnp, msu_client_t *client,
679 GCancellable *cancellable,
680 msu_upnp_task_complete_t cb)
682 gchar *upnp_filter = NULL;
683 gchar *upnp_query = NULL;
684 gchar *sort_by = NULL;
685 msu_async_cb_data_t *cb_data;
686 msu_async_bas_t *cb_task_data;
687 msu_device_t *device;
689 MSU_LOG_DEBUG("Enter");
691 MSU_LOG_DEBUG("Path: %s", task->path);
692 MSU_LOG_DEBUG("Query: %s", task->ut.search.query);
693 MSU_LOG_DEBUG("Start: %u", task->ut.search.start);
694 MSU_LOG_DEBUG("Count: %u", task->ut.search.count);
696 cb_data = msu_async_cb_data_new(task, cb);
697 cb_task_data = &cb_data->ut.bas;
699 if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
700 &cb_data->id, &cb_data->error)) {
701 MSU_LOG_WARNING("Bad path %s", task->path);
706 device = msu_device_from_path(cb_task_data->root_path,
707 upnp->server_udn_map);
709 MSU_LOG_WARNING("Cannot locate device for %s",
710 cb_task_data->root_path);
713 g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
714 "Cannot locate device corresponding to"
715 " the specified path");
719 cb_task_data->filter_mask =
720 msu_props_parse_filter(upnp->filter_map,
721 task->ut.search.filter, &upnp_filter);
723 MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
725 upnp_query = msu_search_translate_search_string(upnp->filter_map,
726 task->ut.search.query);
728 MSU_LOG_WARNING("Query string is not valid:%s",
729 task->ut.search.query);
731 cb_data->error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_QUERY,
732 "Query string is not valid.");
736 MSU_LOG_DEBUG("UPnP Query %s", upnp_query);
738 sort_by = msu_sort_translate_sort_string(upnp->filter_map,
739 task->ut.search.sort_by);
741 MSU_LOG_WARNING("Invalid Sort Criteria");
743 cb_data->error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_QUERY,
744 "Sort Criteria are not valid");
748 MSU_LOG_DEBUG("Sort By %s", sort_by);
750 cb_task_data->protocol_info = client->protocol_info;
752 msu_device_search(device, client, task, cb_data, upnp_filter,
753 upnp_query, sort_by, cancellable);
756 if (!cb_data->action)
757 (void) g_idle_add(msu_async_complete_task, cb_data);
763 MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
766 void msu_upnp_get_resource(msu_upnp_t *upnp, msu_client_t *client,
768 GCancellable *cancellable,
769 msu_upnp_task_complete_t cb)
771 msu_async_cb_data_t *cb_data;
772 msu_async_get_all_t *cb_task_data;
773 msu_device_t *device;
774 gchar *upnp_filter = NULL;
775 gchar *root_path = NULL;
777 MSU_LOG_DEBUG("Enter");
779 MSU_LOG_DEBUG("Protocol Info: %s ", task->ut.resource.protocol_info);
781 cb_data = msu_async_cb_data_new(task, cb);
782 cb_task_data = &cb_data->ut.get_all;
784 if (!msu_path_get_path_and_id(task->path, &root_path, &cb_data->id,
786 MSU_LOG_WARNING("Bad path %s", task->path);
791 MSU_LOG_DEBUG("Root Path %s Id %s", root_path, cb_data->id);
793 device = msu_device_from_path(root_path, upnp->server_udn_map);
795 MSU_LOG_WARNING("Cannot locate device for %s", root_path);
798 g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
799 "Cannot locate device corresponding to"
800 " the specified path");
804 cb_task_data->filter_mask =
805 msu_props_parse_filter(upnp->filter_map,
806 task->ut.resource.filter, &upnp_filter);
808 MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
810 msu_device_get_resource(device, client, task, cb_data, upnp_filter,
815 if (!cb_data->action)
816 (void) g_idle_add(msu_async_complete_task, cb_data);
821 MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
824 static gboolean prv_compute_mime_and_class(msu_task_t *task,
825 msu_async_upload_t *cb_task_data,
828 gchar *content_type = NULL;
830 if (!g_file_test(task->ut.upload.file_path,
831 G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS)) {
833 MSU_LOG_WARNING("File %s does not exist or is not"
834 " a regular file", task->ut.upload.file_path);
836 *error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
837 "File %s does not exist or is not"
839 task->ut.upload.file_path);
843 content_type = g_content_type_guess(task->ut.upload.file_path, NULL, 0,
848 MSU_LOG_WARNING("Unable to determine Content Type "
849 "for %s", task->ut.upload.file_path);
851 *error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_MIME,
852 "Unable to determine Content Type "
853 "for %s", task->ut.upload.file_path);
857 cb_task_data->mime_type = g_content_type_get_mime_type(content_type);
858 g_free(content_type);
860 if (!cb_task_data->mime_type) {
862 MSU_LOG_WARNING("Unable to determine MIME Type for"
863 " %s", task->ut.upload.file_path);
865 *error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_MIME,
866 "Unable to determine MIME Type for"
867 " %s", task->ut.upload.file_path);
871 if (g_content_type_is_a(cb_task_data->mime_type, "image/*")) {
872 cb_task_data->object_class = "object.item.imageItem";
873 } else if (g_content_type_is_a(cb_task_data->mime_type, "audio/*")) {
874 cb_task_data->object_class = "object.item.audioItem";
875 } else if (g_content_type_is_a(cb_task_data->mime_type, "video/*")) {
876 cb_task_data->object_class = "object.item.videoItem";
879 MSU_LOG_WARNING("Unsupported MIME Type"
880 " %s", cb_task_data->mime_type);
882 *error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_MIME,
883 "Unsupported MIME Type"
884 " %s", cb_task_data->mime_type);
895 void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_client_t *client,
897 GCancellable *cancellable,
898 msu_upnp_task_complete_t cb)
900 msu_async_cb_data_t *cb_data;
901 msu_async_upload_t *cb_task_data;
902 msu_device_t *device;
904 MSU_LOG_DEBUG("Enter");
906 cb_data = msu_async_cb_data_new(task, cb);
907 cb_task_data = &cb_data->ut.upload;
909 if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
910 &cb_data->id, &cb_data->error)) {
911 MSU_LOG_WARNING("Bad path %s", task->path);
916 MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
919 device = msu_device_from_path(cb_task_data->root_path,
920 upnp->server_udn_map);
922 MSU_LOG_WARNING("Cannot locate device for %s",
923 cb_task_data->root_path);
926 g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
927 "Cannot locate device corresponding to"
928 " the specified path");
932 if (strcmp(cb_data->id, "0")) {
933 MSU_LOG_WARNING("Bad path %s", task->path);
936 g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
937 "UploadToAnyContainer must be executed "
942 if (!prv_compute_mime_and_class(task, cb_task_data, &cb_data->error))
945 MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
946 MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
948 msu_device_upload(device, client, task, "DLNA.ORG_AnyContainer",
949 cb_data, cancellable);
953 if (!cb_data->action)
954 (void) g_idle_add(msu_async_complete_task, cb_data);
956 MSU_LOG_DEBUG("Exit");
959 void msu_upnp_upload(msu_upnp_t *upnp, msu_client_t *client, msu_task_t *task,
960 GCancellable *cancellable,
961 msu_upnp_task_complete_t cb)
963 msu_async_cb_data_t *cb_data;
964 msu_async_upload_t *cb_task_data;
965 msu_device_t *device;
967 MSU_LOG_DEBUG("Enter");
969 cb_data = msu_async_cb_data_new(task, cb);
970 cb_task_data = &cb_data->ut.upload;
972 if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
973 &cb_data->id, &cb_data->error)) {
974 MSU_LOG_WARNING("Bad path %s", task->path);
979 device = msu_device_from_path(cb_task_data->root_path,
980 upnp->server_udn_map);
982 MSU_LOG_WARNING("Cannot locate device for %s",
983 cb_task_data->root_path);
986 g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
987 "Cannot locate device corresponding to"
988 " the specified path");
992 if (!prv_compute_mime_and_class(task, cb_task_data, &cb_data->error))
995 MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
996 MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
998 msu_device_upload(device, client, task, cb_data->id, cb_data,
1003 if (!cb_data->action)
1004 (void) g_idle_add(msu_async_complete_task, cb_data);
1006 MSU_LOG_DEBUG("Exit");
1009 void msu_upnp_get_upload_status(msu_upnp_t *upnp, msu_task_t *task)
1011 gchar *root_path = NULL;
1013 GError *error = NULL;
1014 msu_device_t *device;
1016 MSU_LOG_DEBUG("Enter");
1018 if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
1019 MSU_LOG_WARNING("Bad path %s", task->path);
1024 MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
1026 device = msu_device_from_path(root_path, upnp->server_udn_map);
1028 MSU_LOG_WARNING("Cannot locate device for %s",
1031 error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1032 "Cannot locate device corresponding to"
1033 " the specified path");
1037 if (strcmp(id, "0")) {
1038 MSU_LOG_WARNING("Bad path %s", task->path);
1040 error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
1041 "GetUploadStatus must be executed "
1046 (void) msu_device_get_upload_status(device, task, &error);
1051 msu_task_fail_and_delete(task, error);
1052 g_error_free(error);
1054 msu_task_complete_and_delete(task);
1060 MSU_LOG_DEBUG("Exit");
1063 void msu_upnp_get_upload_ids(msu_upnp_t *upnp, msu_task_t *task)
1065 gchar *root_path = NULL;
1067 GError *error = NULL;
1068 msu_device_t *device;
1070 MSU_LOG_DEBUG("Enter");
1072 if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
1073 MSU_LOG_WARNING("Bad path %s", task->path);
1078 MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
1080 device = msu_device_from_path(root_path, upnp->server_udn_map);
1082 MSU_LOG_WARNING("Cannot locate device for %s",
1085 error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1086 "Cannot locate device corresponding to"
1087 " the specified path");
1091 if (strcmp(id, "0")) {
1092 MSU_LOG_WARNING("Bad path %s", task->path);
1094 error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
1095 "GetUploadIDs must be executed "
1100 msu_device_get_upload_ids(device, task);
1105 msu_task_fail_and_delete(task, error);
1106 g_error_free(error);
1108 msu_task_complete_and_delete(task);
1114 MSU_LOG_DEBUG("Exit");
1117 void msu_upnp_cancel_upload(msu_upnp_t *upnp, msu_task_t *task)
1119 gchar *root_path = NULL;
1121 GError *error = NULL;
1122 msu_device_t *device;
1124 MSU_LOG_DEBUG("Enter");
1126 if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
1127 MSU_LOG_WARNING("Bad path %s", task->path);
1132 MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
1134 device = msu_device_from_path(root_path, upnp->server_udn_map);
1136 MSU_LOG_WARNING("Cannot locate device for %s",
1139 error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1140 "Cannot locate device corresponding to"
1141 " the specified path");
1145 if (strcmp(id, "0")) {
1146 MSU_LOG_WARNING("Bad path %s", task->path);
1148 error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
1149 "CancelUpload must be executed "
1154 (void) msu_device_cancel_upload(device, task, &error);
1159 msu_task_fail_and_delete(task, error);
1160 g_error_free(error);
1162 msu_task_complete_and_delete(task);
1168 MSU_LOG_DEBUG("Exit");
1171 void msu_upnp_delete_object(msu_upnp_t *upnp, msu_client_t *client,
1173 GCancellable *cancellable,
1174 msu_upnp_task_complete_t cb)
1176 msu_async_cb_data_t *cb_data;
1177 msu_device_t *device;
1178 gchar *root_path = NULL;
1180 MSU_LOG_DEBUG("Enter");
1182 cb_data = msu_async_cb_data_new(task, cb);
1184 if (!msu_path_get_path_and_id(task->path, &root_path,
1185 &cb_data->id, &cb_data->error)) {
1186 MSU_LOG_WARNING("Bad path %s", task->path);
1191 MSU_LOG_DEBUG("Root Path %s Id %s", root_path,
1194 device = msu_device_from_path(root_path, upnp->server_udn_map);
1196 MSU_LOG_WARNING("Cannot locate device for %s",
1200 g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1201 "Cannot locate device corresponding to"
1202 " the specified path");
1206 msu_device_delete_object(device, client, task, cb_data, cancellable);
1212 if (!cb_data->action)
1213 (void) g_idle_add(msu_async_complete_task, cb_data);
1215 MSU_LOG_DEBUG("Exit");
1218 void msu_upnp_create_container(msu_upnp_t *upnp, msu_client_t *client,
1220 GCancellable *cancellable,
1221 msu_upnp_task_complete_t cb)
1223 msu_async_cb_data_t *cb_data;
1224 msu_async_create_container_t *cb_task_data;
1225 msu_device_t *device;
1227 MSU_LOG_DEBUG("Enter");
1229 cb_data = msu_async_cb_data_new(task, cb);
1230 cb_task_data = &cb_data->ut.create_container;
1232 if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
1233 &cb_data->id, &cb_data->error)) {
1234 MSU_LOG_WARNING("Bad path %s", task->path);
1239 MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
1242 device = msu_device_from_path(cb_task_data->root_path,
1243 upnp->server_udn_map);
1245 MSU_LOG_WARNING("Cannot locate device for %s",
1246 cb_task_data->root_path);
1249 g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1250 "Cannot locate device corresponding to"
1251 " the specified path");
1255 msu_device_create_container(device, client, task, cb_data->id,
1256 cb_data, cancellable);
1260 if (!cb_data->action)
1261 (void) g_idle_add(msu_async_complete_task, cb_data);
1263 MSU_LOG_DEBUG("Exit");
1266 void msu_upnp_create_container_in_any(msu_upnp_t *upnp, msu_client_t *client,
1268 GCancellable *cancellable,
1269 msu_upnp_task_complete_t cb)
1271 msu_async_cb_data_t *cb_data;
1272 msu_async_create_container_t *cb_task_data;
1273 msu_device_t *device;
1275 MSU_LOG_DEBUG("Enter");
1277 cb_data = msu_async_cb_data_new(task, cb);
1278 cb_task_data = &cb_data->ut.create_container;
1280 if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
1281 &cb_data->id, &cb_data->error)) {
1282 MSU_LOG_WARNING("Bad path %s", task->path);
1287 MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
1290 if (strcmp(cb_data->id, "0")) {
1291 MSU_LOG_WARNING("Bad path %s", task->path);
1294 g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
1295 "CreateContainerInAnyContainer must be "
1296 "executed on a root path");
1300 device = msu_device_from_path(cb_task_data->root_path,
1301 upnp->server_udn_map);
1303 MSU_LOG_WARNING("Cannot locate device for %s",
1304 cb_task_data->root_path);
1307 g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1308 "Cannot locate device corresponding to"
1309 " the specified path");
1313 msu_device_create_container(device, client, task,
1314 "DLNA.ORG_AnyContainer",
1315 cb_data, cancellable);
1319 if (!cb_data->action)
1320 (void) g_idle_add(msu_async_complete_task, cb_data);
1322 MSU_LOG_DEBUG("Exit");
1325 void msu_upnp_update_object(msu_upnp_t *upnp, msu_client_t *client,
1327 GCancellable *cancellable,
1328 msu_upnp_task_complete_t cb)
1330 msu_async_cb_data_t *cb_data;
1331 msu_async_update_t *cb_task_data;
1332 msu_device_t *device;
1334 gchar *root_path = NULL;
1335 gchar *upnp_filter = NULL;
1336 msu_task_update_t *task_data;
1338 MSU_LOG_DEBUG("Enter");
1340 cb_data = msu_async_cb_data_new(task, cb);
1341 cb_task_data = &cb_data->ut.update;
1342 task_data = &task->ut.update;
1344 if (!msu_path_get_path_and_id(task->path, &root_path,
1345 &cb_data->id, &cb_data->error)) {
1346 MSU_LOG_WARNING("Bad path %s", task->path);
1351 MSU_LOG_DEBUG("Root Path = %s, Id = %s", root_path, cb_data->id);
1353 device = msu_device_from_path(root_path, upnp->server_udn_map);
1355 MSU_LOG_WARNING("Cannot locate device for %s", root_path);
1358 g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1359 "Cannot locate device corresponding to"
1360 " the specified path");
1364 if (!msu_props_parse_update_filter(upnp->filter_map,
1365 task_data->to_add_update,
1366 task_data->to_delete,
1367 &mask, &upnp_filter)) {
1368 MSU_LOG_WARNING("Invalid Parameter");
1370 cb_data->error = g_error_new(MSU_ERROR,
1371 MSU_ERROR_OPERATION_FAILED,
1372 "Invalid Parameter");
1376 cb_task_data->map = upnp->filter_map;
1378 MSU_LOG_DEBUG("Filter = %s", upnp_filter);
1379 MSU_LOG_DEBUG("Mask = 0x%x", mask);
1382 MSU_LOG_WARNING("Empty Parameters");
1384 cb_data->error = g_error_new(MSU_ERROR,
1385 MSU_ERROR_OPERATION_FAILED,
1386 "Empty Parameters");
1391 msu_device_update_object(device, client, task, cb_data, upnp_filter,
1399 g_free(upnp_filter);
1401 if (!cb_data->action)
1402 (void) g_idle_add(msu_async_complete_task, cb_data);
1404 MSU_LOG_DEBUG("Exit");