4 * Copyright (C) 2012-2013 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>
29 #include <libdleyna/core/error.h>
30 #include <libdleyna/core/log.h>
31 #include <libdleyna/core/service-task.h>
35 #include "interface.h"
42 dleyna_connector_id_t connection;
43 const dleyna_connector_dispatch_cb_t *interface_info;
44 GHashTable *filter_map;
45 GHashTable *property_map;
46 dls_upnp_callback_t found_server;
47 dls_upnp_callback_t lost_server;
48 GUPnPContextManager *context_manager;
50 GHashTable *server_udn_map;
51 GHashTable *server_uc_map;
55 /* Private structure used in service task */
56 typedef struct prv_device_new_ct_t_ prv_device_new_ct_t;
57 struct prv_device_new_ct_t_ {
62 const dleyna_task_queue_key_t *queue_id;
65 static void prv_device_new_free(prv_device_new_ct_t *priv_t)
69 g_free(priv_t->ip_address);
74 static void prv_device_chain_end(gboolean cancelled, gpointer data)
77 prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *)data;
79 DLEYNA_LOG_DEBUG("Enter");
81 device = priv_t->device;
86 DLEYNA_LOG_DEBUG("Notify new server available: %s", device->path);
87 g_hash_table_insert(priv_t->upnp->server_udn_map, g_strdup(priv_t->udn),
89 priv_t->upnp->found_server(device->path, priv_t->upnp->user_data);
93 g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
96 dls_device_delete(device);
98 prv_device_new_free(priv_t);
100 DLEYNA_LOG_DEBUG_NL();
103 static void prv_device_context_switch_end(gboolean cancelled, gpointer data)
105 prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *)data;
107 DLEYNA_LOG_DEBUG("Enter");
109 g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
110 prv_device_new_free(priv_t);
112 DLEYNA_LOG_DEBUG("Exit");
115 static const dleyna_task_queue_key_t *prv_create_device_queue(
116 prv_device_new_ct_t **priv_t)
118 const dleyna_task_queue_key_t *queue_id;
120 *priv_t = g_new0(prv_device_new_ct_t, 1);
122 queue_id = dleyna_task_processor_add_queue(
123 dls_server_get_task_processor(),
124 dleyna_service_task_create_source(),
126 DLEYNA_TASK_QUEUE_FLAG_AUTO_REMOVE,
127 dleyna_service_task_process_cb,
128 dleyna_service_task_cancel_cb,
129 dleyna_service_task_delete_cb);
130 dleyna_task_queue_set_finally(queue_id, prv_device_chain_end);
131 dleyna_task_queue_set_user_data(queue_id, *priv_t);
137 static void prv_update_device_context(prv_device_new_ct_t *priv_t,
138 dls_upnp_t *upnp, const char *udn,
139 dls_device_t *device,
140 const gchar *ip_address,
141 const dleyna_task_queue_key_t *queue_id)
144 priv_t->udn = g_strdup(udn);
145 priv_t->ip_address = g_strdup(ip_address);
146 priv_t->queue_id = queue_id;
147 priv_t->device = device;
149 g_hash_table_insert(upnp->server_uc_map, g_strdup(udn), priv_t);
152 static void prv_server_available_cb(GUPnPControlPoint *cp,
153 GUPnPDeviceProxy *proxy,
156 dls_upnp_t *upnp = user_data;
158 dls_device_t *device;
159 const gchar *ip_address;
160 dls_device_context_t *context;
161 const dleyna_task_queue_key_t *queue_id;
163 prv_device_new_ct_t *priv_t;
165 udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy);
169 ip_address = gupnp_context_get_host_ip(
170 gupnp_control_point_get_context(cp));
172 DLEYNA_LOG_DEBUG("UDN %s", udn);
173 DLEYNA_LOG_DEBUG("IP Address %s", ip_address);
175 device = g_hash_table_lookup(upnp->server_udn_map, udn);
178 priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
181 device = priv_t->device;
185 DLEYNA_LOG_DEBUG("Device not found. Adding");
186 DLEYNA_LOG_DEBUG_NL();
188 queue_id = prv_create_device_queue(&priv_t);
190 device = dls_device_new(upnp->connection, proxy, ip_address,
191 upnp->interface_info,
192 upnp->property_map, upnp->counter,
195 prv_update_device_context(priv_t, upnp, udn, device, ip_address,
200 DLEYNA_LOG_DEBUG("Device Found");
202 for (i = 0; i < device->contexts->len; ++i) {
203 context = g_ptr_array_index(device->contexts, i);
204 if (!strcmp(context->ip_address, ip_address))
208 if (i == device->contexts->len) {
209 DLEYNA_LOG_DEBUG("Adding Context");
210 (void) dls_device_append_new_context(device, ip_address,
214 DLEYNA_LOG_DEBUG_NL();
222 static gboolean prv_subscribe_to_contents_change(gpointer user_data)
224 dls_device_t *device = user_data;
226 device->timeout_id = 0;
227 dls_device_subscribe_to_contents_change(device);
232 static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
233 GUPnPDeviceProxy *proxy,
236 dls_upnp_t *upnp = user_data;
238 dls_device_t *device;
239 const gchar *ip_address;
241 dls_device_context_t *context;
243 gboolean construction_ctx = FALSE;
244 gboolean under_construction = FALSE;
245 prv_device_new_ct_t *priv_t;
246 const dleyna_task_queue_key_t *queue_id;
248 DLEYNA_LOG_DEBUG("Enter");
250 udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy);
254 ip_address = gupnp_context_get_host_ip(
255 gupnp_control_point_get_context(cp));
257 DLEYNA_LOG_DEBUG("UDN %s", udn);
258 DLEYNA_LOG_DEBUG("IP Address %s", ip_address);
260 device = g_hash_table_lookup(upnp->server_udn_map, udn);
263 priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
266 device = priv_t->device;
267 under_construction = TRUE;
272 DLEYNA_LOG_WARNING("Device not found. Ignoring");
276 for (i = 0; i < device->contexts->len; ++i) {
277 context = g_ptr_array_index(device->contexts, i);
278 if (!strcmp(context->ip_address, ip_address))
282 if (i >= device->contexts->len)
285 subscribed = context->subscribed;
286 if (under_construction)
287 construction_ctx = !strcmp(context->ip_address,
290 (void) g_ptr_array_remove_index(device->contexts, i);
292 if (device->contexts->len == 0) {
293 if (!under_construction) {
294 DLEYNA_LOG_DEBUG("Last Context lost. Delete device");
295 upnp->lost_server(device->path, upnp->user_data);
296 g_hash_table_remove(upnp->server_udn_map, udn);
299 "Device under construction. Cancelling");
301 dleyna_task_processor_cancel_queue(priv_t->queue_id);
303 } else if (under_construction && construction_ctx) {
305 "Device under construction. Switching context");
307 /* Cancel previous contruction task chain */
308 g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
309 dleyna_task_queue_set_finally(priv_t->queue_id,
310 prv_device_context_switch_end);
311 dleyna_task_processor_cancel_queue(priv_t->queue_id);
313 /* Create a new construction task chain */
314 context = dls_device_get_context(device, NULL);
315 queue_id = prv_create_device_queue(&priv_t);
316 prv_update_device_context(priv_t, upnp, udn, device,
317 context->ip_address, queue_id);
319 /* Start tasks from current construction step */
320 dls_device_construct(device,
323 upnp->interface_info,
327 } else if (subscribed && !device->timeout_id) {
328 DLEYNA_LOG_DEBUG("Subscribe on new context");
330 device->timeout_id = g_timeout_add_seconds(1,
331 prv_subscribe_to_contents_change,
337 DLEYNA_LOG_DEBUG("Exit");
338 DLEYNA_LOG_DEBUG_NL();
343 static void prv_on_context_available(GUPnPContextManager *context_manager,
344 GUPnPContext *context,
347 dls_upnp_t *upnp = user_data;
348 GUPnPControlPoint *cp;
350 cp = gupnp_control_point_new(
352 "urn:schemas-upnp-org:device:MediaServer:1");
354 g_signal_connect(cp, "device-proxy-available",
355 G_CALLBACK(prv_server_available_cb), upnp);
357 g_signal_connect(cp, "device-proxy-unavailable",
358 G_CALLBACK(prv_server_unavailable_cb), upnp);
360 gssdp_resource_browser_set_active(GSSDP_RESOURCE_BROWSER(cp), TRUE);
361 gupnp_context_manager_manage_control_point(upnp->context_manager, cp);
365 dls_upnp_t *dls_upnp_new(dleyna_connector_id_t connection,
366 const dleyna_connector_dispatch_cb_t *dispatch_table,
367 dls_upnp_callback_t found_server,
368 dls_upnp_callback_t lost_server,
371 dls_upnp_t *upnp = g_new0(dls_upnp_t, 1);
373 upnp->connection = connection;
374 upnp->interface_info = dispatch_table;
375 upnp->user_data = user_data;
376 upnp->found_server = found_server;
377 upnp->lost_server = lost_server;
379 upnp->server_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal,
383 upnp->server_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal,
386 dls_prop_maps_new(&upnp->property_map, &upnp->filter_map);
388 upnp->context_manager = gupnp_context_manager_create(0);
390 g_signal_connect(upnp->context_manager, "context-available",
391 G_CALLBACK(prv_on_context_available),
397 void dls_upnp_delete(dls_upnp_t *upnp)
400 g_object_unref(upnp->context_manager);
401 g_hash_table_unref(upnp->property_map);
402 g_hash_table_unref(upnp->filter_map);
403 g_hash_table_unref(upnp->server_udn_map);
404 g_hash_table_unref(upnp->server_uc_map);
409 GVariant *dls_upnp_get_server_ids(dls_upnp_t *upnp)
414 dls_device_t *device;
417 DLEYNA_LOG_DEBUG("Enter");
419 g_variant_builder_init(&vb, G_VARIANT_TYPE("ao"));
421 g_hash_table_iter_init(&iter, upnp->server_udn_map);
422 while (g_hash_table_iter_next(&iter, NULL, &value)) {
424 DLEYNA_LOG_DEBUG("Have device %s", device->path);
425 g_variant_builder_add(&vb, "o", device->path);
428 retval = g_variant_ref_sink(g_variant_builder_end(&vb));
430 DLEYNA_LOG_DEBUG("Exit");
435 GHashTable *dls_upnp_get_server_udn_map(dls_upnp_t *upnp)
437 return upnp->server_udn_map;
440 void dls_upnp_get_children(dls_upnp_t *upnp, dls_client_t *client,
442 dls_upnp_task_complete_t cb)
444 dls_async_task_t *cb_data = (dls_async_task_t *)task;
445 dls_async_bas_t *cb_task_data;
446 gchar *upnp_filter = NULL;
447 gchar *sort_by = NULL;
449 DLEYNA_LOG_DEBUG("Enter");
451 DLEYNA_LOG_DEBUG("Path: %s", task->target.path);
452 DLEYNA_LOG_DEBUG("Start: %u", task->ut.get_children.start);
453 DLEYNA_LOG_DEBUG("Count: %u", task->ut.get_children.count);
456 cb_task_data = &cb_data->ut.bas;
458 cb_task_data->filter_mask =
459 dls_props_parse_filter(upnp->filter_map,
460 task->ut.get_children.filter,
463 DLEYNA_LOG_DEBUG("Filter Mask 0x%"G_GUINT64_FORMAT"x",
464 cb_task_data->filter_mask);
466 sort_by = dls_sort_translate_sort_string(upnp->filter_map,
467 task->ut.get_children.sort_by);
469 DLEYNA_LOG_WARNING("Invalid Sort Criteria");
471 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
472 DLEYNA_ERROR_BAD_QUERY,
473 "Sort Criteria are not valid");
477 DLEYNA_LOG_DEBUG("Sort By %s", sort_by);
479 cb_task_data->protocol_info = client->protocol_info;
481 dls_device_get_children(client, task, upnp_filter, sort_by);
485 if (!cb_data->action)
486 (void) g_idle_add(dls_async_task_complete, cb_data);
491 DLEYNA_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
494 void dls_upnp_get_all_props(dls_upnp_t *upnp, dls_client_t *client,
496 dls_upnp_task_complete_t cb)
498 gboolean root_object;
499 dls_async_task_t *cb_data = (dls_async_task_t *)task;
500 dls_async_get_all_t *cb_task_data;
502 DLEYNA_LOG_DEBUG("Enter");
504 DLEYNA_LOG_DEBUG("Path: %s", task->target.path);
505 DLEYNA_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
508 cb_task_data = &cb_data->ut.get_all;
510 root_object = task->target.id[0] == '0' && task->target.id[1] == 0;
512 DLEYNA_LOG_DEBUG("Root Object = %d", root_object);
514 cb_task_data->protocol_info = client->protocol_info;
516 dls_device_get_all_props(client, task, root_object);
518 DLEYNA_LOG_DEBUG("Exit with SUCCESS");
521 void dls_upnp_get_prop(dls_upnp_t *upnp, dls_client_t *client,
523 dls_upnp_task_complete_t cb)
525 gboolean root_object;
526 dls_async_task_t *cb_data = (dls_async_task_t *)task;
527 dls_async_get_prop_t *cb_task_data;
528 dls_prop_map_t *prop_map;
529 dls_task_get_prop_t *task_data;
531 DLEYNA_LOG_DEBUG("Enter");
533 DLEYNA_LOG_DEBUG("Path: %s", task->target.path);
534 DLEYNA_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
535 DLEYNA_LOG_DEBUG("Prop.%s", task->ut.get_prop.prop_name);
537 task_data = &task->ut.get_prop;
539 cb_task_data = &cb_data->ut.get_prop;
541 root_object = task->target.id[0] == '0' && task->target.id[1] == 0;
543 DLEYNA_LOG_DEBUG("Root Object = %d", root_object);
545 cb_task_data->protocol_info = client->protocol_info;
546 prop_map = g_hash_table_lookup(upnp->filter_map, task_data->prop_name);
548 dls_device_get_prop(client, task, prop_map, root_object);
550 DLEYNA_LOG_DEBUG("Exit with SUCCESS");
553 void dls_upnp_search(dls_upnp_t *upnp, dls_client_t *client,
555 dls_upnp_task_complete_t cb)
557 gchar *upnp_filter = NULL;
558 gchar *upnp_query = NULL;
559 gchar *sort_by = NULL;
560 dls_async_task_t *cb_data = (dls_async_task_t *)task;
561 dls_async_bas_t *cb_task_data;
563 DLEYNA_LOG_DEBUG("Enter");
565 DLEYNA_LOG_DEBUG("Path: %s", task->target.path);
566 DLEYNA_LOG_DEBUG("Query: %s", task->ut.search.query);
567 DLEYNA_LOG_DEBUG("Start: %u", task->ut.search.start);
568 DLEYNA_LOG_DEBUG("Count: %u", task->ut.search.count);
571 cb_task_data = &cb_data->ut.bas;
573 cb_task_data->filter_mask =
574 dls_props_parse_filter(upnp->filter_map,
575 task->ut.search.filter, &upnp_filter);
577 DLEYNA_LOG_DEBUG("Filter Mask 0x%"G_GUINT64_FORMAT"x",
578 cb_task_data->filter_mask);
580 upnp_query = dls_search_translate_search_string(upnp->filter_map,
581 task->ut.search.query);
583 DLEYNA_LOG_WARNING("Query string is not valid:%s",
584 task->ut.search.query);
586 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
587 DLEYNA_ERROR_BAD_QUERY,
588 "Query string is not valid.");
592 DLEYNA_LOG_DEBUG("UPnP Query %s", upnp_query);
594 sort_by = dls_sort_translate_sort_string(upnp->filter_map,
595 task->ut.search.sort_by);
597 DLEYNA_LOG_WARNING("Invalid Sort Criteria");
599 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
600 DLEYNA_ERROR_BAD_QUERY,
601 "Sort Criteria are not valid");
605 DLEYNA_LOG_DEBUG("Sort By %s", sort_by);
607 cb_task_data->protocol_info = client->protocol_info;
609 dls_device_search(client, task, upnp_filter, upnp_query, sort_by);
612 if (!cb_data->action)
613 (void) g_idle_add(dls_async_task_complete, cb_data);
619 DLEYNA_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
622 void dls_upnp_get_resource(dls_upnp_t *upnp, dls_client_t *client,
624 dls_upnp_task_complete_t cb)
626 dls_async_task_t *cb_data = (dls_async_task_t *)task;
627 dls_async_get_all_t *cb_task_data;
628 gchar *upnp_filter = NULL;
630 DLEYNA_LOG_DEBUG("Enter");
632 DLEYNA_LOG_DEBUG("Protocol Info: %s ", task->ut.resource.protocol_info);
635 cb_task_data = &cb_data->ut.get_all;
637 DLEYNA_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
640 cb_task_data->filter_mask =
641 dls_props_parse_filter(upnp->filter_map,
642 task->ut.resource.filter, &upnp_filter);
644 DLEYNA_LOG_DEBUG("Filter Mask 0x%"G_GUINT64_FORMAT"x",
645 cb_task_data->filter_mask);
647 dls_device_get_resource(client, task, upnp_filter);
651 DLEYNA_LOG_DEBUG("Exit");
654 static gboolean prv_compute_mime_and_class(dls_task_t *task,
655 dls_async_upload_t *cb_task_data,
658 gchar *content_type = NULL;
660 if (!g_file_test(task->ut.upload.file_path,
661 G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS)) {
663 "File %s does not exist or is not a regular file",
664 task->ut.upload.file_path);
666 *error = g_error_new(DLEYNA_SERVER_ERROR,
667 DLEYNA_ERROR_OBJECT_NOT_FOUND,
668 "File %s does not exist or is not a regular file",
669 task->ut.upload.file_path);
673 content_type = g_content_type_guess(task->ut.upload.file_path, NULL, 0,
677 DLEYNA_LOG_WARNING("Unable to determine Content Type for %s",
678 task->ut.upload.file_path);
680 *error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_BAD_MIME,
681 "Unable to determine Content Type for %s",
682 task->ut.upload.file_path);
686 cb_task_data->mime_type = g_content_type_get_mime_type(content_type);
687 g_free(content_type);
689 if (!cb_task_data->mime_type) {
690 DLEYNA_LOG_WARNING("Unable to determine MIME Type for %s",
691 task->ut.upload.file_path);
693 *error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_BAD_MIME,
694 "Unable to determine MIME Type for %s",
695 task->ut.upload.file_path);
699 if (g_content_type_is_a(cb_task_data->mime_type, "image/*")) {
700 cb_task_data->object_class = "object.item.imageItem";
701 } else if (g_content_type_is_a(cb_task_data->mime_type, "audio/*")) {
702 cb_task_data->object_class = "object.item.audioItem";
703 } else if (g_content_type_is_a(cb_task_data->mime_type, "video/*")) {
704 cb_task_data->object_class = "object.item.videoItem";
706 DLEYNA_LOG_WARNING("Unsupported MIME Type %s",
707 cb_task_data->mime_type);
709 *error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_BAD_MIME,
710 "Unsupported MIME Type %s",
711 cb_task_data->mime_type);
722 void dls_upnp_upload_to_any(dls_upnp_t *upnp, dls_client_t *client,
724 dls_upnp_task_complete_t cb)
726 dls_async_task_t *cb_data = (dls_async_task_t *)task;
727 dls_async_upload_t *cb_task_data;
729 DLEYNA_LOG_DEBUG("Enter");
732 cb_task_data = &cb_data->ut.upload;
734 DLEYNA_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
737 if (strcmp(task->target.id, "0")) {
738 DLEYNA_LOG_WARNING("Bad path %s", task->target.path);
741 g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_BAD_PATH,
742 "UploadToAnyContainer must be executed on a root path");
746 if (!prv_compute_mime_and_class(task, cb_task_data, &cb_data->error))
749 DLEYNA_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
750 DLEYNA_LOG_DEBUG("Object class %s", cb_task_data->object_class);
752 dls_device_upload(client, task, "DLNA.ORG_AnyContainer");
756 if (!cb_data->action)
757 (void) g_idle_add(dls_async_task_complete, cb_data);
759 DLEYNA_LOG_DEBUG("Exit");
762 void dls_upnp_upload(dls_upnp_t *upnp, dls_client_t *client, dls_task_t *task,
763 dls_upnp_task_complete_t cb)
765 dls_async_task_t *cb_data = (dls_async_task_t *)task;
766 dls_async_upload_t *cb_task_data;
768 DLEYNA_LOG_DEBUG("Enter");
771 cb_task_data = &cb_data->ut.upload;
773 if (!prv_compute_mime_and_class(task, cb_task_data, &cb_data->error))
776 DLEYNA_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
777 DLEYNA_LOG_DEBUG("Object class %s", cb_task_data->object_class);
779 dls_device_upload(client, task, task->target.id);
783 if (!cb_data->action)
784 (void) g_idle_add(dls_async_task_complete, cb_data);
786 DLEYNA_LOG_DEBUG("Exit");
789 void dls_upnp_get_upload_status(dls_upnp_t *upnp, dls_task_t *task)
791 GError *error = NULL;
793 DLEYNA_LOG_DEBUG("Enter");
795 DLEYNA_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
798 if (strcmp(task->target.id, "0")) {
799 DLEYNA_LOG_WARNING("Bad path %s", task->target.path);
801 error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_BAD_PATH,
802 "GetUploadStatus must be executed on a root path");
806 (void) dls_device_get_upload_status(task, &error);
811 dls_task_fail(task, error);
814 dls_task_complete(task);
817 DLEYNA_LOG_DEBUG("Exit");
820 void dls_upnp_get_upload_ids(dls_upnp_t *upnp, dls_task_t *task)
822 GError *error = NULL;
824 DLEYNA_LOG_DEBUG("Enter");
826 DLEYNA_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
829 if (strcmp(task->target.id, "0")) {
830 DLEYNA_LOG_WARNING("Bad path %s", task->target.path);
832 error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_BAD_PATH,
833 "GetUploadIDs must be executed on a root path");
837 dls_device_get_upload_ids(task);
842 dls_task_fail(task, error);
845 dls_task_complete(task);
848 DLEYNA_LOG_DEBUG("Exit");
851 void dls_upnp_cancel_upload(dls_upnp_t *upnp, dls_task_t *task)
853 GError *error = NULL;
855 DLEYNA_LOG_DEBUG("Enter");
857 DLEYNA_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
860 if (strcmp(task->target.id, "0")) {
861 DLEYNA_LOG_WARNING("Bad path %s", task->target.path);
863 error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_BAD_PATH,
864 "CancelUpload must be executed on a root path");
868 (void) dls_device_cancel_upload(task, &error);
873 dls_task_fail(task, error);
876 dls_task_complete(task);
879 DLEYNA_LOG_DEBUG("Exit");
882 void dls_upnp_delete_object(dls_upnp_t *upnp, dls_client_t *client,
884 dls_upnp_task_complete_t cb)
886 dls_async_task_t *cb_data = (dls_async_task_t *)task;
888 DLEYNA_LOG_DEBUG("Enter");
892 DLEYNA_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
895 dls_device_delete_object(client, task);
897 DLEYNA_LOG_DEBUG("Exit");
900 void dls_upnp_create_container(dls_upnp_t *upnp, dls_client_t *client,
902 dls_upnp_task_complete_t cb)
904 dls_async_task_t *cb_data = (dls_async_task_t *)task;
906 DLEYNA_LOG_DEBUG("Enter");
910 DLEYNA_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
913 dls_device_create_container(client, task, task->target.id);
915 if (!cb_data->action)
916 (void) g_idle_add(dls_async_task_complete, cb_data);
918 DLEYNA_LOG_DEBUG("Exit");
921 void dls_upnp_create_container_in_any(dls_upnp_t *upnp, dls_client_t *client,
923 dls_upnp_task_complete_t cb)
925 dls_async_task_t *cb_data = (dls_async_task_t *)task;
927 DLEYNA_LOG_DEBUG("Enter");
931 DLEYNA_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
934 if (strcmp(task->target.id, "0")) {
935 DLEYNA_LOG_WARNING("Bad path %s", task->target.path);
938 g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_BAD_PATH,
939 "CreateContainerInAnyContainer must be executed on a root path");
943 dls_device_create_container(client, task, "DLNA.ORG_AnyContainer");
947 if (!cb_data->action)
948 (void) g_idle_add(dls_async_task_complete, cb_data);
950 DLEYNA_LOG_DEBUG("Exit");
953 void dls_upnp_update_object(dls_upnp_t *upnp, dls_client_t *client,
955 dls_upnp_task_complete_t cb)
957 dls_async_task_t *cb_data = (dls_async_task_t *)task;
958 dls_async_update_t *cb_task_data;
959 dls_upnp_prop_mask mask;
960 gchar *upnp_filter = NULL;
961 dls_task_update_t *task_data;
963 DLEYNA_LOG_DEBUG("Enter");
966 cb_task_data = &cb_data->ut.update;
967 task_data = &task->ut.update;
969 DLEYNA_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
972 if (!dls_props_parse_update_filter(upnp->filter_map,
973 task_data->to_add_update,
974 task_data->to_delete,
975 &mask, &upnp_filter)) {
976 DLEYNA_LOG_WARNING("Invalid Parameter");
978 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
979 DLEYNA_ERROR_OPERATION_FAILED,
980 "Invalid Parameter");
984 cb_task_data->map = upnp->filter_map;
986 DLEYNA_LOG_DEBUG("Filter = %s", upnp_filter);
987 DLEYNA_LOG_DEBUG("Mask = 0x%"G_GUINT64_FORMAT"x", mask);
990 DLEYNA_LOG_WARNING("Empty Parameters");
992 cb_data->error = g_error_new(DLEYNA_SERVER_ERROR,
993 DLEYNA_ERROR_OPERATION_FAILED,
999 dls_device_update_object(client, task, upnp_filter);
1003 g_free(upnp_filter);
1005 if (!cb_data->action)
1006 (void) g_idle_add(dls_async_task_complete, cb_data);
1008 DLEYNA_LOG_DEBUG("Exit");
1011 void dls_upnp_get_object_metadata(dls_upnp_t *upnp, dls_client_t *client,
1012 dls_task_t *task, dls_upnp_task_complete_t cb)
1014 dls_async_task_t *cb_data = (dls_async_task_t *)task;
1016 DLEYNA_LOG_DEBUG("Enter");
1020 DLEYNA_LOG_DEBUG("Root Path %s Id %s", task->target.root_path,
1023 dls_device_get_object_metadata(client, task, task->target.id);
1025 DLEYNA_LOG_DEBUG("Exit");
1028 void dls_upnp_create_reference(dls_upnp_t *upnp, dls_client_t *client,
1030 dls_upnp_task_complete_t cb)
1032 dls_async_task_t *cb_data = (dls_async_task_t *)task;
1034 DLEYNA_LOG_DEBUG("Enter");
1038 DLEYNA_LOG_DEBUG("Root Path: %s - Id: %s", task->target.root_path,
1041 dls_device_create_reference(client, task);
1043 DLEYNA_LOG_DEBUG("Exit");
1048 void dls_upnp_get_icon(dls_upnp_t *upnp, dls_client_t *client,
1050 dls_upnp_task_complete_t cb)
1052 dls_async_task_t *cb_data = (dls_async_task_t *)task;
1054 DLEYNA_LOG_DEBUG("Enter");
1058 dls_device_get_icon(client, task);
1060 DLEYNA_LOG_DEBUG("Exit");
1063 void dls_upnp_unsubscribe(dls_upnp_t *upnp)
1065 GHashTableIter iter;
1067 dls_device_t *device;
1069 DLEYNA_LOG_DEBUG("Enter");
1071 g_hash_table_iter_init(&iter, upnp->server_udn_map);
1072 while (g_hash_table_iter_next(&iter, NULL, &value)) {
1074 dls_device_unsubscribe(device);
1077 DLEYNA_LOG_DEBUG("Exit");
1080 static gboolean prv_device_uc_find(gpointer key, gpointer value,
1083 prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *)value;
1085 return (priv_t->device == user_data) ? TRUE : FALSE;
1088 static gboolean prv_device_find(gpointer key, gpointer value,
1091 return (value == user_data) ? TRUE : FALSE;
1094 gboolean dls_upnp_device_context_exist(dls_device_t *device,
1095 dls_device_context_t *context)
1099 gboolean found = FALSE;
1100 dls_upnp_t *upnp = dls_server_get_upnp();
1105 /* Check if the device still exist */
1106 result = g_hash_table_find(upnp->server_udn_map, prv_device_find,
1110 if (g_hash_table_find(upnp->server_uc_map, prv_device_uc_find,
1114 /* Search if the context still exist in the device */
1115 for (i = 0; i < device->contexts->len; ++i) {
1116 if (g_ptr_array_index(device->contexts, i) == context) {
1126 void dls_upnp_rescan(dls_upnp_t *upnp)
1128 DLEYNA_LOG_DEBUG("re-scanning control points");
1130 gupnp_context_manager_rescan_control_points(upnp->context_manager);