Update media-service-upnp to version 0.3.0 ( ca17a69 )
[profile/ivi/media-service-upnp.git] / src / upnp.c
1 /*
2  * media-service-upnp
3  *
4  * Copyright (C) 2012 Intel Corporation. All rights reserved.
5  *
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.
9  *
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
13  * for more details.
14  *
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.
18  *
19  * Mark Ryan <mark.d.ryan@intel.com>
20  *
21  */
22
23 #include <string.h>
24
25 #include <libgssdp/gssdp-resource-browser.h>
26 #include <libgupnp/gupnp-control-point.h>
27 #include <libgupnp/gupnp-error.h>
28
29 #include "async.h"
30 #include "chain-task.h"
31 #include "device.h"
32 #include "error.h"
33 #include "interface.h"
34 #include "log.h"
35 #include "path.h"
36 #include "search.h"
37 #include "sort.h"
38 #include "upnp.h"
39
40 struct msu_upnp_t_ {
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;
48         void *user_data;
49         GHashTable *server_udn_map;
50         GHashTable *server_uc_map;
51         guint counter;
52 };
53
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_ {
57         msu_upnp_t *upnp;
58         const char *udn;
59         msu_device_t *device;
60         msu_chain_task_t *chain;
61 };
62
63 static gchar **prv_subtree_enumerate(GDBusConnection *connection,
64                                      const gchar *sender,
65                                      const gchar *object_path,
66                                      gpointer user_data);
67
68 static GDBusInterfaceInfo **prv_subtree_introspect(
69         GDBusConnection *connection,
70         const gchar *sender,
71         const gchar *object_path,
72         const gchar *node,
73         gpointer user_data);
74
75 static const GDBusInterfaceVTable *prv_subtree_dispatch(
76         GDBusConnection *connection,
77         const gchar *sender,
78         const gchar *object_path,
79         const gchar *interface_name,
80         const gchar *node,
81         gpointer *out_user_data,
82         gpointer user_data);
83
84
85 static const GDBusSubtreeVTable gSubtreeVtable = {
86         prv_subtree_enumerate,
87         prv_subtree_introspect,
88         prv_subtree_dispatch
89 };
90
91 static gchar **prv_subtree_enumerate(GDBusConnection *connection,
92                                      const gchar *sender,
93                                      const gchar *object_path,
94                                      gpointer user_data)
95 {
96         return g_malloc0(sizeof(gchar *));
97 }
98
99 static GDBusInterfaceInfo **prv_subtree_introspect(
100         GDBusConnection *connection,
101         const gchar *sender,
102         const gchar *object_path,
103         const gchar *node,
104         gpointer user_data)
105 {
106         msu_upnp_t *upnp = user_data;
107         GDBusInterfaceInfo **retval = g_new(GDBusInterfaceInfo *,
108                                             MSU_INTERFACE_INFO_MAX + 1);
109         GDBusInterfaceInfo *info;
110         unsigned int i;
111         gboolean root_object = FALSE;
112         const gchar *slash;
113
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.
122
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
126            interface.
127         */
128
129         if (msu_path_get_non_root_id(object_path, &slash))
130                 root_object = !slash;
131
132         i = 0;
133         info = upnp->interface_info[MSU_INTERFACE_INFO_PROPERTIES].interface;
134         retval[i++] =  g_dbus_interface_info_ref(info);
135
136         info = upnp->interface_info[MSU_INTERFACE_INFO_OBJECT].interface;
137         retval[i++] =  g_dbus_interface_info_ref(info);
138
139         info = upnp->interface_info[MSU_INTERFACE_INFO_CONTAINER].interface;
140         retval[i++] =  g_dbus_interface_info_ref(info);
141
142         if (!root_object) {
143                 info = upnp->interface_info[MSU_INTERFACE_INFO_ITEM].interface;
144                 retval[i++] =  g_dbus_interface_info_ref(info);
145         } else {
146                 info = upnp->interface_info[
147                         MSU_INTERFACE_INFO_DEVICE].interface;
148                 retval[i++] =  g_dbus_interface_info_ref(info);
149         }
150
151         retval[i] = NULL;
152
153         return retval;
154 }
155
156 static const GDBusInterfaceVTable *prv_subtree_dispatch(
157         GDBusConnection *connection,
158         const gchar *sender,
159         const gchar *object_path,
160         const gchar *interface_name,
161         const gchar *node,
162         gpointer *out_user_data,
163         gpointer user_data)
164 {
165         msu_upnp_t *upnp = user_data;
166         const GDBusInterfaceVTable *retval = NULL;
167
168         *out_user_data = upnp->user_data;
169
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;
185
186
187         return retval;
188 }
189
190 static void prv_device_chain_end(msu_chain_task_t *chain, gpointer data)
191 {
192         msu_device_t *device;
193         gboolean canceled;
194         prv_device_new_ct_t *priv_t = (prv_device_new_ct_t *) data;
195
196         device = msu_chain_task_get_device(chain);
197         canceled = msu_chain_task_is_canceled(chain);
198         if (canceled)
199                 goto on_clear;
200
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),
203                             device);
204         priv_t->upnp->found_server(device->path, priv_t->upnp->user_data);
205
206 on_clear:
207
208         g_hash_table_remove(priv_t->upnp->server_uc_map, priv_t->udn);
209         msu_chain_task_delete(chain);
210         g_free(priv_t);
211
212         if (canceled)
213                 msu_device_delete(device);
214
215         MSU_LOG_DEBUG_NL();
216 }
217
218 static void prv_server_available_cb(GUPnPControlPoint *cp,
219                                     GUPnPDeviceProxy *proxy,
220                                     gpointer user_data)
221 {
222         msu_upnp_t *upnp = user_data;
223         const char *udn;
224         msu_device_t *device;
225         const gchar *ip_address;
226         msu_device_context_t *context;
227         msu_chain_task_t *chain;
228         unsigned int i;
229         prv_device_new_ct_t *priv_t;
230
231         udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *) proxy);
232         if (!udn)
233                 goto on_error;
234
235         ip_address = gupnp_context_get_host_ip(
236                 gupnp_control_point_get_context(cp));
237
238         MSU_LOG_DEBUG("UDN %s", udn);
239         MSU_LOG_DEBUG("IP Address %s", ip_address);
240
241         device = g_hash_table_lookup(upnp->server_udn_map, udn);
242
243         if (!device) {
244                 priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
245
246                 if (priv_t)
247                         device = priv_t->device;
248         }
249
250         if (!device) {
251                 MSU_LOG_DEBUG("Device not found. Adding");
252                 MSU_LOG_DEBUG_NL();
253
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,
259                                         chain);
260
261                 upnp->counter++;
262
263                 priv_t->upnp = upnp;
264                 priv_t->udn = udn;
265                 priv_t->chain = chain;
266                 priv_t->device = device;
267
268                 g_hash_table_insert(upnp->server_uc_map, g_strdup(udn), priv_t);
269         } else {
270                 MSU_LOG_DEBUG("Device Found");
271
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))
275                                 break;
276                 }
277
278                 if (i == device->contexts->len) {
279                         MSU_LOG_DEBUG("Adding Context");
280                         msu_device_append_new_context(device, ip_address,
281                                                       proxy);
282                 }
283
284                 MSU_LOG_DEBUG_NL();
285         }
286
287 on_error:
288
289         return;
290 }
291
292 static gboolean prv_subscribe_to_contents_change(gpointer user_data)
293 {
294         msu_device_t *device = user_data;
295
296         device->timeout_id = 0;
297         msu_device_subscribe_to_contents_change(device);
298
299         return FALSE;
300 }
301
302 static void prv_server_unavailable_cb(GUPnPControlPoint *cp,
303                                       GUPnPDeviceProxy *proxy,
304                                       gpointer user_data)
305 {
306         msu_upnp_t *upnp = user_data;
307         const char *udn;
308         msu_device_t *device;
309         const gchar *ip_address;
310         unsigned int i;
311         msu_device_context_t *context;
312         gboolean subscribed;
313         gboolean under_construction = FALSE;
314         prv_device_new_ct_t *priv_t;
315
316         MSU_LOG_DEBUG("Enter");
317
318         udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *) proxy);
319         if (!udn)
320                 goto on_error;
321
322         ip_address = gupnp_context_get_host_ip(
323                 gupnp_control_point_get_context(cp));
324
325         MSU_LOG_DEBUG("UDN %s", udn);
326         MSU_LOG_DEBUG("IP Address %s", ip_address);
327
328         device = g_hash_table_lookup(upnp->server_udn_map, udn);
329
330         if (!device) {
331                 priv_t = g_hash_table_lookup(upnp->server_uc_map, udn);
332
333                 if (priv_t) {
334                         device = priv_t->device;
335                         under_construction = TRUE;
336                 }
337         }
338
339         if (!device) {
340                 MSU_LOG_WARNING("Device not found. Ignoring");
341                 goto on_error;
342         }
343
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))
347                         break;
348         }
349
350         if (i < device->contexts->len) {
351                 subscribed = context->subscribed;
352
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. " \
357                                                "Delete device");
358
359                                 upnp->lost_server(device->path,
360                                                   upnp->user_data);
361                                 g_hash_table_remove(upnp->server_udn_map, udn);
362                         } else {
363                                 MSU_LOG_WARNING("Device under construction. "\
364                                                  "Cancelling");
365
366                                 msu_chain_task_cancel(priv_t->chain);
367                                 prv_device_chain_end(priv_t->chain, priv_t);
368                         }
369                 } else if (subscribed && !device->timeout_id) {
370
371                         MSU_LOG_DEBUG("Subscribe on new context");
372
373                         device->timeout_id = g_timeout_add_seconds(1,
374                                         prv_subscribe_to_contents_change,
375                                         device);
376                 }
377         }
378
379 on_error:
380
381         MSU_LOG_DEBUG("Exit");
382         MSU_LOG_DEBUG_NL();
383
384         return;
385 }
386
387 static void prv_on_context_available(GUPnPContextManager *context_manager,
388                                      GUPnPContext *context,
389                                      gpointer user_data)
390 {
391         msu_upnp_t *upnp = user_data;
392         GUPnPControlPoint *cp;
393
394         cp = gupnp_control_point_new(
395                 context,
396                 "urn:schemas-upnp-org:device:MediaServer:1");
397
398         g_signal_connect(cp, "device-proxy-available",
399                          G_CALLBACK(prv_server_available_cb), upnp);
400
401         g_signal_connect(cp, "device-proxy-unavailable",
402                          G_CALLBACK(prv_server_unavailable_cb), upnp);
403
404         gssdp_resource_browser_set_active(GSSDP_RESOURCE_BROWSER(cp), TRUE);
405         gupnp_context_manager_manage_control_point(upnp->context_manager, cp);
406         g_object_unref(cp);
407 }
408
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,
413                          void *user_data)
414 {
415         msu_upnp_t *upnp = g_new0(msu_upnp_t, 1);
416
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;
422
423         upnp->server_udn_map = g_hash_table_new_full(g_str_hash, g_str_equal,
424                                                      g_free,
425                                                      msu_device_delete);
426
427         upnp->server_uc_map = g_hash_table_new_full(g_str_hash, g_str_equal,
428                                                      g_free, NULL);
429
430         msu_prop_maps_new(&upnp->property_map, &upnp->filter_map);
431
432         upnp->context_manager = gupnp_context_manager_create(0);
433
434         g_signal_connect(upnp->context_manager, "context-available",
435                          G_CALLBACK(prv_on_context_available),
436                          upnp);
437
438         return upnp;
439 }
440
441 void msu_upnp_delete(msu_upnp_t *upnp)
442 {
443         if (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);
450                 g_free(upnp);
451         }
452 }
453
454 GVariant *msu_upnp_get_server_ids(msu_upnp_t *upnp)
455 {
456         GVariantBuilder vb;
457         GHashTableIter iter;
458         gpointer value;
459         msu_device_t *device;
460         GVariant *retval;
461
462         MSU_LOG_DEBUG("Enter");
463
464         g_variant_builder_init(&vb, G_VARIANT_TYPE("ao"));
465
466         g_hash_table_iter_init(&iter, upnp->server_udn_map);
467         while (g_hash_table_iter_next(&iter, NULL, &value)) {
468                 device = value;
469                 MSU_LOG_DEBUG("Have device %s", device->path);
470                 g_variant_builder_add(&vb, "o", device->path);
471         }
472
473         retval = g_variant_ref_sink(g_variant_builder_end(&vb));
474
475         MSU_LOG_DEBUG("Exit");
476
477         return retval;
478 }
479
480 void msu_upnp_get_children(msu_upnp_t *upnp, msu_client_t *client,
481                            msu_task_t *task,
482                            GCancellable *cancellable,
483                            msu_upnp_task_complete_t cb)
484 {
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;
490
491         MSU_LOG_DEBUG("Enter");
492
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);
496
497         cb_data = msu_async_cb_data_new(task, cb);
498         cb_task_data = &cb_data->ut.bas;
499
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);
503
504                 goto on_error;
505         }
506
507         device = msu_device_from_path(cb_task_data->root_path,
508                                       upnp->server_udn_map);
509         if (!device) {
510                 MSU_LOG_WARNING("Cannot locate device for %s",
511                               cb_task_data->root_path);
512
513                 cb_data->error =
514                         g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
515                                     "Cannot locate device corresponding to"
516                                     " the specified path");
517                 goto on_error;
518         }
519
520         cb_task_data->filter_mask =
521                 msu_props_parse_filter(upnp->filter_map,
522                                         task->ut.get_children.filter,
523                                         &upnp_filter);
524
525         MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
526
527         sort_by = msu_sort_translate_sort_string(upnp->filter_map,
528                                                  task->ut.get_children.sort_by);
529         if (!sort_by) {
530                 MSU_LOG_WARNING("Invalid Sort Criteria");
531
532                 cb_data->error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_QUERY,
533                                              "Sort Criteria are not valid");
534                 goto on_error;
535         }
536
537         MSU_LOG_DEBUG("Sort By %s", sort_by);
538
539         cb_task_data->protocol_info = client->protocol_info;
540
541         msu_device_get_children(device, client, task, cb_data,
542                                 upnp_filter, sort_by, cancellable);
543
544 on_error:
545
546         if (!cb_data->action)
547                 (void) g_idle_add(msu_async_complete_task, cb_data);
548
549         g_free(sort_by);
550         g_free(upnp_filter);
551
552         MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
553 }
554
555 void msu_upnp_get_all_props(msu_upnp_t *upnp, msu_client_t *client,
556                             msu_task_t *task,
557                             GCancellable *cancellable,
558                             msu_upnp_task_complete_t cb)
559 {
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;
564
565         MSU_LOG_DEBUG("Enter");
566
567         MSU_LOG_DEBUG("Path: %s", task->path);
568         MSU_LOG_DEBUG("Interface %s", task->ut.get_prop.interface_name);
569
570         cb_data = msu_async_cb_data_new(task, cb);
571         cb_task_data = &cb_data->ut.get_all;
572
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);
576
577                 goto on_error;
578         }
579
580         root_object = cb_data->id[0] == '0' && cb_data->id[1] == 0;
581
582         MSU_LOG_DEBUG("Root Object = %d", root_object);
583
584         device = msu_device_from_path(cb_task_data->root_path,
585                                       upnp->server_udn_map);
586         if (!device) {
587                 MSU_LOG_WARNING("Cannot locate device for %s",
588                               cb_task_data->root_path);
589
590                 cb_data->error =
591                         g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
592                                     "Cannot locate device corresponding to"
593                                     " the specified path");
594                 goto on_error;
595         }
596
597         cb_task_data->protocol_info = client->protocol_info;
598
599         msu_device_get_all_props(device, client, task, cb_data, root_object,
600                                  cancellable);
601
602         MSU_LOG_DEBUG("Exit with SUCCESS");
603
604         return;
605
606 on_error:
607
608         (void) g_idle_add(msu_async_complete_task, cb_data);
609
610         MSU_LOG_DEBUG("Exit with FAIL");
611 }
612
613 void msu_upnp_get_prop(msu_upnp_t *upnp, msu_client_t *client,
614                        msu_task_t *task,
615                        GCancellable *cancellable,
616                        msu_upnp_task_complete_t cb)
617 {
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;
624
625         MSU_LOG_DEBUG("Enter");
626
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);
630
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;
634
635         if (!msu_path_get_path_and_id(task->path, &cb_task_data->root_path,
636                                       &cb_data->id,
637                                       &cb_data->error)) {
638                 MSU_LOG_WARNING("Bad path %s", task->path);
639
640                 goto on_error;
641         }
642
643         root_object = cb_data->id[0] == '0' && cb_data->id[1] == 0;
644
645         MSU_LOG_DEBUG("Root Object = %d", root_object);
646
647         device = msu_device_from_path(cb_task_data->root_path,
648                                       upnp->server_udn_map);
649         if (!device) {
650                 MSU_LOG_WARNING("Cannot locate device for %s",
651                               cb_task_data->root_path);
652
653                 cb_data->error =
654                         g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
655                                     "Cannot locate device corresponding to"
656                                     " the specified path");
657                 goto on_error;
658         }
659
660         cb_task_data->protocol_info = client->protocol_info;
661         prop_map = g_hash_table_lookup(upnp->filter_map, task_data->prop_name);
662
663         msu_device_get_prop(device, client, task, cb_data, prop_map,
664                             root_object, cancellable);
665
666         MSU_LOG_DEBUG("Exit with SUCCESS");
667
668         return;
669
670 on_error:
671
672         (void) g_idle_add(msu_async_complete_task, cb_data);
673
674         MSU_LOG_DEBUG("Exit with FAIL");
675 }
676
677 void msu_upnp_search(msu_upnp_t *upnp, msu_client_t *client,
678                      msu_task_t *task,
679                      GCancellable *cancellable,
680                      msu_upnp_task_complete_t cb)
681 {
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;
688
689         MSU_LOG_DEBUG("Enter");
690
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);
695
696         cb_data = msu_async_cb_data_new(task, cb);
697         cb_task_data = &cb_data->ut.bas;
698
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);
702
703                 goto on_error;
704         }
705
706         device = msu_device_from_path(cb_task_data->root_path,
707                                       upnp->server_udn_map);
708         if (!device) {
709                 MSU_LOG_WARNING("Cannot locate device for %s",
710                               cb_task_data->root_path);
711
712                 cb_data->error =
713                         g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
714                                     "Cannot locate device corresponding to"
715                                     " the specified path");
716                 goto on_error;
717         }
718
719         cb_task_data->filter_mask =
720                 msu_props_parse_filter(upnp->filter_map,
721                                        task->ut.search.filter, &upnp_filter);
722
723         MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
724
725         upnp_query = msu_search_translate_search_string(upnp->filter_map,
726                                                         task->ut.search.query);
727         if (!upnp_query) {
728                 MSU_LOG_WARNING("Query string is not valid:%s",
729                               task->ut.search.query);
730
731                 cb_data->error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_QUERY,
732                                              "Query string is not valid.");
733                 goto on_error;
734         }
735
736         MSU_LOG_DEBUG("UPnP Query %s", upnp_query);
737
738         sort_by = msu_sort_translate_sort_string(upnp->filter_map,
739                                                  task->ut.search.sort_by);
740         if (!sort_by) {
741                 MSU_LOG_WARNING("Invalid Sort Criteria");
742
743                 cb_data->error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_QUERY,
744                                              "Sort Criteria are not valid");
745                 goto on_error;
746         }
747
748         MSU_LOG_DEBUG("Sort By %s", sort_by);
749
750         cb_task_data->protocol_info = client->protocol_info;
751
752         msu_device_search(device, client, task, cb_data, upnp_filter,
753                           upnp_query, sort_by, cancellable);
754 on_error:
755
756         if (!cb_data->action)
757                 (void) g_idle_add(msu_async_complete_task, cb_data);
758
759         g_free(sort_by);
760         g_free(upnp_query);
761         g_free(upnp_filter);
762
763         MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
764 }
765
766 void msu_upnp_get_resource(msu_upnp_t *upnp, msu_client_t *client,
767                            msu_task_t *task,
768                            GCancellable *cancellable,
769                            msu_upnp_task_complete_t cb)
770 {
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;
776
777         MSU_LOG_DEBUG("Enter");
778
779         MSU_LOG_DEBUG("Protocol Info: %s ", task->ut.resource.protocol_info);
780
781         cb_data = msu_async_cb_data_new(task, cb);
782         cb_task_data = &cb_data->ut.get_all;
783
784         if (!msu_path_get_path_and_id(task->path, &root_path, &cb_data->id,
785                                       &cb_data->error)) {
786                 MSU_LOG_WARNING("Bad path %s", task->path);
787
788                 goto on_error;
789         }
790
791         MSU_LOG_DEBUG("Root Path %s Id %s", root_path, cb_data->id);
792
793         device = msu_device_from_path(root_path, upnp->server_udn_map);
794         if (!device) {
795                 MSU_LOG_WARNING("Cannot locate device for %s", root_path);
796
797                 cb_data->error =
798                         g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
799                                     "Cannot locate device corresponding to"
800                                     " the specified path");
801                 goto on_error;
802         }
803
804         cb_task_data->filter_mask =
805                 msu_props_parse_filter(upnp->filter_map,
806                                        task->ut.resource.filter, &upnp_filter);
807
808         MSU_LOG_DEBUG("Filter Mask 0x%x", cb_task_data->filter_mask);
809
810         msu_device_get_resource(device, client, task, cb_data, upnp_filter,
811                                 cancellable);
812
813 on_error:
814
815         if (!cb_data->action)
816                 (void) g_idle_add(msu_async_complete_task, cb_data);
817
818         g_free(upnp_filter);
819         g_free(root_path);
820
821         MSU_LOG_DEBUG("Exit with %s", !cb_data->action ? "FAIL" : "SUCCESS");
822 }
823
824 static gboolean prv_compute_mime_and_class(msu_task_t *task,
825                                            msu_async_upload_t *cb_task_data,
826                                            GError **error)
827 {
828         gchar *content_type = NULL;
829
830         if (!g_file_test(task->ut.upload.file_path,
831                          G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS)) {
832
833                 MSU_LOG_WARNING("File %s does not exist or is not"
834                                 " a regular file", task->ut.upload.file_path);
835
836                 *error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
837                                      "File %s does not exist or is not"
838                                      " a regular file",
839                                      task->ut.upload.file_path);
840                 goto on_error;
841         }
842
843         content_type = g_content_type_guess(task->ut.upload.file_path, NULL, 0,
844                                             NULL);
845
846         if (!content_type) {
847
848                 MSU_LOG_WARNING("Unable to determine Content Type "
849                                 "for %s", task->ut.upload.file_path);
850
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);
854                 goto on_error;
855         }
856
857         cb_task_data->mime_type = g_content_type_get_mime_type(content_type);
858         g_free(content_type);
859
860         if (!cb_task_data->mime_type) {
861
862                 MSU_LOG_WARNING("Unable to determine MIME Type for"
863                                 " %s", task->ut.upload.file_path);
864
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);
868                 goto on_error;
869         }
870
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";
877         } else {
878
879                 MSU_LOG_WARNING("Unsupported MIME Type"
880                                 " %s", cb_task_data->mime_type);
881
882                 *error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_MIME,
883                                      "Unsupported MIME Type"
884                                      " %s", cb_task_data->mime_type);
885                 goto on_error;
886         }
887
888         return TRUE;
889
890 on_error:
891
892         return FALSE;
893 }
894
895 void msu_upnp_upload_to_any(msu_upnp_t *upnp, msu_client_t *client,
896                             msu_task_t *task,
897                             GCancellable *cancellable,
898                             msu_upnp_task_complete_t cb)
899 {
900         msu_async_cb_data_t *cb_data;
901         msu_async_upload_t *cb_task_data;
902         msu_device_t *device;
903
904         MSU_LOG_DEBUG("Enter");
905
906         cb_data = msu_async_cb_data_new(task, cb);
907         cb_task_data = &cb_data->ut.upload;
908
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);
912
913                 goto on_error;
914         }
915
916         MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
917                       cb_data->id);
918
919         device = msu_device_from_path(cb_task_data->root_path,
920                                       upnp->server_udn_map);
921         if (!device) {
922                 MSU_LOG_WARNING("Cannot locate device for %s",
923                                 cb_task_data->root_path);
924
925                 cb_data->error =
926                         g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
927                                     "Cannot locate device corresponding to"
928                                     " the specified path");
929                 goto on_error;
930         }
931
932         if (strcmp(cb_data->id, "0")) {
933                 MSU_LOG_WARNING("Bad path %s", task->path);
934
935                 cb_data->error =
936                         g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
937                                     "UploadToAnyContainer must be executed "
938                                     " on a root path");
939                 goto on_error;
940         }
941
942         if (!prv_compute_mime_and_class(task, cb_task_data, &cb_data->error))
943                 goto on_error;
944
945         MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
946         MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
947
948         msu_device_upload(device, client, task, "DLNA.ORG_AnyContainer",
949                           cb_data, cancellable);
950
951 on_error:
952
953         if (!cb_data->action)
954                 (void) g_idle_add(msu_async_complete_task, cb_data);
955
956         MSU_LOG_DEBUG("Exit");
957 }
958
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)
962 {
963         msu_async_cb_data_t *cb_data;
964         msu_async_upload_t *cb_task_data;
965         msu_device_t *device;
966
967         MSU_LOG_DEBUG("Enter");
968
969         cb_data = msu_async_cb_data_new(task, cb);
970         cb_task_data = &cb_data->ut.upload;
971
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);
975
976                 goto on_error;
977         }
978
979         device = msu_device_from_path(cb_task_data->root_path,
980                                       upnp->server_udn_map);
981         if (!device) {
982                 MSU_LOG_WARNING("Cannot locate device for %s",
983                                 cb_task_data->root_path);
984
985                 cb_data->error =
986                         g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
987                                     "Cannot locate device corresponding to"
988                                     " the specified path");
989                 goto on_error;
990         }
991
992         if (!prv_compute_mime_and_class(task, cb_task_data, &cb_data->error))
993                 goto on_error;
994
995         MSU_LOG_DEBUG("MIME Type %s", cb_task_data->mime_type);
996         MSU_LOG_DEBUG("Object class %s", cb_task_data->object_class);
997
998         msu_device_upload(device, client, task, cb_data->id, cb_data,
999                           cancellable);
1000
1001 on_error:
1002
1003         if (!cb_data->action)
1004                 (void) g_idle_add(msu_async_complete_task, cb_data);
1005
1006         MSU_LOG_DEBUG("Exit");
1007 }
1008
1009 void msu_upnp_get_upload_status(msu_upnp_t *upnp, msu_task_t *task)
1010 {
1011         gchar *root_path = NULL;
1012         gchar *id = NULL;
1013         GError *error = NULL;
1014         msu_device_t *device;
1015
1016         MSU_LOG_DEBUG("Enter");
1017
1018         if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
1019                 MSU_LOG_WARNING("Bad path %s", task->path);
1020
1021                 goto on_error;
1022         }
1023
1024         MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
1025
1026         device = msu_device_from_path(root_path, upnp->server_udn_map);
1027         if (!device) {
1028                 MSU_LOG_WARNING("Cannot locate device for %s",
1029                                 root_path);
1030
1031                 error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1032                                     "Cannot locate device corresponding to"
1033                                     " the specified path");
1034                 goto on_error;
1035         }
1036
1037         if (strcmp(id, "0")) {
1038                 MSU_LOG_WARNING("Bad path %s", task->path);
1039
1040                 error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
1041                                     "GetUploadStatus must be executed "
1042                                     " on a root path");
1043                 goto on_error;
1044         }
1045
1046         (void) msu_device_get_upload_status(device, task, &error);
1047
1048 on_error:
1049
1050         if (error) {
1051                 msu_task_fail_and_delete(task, error);
1052                 g_error_free(error);
1053         } else {
1054                 msu_task_complete_and_delete(task);
1055         }
1056
1057         g_free(id);
1058         g_free(root_path);
1059
1060         MSU_LOG_DEBUG("Exit");
1061 }
1062
1063 void msu_upnp_get_upload_ids(msu_upnp_t *upnp, msu_task_t *task)
1064 {
1065         gchar *root_path = NULL;
1066         gchar *id = NULL;
1067         GError *error = NULL;
1068         msu_device_t *device;
1069
1070         MSU_LOG_DEBUG("Enter");
1071
1072         if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
1073                 MSU_LOG_WARNING("Bad path %s", task->path);
1074
1075                 goto on_error;
1076         }
1077
1078         MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
1079
1080         device = msu_device_from_path(root_path, upnp->server_udn_map);
1081         if (!device) {
1082                 MSU_LOG_WARNING("Cannot locate device for %s",
1083                                 root_path);
1084
1085                 error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1086                                     "Cannot locate device corresponding to"
1087                                     " the specified path");
1088                 goto on_error;
1089         }
1090
1091         if (strcmp(id, "0")) {
1092                 MSU_LOG_WARNING("Bad path %s", task->path);
1093
1094                 error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
1095                                     "GetUploadIDs must be executed "
1096                                     " on a root path");
1097                 goto on_error;
1098         }
1099
1100          msu_device_get_upload_ids(device, task);
1101
1102 on_error:
1103
1104         if (error) {
1105                 msu_task_fail_and_delete(task, error);
1106                 g_error_free(error);
1107         } else {
1108                 msu_task_complete_and_delete(task);
1109         }
1110
1111         g_free(id);
1112         g_free(root_path);
1113
1114         MSU_LOG_DEBUG("Exit");
1115 }
1116
1117 void msu_upnp_cancel_upload(msu_upnp_t *upnp, msu_task_t *task)
1118 {
1119         gchar *root_path = NULL;
1120         gchar *id = NULL;
1121         GError *error = NULL;
1122         msu_device_t *device;
1123
1124         MSU_LOG_DEBUG("Enter");
1125
1126         if (!msu_path_get_path_and_id(task->path, &root_path, &id, &error)) {
1127                 MSU_LOG_WARNING("Bad path %s", task->path);
1128
1129                 goto on_error;
1130         }
1131
1132         MSU_LOG_DEBUG("Root Path %s Id %s", root_path, id);
1133
1134         device = msu_device_from_path(root_path, upnp->server_udn_map);
1135         if (!device) {
1136                 MSU_LOG_WARNING("Cannot locate device for %s",
1137                                 root_path);
1138
1139                 error = g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1140                                     "Cannot locate device corresponding to"
1141                                     " the specified path");
1142                 goto on_error;
1143         }
1144
1145         if (strcmp(id, "0")) {
1146                 MSU_LOG_WARNING("Bad path %s", task->path);
1147
1148                 error = g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
1149                                     "CancelUpload must be executed "
1150                                     " on a root path");
1151                 goto on_error;
1152         }
1153
1154         (void) msu_device_cancel_upload(device, task, &error);
1155
1156 on_error:
1157
1158         if (error) {
1159                 msu_task_fail_and_delete(task, error);
1160                 g_error_free(error);
1161         } else {
1162                 msu_task_complete_and_delete(task);
1163         }
1164
1165         g_free(id);
1166         g_free(root_path);
1167
1168         MSU_LOG_DEBUG("Exit");
1169 }
1170
1171 void msu_upnp_delete_object(msu_upnp_t *upnp, msu_client_t *client,
1172                             msu_task_t *task,
1173                             GCancellable *cancellable,
1174                             msu_upnp_task_complete_t cb)
1175 {
1176         msu_async_cb_data_t *cb_data;
1177         msu_device_t *device;
1178         gchar *root_path = NULL;
1179
1180         MSU_LOG_DEBUG("Enter");
1181
1182         cb_data = msu_async_cb_data_new(task, cb);
1183
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);
1187
1188                 goto on_error;
1189         }
1190
1191         MSU_LOG_DEBUG("Root Path %s Id %s", root_path,
1192                       cb_data->id);
1193
1194         device = msu_device_from_path(root_path, upnp->server_udn_map);
1195         if (!device) {
1196                 MSU_LOG_WARNING("Cannot locate device for %s",
1197                                 root_path);
1198
1199                 cb_data->error =
1200                         g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1201                                     "Cannot locate device corresponding to"
1202                                     " the specified path");
1203                 goto on_error;
1204         }
1205
1206         msu_device_delete_object(device, client, task, cb_data, cancellable);
1207
1208 on_error:
1209
1210         if (root_path)
1211                 g_free(root_path);
1212         if (!cb_data->action)
1213                 (void) g_idle_add(msu_async_complete_task, cb_data);
1214
1215         MSU_LOG_DEBUG("Exit");
1216 }
1217
1218 void msu_upnp_create_container(msu_upnp_t *upnp, msu_client_t *client,
1219                                msu_task_t *task,
1220                                GCancellable *cancellable,
1221                                msu_upnp_task_complete_t cb)
1222 {
1223         msu_async_cb_data_t *cb_data;
1224         msu_async_create_container_t *cb_task_data;
1225         msu_device_t *device;
1226
1227         MSU_LOG_DEBUG("Enter");
1228
1229         cb_data = msu_async_cb_data_new(task, cb);
1230         cb_task_data = &cb_data->ut.create_container;
1231
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);
1235
1236                 goto on_error;
1237         }
1238
1239         MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
1240                       cb_data->id);
1241
1242         device = msu_device_from_path(cb_task_data->root_path,
1243                                                         upnp->server_udn_map);
1244         if (!device) {
1245                 MSU_LOG_WARNING("Cannot locate device for %s",
1246                                                 cb_task_data->root_path);
1247
1248                 cb_data->error =
1249                         g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1250                                     "Cannot locate device corresponding to"
1251                                     " the specified path");
1252                 goto on_error;
1253         }
1254
1255         msu_device_create_container(device, client, task, cb_data->id,
1256                                     cb_data, cancellable);
1257
1258 on_error:
1259
1260         if (!cb_data->action)
1261                 (void) g_idle_add(msu_async_complete_task, cb_data);
1262
1263         MSU_LOG_DEBUG("Exit");
1264 }
1265
1266 void msu_upnp_create_container_in_any(msu_upnp_t *upnp, msu_client_t *client,
1267                                       msu_task_t *task,
1268                                       GCancellable *cancellable,
1269                                       msu_upnp_task_complete_t cb)
1270 {
1271         msu_async_cb_data_t *cb_data;
1272         msu_async_create_container_t *cb_task_data;
1273         msu_device_t *device;
1274
1275         MSU_LOG_DEBUG("Enter");
1276
1277         cb_data = msu_async_cb_data_new(task, cb);
1278         cb_task_data = &cb_data->ut.create_container;
1279
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);
1283
1284                 goto on_error;
1285         }
1286
1287         MSU_LOG_DEBUG("Root Path %s Id %s", cb_task_data->root_path,
1288                       cb_data->id);
1289
1290         if (strcmp(cb_data->id, "0")) {
1291                 MSU_LOG_WARNING("Bad path %s", task->path);
1292
1293                 cb_data->error =
1294                         g_error_new(MSU_ERROR, MSU_ERROR_BAD_PATH,
1295                                     "CreateContainerInAnyContainer must be "
1296                                     "executed on a root path");
1297                 goto on_error;
1298         }
1299
1300         device = msu_device_from_path(cb_task_data->root_path,
1301                                                         upnp->server_udn_map);
1302         if (!device) {
1303                 MSU_LOG_WARNING("Cannot locate device for %s",
1304                                                 cb_task_data->root_path);
1305
1306                 cb_data->error =
1307                         g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1308                                     "Cannot locate device corresponding to"
1309                                     " the specified path");
1310                 goto on_error;
1311         }
1312
1313         msu_device_create_container(device, client, task,
1314                                     "DLNA.ORG_AnyContainer",
1315                                     cb_data, cancellable);
1316
1317 on_error:
1318
1319         if (!cb_data->action)
1320                 (void) g_idle_add(msu_async_complete_task, cb_data);
1321
1322         MSU_LOG_DEBUG("Exit");
1323 }
1324
1325 void msu_upnp_update_object(msu_upnp_t *upnp, msu_client_t *client,
1326                             msu_task_t *task,
1327                             GCancellable *cancellable,
1328                             msu_upnp_task_complete_t cb)
1329 {
1330         msu_async_cb_data_t *cb_data;
1331         msu_async_update_t *cb_task_data;
1332         msu_device_t *device;
1333         guint32 mask;
1334         gchar *root_path = NULL;
1335         gchar *upnp_filter = NULL;
1336         msu_task_update_t *task_data;
1337
1338         MSU_LOG_DEBUG("Enter");
1339
1340         cb_data = msu_async_cb_data_new(task, cb);
1341         cb_task_data = &cb_data->ut.update;
1342         task_data = &task->ut.update;
1343
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);
1347
1348                 goto on_error;
1349         }
1350
1351         MSU_LOG_DEBUG("Root Path = %s, Id = %s", root_path, cb_data->id);
1352
1353         device = msu_device_from_path(root_path, upnp->server_udn_map);
1354         if (!device) {
1355                 MSU_LOG_WARNING("Cannot locate device for %s", root_path);
1356
1357                 cb_data->error =
1358                         g_error_new(MSU_ERROR, MSU_ERROR_OBJECT_NOT_FOUND,
1359                                     "Cannot locate device corresponding to"
1360                                     " the specified path");
1361                 goto on_error;
1362         }
1363
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");
1369
1370                 cb_data->error = g_error_new(MSU_ERROR,
1371                                              MSU_ERROR_OPERATION_FAILED,
1372                                              "Invalid Parameter");
1373                 goto on_error;
1374         }
1375
1376         cb_task_data->map = upnp->filter_map;
1377
1378         MSU_LOG_DEBUG("Filter = %s", upnp_filter);
1379         MSU_LOG_DEBUG("Mask = 0x%x", mask);
1380
1381         if (mask == 0) {
1382                 MSU_LOG_WARNING("Empty Parameters");
1383
1384                 cb_data->error = g_error_new(MSU_ERROR,
1385                                              MSU_ERROR_OPERATION_FAILED,
1386                                              "Empty Parameters");
1387
1388                 goto on_error;
1389         }
1390
1391         msu_device_update_object(device, client, task, cb_data, upnp_filter,
1392                                  cancellable);
1393
1394 on_error:
1395
1396         if (root_path)
1397                 g_free(root_path);
1398
1399         g_free(upnp_filter);
1400
1401         if (!cb_data->action)
1402                 (void) g_idle_add(msu_async_complete_task, cb_data);
1403
1404         MSU_LOG_DEBUG("Exit");
1405 }