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