Update to v0.4.0
[profile/ivi/dLeyna.git] / dleyna-server / libdleyna / server / task.c
1 /*
2  * dLeyna
3  *
4  * Copyright (C) 2012-2013 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 <libdleyna/core/error.h>
24 #include <libdleyna/core/log.h>
25
26 #include "async.h"
27 #include "path.h"
28
29 static void prv_delete(dls_task_t *task)
30 {
31         if (!task->synchronous)
32                 dls_async_task_delete((dls_async_task_t *)task);
33
34         switch (task->type) {
35         case DLS_TASK_GET_CHILDREN:
36                 if (task->ut.get_children.filter)
37                         g_variant_unref(task->ut.get_children.filter);
38                 g_free(task->ut.get_children.sort_by);
39                 break;
40         case DLS_TASK_MANAGER_GET_ALL_PROPS:
41         case DLS_TASK_GET_ALL_PROPS:
42                 g_free(task->ut.get_props.interface_name);
43                 break;
44         case DLS_TASK_MANAGER_GET_PROP:
45         case DLS_TASK_GET_PROP:
46                 g_free(task->ut.get_prop.interface_name);
47                 g_free(task->ut.get_prop.prop_name);
48                 break;
49         case DLS_TASK_MANAGER_SET_PROP:
50                 g_free(task->ut.set_prop.interface_name);
51                 g_free(task->ut.set_prop.prop_name);
52                 g_variant_unref(task->ut.set_prop.params);
53                 break;
54         case DLS_TASK_SEARCH:
55                 g_free(task->ut.search.query);
56                 if (task->ut.search.filter)
57                         g_variant_unref(task->ut.search.filter);
58                 g_free(task->ut.search.sort_by);
59                 break;
60         case DLS_TASK_BROWSE_OBJECTS:
61                 if (task->ut.browse_objects.objects)
62                         g_variant_unref(task->ut.browse_objects.objects);
63                 if (task->ut.browse_objects.filter)
64                         g_variant_unref(task->ut.browse_objects.filter);
65                 break;
66         case DLS_TASK_GET_RESOURCE:
67                 if (task->ut.resource.filter)
68                         g_variant_unref(task->ut.resource.filter);
69                 g_free(task->ut.resource.protocol_info);
70                 break;
71         case DLS_TASK_SET_PROTOCOL_INFO:
72                 if (task->ut.protocol_info.protocol_info)
73                         g_free(task->ut.protocol_info.protocol_info);
74                 break;
75         case DLS_TASK_UPLOAD_TO_ANY:
76         case DLS_TASK_UPLOAD:
77                 g_free(task->ut.upload.display_name);
78                 g_free(task->ut.upload.file_path);
79                 break;
80         case DLS_TASK_CREATE_CONTAINER:
81         case DLS_TASK_CREATE_CONTAINER_IN_ANY:
82                 g_free(task->ut.create_container.display_name);
83                 g_free(task->ut.create_container.type);
84                 if (task->ut.create_container.child_types)
85                         g_variant_unref(task->ut.create_container.child_types);
86                 break;
87         case DLS_TASK_UPDATE_OBJECT:
88                 if (task->ut.update.to_add_update)
89                         g_variant_unref(task->ut.update.to_add_update);
90                 if (task->ut.update.to_delete)
91                         g_variant_unref(task->ut.update.to_delete);
92                 break;
93         case DLS_TASK_CREATE_REFERENCE:
94                 g_free(task->ut.create_reference.item_path);
95                 break;
96         case DLS_TASK_GET_ICON:
97                 g_free(task->ut.get_icon.resolution);
98                 g_free(task->ut.get_icon.mime_type);
99                 break;
100         default:
101                 break;
102         }
103
104         g_free(task->target.path);
105         g_free(task->target.root_path);
106         g_free(task->target.id);
107
108         if (task->result)
109                 g_variant_unref(task->result);
110
111         g_free(task);
112 }
113
114 dls_task_t *dls_task_rescan_new(dleyna_connector_msg_id_t invocation)
115 {
116         dls_task_t *task = g_new0(dls_task_t, 1);
117
118         task->type = DLS_TASK_RESCAN;
119         task->invocation = invocation;
120         task->synchronous = TRUE;
121
122         return task;
123 }
124
125 dls_task_t *dls_task_get_version_new(dleyna_connector_msg_id_t invocation)
126 {
127         dls_task_t *task = g_new0(dls_task_t, 1);
128
129         task->type = DLS_TASK_GET_VERSION;
130         task->invocation = invocation;
131         task->result_format = "(@s)";
132         task->synchronous = TRUE;
133
134         return task;
135 }
136
137 dls_task_t *dls_task_get_servers_new(dleyna_connector_msg_id_t invocation)
138 {
139         dls_task_t *task = g_new0(dls_task_t, 1);
140
141         task->type = DLS_TASK_GET_SERVERS;
142         task->invocation = invocation;
143         task->result_format = "(@ao)";
144         task->synchronous = TRUE;
145
146         return task;
147 }
148
149 dls_task_t *dls_task_manager_get_prop_new(dleyna_connector_msg_id_t invocation,
150                                           const gchar *path,
151                                           GVariant *parameters,
152                                           GError **error)
153 {
154         dls_task_t *task = (dls_task_t *)g_new0(dls_async_task_t, 1);
155
156         g_variant_get(parameters, "(ss)", &task->ut.get_prop.interface_name,
157                       &task->ut.get_prop.prop_name);
158         g_strstrip(task->ut.get_prop.interface_name);
159         g_strstrip(task->ut.get_prop.prop_name);
160
161         task->target.path = g_strstrip(g_strdup(path));
162
163         task->type = DLS_TASK_MANAGER_GET_PROP;
164         task->invocation = invocation;
165         task->result_format = "(v)";
166
167         return task;
168 }
169
170 dls_task_t *dls_task_manager_get_props_new(dleyna_connector_msg_id_t invocation,
171                                            const gchar *path,
172                                            GVariant *parameters,
173                                            GError **error)
174 {
175         dls_task_t *task = (dls_task_t *)g_new0(dls_async_task_t, 1);
176
177         g_variant_get(parameters, "(s)", &task->ut.get_props.interface_name);
178         g_strstrip(task->ut.get_props.interface_name);
179
180         task->target.path = g_strstrip(g_strdup(path));
181
182         task->type = DLS_TASK_MANAGER_GET_ALL_PROPS;
183         task->invocation = invocation;
184         task->result_format = "(@a{sv})";
185
186         return task;
187 }
188
189 dls_task_t *dls_task_manager_set_prop_new(dleyna_connector_msg_id_t invocation,
190                                           const gchar *path,
191                                           GVariant *parameters,
192                                           GError **error)
193 {
194         dls_task_t *task = (dls_task_t *)g_new0(dls_async_task_t, 1);
195
196         g_variant_get(parameters, "(ssv)",
197                       &task->ut.set_prop.interface_name,
198                       &task->ut.set_prop.prop_name,
199                       &task->ut.set_prop.params);
200
201         g_strstrip(task->ut.set_prop.interface_name);
202         g_strstrip(task->ut.set_prop.prop_name);
203
204         task->target.path = g_strstrip(g_strdup(path));
205
206         task->type = DLS_TASK_MANAGER_SET_PROP;
207         task->invocation = invocation;
208
209         return task;
210 }
211
212 static gboolean prv_set_task_target_info(dls_task_t *task, const gchar *path,
213                                          GError **error)
214 {
215         task->target.path = g_strdup(path);
216         g_strstrip(task->target.path);
217
218         return dls_server_get_object_info(path, &task->target.root_path,
219                                                &task->target.id,
220                                                &task->target.device, error);
221 }
222
223 static dls_task_t *prv_m2spec_task_new(dls_task_type_t type,
224                                        dleyna_connector_msg_id_t invocation,
225                                        const gchar *path,
226                                        const gchar *result_format,
227                                        GError **error,
228                                        gboolean synchronous)
229 {
230         dls_task_t *task;
231
232         if (synchronous) {
233                 task = g_new0(dls_task_t, 1);
234                 task->synchronous = TRUE;
235         } else {
236                 task = (dls_task_t *)g_new0(dls_async_task_t, 1);
237         }
238
239         if (!prv_set_task_target_info(task, path, error)) {
240                 prv_delete(task);
241                 task = NULL;
242
243                 goto finished;
244         }
245
246         task->type = type;
247         task->invocation = invocation;
248         task->result_format = result_format;
249
250 finished:
251
252         return task;
253 }
254
255 dls_task_t *dls_task_get_children_new(dleyna_connector_msg_id_t invocation,
256                                       const gchar *path, GVariant *parameters,
257                                       gboolean items, gboolean containers,
258                                       GError **error)
259 {
260         dls_task_t *task;
261
262         task = prv_m2spec_task_new(DLS_TASK_GET_CHILDREN, invocation, path,
263                                    "(@aa{sv})", error, FALSE);
264         if (!task)
265                 goto finished;
266
267         task->ut.get_children.containers = containers;
268         task->ut.get_children.items = items;
269
270         g_variant_get(parameters, "(uu@as)",
271                       &task->ut.get_children.start,
272                       &task->ut.get_children.count,
273                       &task->ut.get_children.filter);
274
275         task->ut.get_children.sort_by = g_strdup("");
276
277 finished:
278
279         return task;
280 }
281
282 dls_task_t *dls_task_get_children_ex_new(dleyna_connector_msg_id_t invocation,
283                                          const gchar *path,
284                                          GVariant *parameters, gboolean items,
285                                          gboolean containers,
286                                          GError **error)
287 {
288         dls_task_t *task;
289
290         task = prv_m2spec_task_new(DLS_TASK_GET_CHILDREN, invocation, path,
291                                    "(@aa{sv})", error, FALSE);
292         if (!task)
293                 goto finished;
294
295         task->ut.get_children.containers = containers;
296         task->ut.get_children.items = items;
297
298         g_variant_get(parameters, "(uu@ass)",
299                       &task->ut.get_children.start,
300                       &task->ut.get_children.count,
301                       &task->ut.get_children.filter,
302                       &task->ut.get_children.sort_by);
303
304 finished:
305
306         return task;
307 }
308
309 dls_task_t *dls_task_get_prop_new(dleyna_connector_msg_id_t invocation,
310                                   const gchar *path, GVariant *parameters,
311                                   GError **error)
312 {
313         dls_task_t *task;
314
315         task = prv_m2spec_task_new(DLS_TASK_GET_PROP, invocation, path, "(v)",
316                                    error, FALSE);
317         if (!task)
318                 goto finished;
319
320         g_variant_get(parameters, "(ss)", &task->ut.get_prop.interface_name,
321                       &task->ut.get_prop.prop_name);
322
323         g_strstrip(task->ut.get_prop.interface_name);
324         g_strstrip(task->ut.get_prop.prop_name);
325
326 finished:
327
328         return task;
329 }
330
331 dls_task_t *dls_task_get_props_new(dleyna_connector_msg_id_t invocation,
332                                    const gchar *path, GVariant *parameters,
333                                    GError **error)
334 {
335         dls_task_t *task;
336
337         task = prv_m2spec_task_new(DLS_TASK_GET_ALL_PROPS, invocation, path,
338                                    "(@a{sv})", error, FALSE);
339         if (!task)
340                 goto finished;
341
342         g_variant_get(parameters, "(s)", &task->ut.get_props.interface_name);
343         g_strstrip(task->ut.get_props.interface_name);
344
345 finished:
346
347         return task;
348 }
349
350 dls_task_t *dls_task_search_new(dleyna_connector_msg_id_t invocation,
351                                 const gchar *path, GVariant *parameters,
352                                 GError **error)
353 {
354         dls_task_t *task;
355
356         task = prv_m2spec_task_new(DLS_TASK_SEARCH, invocation, path,
357                                    "(@aa{sv})", error, FALSE);
358         if (!task)
359                 goto finished;
360
361         g_variant_get(parameters, "(suu@as)", &task->ut.search.query,
362                       &task->ut.search.start, &task->ut.search.count,
363                       &task->ut.search.filter);
364
365         task->ut.search.sort_by = g_strdup("");
366
367 finished:
368         return task;
369 }
370
371 dls_task_t *dls_task_search_ex_new(dleyna_connector_msg_id_t invocation,
372                                    const gchar *path, GVariant *parameters,
373                                    GError **error)
374 {
375         dls_task_t *task;
376
377         task = prv_m2spec_task_new(DLS_TASK_SEARCH, invocation, path,
378                                    "(@aa{sv}u)", error, FALSE);
379         if (!task)
380                 goto finished;
381
382         g_variant_get(parameters, "(suu@ass)", &task->ut.search.query,
383                       &task->ut.search.start, &task->ut.search.count,
384                       &task->ut.search.filter, &task->ut.search.sort_by);
385
386         task->multiple_retvals = TRUE;
387
388 finished:
389
390         return task;
391 }
392
393 dls_task_t *dls_task_browse_objects_new(dleyna_connector_msg_id_t invocation,
394                                         const gchar *path, GVariant *parameters,
395                                         GError **error)
396 {
397         dls_task_t *task;
398
399         task = prv_m2spec_task_new(DLS_TASK_BROWSE_OBJECTS, invocation, path,
400                                    "(@aa{sv})", error, FALSE);
401         if (!task)
402                 goto finished;
403
404         g_variant_get(parameters, "(@ao@as)",
405                       &task->ut.browse_objects.objects,
406                       &task->ut.browse_objects.filter);
407
408 finished:
409
410         return task;
411 }
412
413 dls_task_t *dls_task_get_resource_new(dleyna_connector_msg_id_t invocation,
414                                       const gchar *path, GVariant *parameters,
415                                       GError **error)
416 {
417         dls_task_t *task;
418
419         task = prv_m2spec_task_new(DLS_TASK_GET_RESOURCE, invocation, path,
420                                    "(@a{sv})", error, FALSE);
421         if (!task)
422                 goto finished;
423
424         g_variant_get(parameters, "(s@as)",
425                       &task->ut.resource.protocol_info,
426                       &task->ut.resource.filter);
427
428 finished:
429
430         return task;
431 }
432
433 dls_task_t *dls_task_set_protocol_info_new(dleyna_connector_msg_id_t invocation,
434                                            GVariant *parameters)
435 {
436         dls_task_t *task = g_new0(dls_task_t, 1);
437
438         task->type = DLS_TASK_SET_PROTOCOL_INFO;
439         task->invocation = invocation;
440         task->synchronous = TRUE;
441         g_variant_get(parameters, "(s)", &task->ut.protocol_info.protocol_info);
442
443         return task;
444 }
445
446 static dls_task_t *prv_upload_new_generic(dls_task_type_t type,
447                                           dleyna_connector_msg_id_t invocation,
448                                           const gchar *path,
449                                           GVariant *parameters,
450                                           GError **error)
451 {
452         dls_task_t *task;
453
454         task = prv_m2spec_task_new(type, invocation, path,
455                                    "(uo)", error, FALSE);
456         if (!task)
457                 goto finished;
458
459         g_variant_get(parameters, "(ss)", &task->ut.upload.display_name,
460                       &task->ut.upload.file_path);
461         g_strstrip(task->ut.upload.file_path);
462         task->multiple_retvals = TRUE;
463
464 finished:
465
466         return task;
467 }
468
469 dls_task_t *dls_task_prefer_local_addresses_new(
470                                         dleyna_connector_msg_id_t invocation,
471                                         GVariant *parameters)
472 {
473         dls_task_t *task = g_new0(dls_task_t, 1);
474
475         task->type = DLS_TASK_SET_PREFER_LOCAL_ADDRESSES;
476         task->invocation = invocation;
477         task->synchronous = TRUE;
478         g_variant_get(parameters, "(b)",
479                       &task->ut.prefer_local_addresses.prefer);
480
481         return task;
482 }
483
484 dls_task_t *dls_task_upload_to_any_new(dleyna_connector_msg_id_t invocation,
485                                        const gchar *path, GVariant *parameters,
486                                        GError **error)
487 {
488         return prv_upload_new_generic(DLS_TASK_UPLOAD_TO_ANY, invocation,
489                                       path, parameters, error);
490 }
491
492 dls_task_t *dls_task_upload_new(dleyna_connector_msg_id_t invocation,
493                                 const gchar *path, GVariant *parameters,
494                                 GError **error)
495 {
496         return prv_upload_new_generic(DLS_TASK_UPLOAD, invocation,
497                                       path, parameters, error);
498 }
499
500 dls_task_t *dls_task_get_upload_status_new(dleyna_connector_msg_id_t invocation,
501                                            const gchar *path,
502                                            GVariant *parameters,
503                                            GError **error)
504 {
505         dls_task_t *task;
506
507         task = prv_m2spec_task_new(DLS_TASK_GET_UPLOAD_STATUS, invocation, path,
508                                    "(stt)", error, TRUE);
509         if (!task)
510                 goto finished;
511
512         g_variant_get(parameters, "(u)",
513                       &task->ut.upload_action.upload_id);
514         task->multiple_retvals = TRUE;
515
516 finished:
517
518         return task;
519 }
520
521 dls_task_t *dls_task_get_upload_ids_new(dleyna_connector_msg_id_t invocation,
522                                         const gchar *path,
523                                         GError **error)
524 {
525         dls_task_t *task;
526
527         task = prv_m2spec_task_new(DLS_TASK_GET_UPLOAD_IDS, invocation, path,
528                                    "(@au)", error, TRUE);
529
530         return task;
531 }
532
533 dls_task_t *dls_task_cancel_upload_new(dleyna_connector_msg_id_t invocation,
534                                        const gchar *path,
535                                        GVariant *parameters,
536                                        GError **error)
537 {
538         dls_task_t *task;
539
540         task = prv_m2spec_task_new(DLS_TASK_CANCEL_UPLOAD, invocation, path,
541                                    NULL, error, TRUE);
542         if (!task)
543                 goto finished;
544
545         g_variant_get(parameters, "(u)",
546                       &task->ut.upload_action.upload_id);
547
548 finished:
549
550         return task;
551 }
552
553 dls_task_t *dls_task_delete_new(dleyna_connector_msg_id_t invocation,
554                                 const gchar *path,
555                                 GError **error)
556 {
557         dls_task_t *task;
558
559         task = prv_m2spec_task_new(DLS_TASK_DELETE_OBJECT, invocation,
560                                    path, NULL, error, FALSE);
561         return task;
562 }
563
564 dls_task_t *dls_task_create_container_new_generic(
565                                         dleyna_connector_msg_id_t invocation,
566                                         dls_task_type_t type,
567                                         const gchar *path,
568                                         GVariant *parameters,
569                                         GError **error)
570 {
571         dls_task_t *task;
572
573         task = prv_m2spec_task_new(type, invocation, path,
574                                    "(@o)", error, FALSE);
575         if (!task)
576                 goto finished;
577
578         g_variant_get(parameters, "(ss@as)",
579                       &task->ut.create_container.display_name,
580                       &task->ut.create_container.type,
581                       &task->ut.create_container.child_types);
582
583 finished:
584
585         return task;
586 }
587
588 dls_task_t *dls_task_create_reference_new(dleyna_connector_msg_id_t invocation,
589                                           dls_task_type_t type,
590                                           const gchar *path,
591                                           GVariant *parameters,
592                                           GError **error)
593 {
594         dls_task_t *task;
595
596         task = prv_m2spec_task_new(type, invocation, path,
597                                    "(@o)", error, FALSE);
598         if (!task)
599                 goto finished;
600
601         g_variant_get(parameters, "(o)", &task->ut.create_reference.item_path);
602         (void) g_strstrip(task->ut.create_reference.item_path);
603
604 finished:
605
606         return task;
607 }
608
609 dls_task_t *dls_task_update_new(dleyna_connector_msg_id_t invocation,
610                                 const gchar *path, GVariant *parameters,
611                                 GError **error)
612 {
613         dls_task_t *task;
614
615         task = prv_m2spec_task_new(DLS_TASK_UPDATE_OBJECT, invocation, path,
616                                    NULL, error, FALSE);
617         if (!task)
618                 goto finished;
619
620         g_variant_get(parameters, "(@a{sv}@as)",
621                       &task->ut.update.to_add_update,
622                       &task->ut.update.to_delete);
623
624 finished:
625
626         return task;
627 }
628
629 dls_task_t *dls_task_get_metadata_new(dleyna_connector_msg_id_t invocation,
630                                 const gchar *path, GError **error)
631 {
632         dls_task_t *task;
633
634         task = prv_m2spec_task_new(DLS_TASK_GET_OBJECT_METADATA, invocation,
635                                    path, "(@s)", error, FALSE);
636
637         return task;
638 }
639
640 dls_task_t *dls_task_get_icon_new(dleyna_connector_msg_id_t invocation,
641                                   const gchar *path, GVariant *parameters,
642                                   GError **error)
643 {
644         dls_task_t *task;
645
646         task = prv_m2spec_task_new(DLS_TASK_GET_ICON, invocation, path,
647                                    "(@ays)", error, FALSE);
648         if (!task)
649                 goto finished;
650
651         task->multiple_retvals = TRUE;
652
653         g_variant_get(parameters, "(ss)", &task->ut.get_icon.mime_type,
654                       &task->ut.get_icon.resolution);
655
656 finished:
657
658         return task;
659 }
660
661 void dls_task_complete(dls_task_t *task)
662 {
663         GVariant *variant = NULL;
664
665         if (!task)
666                 goto finished;
667
668         if (task->invocation) {
669                 if (task->result_format) {
670                         if (task->multiple_retvals)
671                                 variant = g_variant_ref(task->result);
672                         else
673                                 variant = g_variant_ref_sink(
674                                         g_variant_new(task->result_format,
675                                                       task->result));
676                 }
677
678                 dls_server_get_connector()->return_response(task->invocation,
679                                                             variant);
680                 if (variant)
681                         g_variant_unref(variant);
682
683                 task->invocation = NULL;
684         }
685
686 finished:
687
688         return;
689 }
690
691 void dls_task_fail(dls_task_t *task, GError *error)
692 {
693         if (!task)
694                 goto finished;
695
696         if (task->invocation) {
697                 dls_server_get_connector()->return_error(task->invocation,
698                                                          error);
699                 task->invocation = NULL;
700         }
701
702 finished:
703
704         return;
705 }
706
707 void dls_task_cancel(dls_task_t *task)
708 {
709         GError *error;
710
711         if (!task)
712                 goto finished;
713
714         if (task->invocation) {
715                 error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_CANCELLED,
716                                     "Operation cancelled.");
717                 dls_server_get_connector()->return_error(task->invocation,
718                                                          error);
719                 task->invocation = NULL;
720                 g_error_free(error);
721         }
722
723         if (!task->synchronous)
724                 dls_async_task_cancel((dls_async_task_t *)task);
725
726 finished:
727
728         return;
729 }
730
731 void dls_task_delete(dls_task_t *task)
732 {
733         GError *error;
734
735         if (!task)
736                 goto finished;
737
738         if (task->invocation) {
739                 error = g_error_new(DLEYNA_SERVER_ERROR, DLEYNA_ERROR_DIED,
740                                     "Unable to complete command.");
741                 dls_server_get_connector()->return_error(task->invocation,
742                                                          error);
743                 g_error_free(error);
744         }
745
746         prv_delete(task);
747
748 finished:
749
750         return;
751 }