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