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