Imported Upstream version 1.7.8
[platform/upstream/edbus.git] / src / lib / bluez / e_bluez_element.c
1 #include "e_bluez_private.h"
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5
6 static Eina_Hash *elements = NULL;
7
8 typedef struct _E_Bluez_Element_Pending     E_Bluez_Element_Pending;
9 typedef struct _E_Bluez_Element_Call_Data   E_Bluez_Element_Call_Data;
10 typedef struct _E_Bluez_Element_Property    E_Bluez_Element_Property;
11 typedef struct _E_Bluez_Element_Listener    E_Bluez_Element_Listener;
12
13 struct _E_Bluez_Element_Pending
14 {
15                            EINA_INLIST;
16    DBusPendingCall        *pending;
17    void                   *data;
18    E_DBus_Method_Return_Cb user_cb;
19    void                   *user_data;
20 };
21
22 struct _E_Bluez_Element_Call_Data
23 {
24    E_Bluez_Element         *element;
25    E_DBus_Method_Return_Cb  cb;
26    E_Bluez_Element_Pending *pending;
27    Eina_Inlist            **p_list;
28 };
29
30 struct _E_Bluez_Element_Property
31 {
32                EINA_INLIST;
33    const char *name;
34    int         type;
35    union {
36       Eina_Bool      boolean;
37       const char    *str;
38       unsigned short u16;
39       unsigned int   u32;
40       unsigned char  byte;
41       const char    *path;
42       void          *variant;
43       E_Bluez_Array *array;
44    } value;
45 };
46
47 struct _E_Bluez_Element_Listener
48 {
49          EINA_INLIST;
50    void  (*cb)(void *data, const E_Bluez_Element *element);
51    void *data;
52    void  (*free_data)(void *data);
53 };
54
55 static void
56 _e_bluez_element_event_no_free(void *data __UNUSED__, void *ev)
57 {
58    E_Bluez_Element *element = ev;
59    e_bluez_element_unref(element);
60 }
61
62 void
63 e_bluez_element_event_add(int event_type, E_Bluez_Element *element)
64 {
65    e_bluez_element_ref(element);
66    ecore_event_add
67       (event_type, element, _e_bluez_element_event_no_free, element);
68 }
69
70 static void
71 e_bluez_element_call_dispatch_and_free(void *d, DBusMessage *msg, DBusError *err)
72 {
73    E_Bluez_Element_Call_Data *data = d;
74    E_Bluez_Element_Pending *pending;
75
76    pending = data->pending;
77    pending->pending = NULL;
78
79    if (data->cb)
80       data->cb(data->element, msg, err);
81
82    if (pending->user_cb)
83       pending->user_cb(pending->user_data, msg, err);
84
85    pending->data = NULL;
86    *data->p_list = eina_inlist_remove(*data->p_list, EINA_INLIST_GET(pending));
87    free(pending);
88    free(data);
89 }
90
91 static void
92 e_bluez_element_pending_cancel_and_free(Eina_Inlist **pending)
93 {
94    while (*pending)
95      {
96         E_Bluez_Element_Pending *p = (E_Bluez_Element_Pending *)*pending;
97         DBusError err;
98
99         dbus_pending_call_cancel(p->pending);
100
101         dbus_error_init(&err);
102         dbus_set_error(&err, "Canceled", "Pending method call was canceled.");
103         e_bluez_element_call_dispatch_and_free(p->data, NULL, &err);
104         dbus_error_free(&err);
105      }
106 }
107
108 void
109 e_bluez_element_listener_add(E_Bluez_Element *element, void (*cb)(void *data, const E_Bluez_Element *element), const void *data, void (*free_data)(void *data))
110 {
111    E_Bluez_Element_Listener *l;
112
113    if (!element)
114      {
115         ERR("safety check failed: element == NULL");
116         goto error;
117      }
118
119    if (!cb)
120      {
121         ERR("safety check failed: cb == NULL");
122         goto error;
123      }
124
125    l = malloc(sizeof(*l));
126    if (!l)
127      {
128         ERR("could not allocate E_Bluez_Element_Listener");
129         goto error;
130      }
131
132    l->cb = cb;
133    l->data = (void *)data;
134    l->free_data = free_data;
135
136    element->_listeners = eina_inlist_append
137          (element->_listeners, EINA_INLIST_GET(l));
138
139    return;
140
141 error:
142    if (free_data)
143       free_data((void *)data);
144 }
145
146 void
147 e_bluez_element_listener_del(E_Bluez_Element *element, void (*cb)(void *data, const E_Bluez_Element *element), const void *data)
148 {
149    E_Bluez_Element_Listener *l;
150
151    EINA_SAFETY_ON_NULL_RETURN(element);
152    EINA_SAFETY_ON_NULL_RETURN(cb);
153
154    EINA_INLIST_FOREACH(element->_listeners, l)
155    if ((l->cb == cb) && (l->data == data))
156      {
157         element->_listeners = eina_inlist_remove
158               (element->_listeners, EINA_INLIST_GET(l));
159         if (l->free_data)
160            l->free_data(l->data);
161
162         free(l);
163         return;
164      }
165 }
166
167 static void
168 _e_bluez_element_listeners_call_do(E_Bluez_Element *element)
169 {
170    E_Bluez_Element_Listener *l, **shadow;
171    unsigned int i, count;
172
173    /* NB: iterate on a copy in order to allow listeners to be deleted
174     * from callbacks.  number of listeners should be small, so the
175     * following should do fine.
176     */
177    count = eina_inlist_count(element->_listeners);
178    if (count < 1)
179       goto end;
180
181    shadow = alloca(sizeof(*shadow) * count);
182    if (!shadow)
183       goto end;
184
185    i = 0;
186    EINA_INLIST_FOREACH(element->_listeners, l)
187    shadow[i++] = l;
188
189    for (i = 0; i < count; i++)
190       shadow[i]->cb(shadow[i]->data, element);
191
192 end:
193    e_bluez_element_event_add(E_BLUEZ_EVENT_ELEMENT_UPDATED, element);
194 }
195
196 static Eina_Bool
197 _e_bluez_element_listeners_call_idler(void *data)
198 {
199    E_Bluez_Element *element = data;
200    _e_bluez_element_listeners_call_do(element);
201    element->_idler.changed = NULL;
202    return ECORE_CALLBACK_CANCEL;
203 }
204
205 static void
206 _e_bluez_element_listeners_call(E_Bluez_Element *element)
207 {
208    if (element->_idler.changed)
209       return;
210
211    element->_idler.changed = ecore_idler_add
212          (_e_bluez_element_listeners_call_idler, element);
213 }
214
215 /***********************************************************************
216 * Property
217 ***********************************************************************/
218
219 static void
220 _e_bluez_element_dict_entry_free(E_Bluez_Element_Dict_Entry *entry)
221 {
222    switch (entry->type)
223      {
224       case DBUS_TYPE_BOOLEAN:
225       case DBUS_TYPE_BYTE:
226       case DBUS_TYPE_INT16:
227       case DBUS_TYPE_UINT16:
228       case DBUS_TYPE_UINT32:
229          break;
230
231       case DBUS_TYPE_OBJECT_PATH:
232          eina_stringshare_del(entry->value.path);
233          break;
234
235       case DBUS_TYPE_STRING:
236          eina_stringshare_del(entry->value.str);
237          break;
238
239       default:
240          ERR("don't know how to free dict entry '%s' of type %c (%d)",
241              entry->name, entry->type, entry->type);
242      }
243
244    eina_stringshare_del(entry->name);
245    free(entry);
246 }
247
248 static E_Bluez_Element_Dict_Entry *
249 _e_bluez_element_dict_entry_new(DBusMessageIter *itr)
250 {
251    E_Bluez_Element_Dict_Entry *entry;
252    DBusMessageIter e_itr, v_itr;
253    int t;
254    const char *key = NULL;
255    void *value = NULL;
256
257    dbus_message_iter_recurse(itr, &e_itr);
258
259    t = dbus_message_iter_get_arg_type(&e_itr);
260    if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
261      {
262         ERR("invalid format for dict entry. first type not a string: %c (%d)",
263             t, t);
264         return NULL;
265      }
266
267    dbus_message_iter_get_basic(&e_itr, &key);
268    if (!key || !key[0])
269      {
270         ERR("invalid format for dict entry. no key.");
271         return NULL;
272      }
273
274    dbus_message_iter_next(&e_itr);
275    t = dbus_message_iter_get_arg_type(&e_itr);
276    if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
277      {
278         ERR("invalid format for dict entry '%s'. "
279             "second type not a variant: %c (%d)",
280             key, t, t);
281         return NULL;
282      }
283
284    dbus_message_iter_recurse(&e_itr, &v_itr);
285
286    t = dbus_message_iter_get_arg_type(&v_itr);
287    if ((t == DBUS_TYPE_INVALID) || (t == DBUS_TYPE_ARRAY))
288      {
289         ERR("invalid type for dict value for entry '%s': %c (%d)",
290             key, t, t);
291         return NULL;
292      }
293
294    entry = calloc(1, sizeof(*entry));
295    if (!entry)
296      {
297         ERR("could not allocate memory for dict entry.");
298         return NULL;
299      }
300
301    dbus_message_iter_get_basic(&v_itr, &value);
302    switch (t)
303      {
304       case DBUS_TYPE_BOOLEAN:
305          entry->value.boolean = (Eina_Bool)(long)value;
306          break;
307
308       case DBUS_TYPE_BYTE:
309          entry->value.byte = (unsigned char)(long)value;
310          break;
311
312       case DBUS_TYPE_INT16:
313          entry->value.i16 = (short)(long)value;
314          break;
315
316       case DBUS_TYPE_UINT16:
317          entry->value.u16 = (unsigned short)(long)value;
318          break;
319
320       case DBUS_TYPE_UINT32:
321          entry->value.u32 = (unsigned int)(long)value;
322          break;
323
324       case DBUS_TYPE_STRING:
325          entry->value.str = eina_stringshare_add(value);
326          break;
327
328       case DBUS_TYPE_OBJECT_PATH:
329          entry->value.path = eina_stringshare_add(value);
330          break;
331
332       default:
333          ERR("don't know how to create dict entry '%s' for of type %c (%d)",
334              key, t, t);
335          free(entry);
336          return NULL;
337      }
338
339    entry->name = eina_stringshare_add(key);
340    entry->type = t;
341    return entry;
342 }
343
344 E_Bluez_Element_Dict_Entry *
345 e_bluez_element_array_dict_find_stringshared(const E_Bluez_Array *array, const char *key)
346 {
347    E_Bluez_Element_Dict_Entry *entry;
348    Eina_Array_Iterator iterator;
349    unsigned int i;
350
351    EINA_ARRAY_ITER_NEXT(array->array, i, entry, iterator)
352    if (entry->name == key)
353       return entry;
354
355    return NULL;
356 }
357
358 void
359 e_bluez_element_array_free(E_Bluez_Array *array, E_Bluez_Array *new __UNUSED__)
360 {
361    Eina_Array_Iterator iterator;
362    unsigned int i;
363    void *item;
364
365    if (!array)
366       return;
367
368    switch (array->type)
369      {
370       case DBUS_TYPE_BOOLEAN:
371       case DBUS_TYPE_BYTE:
372       case DBUS_TYPE_INT16:
373       case DBUS_TYPE_UINT16:
374       case DBUS_TYPE_UINT32:
375          break;
376
377       case DBUS_TYPE_OBJECT_PATH:
378          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
379          eina_stringshare_del(item);
380          break;
381
382       case DBUS_TYPE_STRING:
383          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
384          eina_stringshare_del(item);
385          break;
386
387       case DBUS_TYPE_DICT_ENTRY:
388          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
389          _e_bluez_element_dict_entry_free(item);
390          break;
391
392       default:
393          ERR("don't know how to free array of values of type %c (%d)",
394              array->type, array->type);
395          break;
396      }
397    eina_array_free(array->array);
398    free(array);
399 }
400
401 static void
402 _e_bluez_element_property_value_free(E_Bluez_Element_Property *property)
403 {
404    switch (property->type)
405      {
406       case 0:
407          return;
408
409       case DBUS_TYPE_BOOLEAN:
410       case DBUS_TYPE_BYTE:
411       case DBUS_TYPE_UINT16:
412       case DBUS_TYPE_UINT32:
413          break;
414
415       case DBUS_TYPE_STRING:
416          eina_stringshare_del(property->value.str);
417          break;
418
419       case DBUS_TYPE_OBJECT_PATH:
420          eina_stringshare_del(property->value.path);
421          break;
422
423       case DBUS_TYPE_ARRAY:
424          e_bluez_element_array_free(property->value.array, NULL);
425          break;
426
427       default:
428          ERR("don't know how to free value of property type %c (%d)",
429              property->type, property->type);
430      }
431 }
432
433 static const char *
434 _e_bluez_element_get_interface(const char *key)
435 {
436    const char *interface = NULL, *tail;
437    char head;
438
439    head = key[0];
440    tail = key + 1;
441
442    switch (head)
443      {
444       case 'A':
445          if (strcmp(tail, "dapters") == 0)
446             interface = e_bluez_iface_adapter;
447
448          break;
449
450       case 'D':
451          if (strcmp(tail, "evices") == 0)
452             interface = e_bluez_iface_device;
453
454          break;
455
456       default:
457          break;
458      }
459
460    if (!interface)
461       ERR("failed to find interface for property \"%s\"", key);
462
463    return interface;
464 }
465
466 static void
467 _e_bluez_element_item_register(const char *key, const char *item)
468 {
469    E_Bluez_Element *element;
470    const char *interface;
471
472    interface = _e_bluez_element_get_interface(key);
473    if (!interface)
474       return;
475
476    element = e_bluez_element_register(item, interface);
477    if ((element) && (!e_bluez_element_properties_sync(element)))
478       WRN("could not get properties of %s", element->path);
479 }
480
481 /* Match 2 arrays to find which are new and which are old elements
482  * For new elements, register them under prop_name property
483  * For old elements, unregister them, sending proper DEL event
484  */
485 static void
486 _e_bluez_element_array_match(E_Bluez_Array *old, E_Bluez_Array *new, const char *prop_name)
487 {
488    Eina_List *deleted = NULL;
489    Eina_Array_Iterator iter_old, iter_new;
490    unsigned int i_old = 0, i_new = 0;
491    void *item_old, *item_new;
492    Eina_List *l;
493    void *data;
494
495    if (!old)
496       return;
497
498    if (old->type != DBUS_TYPE_OBJECT_PATH)
499       return;
500
501    if ((!new) || (!new->array) || eina_array_count(new->array) == 0)
502      {
503         if ((!old) || (!old->array) || eina_array_count(old->array) == 0)
504           {
505              return;
506           }
507         else
508           {
509              iter_old = old->array->data;
510              goto out_remove_remaining;
511           }
512      }
513
514    iter_new = new->array->data;
515    item_new = *iter_new;
516    EINA_ARRAY_ITER_NEXT(old->array, i_old, item_old, iter_old)
517    {
518       if (item_old == item_new)
519         {
520            i_new++;
521            if (i_new >= eina_array_count(new->array))
522              {
523                 i_old++;
524                 break;
525              }
526
527            iter_new++;
528            item_new = *iter_new;
529         }
530       else
531         {
532            deleted = eina_list_append(deleted, item_old);
533         }
534    }
535
536    for(; i_new < eina_array_count(new->array); iter_new++, i_new++)
537      {
538         Eina_Bool found = EINA_FALSE;
539         item_new = *iter_new;
540         if (!item_new)
541            break;
542
543         EINA_LIST_FOREACH(deleted, l, data)
544         {
545            if (data == item_new)
546              {
547                 deleted = eina_list_remove_list(deleted, l);
548                 found = EINA_TRUE;
549                 break;
550              }
551         }
552         if (!found)
553           {
554              _e_bluez_element_item_register(prop_name, item_new);
555              DBG("Add element %s\n", (const char *)item_new);
556           }
557      }
558
559    /* everybody after i_old on old->array + everybody from deleted list
560       will be removed
561     */
562    EINA_LIST_FREE(deleted, data)
563    {
564       E_Bluez_Element *e = e_bluez_element_get(data);
565       if (e)
566          e_bluez_element_unregister(e);
567
568       DBG("Delete element %s\n", (const char *)data);
569    }
570
571 out_remove_remaining:
572    for(; i_old < eina_array_count(old->array); iter_old++, i_old++)
573      {
574         E_Bluez_Element *e;
575         item_old = *iter_old;
576         if (!item_old)
577            break;
578
579         e = e_bluez_element_get(item_old);
580         if (e)
581            e_bluez_element_unregister(e);
582
583         DBG("Delete element %s\n", (const char *)item_old);
584      }
585 }
586
587 static Eina_Bool
588 _e_bluez_element_property_update(E_Bluez_Element_Property *property, int type, void *data)
589 {
590    Eina_Bool changed = EINA_FALSE;
591
592    if ((type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) && data)
593       data = (char *)eina_stringshare_add(data);
594
595    if (property->type != type)
596      {
597         if (property->type)
598            DBG("property type changed from '%c' to '%c'",
599                property->type, type);
600
601         _e_bluez_element_property_value_free(property);
602         memset(&property->value, 0, sizeof(property->value));
603         property->type = type;
604         changed = EINA_TRUE;
605      }
606
607    switch (type)
608      {
609       case DBUS_TYPE_BOOLEAN:
610          if (changed || property->value.boolean != (Eina_Bool)(long)data)
611            {
612               property->value.boolean = (Eina_Bool)(long)data;
613               changed = EINA_TRUE;
614            }
615
616          break;
617
618       case DBUS_TYPE_BYTE:
619          if (changed || property->value.byte != (unsigned char)(long)data)
620            {
621               property->value.byte = (unsigned char)(long)data;
622               changed = EINA_TRUE;
623            }
624
625          break;
626
627       case DBUS_TYPE_UINT16:
628          if (changed || property->value.u16 != (unsigned short)(long)data)
629            {
630               property->value.u16 = (unsigned short)(long)data;
631               changed = EINA_TRUE;
632            }
633
634          break;
635
636       case DBUS_TYPE_UINT32:
637          if (changed || property->value.u32 != (unsigned int)(long)data)
638            {
639               property->value.u32 = (unsigned int)(long)data;
640               changed = EINA_TRUE;
641            }
642
643          break;
644
645       case DBUS_TYPE_STRING:
646          if (changed)
647            {
648               property->value.str = data;
649            }
650          else
651            {
652               if (property->value.str)
653                  eina_stringshare_del(property->value.str);
654
655               if (property->value.str != data)
656                 {
657                    property->value.str = data;
658                    changed = EINA_TRUE;
659                 }
660            }
661
662          break;
663
664       case DBUS_TYPE_OBJECT_PATH:
665          if (changed)
666            {
667               property->value.path = data;
668            }
669          else
670            {
671               if (property->value.path)
672                  eina_stringshare_del(property->value.path);
673
674               if (property->value.path != data)
675                 {
676                    property->value.path = data;
677                    changed = EINA_TRUE;
678                 }
679            }
680
681          break;
682
683       case DBUS_TYPE_ARRAY:
684          if (!changed)
685             if (property->value.array)
686               {
687                  _e_bluez_element_array_match(property->value.array, data, property->name);
688                  e_bluez_element_array_free(property->value.array, data);
689               }
690
691          property->value.array = data;
692          changed = EINA_TRUE;
693          break;
694
695       default:
696          ERR("don't know how to update property type %c (%d)", type, type);
697      }
698
699    return changed;
700 }
701
702 static E_Bluez_Element_Property *
703 _e_bluez_element_property_new(const char *name, int type, void *data)
704 {
705    E_Bluez_Element_Property *property;
706
707    property = calloc(1, sizeof(*property));
708    if (!property)
709      {
710         eina_stringshare_del(name);
711         ERR("could not allocate property: %s", strerror(errno));
712         return NULL;
713      }
714
715    property->name = name;
716    _e_bluez_element_property_update(property, type, data);
717    return property;
718 }
719
720 static void
721 _e_bluez_element_property_free(E_Bluez_Element_Property *property)
722 {
723    _e_bluez_element_property_value_free(property);
724    eina_stringshare_del(property->name);
725    free(property);
726 }
727
728 /***********************************************************************
729 * Element
730 ***********************************************************************/
731 unsigned char *
732 e_bluez_element_bytes_array_get_stringshared(const E_Bluez_Element *element, const char *property, unsigned int *count)
733 {
734    Eina_Array_Iterator iterator;
735    E_Bluez_Array *array;
736    unsigned char *ret, *p;
737    unsigned int i;
738    void *item;
739
740    EINA_SAFETY_ON_NULL_RETURN_VAL(element, NULL);
741    EINA_SAFETY_ON_NULL_RETURN_VAL(property, NULL);
742    EINA_SAFETY_ON_NULL_RETURN_VAL(count, NULL);
743
744    *count = 0;
745
746    if (!e_bluez_element_property_get_stringshared
747           (element, property, NULL, &array))
748       return NULL;
749
750    if ((!array) || (!(array->array)))
751       return NULL;
752
753    *count = eina_array_count(array->array);
754    ret = malloc(*count * sizeof(unsigned char));
755    if (!ret)
756      {
757         ERR("could not allocate return array of %d bytes: %s",
758             *count, strerror(errno));
759         return NULL;
760      }
761
762    p = ret;
763
764    EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
765    {
766       *p = (unsigned char)(long)item;
767       p++;
768    }
769    return ret;
770 }
771
772 Eina_Bool
773 e_bluez_element_objects_array_get_stringshared(const E_Bluez_Element *element, const char *property, unsigned int *count, E_Bluez_Element ***p_elements)
774 {
775    E_Bluez_Element **ret, **p;
776    Eina_Array_Iterator iterator;
777    E_Bluez_Array *array;
778    unsigned int i;
779    int type;
780    void *item;
781
782    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
783    EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE);
784    EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
785    EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
786
787    *count = 0;
788    *p_elements = NULL;
789
790    if (!e_bluez_element_property_get_stringshared
791           (element, property, &type, &array))
792       return EINA_FALSE;
793
794    if (type != DBUS_TYPE_ARRAY)
795      {
796         ERR("property %s is not an array!", property);
797         return EINA_FALSE;
798      }
799
800    if ((!array) || (!array->array) || (array->type == DBUS_TYPE_INVALID))
801       return EINA_FALSE;
802
803    if (array->type != DBUS_TYPE_OBJECT_PATH)
804      {
805         ERR("property %s is not an array of object paths!", property);
806         return EINA_FALSE;
807      }
808
809    *count = eina_array_count(array->array);
810    ret = malloc(*count * sizeof(E_Bluez_Element *));
811    if (!ret)
812      {
813         ERR("could not allocate return array of %d elements: %s",
814             *count, strerror(errno));
815         *count = 0;
816         return EINA_FALSE;
817      }
818
819    p = ret;
820
821    EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
822    {
823       E_Bluez_Element *e = e_bluez_element_get(item);
824       if (!e)
825          continue;
826
827       *p = e;
828       p++;
829    }
830    *count = p - ret;
831    *p_elements = ret;
832    return EINA_TRUE;
833 }
834
835 /* strings are just pointers (references), no strdup or stringshare_add/ref */
836 Eina_Bool
837 e_bluez_element_strings_array_get_stringshared(const E_Bluez_Element *element, const char *property, unsigned int *count, const char ***strings)
838 {
839    const char **ret, **p;
840    Eina_Array_Iterator iterator;
841    E_Bluez_Array *array;
842    unsigned int i;
843    int type;
844    void *item;
845
846    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
847    EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE);
848    EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
849    EINA_SAFETY_ON_NULL_RETURN_VAL(strings, EINA_FALSE);
850
851    *count = 0;
852    *strings = NULL;
853
854    if (!e_bluez_element_property_get_stringshared
855           (element, property, &type, &array))
856       return EINA_FALSE;
857
858    if (type != DBUS_TYPE_ARRAY)
859      {
860         ERR("property %s is not an array!", property);
861         return EINA_FALSE;
862      }
863
864    if ((!array) || (!array->array) || (array->type == DBUS_TYPE_INVALID))
865       return EINA_FALSE;
866
867    if (array->type != DBUS_TYPE_STRING)
868      {
869         ERR("property %s is not an array of strings!", property);
870         return EINA_FALSE;
871      }
872
873    *count = eina_array_count(array->array);
874    ret = malloc(*count * sizeof(char *));
875    if (!ret)
876      {
877         ERR("could not allocate return array of %d strings: %s",
878             *count, strerror(errno));
879         *count = 0;
880         return EINA_FALSE;
881      }
882
883    p = ret;
884
885    EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
886    {
887       if (!item)
888          continue;
889
890       *p = item;
891       p++;
892    }
893    *count = p - ret;
894    *strings = ret;
895    return EINA_TRUE;
896 }
897
898 void
899 e_bluez_element_array_print(FILE *fp, E_Bluez_Array *array)
900 {
901    Eina_Array_Iterator iterator;
902    unsigned int i;
903    void *item;
904
905    if (!array)
906       return;
907
908    switch (array->type)
909      {
910       case DBUS_TYPE_OBJECT_PATH:
911          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
912          fprintf(fp, "\"%s\", ", (const char *)item);
913          break;
914
915       case DBUS_TYPE_STRING:
916          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
917          fprintf(fp, "\"%s\", ", (const char *)item);
918          break;
919
920       case DBUS_TYPE_BYTE:
921          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
922          fprintf(fp, "%#02hhx (\"%c\"), ", (unsigned char)(long)item,
923                  (unsigned char)(long)item);
924          break;
925
926       case DBUS_TYPE_UINT16:
927          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
928          fprintf(fp, "%#04hx (%hu), ", (unsigned short)(long)item,
929                  (unsigned short)(long)item);
930          break;
931
932       case DBUS_TYPE_UINT32:
933          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
934          fprintf(fp, "%#08x (%u), ", (unsigned int)(long)item,
935                  (unsigned int)(long)item);
936          break;
937
938       case DBUS_TYPE_DICT_ENTRY:
939          fputs("{ ", fp);
940          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
941          {
942             E_Bluez_Element_Dict_Entry *entry = item;
943             fprintf(fp, "%s: ", entry->name);
944             switch (entry->type)
945               {
946                case DBUS_TYPE_OBJECT_PATH:
947                   fprintf(fp, "\"%s\", ", entry->value.path);
948                   break;
949
950                case DBUS_TYPE_STRING:
951                   fprintf(fp, "\"%s\", ", entry->value.str);
952                   break;
953
954                case DBUS_TYPE_BOOLEAN:
955                   fprintf(fp, "%hhu, ",
956                           entry->value.boolean);
957                   break;
958
959                case DBUS_TYPE_BYTE:
960                   fprintf(fp, "%#02hhx (\"%c\"), ",
961                           entry->value.byte, entry->value.byte);
962                   break;
963
964                case DBUS_TYPE_INT16:
965                   fprintf(fp, "%#04hx (%hi), ",
966                           entry->value.i16, entry->value.i16);
967                   break;
968
969                case DBUS_TYPE_UINT16:
970                   fprintf(fp, "%#04hx (%hu), ",
971                           entry->value.u16, entry->value.u16);
972                   break;
973
974                case DBUS_TYPE_UINT32:
975                   fprintf(fp, "%#08x (%u), ",
976                           entry->value.u32, entry->value.u32);
977                   break;
978
979                default:
980                   fprintf(fp, "<UNKNOWN TYPE '%c'>", entry->type);
981               }
982          }
983          fputs("}", fp);
984          break;
985
986       default:
987          fprintf(fp, "<UNKNOWN ARRAY TYPE '%c'>", array->type);
988      }
989 }
990
991 /**
992  * Print element to file descriptor.
993  */
994 void
995 e_bluez_element_print(FILE *fp, const E_Bluez_Element *element)
996 {
997    const E_Bluez_Element_Property *p;
998
999    EINA_SAFETY_ON_NULL_RETURN(fp);
1000    if (!element)
1001      {
1002         fputs("Error: no element to print\n", fp);
1003         return;
1004      }
1005
1006    fprintf(fp,
1007            "Element %p: %s [%s]\n"
1008            "\tProperties:\n",
1009            element, element->path, element->interface);
1010
1011    EINA_INLIST_FOREACH(element->props, p)
1012    {
1013       fprintf(fp, "\t\t%s (%c) = ", p->name, p->type);
1014
1015       switch (p->type)
1016         {
1017          case DBUS_TYPE_STRING:
1018             fprintf(fp, "\"%s\"", p->value.str);
1019             break;
1020
1021          case DBUS_TYPE_OBJECT_PATH:
1022             fprintf(fp, "\"%s\"", p->value.path);
1023             break;
1024
1025          case DBUS_TYPE_BOOLEAN:
1026             fprintf(fp, "%hhu", p->value.boolean);
1027             break;
1028
1029          case DBUS_TYPE_BYTE:
1030             fprintf(fp, "%#02hhx (%d), ", p->value.byte, p->value.byte);
1031             break;
1032
1033          case DBUS_TYPE_UINT16:
1034             fprintf(fp, "%hu", p->value.u16);
1035             break;
1036
1037          case DBUS_TYPE_UINT32:
1038             fprintf(fp, "%u", p->value.u32);
1039             break;
1040
1041          case DBUS_TYPE_ARRAY:
1042             e_bluez_element_array_print(fp, p->value.array);
1043             break;
1044
1045          default:
1046             fputs("don't know how to print type", fp);
1047         }
1048
1049       fputc('\n', fp);
1050    }
1051 }
1052
1053 static E_Bluez_Element *
1054 e_bluez_element_new(const char *path, const char *interface)
1055 {
1056    E_Bluez_Element *element;
1057
1058    element = calloc(1, sizeof(*element));
1059    if (!element)
1060      {
1061         ERR("could not allocate element: %s",   strerror(errno));
1062         return NULL;
1063      }
1064
1065    element->path = eina_stringshare_add(path);
1066    element->interface = eina_stringshare_ref(interface);
1067    element->_references = 1;
1068
1069    return element;
1070 }
1071
1072 static void
1073 e_bluez_element_extra_properties_free(E_Bluez_Element *element)
1074 {
1075    while (element->props)
1076      {
1077         E_Bluez_Element_Property *prop;
1078         prop = (E_Bluez_Element_Property *)element->props;
1079         element->props = element->props->next;
1080         _e_bluez_element_property_free(prop);
1081      }
1082 }
1083
1084 static void
1085 e_bluez_element_free(E_Bluez_Element *element)
1086 {
1087    if (element->_idler.changed)
1088       ecore_idler_del(element->_idler.changed);
1089
1090    while (element->_listeners)
1091      {
1092         E_Bluez_Element_Listener *l = (void *)element->_listeners;
1093         element->_listeners = eina_inlist_remove
1094               (element->_listeners, element->_listeners);
1095
1096         if (l->free_data)
1097            l->free_data(l->data);
1098
1099         free(l);
1100      }
1101
1102    e_bluez_element_pending_cancel_and_free(&element->_pending.properties_get);
1103    e_bluez_element_pending_cancel_and_free(&element->_pending.property_set);
1104    e_bluez_element_pending_cancel_and_free(&element->_pending.agent_register);
1105    e_bluez_element_pending_cancel_and_free(&element->_pending.agent_unregister);
1106
1107    e_bluez_element_extra_properties_free(element);
1108    eina_stringshare_del(element->interface);
1109    eina_stringshare_del(element->path);
1110    free(element);
1111 }
1112
1113 /**
1114  * Add reference to element.
1115  */
1116 int
1117 e_bluez_element_ref(E_Bluez_Element *element)
1118 {
1119    EINA_SAFETY_ON_NULL_RETURN_VAL(element, 0);
1120    return ++element->_references;
1121 }
1122
1123 /**
1124  * Remove reference from element.
1125  *
1126  * If reference count drops to 0 element will be freed.
1127  */
1128 int
1129 e_bluez_element_unref(E_Bluez_Element *element)
1130 {
1131    int i;
1132    EINA_SAFETY_ON_NULL_RETURN_VAL(element, 0);
1133
1134    i = --element->_references;
1135    if (i == 0)
1136       e_bluez_element_free(element);
1137    else if (i < 0)
1138       ERR("element %p references %d < 0", element, i);
1139
1140    return i;
1141 }
1142
1143 /**
1144  * Send message with callbacks set to work with bluez elements.
1145  *
1146  * If this call fails (returns @c EINA_FALSE), pending callbacks will not be called,
1147  * not even with error messages.
1148  *
1149  * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
1150  */
1151 Eina_Bool
1152 e_bluez_element_message_send(E_Bluez_Element *element, const char *method_name, E_DBus_Method_Return_Cb cb, DBusMessage *msg, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
1153 {
1154    E_Bluez_Element_Call_Data *data;
1155    E_Bluez_Element_Pending *p;
1156
1157    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1158    EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
1159    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
1160    EINA_SAFETY_ON_NULL_RETURN_VAL(msg, EINA_FALSE);
1161
1162    data = malloc(sizeof(*data));
1163    if (!data)
1164      {
1165         ERR("could not alloc e_bluez_element_call_data: %s",
1166             strerror(errno));
1167         dbus_message_unref(msg);
1168         return EINA_FALSE;
1169      }
1170
1171    p = malloc(sizeof(*p));
1172    if (!p)
1173      {
1174         ERR("could not alloc E_Bluez_Element_Pending: %s",
1175             strerror(errno));
1176         free(data);
1177         dbus_message_unref(msg);
1178         return EINA_FALSE;
1179      }
1180
1181    data->element = element;
1182    data->cb = cb;
1183    data->pending = p;
1184    data->p_list = pending;
1185    p->user_cb = user_cb;
1186    p->user_data = (void *)user_data;
1187    p->data = data;
1188    p->pending = e_dbus_message_send
1189          (e_bluez_conn, msg, e_bluez_element_call_dispatch_and_free, -1, data);
1190    dbus_message_unref(msg);
1191
1192    if (p->pending)
1193      {
1194         *pending = eina_inlist_append(*pending, EINA_INLIST_GET(p));
1195         return EINA_TRUE;
1196      }
1197
1198    ERR("failed to call %s (obj=%s, path=%s, iface=%s)",
1199        method_name, e_bluez_system_bus_name_get(),
1200        element->path, element->interface);
1201    free(data);
1202    free(p);
1203    return EINA_FALSE;
1204 }
1205
1206 Eina_Bool
1207 e_bluez_element_call_full(E_Bluez_Element *element, const char *method_name, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
1208 {
1209    DBusMessage *msg;
1210
1211    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1212    EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
1213    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
1214
1215    msg = dbus_message_new_method_call
1216          (e_bluez_system_bus_name_get(), element->path, element->interface,
1217          method_name);
1218
1219    return e_bluez_element_message_send
1220              (element, method_name, cb, msg, pending, user_cb, user_data);
1221 }
1222
1223 static Eina_Bool
1224 _e_bluez_element_property_value_add(E_Bluez_Element *element, const char *name, int type, void *value)
1225 {
1226    E_Bluez_Element_Property *p;
1227
1228    name = eina_stringshare_add(name);
1229    EINA_INLIST_FOREACH(element->props, p)
1230    {
1231       if (p->name == name)
1232         {
1233            eina_stringshare_del(name);
1234            return _e_bluez_element_property_update(p, type, value);
1235         }
1236    }
1237
1238    p = _e_bluez_element_property_new(name, type, value);
1239    if (!p)
1240      {
1241         ERR("could not create property %s (%c)", name, type);
1242         return EINA_FALSE;
1243      }
1244
1245    element->props = eina_inlist_append(element->props, EINA_INLIST_GET(p));
1246    return EINA_TRUE;
1247 }
1248
1249 E_Bluez_Array *
1250 e_bluez_element_iter_get_array(DBusMessageIter *itr, const char *key)
1251 {
1252    E_Bluez_Array *array;
1253    DBusMessageIter e_itr;
1254
1255    array = malloc(sizeof(E_Bluez_Array));
1256    if (!array)
1257      {
1258         ERR("could not create new e_bluez array.");
1259         return NULL;
1260      }
1261
1262    array->array = eina_array_new(16);
1263    if (!(array->array))
1264      {
1265         ERR("could not create new eina array.");
1266         free(array);
1267         return NULL;
1268      }
1269
1270    dbus_message_iter_recurse(itr, &e_itr);
1271    array->type = dbus_message_iter_get_arg_type(&e_itr);
1272    if (array->type == DBUS_TYPE_INVALID)
1273      {
1274         DBG("array %s is of type 'invalid' (empty?)", key);
1275         eina_array_free(array->array);
1276         free(array);
1277         return NULL;
1278      }
1279
1280    do
1281      {
1282         switch (array->type)
1283           {
1284            case DBUS_TYPE_OBJECT_PATH:
1285            {
1286               const char *path;
1287
1288               dbus_message_iter_get_basic(&e_itr, &path);
1289               path = eina_stringshare_add(path);
1290               eina_array_push(array->array, path);
1291               _e_bluez_element_item_register(key, path);
1292            }
1293            break;
1294
1295            case DBUS_TYPE_STRING:
1296            {
1297               const char *str;
1298
1299               dbus_message_iter_get_basic(&e_itr, &str);
1300               str = eina_stringshare_add(str);
1301               eina_array_push(array->array, str);
1302            }
1303            break;
1304
1305            case DBUS_TYPE_BYTE:
1306            {
1307               unsigned char byte;
1308               dbus_message_iter_get_basic(&e_itr, &byte);
1309               eina_array_push(array->array, (void *)(long)byte);
1310            }
1311            break;
1312
1313            case DBUS_TYPE_DICT_ENTRY:
1314            {
1315               E_Bluez_Element_Dict_Entry *entry;
1316               entry = _e_bluez_element_dict_entry_new(&e_itr);
1317               if (entry)
1318                  eina_array_push(array->array, entry);
1319            }
1320            break;
1321
1322            default:
1323               ERR("don't know how to build array '%s' of type %c (%d)",
1324                   key, array->type, array->type);
1325               eina_array_free(array->array);
1326               free(array);
1327               return NULL;
1328           }
1329      }
1330    while (dbus_message_iter_next(&e_itr));
1331    return array;
1332 }
1333
1334 static void
1335 _e_bluez_element_get_properties_callback(void *user_data, DBusMessage *msg, DBusError *err)
1336 {
1337    E_Bluez_Element *element = user_data;
1338    DBusMessageIter itr, s_itr;
1339    int t, changed;
1340
1341    DBG("get_properties msg=%p", msg);
1342
1343    if (!_dbus_callback_check_and_init(msg, &itr, err))
1344       return;
1345
1346    t = dbus_message_iter_get_arg_type(&itr);
1347    if (!_dbus_iter_type_check(t, DBUS_TYPE_ARRAY))
1348       return;
1349
1350    changed = 0;
1351    dbus_message_iter_recurse(&itr, &s_itr);
1352    do
1353      {
1354         DBusMessageIter e_itr, v_itr;
1355         const char *key;
1356         void *value = NULL;
1357         int r;
1358
1359         t = dbus_message_iter_get_arg_type(&s_itr);
1360         if (!_dbus_iter_type_check(t, DBUS_TYPE_DICT_ENTRY))
1361            continue;
1362
1363         dbus_message_iter_recurse(&s_itr, &e_itr);
1364
1365         t = dbus_message_iter_get_arg_type(&e_itr);
1366         if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
1367            continue;
1368
1369         dbus_message_iter_get_basic(&e_itr, &key);
1370         dbus_message_iter_next(&e_itr);
1371         t = dbus_message_iter_get_arg_type(&e_itr);
1372         if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
1373            continue;
1374
1375         dbus_message_iter_recurse(&e_itr, &v_itr);
1376         t = dbus_message_iter_get_arg_type(&v_itr);
1377         if (t == DBUS_TYPE_ARRAY)
1378           {
1379              value = e_bluez_element_iter_get_array(&v_itr, key);
1380           }
1381         else if (t != DBUS_TYPE_INVALID)
1382           {
1383              dbus_message_iter_get_basic(&v_itr, &value);
1384           }
1385         else
1386           {
1387              ERR("property has invalid type %s", key);
1388              continue;
1389           }
1390
1391         r = _e_bluez_element_property_value_add(element, key, t, value);
1392         if (r < 0)
1393           {
1394              ERR("failed to add property value %s (%c)", key, t);
1395           }
1396         else if (r == 1)
1397           {
1398              INF("property value changed %s (%c)", key, t);
1399              changed = 1;
1400           }
1401      }
1402    while (dbus_message_iter_next(&s_itr));
1403
1404    if (changed)
1405       _e_bluez_element_listeners_call(element);
1406 }
1407
1408 /**
1409  * Sync element properties with server.
1410  *
1411  * Call method GetProperties() at the given element on server in order to sync
1412  * them.
1413  *
1414  * @param element to call method on server.
1415  * @param cb function to call when server replies or some error happens.
1416  * @param data data to give to cb when it is called.
1417  *
1418  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1419  */
1420 Eina_Bool
1421 e_bluez_element_properties_sync_full(E_Bluez_Element *element, E_DBus_Method_Return_Cb cb, const void *data)
1422 {
1423    const char name[] = "GetProperties";
1424
1425    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1426    return e_bluez_element_call_full
1427              (element, name, _e_bluez_element_get_properties_callback,
1428              &element->_pending.properties_get, cb, data);
1429 }
1430
1431 /**
1432  * Sync element properties with server, simple version.
1433  *
1434  * Call method GetProperties() at the given element on server in order to sync
1435  * them. This is the simple version and there is no check of server reply
1436  * for errors.
1437  *
1438  * @param element to call method on server.
1439  *
1440  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1441  */
1442 Eina_Bool
1443 e_bluez_element_properties_sync(E_Bluez_Element *element)
1444 {
1445    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1446    return e_bluez_element_properties_sync_full(element, NULL, NULL);
1447 }
1448
1449 /**
1450  * Call method SetProperty(prop, {key: value}) at the given element on server.
1451  *
1452  * This is a server call, not local, so it may fail and in that case
1453  * no property is updated locally. If the value was set the event
1454  * E_BLUEZ_EVENT_ELEMENT_UPDATED will be added to main loop.
1455  *
1456  * @param element to call method on server.
1457  * @param prop property name.
1458  * @param key dict key name.
1459  * @param type DBus type to use for value.
1460  * @param value pointer to value, just like regular DBus, see
1461  *        dbus_message_iter_append_basic().
1462  * @param cb function to call when server replies or some error happens.
1463  * @param data data to give to cb when it is called.
1464  *
1465  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1466  */
1467 Eina_Bool
1468 e_bluez_element_property_dict_set_full(E_Bluez_Element *element, const char *prop, const char *key, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data)
1469 {
1470    const char name[] = "SetProperty";
1471    DBusMessage *msg;
1472    DBusMessageIter itr, variant, dict, entry;
1473    char typestr[32];
1474
1475    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1476    EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
1477
1478    msg = dbus_message_new_method_call
1479          (e_bluez_system_bus_name_get(), element->path, element->interface, name);
1480
1481    if (!msg)
1482       return EINA_FALSE;
1483
1484    dbus_message_iter_init_append(msg, &itr);
1485    dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
1486
1487    if ((size_t)snprintf(typestr, sizeof(typestr),
1488                         (DBUS_TYPE_ARRAY_AS_STRING
1489                          DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1490                          DBUS_TYPE_STRING_AS_STRING
1491                          "%c"
1492                          DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
1493                         type) >= sizeof(typestr))
1494      {
1495         ERR("sizeof(typestr) is too small!");
1496         return EINA_FALSE;
1497      }
1498
1499    if (dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, typestr, &variant))
1500      {
1501         snprintf(typestr, sizeof(typestr),
1502                  (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1503                      DBUS_TYPE_STRING_AS_STRING
1504                      "%c"
1505                      DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
1506                  type);
1507         
1508         if (dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, typestr, &dict))
1509           {
1510              if (dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry))
1511                {
1512                   dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1513
1514                   if ((type == DBUS_TYPE_STRING) || (type == DBUS_TYPE_OBJECT_PATH))
1515                     dbus_message_iter_append_basic(&entry, type, &value);
1516                   else
1517                     dbus_message_iter_append_basic(&entry, type, value);
1518                   
1519                   dbus_message_iter_close_container(&dict, &entry);
1520                }
1521              else
1522                {
1523                   ERR("dbus_message_iter_open_container() failed");
1524                }
1525              dbus_message_iter_close_container(&variant, &dict);
1526           }
1527         else
1528           {
1529              ERR("dbus_message_iter_open_container() failed");
1530           }
1531         dbus_message_iter_close_container(&itr, &variant);
1532      }
1533    else
1534      {
1535         ERR("dbus_message_iter_open_container() failed");
1536      }
1537
1538    return e_bluez_element_message_send
1539              (element, name, NULL, msg, &element->_pending.property_set, cb, data);
1540 }
1541
1542 /**
1543  * Call method SetProperty(prop, value) at the given element on server.
1544  *
1545  * This is a server call, not local, so it may fail and in that case
1546  * no property is updated locally. If the value was set the event
1547  * E_BLUEZ_EVENT_ELEMENT_UPDATED will be added to main loop.
1548  *
1549  * @param element to call method on server.
1550  * @param prop property name.
1551  * @param type DBus type to use for value.
1552  * @param value pointer to value, just like regular DBus, see
1553  *        dbus_message_iter_append_basic().
1554  * @param cb function to call when server replies or some error happens.
1555  * @param data data to give to cb when it is called.
1556  *
1557  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1558  */
1559 Eina_Bool
1560 e_bluez_element_property_set_full(E_Bluez_Element *element, const char *prop, int type, const void *value, E_DBus_Method_Return_Cb cb, const void *data)
1561 {
1562    const char name[] = "SetProperty";
1563    char typestr[2];
1564    DBusMessage *msg;
1565
1566    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1567    EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
1568
1569    msg = dbus_message_new_method_call
1570          (e_bluez_system_bus_name_get(), element->path, element->interface, name);
1571
1572    if (!msg)
1573       return EINA_FALSE;
1574
1575    DBusMessageIter itr, v;
1576    dbus_message_iter_init_append(msg, &itr);
1577    dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
1578
1579    typestr[0] = type;
1580    typestr[1] = '\0';
1581    if (dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, typestr, &v))
1582      {
1583         if ((type == DBUS_TYPE_STRING) || (type == DBUS_TYPE_OBJECT_PATH))
1584           {
1585              dbus_message_iter_append_basic(&v, type, &value);
1586           }
1587         else if (type == DBUS_TYPE_BOOLEAN)
1588           {
1589              unsigned int b = *(char *)value;
1590              dbus_message_iter_append_basic(&v, type, &b);
1591           }
1592         else
1593           {
1594              dbus_message_iter_append_basic(&v, type, value);
1595           }
1596         dbus_message_iter_close_container(&itr, &v);
1597      }
1598    else
1599      {
1600         ERR("dbus_message_iter_open_container() failed");
1601      }
1602    
1603    return e_bluez_element_message_send
1604              (element, name, NULL, msg, &element->_pending.property_set, cb, data);
1605 }
1606
1607 /**
1608  * Call method SetProperty(prop, value) at the given element on server.
1609  *
1610  * This is the simple version and there is no check of server reply
1611  * for errors.
1612  *
1613  * @param element to call method on server.
1614  * @param prop property name.
1615  * @param type DBus type to use for value.
1616  * @param value pointer to value, just like regular DBus, see
1617  *        dbus_message_iter_append_basic().
1618  *
1619  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1620  */
1621 Eina_Bool
1622 e_bluez_element_property_set(E_Bluez_Element *element, const char *prop, int type, const void *value)
1623 {
1624    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1625    EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
1626    return e_bluez_element_property_set_full
1627              (element, prop, type, value, NULL, NULL);
1628 }
1629
1630 Eina_Bool
1631 e_bluez_element_call_with_path(E_Bluez_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
1632 {
1633    DBusMessageIter itr;
1634    DBusMessage *msg;
1635
1636    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1637    EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
1638    EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
1639    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
1640
1641    msg = dbus_message_new_method_call
1642          (e_bluez_system_bus_name_get(), element->path, element->interface,
1643          method_name);
1644
1645    if (!msg)
1646       return EINA_FALSE;
1647
1648    dbus_message_iter_init_append(msg, &itr);
1649    dbus_message_iter_append_basic(&itr, DBUS_TYPE_OBJECT_PATH, &string);
1650
1651    return e_bluez_element_message_send
1652              (element, method_name, cb, msg, pending, user_cb, user_data);
1653 }
1654
1655 Eina_Bool
1656 e_bluez_element_call_with_string(E_Bluez_Element *element, const char *method_name, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
1657 {
1658    DBusMessageIter itr;
1659    DBusMessage *msg;
1660
1661    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1662    EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
1663    EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
1664    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
1665
1666    msg = dbus_message_new_method_call
1667          (e_bluez_system_bus_name_get(), element->path, element->interface,
1668          method_name);
1669
1670    if (!msg)
1671       return EINA_FALSE;
1672
1673    dbus_message_iter_init_append(msg, &itr);
1674    dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &string);
1675
1676    return e_bluez_element_message_send
1677              (element, method_name, cb, msg, pending, user_cb, user_data);
1678 }
1679
1680 Eina_Bool
1681 e_bluez_element_call_with_path_and_string(E_Bluez_Element *element, const char *method_name, const char *path, const char *string, E_DBus_Method_Return_Cb cb, Eina_Inlist **pending, E_DBus_Method_Return_Cb user_cb, const void *user_data)
1682 {
1683    DBusMessageIter itr;
1684    DBusMessage *msg;
1685
1686    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1687    EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
1688    EINA_SAFETY_ON_NULL_RETURN_VAL(path, EINA_FALSE);
1689    EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
1690    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
1691
1692    msg = dbus_message_new_method_call
1693          (e_bluez_system_bus_name_get(), element->path, element->interface,
1694          method_name);
1695
1696    if (!msg)
1697       return EINA_FALSE;
1698
1699    dbus_message_iter_init_append(msg, &itr);
1700    dbus_message_iter_append_basic(&itr, DBUS_TYPE_OBJECT_PATH, &path);
1701    dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &string);
1702
1703    return e_bluez_element_message_send
1704              (element, method_name, cb, msg, pending, user_cb, user_data);
1705 }
1706
1707 /**
1708  * Get property type.
1709  *
1710  * If @c EINA_FALSE is returned, then this call failed and parameter-returned
1711  * values shall be considered invalid.
1712  *
1713  * @param element which element to get the property
1714  * @param name property name, must be previously stringshared
1715  * @param type will contain the value type.
1716  *
1717  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1718  */
1719 Eina_Bool
1720 e_bluez_element_property_type_get_stringshared(const E_Bluez_Element *element, const char *name, int *type)
1721 {
1722    const E_Bluez_Element_Property *p;
1723
1724    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1725    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
1726    EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
1727
1728    EINA_INLIST_FOREACH(element->props, p)
1729    {
1730       if (p->name == name)
1731         {
1732            *type = p->type;
1733            return EINA_TRUE;
1734         }
1735    }
1736
1737    WRN("element %s (%p) has no property with name \"%s\".",
1738        element->path, element, name);
1739    return EINA_FALSE;
1740 }
1741
1742 /**
1743  * Get property type.
1744  *
1745  * If @c EINA_FALSE is returned, then this call failed and parameter-returned
1746  * values shall be considered invalid.
1747  *
1748  * @param element which element to get the property
1749  * @param name property name
1750  * @param type will contain the value type.
1751  *
1752  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1753  */
1754 Eina_Bool
1755 e_bluez_element_property_type_get(const E_Bluez_Element *element, const char *name, int *type)
1756 {
1757    Eina_Bool ret;
1758    name = eina_stringshare_add(name);
1759    ret = e_bluez_element_property_type_get_stringshared(element, name, type);
1760    eina_stringshare_del(name);
1761    return ret;
1762 }
1763
1764 void
1765 e_bluez_element_list_properties(const E_Bluez_Element *element, Eina_Bool (*cb)(void *data, const E_Bluez_Element *element, const char *name, int type, const void *value), const void *data)
1766 {
1767    e_bluez_element_properties_list(element, cb, data);
1768 }
1769
1770 void
1771 e_bluez_element_properties_list(const E_Bluez_Element *element, Eina_Bool (*cb)(void *data, const E_Bluez_Element *element, const char *name, int type, const void *value), const void *data)
1772 {
1773    const E_Bluez_Element_Property *p;
1774
1775    EINA_SAFETY_ON_NULL_RETURN(element);
1776    EINA_SAFETY_ON_NULL_RETURN(cb);
1777
1778    EINA_INLIST_FOREACH(element->props, p)
1779    {
1780       const void *value = NULL;
1781
1782       switch (p->type)
1783         {
1784          case DBUS_TYPE_STRING:
1785             value = &p->value.str;
1786             break;
1787
1788          case DBUS_TYPE_OBJECT_PATH:
1789             value = &p->value.path;
1790             break;
1791
1792          case DBUS_TYPE_BOOLEAN:
1793             value = (void *)(unsigned long)p->value.boolean;
1794             break;
1795
1796          case DBUS_TYPE_UINT16:
1797             value = &p->value.u16;
1798             break;
1799
1800          case DBUS_TYPE_UINT32:
1801             value = &p->value.u32;
1802             break;
1803
1804          default:
1805             ERR("unsupported type %c", p->type);
1806         }
1807
1808       if (!cb((void *)data, element, p->name, p->type, value))
1809          return;
1810    }
1811 }
1812
1813 /**
1814  * Get dict value given its key inside a dict property.
1815  *
1816  * This will look into properties for one of type dict that contains
1817  * the given key, to find the property.  If no property is found then
1818  * @c EINA_FALSE is returned.
1819  *
1820  * If @c EINA_FALSE is returned, then this call failed and parameter-returned
1821  * values shall be considered invalid.
1822  *
1823  * @param element which element to get the property
1824  * @param dict_name property name, must be previously stringshared
1825  * @param key key inside dict, must be previously stringshared
1826  * @param type if provided it will contain the value type.
1827  * @param value where to store the property value, must be a pointer to the
1828  *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
1829  *
1830  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1831  */
1832 Eina_Bool
1833 e_bluez_element_property_dict_get_stringshared(const E_Bluez_Element *element, const char *dict_name, const char *key, int *type, void *value)
1834 {
1835    const E_Bluez_Element_Property *p;
1836
1837    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1838    EINA_SAFETY_ON_NULL_RETURN_VAL(dict_name, EINA_FALSE);
1839    EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
1840    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
1841
1842    EINA_INLIST_FOREACH(element->props, p)
1843    {
1844       E_Bluez_Element_Dict_Entry *entry;
1845       E_Bluez_Array *array;
1846
1847       if (p->name != dict_name)
1848          continue;
1849
1850       if (p->type != DBUS_TYPE_ARRAY)
1851         {
1852            WRN("element %s (%p) has property \"%s\" is not an array: %c (%d)",
1853                element->path, element, dict_name, p->type, p->type);
1854            return EINA_FALSE;
1855         }
1856
1857       array = p->value.array;
1858       if ((!array) || (array->type != DBUS_TYPE_DICT_ENTRY))
1859         {
1860            int t = array ? array->type : DBUS_TYPE_INVALID;
1861            WRN("element %s (%p) has property \"%s\" is not a dict: %c (%d)",
1862                element->path, element, dict_name, t, t);
1863            return EINA_FALSE;
1864         }
1865
1866       entry = e_bluez_element_array_dict_find_stringshared(array, key);
1867       if (!entry)
1868         {
1869            WRN("element %s (%p) has no dict property with name \"%s\" with "
1870                "key \"%s\".",
1871                element->path, element, dict_name, key);
1872            return EINA_FALSE;
1873         }
1874
1875       if (type)
1876          *type = entry->type;
1877
1878       switch (entry->type)
1879         {
1880          case DBUS_TYPE_BOOLEAN:
1881             *(Eina_Bool *)value = entry->value.boolean;
1882             return EINA_TRUE;
1883
1884          case DBUS_TYPE_BYTE:
1885             *(unsigned char *)value = entry->value.byte;
1886             return EINA_TRUE;
1887
1888          case DBUS_TYPE_INT16:
1889             *(short *)value = entry->value.i16;
1890             return EINA_TRUE;
1891
1892          case DBUS_TYPE_UINT16:
1893             *(unsigned short *)value = entry->value.u16;
1894             return EINA_TRUE;
1895
1896          case DBUS_TYPE_UINT32:
1897             *(unsigned int *)value = entry->value.u32;
1898             return EINA_TRUE;
1899
1900          case DBUS_TYPE_STRING:
1901             *(const char **)value = entry->value.str;
1902             return EINA_TRUE;
1903
1904          case DBUS_TYPE_OBJECT_PATH:
1905             *(const char **)value = entry->value.path;
1906             return EINA_TRUE;
1907
1908          default:
1909             ERR("don't know how to get property %s, key %s type %c (%d)",
1910                 dict_name, key, entry->type, entry->type);
1911             return EINA_FALSE;
1912         }
1913    }
1914
1915    WRN("element %s (%p) has no property with name \"%s\".",
1916        element->path, element, dict_name);
1917    return EINA_FALSE;
1918 }
1919
1920 /**
1921  * Get property value given its name.
1922  *
1923  * This will look into properties, to find the property.
1924  * If no property is found then @c EINA_FALSE is returned.
1925  *
1926  * If @c EINA_FALSE is returned, then this call failed and parameter-returned
1927  * values shall be considered invalid.
1928  *
1929  * @param element which element to get the property
1930  * @param name property name, must be previously stringshared
1931  * @param type if provided it will contain the value type.
1932  * @param value where to store the property value, must be a pointer to the
1933  *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
1934  *
1935  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1936  */
1937 Eina_Bool
1938 e_bluez_element_property_get_stringshared(const E_Bluez_Element *element, const char *name, int *type, void *value)
1939 {
1940    const E_Bluez_Element_Property *p;
1941
1942    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1943    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
1944    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
1945
1946    EINA_INLIST_FOREACH(element->props, p)
1947    {
1948       if (p->name != name)
1949          continue;
1950
1951       if (type)
1952          *type = p->type;
1953
1954       switch (p->type)
1955         {
1956          case DBUS_TYPE_BOOLEAN:
1957             *(Eina_Bool *)value = p->value.boolean;
1958             return EINA_TRUE;
1959
1960          case DBUS_TYPE_BYTE:
1961             *(unsigned char *)value = p->value.byte;
1962             return EINA_TRUE;
1963
1964          case DBUS_TYPE_UINT16:
1965             *(unsigned short *)value = p->value.u16;
1966             return EINA_TRUE;
1967
1968          case DBUS_TYPE_UINT32:
1969             *(unsigned int *)value = p->value.u32;
1970             return EINA_TRUE;
1971
1972          case DBUS_TYPE_STRING:
1973             *(const char **)value = p->value.str;
1974             return EINA_TRUE;
1975
1976          case DBUS_TYPE_OBJECT_PATH:
1977             *(const char **)value = p->value.path;
1978             return EINA_TRUE;
1979
1980          case DBUS_TYPE_ARRAY:
1981             *(E_Bluez_Array **)value = p->value.array;
1982             return EINA_TRUE;
1983
1984          default:
1985             ERR("don't know how to get property type %c (%d)",
1986                 p->type, p->type);
1987             return EINA_FALSE;
1988         }
1989    }
1990
1991    WRN("element %s (%p) has no property with name \"%s\".",
1992        element->path, element, name);
1993    return EINA_FALSE;
1994 }
1995
1996 /**
1997  * Get property value given its name.
1998  *
1999  * This will look into properties, to find the property.
2000  * If no property is found then @c EINA_FALSE is returned.
2001  *
2002  * If @c EINA_FALSE is returned, then this call failed and parameter-returned
2003  * values shall be considered invalid.
2004  *
2005  * @param element which element to get the property
2006  * @param name property name
2007  * @param type if provided it will contain the value type.
2008  * @param value where to store the property value, must be a pointer to the
2009  *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
2010  *
2011  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
2012  */
2013 Eina_Bool
2014 e_bluez_element_property_get(const E_Bluez_Element *element, const char *name, int *type, void *value)
2015 {
2016    Eina_Bool ret;
2017    name = eina_stringshare_add(name);
2018    ret = e_bluez_element_property_get_stringshared
2019          (element, name, type, value);
2020    eina_stringshare_del(name);
2021    return ret;
2022 }
2023
2024 struct e_bluez_elements_for_each_data
2025 {
2026    Eina_Hash_Foreach cb;
2027    void             *data;
2028 };
2029
2030 static Eina_Bool
2031 _e_bluez_elements_for_each(Eina_Hash *hash __UNUSED__, const char *key, void *data, void *fdata)
2032 {
2033    struct e_bluez_elements_for_each_data *each_data = fdata;
2034
2035    each_data->cb(elements, key, data, each_data->data);
2036    return EINA_TRUE;
2037 }
2038
2039 /**
2040  * Call the given function for each existing element.
2041  *
2042  * @param cb function to call for each element. It will get as parameters,
2043  *        in order: the element pointer and the given @a user_data.
2044  * @param user_data data to give to @a cb for each element.
2045  */
2046 void
2047 e_bluez_elements_for_each(Eina_Hash_Foreach cb, const void *user_data)
2048 {
2049    struct e_bluez_elements_for_each_data data = {cb, (void *)user_data};
2050
2051    EINA_SAFETY_ON_NULL_RETURN(cb);
2052
2053    eina_hash_foreach(elements, (Eina_Hash_Foreach)_e_bluez_elements_for_each,
2054                      &data);
2055 }
2056
2057 static Eina_Bool
2058 _e_bluez_elements_get_allocate(unsigned int *count, E_Bluez_Element ***p_elements)
2059 {
2060    *count = eina_hash_population(elements);
2061    if (*count == 0)
2062      {
2063         *p_elements = NULL;
2064         return EINA_TRUE;
2065      }
2066
2067    *p_elements = malloc(*count * sizeof(E_Bluez_Element *));
2068    if (!*p_elements)
2069      {
2070         ERR("could not allocate return array of %d elements: %s",
2071             *count, strerror(errno));
2072         *count = 0;
2073         return EINA_FALSE;
2074      }
2075
2076    return EINA_TRUE;
2077 }
2078
2079 static Eina_Bool
2080 _e_bluez_elements_get_all(Eina_Hash *hash __UNUSED__, const char *key __UNUSED__, void *data, void *fdata)
2081 {
2082    E_Bluez_Element *element = data;
2083    E_Bluez_Element ***p_ret = fdata;
2084
2085    **p_ret = element;
2086    (*p_ret)++;
2087    return EINA_TRUE;
2088 }
2089
2090 /**
2091  * Get all known elements.
2092  *
2093  * No reference is added to these elements, since there are no threads
2094  * in the system, you are free to add references yourself right after
2095  * the return of this call without race condition, elements by the
2096  * system (ie: elementRemoved signal)could only be touched on the next
2097  * main loop iteration.
2098  *
2099  * @param count return the number of elements in array.
2100  * @param p_elements array with all elements, these are not referenced
2101  *        and in no particular order, just set if return is 1.
2102  *
2103  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
2104  */
2105 Eina_Bool
2106 e_bluez_elements_get_all(unsigned int *count, E_Bluez_Element ***p_elements)
2107 {
2108    E_Bluez_Element **p;
2109
2110    EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
2111    EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
2112
2113    if (!_e_bluez_elements_get_allocate(count, p_elements))
2114       return EINA_FALSE;
2115
2116    p = *p_elements;
2117    eina_hash_foreach(elements, (Eina_Hash_Foreach)_e_bluez_elements_get_all,
2118                      &p);
2119    return EINA_TRUE;
2120 }
2121
2122 struct e_bluez_elements_get_all_str_data
2123 {
2124    E_Bluez_Element **elements;
2125    int               count;
2126    const char       *str;
2127 };
2128
2129 static Eina_Bool
2130 _e_bluez_elements_get_all_type(Eina_Hash *hash __UNUSED__, const char *key __UNUSED__, void *e, void *user_data)
2131 {
2132    struct e_bluez_elements_get_all_str_data *data = user_data;
2133    E_Bluez_Element *element = e;
2134
2135    if ((data->str) && (element->interface != data->str))
2136       return EINA_TRUE;
2137
2138    data->elements[data->count] = element;
2139    data->count++;
2140    return EINA_TRUE;
2141 }
2142
2143 /**
2144  * Get all known elements of type.
2145  *
2146  * No reference is added to these elements, since there are no threads
2147  * in the system, you are free to add references yourself right after
2148  * the return of this call without race condition, elements by the
2149  * system (ie: ElementRemoved signal) could only be touched on the next
2150  * main loop iteration.
2151  *
2152  * @param type type to filter, or NULL to get all.
2153  * @param count return the number of elements in array.
2154  * @param p_elements array with all elements, these are not referenced
2155  *        and in no particular order, just set if return is 1.
2156  *
2157  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
2158  *
2159  * @see e_bluez_elements_get_all()
2160  */
2161 Eina_Bool
2162 e_bluez_elements_get_all_type(const char *type, unsigned int *count, E_Bluez_Element ***p_elements)
2163 {
2164    struct e_bluez_elements_get_all_str_data data;
2165
2166    EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
2167    EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
2168
2169    if (!_e_bluez_elements_get_allocate(count, p_elements))
2170       return EINA_FALSE;
2171
2172    data.elements = *p_elements;
2173    data.count = 0;
2174    data.str = eina_stringshare_add(type);
2175    eina_hash_foreach(elements,
2176                      (Eina_Hash_Foreach)_e_bluez_elements_get_all_type,
2177                      &data);
2178
2179    eina_stringshare_del(data.str);
2180    *count = data.count;
2181    return EINA_TRUE;
2182 }
2183
2184 /**
2185  * Get the element registered at given path.
2186  *
2187  * @param path the path to query for registered object.
2188  *
2189  * @return element pointer if found, NULL otherwise. No references are added.
2190  */
2191 E_Bluez_Element *
2192 e_bluez_element_get(const char *path)
2193 {
2194    E_Bluez_Element *element;
2195
2196    EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
2197    element = eina_hash_find(elements, path);
2198
2199    return element;
2200 }
2201
2202 static void
2203 _e_bluez_element_property_changed_callback(void *data, DBusMessage *msg)
2204 {
2205    E_Bluez_Element *element = (E_Bluez_Element *)data;
2206    DBusMessageIter itr, v_itr;
2207    int t, r, changed = 0;
2208    const char *name = NULL;
2209    void *value = NULL;
2210
2211    DBG("Property changed in element %s", element->path);
2212
2213    if (!_dbus_callback_check_and_init(msg, &itr, NULL))
2214       return;
2215
2216    t = dbus_message_iter_get_arg_type(&itr);
2217    if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
2218      {
2219         ERR("missing name in property changed signal");
2220         return;
2221      }
2222
2223    dbus_message_iter_get_basic(&itr, &name);
2224
2225    dbus_message_iter_next(&itr);
2226    t = dbus_message_iter_get_arg_type(&itr);
2227    if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
2228      {
2229         ERR("missing value in property changed signal");
2230         return;
2231      }
2232
2233    dbus_message_iter_recurse(&itr, &v_itr);
2234    t = dbus_message_iter_get_arg_type(&v_itr);
2235
2236    if (t == DBUS_TYPE_ARRAY)
2237      {
2238         value = e_bluez_element_iter_get_array(&v_itr, name);
2239      }
2240    else if (t != DBUS_TYPE_INVALID)
2241      {
2242         dbus_message_iter_get_basic(&v_itr, &value);
2243      }
2244    else
2245      {
2246         ERR("property has invalid type %s", name);
2247         return;
2248      }
2249
2250    r = _e_bluez_element_property_value_add(element, name, t, value);
2251    if (r < 0)
2252      {
2253         ERR("failed to add property value %s (%c)", name, t);
2254      }
2255    else if (r == 1)
2256      {
2257         INF("property value changed %s (%c)", name, t);
2258         changed = 1;
2259      }
2260
2261    if (changed)
2262       _e_bluez_element_listeners_call(element);
2263 }
2264
2265 /**
2266  * Register the given path, possible creating and element and return it.
2267  *
2268  * This will check if path is already registered, in that case the
2269  * exiting element is returned. If it was not registered yet, a new
2270  * element is created, registered and returned.
2271  *
2272  * This call will not add extra references to the object.
2273  *
2274  * @param path the path to register the element
2275  *
2276  * @return the registered object, no references are added.
2277  */
2278 E_Bluez_Element *
2279 e_bluez_element_register(const char *path, const char *interface)
2280 {
2281    E_Bluez_Element *element;
2282
2283    EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
2284    EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL);
2285
2286    element = eina_hash_find(elements, path);
2287    if (element)
2288       return element;
2289
2290    element = e_bluez_element_new(path, interface);
2291    if (!element)
2292       return NULL;
2293
2294    if (!eina_hash_add(elements, element->path, element))
2295      {
2296         ERR("could not add element %s to hash, delete it.", path);
2297         e_bluez_element_free(element);
2298         return NULL;
2299      }
2300
2301    element->signal_handler =
2302       e_dbus_signal_handler_add
2303          (e_bluez_conn, e_bluez_system_bus_name_get(),
2304          element->path, element->interface, "PropertyChanged",
2305          _e_bluez_element_property_changed_callback, element);
2306
2307    e_bluez_element_event_add(E_BLUEZ_EVENT_ELEMENT_ADD, element);
2308
2309    return element;
2310 }
2311
2312 static void
2313 _e_bluez_element_event_unregister_and_free(void *data __UNUSED__, void *ev)
2314 {
2315    E_Bluez_Element *element = ev;
2316    e_bluez_element_unref(element);
2317 }
2318
2319 static void
2320 _e_bluez_element_unregister_internal(E_Bluez_Element *element)
2321 {
2322    if (element->signal_handler)
2323      {
2324         e_dbus_signal_handler_del(e_bluez_conn, element->signal_handler);
2325         element->signal_handler = NULL;
2326      }
2327
2328    ecore_event_add(E_BLUEZ_EVENT_ELEMENT_DEL, element,
2329                    _e_bluez_element_event_unregister_and_free, NULL);
2330 }
2331
2332 /**
2333  * Forget about the given element.
2334  *
2335  * This will remove the element from the pool of known objects, then
2336  * add an E_BLUEZ_EVENT_ELEMENT_DEL and after that will unreference it,
2337  * possible freeing it.
2338  *
2339  * @param element element to forget about. Its reference will be removed.
2340  */
2341 void
2342 e_bluez_element_unregister(E_Bluez_Element *element)
2343 {
2344    if (!element)
2345       return;
2346
2347    if (elements)
2348       eina_hash_del_by_key(elements, element->path);
2349 }
2350
2351 /**
2352  * Remove all known elements.
2353  *
2354  * This will remove all known elements but will NOT add any
2355  * E_BLUEZ_EVENT_ELEMENT_DEL to main loop.
2356  *
2357  * This is just useful to make sure next e_bluez_manager_sync_elements()
2358  * will not leave any stale elements. This is unlikely to happen, as
2359  * E_Bluez is supposed to catch all required events to avoid stale elements.
2360  */
2361 void
2362 e_bluez_manager_clear_elements(void)
2363 {
2364    e_bluez_elements_shutdown();
2365    e_bluez_elements_init();
2366 }
2367
2368 /**
2369  * Creates elements hash.
2370  *
2371  * This has no init counter since its already guarded by other code.
2372  * @internal
2373  */
2374 void
2375 e_bluez_elements_init(void)
2376 {
2377    EINA_SAFETY_ON_FALSE_RETURN(!elements);
2378    elements =
2379       eina_hash_string_superfast_new(EINA_FREE_CB
2380                                         (_e_bluez_element_unregister_internal));
2381 }
2382
2383 void
2384 e_bluez_elements_shutdown(void)
2385 {
2386    EINA_SAFETY_ON_FALSE_RETURN(!!elements);
2387    eina_hash_free(elements);
2388    elements = NULL;
2389 }
2390
2391 static inline Eina_Bool
2392 _e_bluez_element_is(const E_Bluez_Element *element, const char *interface)
2393 {
2394    return element->interface == interface;
2395 }
2396
2397 Eina_Bool
2398 e_bluez_element_is_adapter(const E_Bluez_Element *element)
2399 {
2400    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
2401    return _e_bluez_element_is(element, e_bluez_iface_adapter);
2402 }
2403
2404 Eina_Bool
2405 e_bluez_element_is_device(const E_Bluez_Element *element)
2406 {
2407    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
2408    return _e_bluez_element_is(element, e_bluez_iface_device);
2409 }
2410