e_dbus/connman: set array property
[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 /* strings are just pointers (references), no strdup or stringshare_add/ref */
827 Eina_Bool
828 e_connman_element_strings_array_get_stringshared(const E_Connman_Element *element, const char *property, unsigned int *count, const char ***strings)
829 {
830    const char **ret, **p;
831    Eina_Array_Iterator iterator;
832    E_Connman_Array *array;
833    unsigned int i;
834    int type;
835    void *item;
836
837    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
838    EINA_SAFETY_ON_NULL_RETURN_VAL(property, EINA_FALSE);
839    EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
840    EINA_SAFETY_ON_NULL_RETURN_VAL(strings, EINA_FALSE);
841
842    *count = 0;
843    *strings = NULL;
844
845    if (!e_connman_element_property_get_stringshared
846           (element, property, &type, &array))
847       return EINA_FALSE;
848
849    if (type != DBUS_TYPE_ARRAY)
850      {
851         ERR("property %s is not an array!", property);
852         return EINA_FALSE;
853      }
854
855    if ((!array) || (!array->array) || (array->type == DBUS_TYPE_INVALID))
856       return EINA_FALSE;
857
858    if (array->type != DBUS_TYPE_STRING)
859      {
860         ERR("property %s is not an array of strings!", property);
861         return EINA_FALSE;
862      }
863
864    *count = eina_array_count_get(array->array);
865    ret = malloc(*count * sizeof(char *));
866    if (!ret)
867      {
868         ERR("could not allocate return array of %d strings: %s",
869             *count, strerror(errno));
870         *count = 0;
871         return EINA_FALSE;
872      }
873
874    p = ret;
875
876    EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
877    {
878       if (!item)
879          continue;
880
881       *p = item;
882       p++;
883    }
884    *count = p - ret;
885    *strings = ret;
886    return EINA_TRUE;
887 }
888
889 static void
890 _e_connman_element_array_print(FILE *fp, E_Connman_Array *array)
891 {
892    Eina_Array_Iterator iterator;
893    unsigned int i;
894    void *item;
895
896    if (!array)
897       return;
898
899    switch (array->type)
900      {
901       case DBUS_TYPE_OBJECT_PATH:
902          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
903          fprintf(fp, "\"%s\", ", (const char *)item);
904          break;
905
906       case DBUS_TYPE_STRING:
907          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
908          fprintf(fp, "\"%s\", ", (const char *)item);
909          break;
910
911       case DBUS_TYPE_BYTE:
912          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
913          fprintf(fp, "%#02hhx (\"%c\"), ", (unsigned char)(long)item,
914                  (unsigned char)(long)item);
915          break;
916
917       case DBUS_TYPE_UINT16:
918          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
919          fprintf(fp, "%#04hx (%hu), ", (unsigned short)(long)item,
920                  (unsigned short)(long)item);
921          break;
922
923       case DBUS_TYPE_UINT32:
924          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
925          fprintf(fp, "%#08x (%u), ", (unsigned int)(long)item,
926                  (unsigned int)(long)item);
927          break;
928
929       case DBUS_TYPE_DICT_ENTRY:
930          fputs("{ ", fp);
931          EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
932          {
933             E_Connman_Element_Dict_Entry *entry = item;
934             fprintf(fp, "%s: ", entry->name);
935             switch (entry->type)
936               {
937                case DBUS_TYPE_OBJECT_PATH:
938                   fprintf(fp, "\"%s\", ", entry->value.path);
939                   break;
940
941                case DBUS_TYPE_STRING:
942                   fprintf(fp, "\"%s\", ", entry->value.str);
943                   break;
944
945                case DBUS_TYPE_BYTE:
946                   fprintf(fp, "%#02hhx (\"%c\"), ",
947                           entry->value.byte, entry->value.byte);
948                   break;
949
950                case DBUS_TYPE_UINT16:
951                   fprintf(fp, "%#04hx (%hu), ",
952                           entry->value.u16, entry->value.u16);
953                   break;
954
955                case DBUS_TYPE_UINT32:
956                   fprintf(fp, "%#08x (%u), ",
957                           entry->value.u32, entry->value.u32);
958                   break;
959
960                default:
961                   fprintf(fp, "<UNKNOWN TYPE '%c'>", entry->type);
962               }
963          }
964          fputs("}", fp);
965          break;
966
967       default:
968          fprintf(fp, "<UNKNOWN ARRAY TYPE '%c'>", array->type);
969      }
970 }
971
972 /**
973  * Print element to file descriptor.
974  */
975 void
976 e_connman_element_print(FILE *fp, const E_Connman_Element *element)
977 {
978    const E_Connman_Element_Property *p;
979
980    EINA_SAFETY_ON_NULL_RETURN(fp);
981    if (!element)
982      {
983         fputs("Error: no element to print\n", fp);
984         return;
985      }
986
987    fprintf(fp,
988            "Element %p: %s [%s]\n"
989            "\tProperties:\n",
990            element, element->path, element->interface);
991
992    EINA_INLIST_FOREACH(element->props, p)
993    {
994       fprintf(fp, "\t\t%s (%c) = ", p->name, p->type);
995
996       switch (p->type)
997         {
998          case DBUS_TYPE_STRING:
999             fprintf(fp, "\"%s\"", p->value.str);
1000             break;
1001
1002          case DBUS_TYPE_OBJECT_PATH:
1003             fprintf(fp, "\"%s\"", p->value.path);
1004             break;
1005
1006          case DBUS_TYPE_BOOLEAN:
1007             fprintf(fp, "%hhu", p->value.boolean);
1008             break;
1009
1010          case DBUS_TYPE_BYTE:
1011             fprintf(fp, "%#02hhx (%d), ", p->value.byte, p->value.byte);
1012             break;
1013
1014          case DBUS_TYPE_UINT16:
1015             fprintf(fp, "%hu", p->value.u16);
1016             break;
1017
1018          case DBUS_TYPE_UINT32:
1019             fprintf(fp, "%u", p->value.u32);
1020             break;
1021
1022          case DBUS_TYPE_ARRAY:
1023             _e_connman_element_array_print(fp, p->value.array);
1024             break;
1025
1026          default:
1027             fputs("don't know how to print type", fp);
1028         }
1029
1030       fputc('\n', fp);
1031    }
1032 }
1033
1034 static E_Connman_Element *
1035 e_connman_element_new(const char *path, const char *interface)
1036 {
1037    E_Connman_Element *element;
1038
1039    element = calloc(1, sizeof(*element));
1040    if (!element)
1041      {
1042         ERR("could not allocate element: %s",   strerror(errno));
1043         return NULL;
1044      }
1045
1046    element->path = eina_stringshare_add(path);
1047    element->interface = eina_stringshare_ref(interface);
1048    element->_references = 1;
1049
1050    return element;
1051 }
1052
1053 static void
1054 e_connman_element_extra_properties_free(E_Connman_Element *element)
1055 {
1056    while (element->props)
1057      {
1058         E_Connman_Element_Property *prop;
1059         prop = (E_Connman_Element_Property *)element->props;
1060         element->props = element->props->next;
1061         _e_connman_element_property_free(prop);
1062      }
1063 }
1064
1065 static void
1066 e_connman_element_free(E_Connman_Element *element)
1067 {
1068    if (element->_idler.changed)
1069       ecore_idler_del(element->_idler.changed);
1070
1071    while (element->_listeners)
1072      {
1073         E_Connman_Element_Listener *l = (void *)element->_listeners;
1074         element->_listeners = eina_inlist_remove
1075               (element->_listeners, element->_listeners);
1076
1077         if (l->free_data)
1078            l->free_data(l->data);
1079
1080         free(l);
1081      }
1082
1083    e_connman_element_pending_cancel_and_free(&element->_pending.properties_get);
1084    e_connman_element_pending_cancel_and_free(&element->_pending.property_set);
1085    e_connman_element_pending_cancel_and_free(&element->_pending.agent_register);
1086    e_connman_element_pending_cancel_and_free(&element->_pending.agent_unregister);
1087    e_connman_element_pending_cancel_and_free(&element->_pending.request_scan);
1088    e_connman_element_pending_cancel_and_free(&element->_pending.technology_enable);
1089    e_connman_element_pending_cancel_and_free(&element->_pending.technology_disable);
1090    e_connman_element_pending_cancel_and_free(&element->_pending.profile_remove);
1091    e_connman_element_pending_cancel_and_free(&element->_pending.service_connect);
1092    e_connman_element_pending_cancel_and_free(&element->_pending.service_disconnect);
1093    e_connman_element_pending_cancel_and_free(&element->_pending.service_remove);
1094    e_connman_element_pending_cancel_and_free(&element->_pending.service_move_before);
1095    e_connman_element_pending_cancel_and_free(&element->_pending.service_move_after);
1096    e_connman_element_pending_cancel_and_free(&element->_pending.service_clear_property);
1097
1098    e_connman_element_extra_properties_free(element);
1099    eina_stringshare_del(element->interface);
1100    eina_stringshare_del(element->path);
1101    free(element);
1102 }
1103
1104 /**
1105  * Add reference to element.
1106  */
1107 int
1108 e_connman_element_ref(E_Connman_Element *element)
1109 {
1110    EINA_SAFETY_ON_NULL_RETURN_VAL(element, 0);
1111    return ++element->_references;
1112 }
1113
1114 /**
1115  * Remove reference from element.
1116  *
1117  * If reference count drops to 0 element will be freed.
1118  */
1119 int
1120 e_connman_element_unref(E_Connman_Element *element)
1121 {
1122    int i;
1123    EINA_SAFETY_ON_NULL_RETURN_VAL(element, 0);
1124
1125    i = --element->_references;
1126    if (i == 0)
1127       e_connman_element_free(element);
1128    else if (i < 0)
1129       ERR("element %p references %d < 0", element, i);
1130
1131    return i;
1132 }
1133
1134 /**
1135  * Send message with callbacks set to work with connman elements.
1136  *
1137  * If this call fails (returns @c EINA_FALSE), pending callbacks will not be called,
1138  * not even with error messages.
1139  *
1140  * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
1141  */
1142 Eina_Bool
1143 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)
1144 {
1145    E_Connman_Element_Call_Data *data;
1146    E_Connman_Element_Pending *p;
1147
1148    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1149    EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
1150    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
1151    EINA_SAFETY_ON_NULL_RETURN_VAL(msg, EINA_FALSE);
1152
1153    data = malloc(sizeof(*data));
1154    if (!data)
1155      {
1156         ERR("could not alloc e_connman_element_call_data: %s",
1157             strerror(errno));
1158         dbus_message_unref(msg);
1159         return EINA_FALSE;
1160      }
1161
1162    p = malloc(sizeof(*p));
1163    if (!p)
1164      {
1165         ERR("could not alloc E_Connman_Element_Pending: %s",
1166             strerror(errno));
1167         free(data);
1168         dbus_message_unref(msg);
1169         return EINA_FALSE;
1170      }
1171
1172    data->element = element;
1173    data->cb = cb;
1174    data->pending = p;
1175    data->p_list = pending;
1176    p->user_cb = user_cb;
1177    p->user_data = (void *)user_data;
1178    p->data = data;
1179    p->pending = e_dbus_message_send
1180          (e_connman_conn, msg, e_connman_element_call_dispatch_and_free, -1, data);
1181    dbus_message_unref(msg);
1182
1183    if (p->pending)
1184      {
1185         *pending = eina_inlist_append(*pending, EINA_INLIST_GET(p));
1186         return EINA_TRUE;
1187      }
1188
1189    ERR("failed to call %s (obj=%s, path=%s, iface=%s)",
1190        method_name, e_connman_system_bus_name_get(),
1191        element->path, element->interface);
1192    free(data);
1193    free(p);
1194    return EINA_FALSE;
1195 }
1196
1197 Eina_Bool
1198 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)
1199 {
1200    DBusMessage *msg;
1201
1202    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1203    EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
1204    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
1205
1206    msg = dbus_message_new_method_call
1207          (e_connman_system_bus_name_get(), element->path, element->interface,
1208          method_name);
1209
1210    return e_connman_element_message_send
1211              (element, method_name, cb, msg, pending, user_cb, user_data);
1212 }
1213
1214 static Eina_Bool
1215 _e_connman_element_property_value_add(E_Connman_Element *element, const char *name, int type, void *value)
1216 {
1217    E_Connman_Element_Property *p;
1218
1219    name = eina_stringshare_add(name);
1220    EINA_INLIST_FOREACH(element->props, p)
1221    {
1222       if (p->name == name)
1223         {
1224            eina_stringshare_del(name);
1225            return _e_connman_element_property_update(p, type, value);
1226         }
1227    }
1228
1229    p = _e_connman_element_property_new(name, type, value);
1230    if (!p)
1231      {
1232         ERR("could not create property %s (%c)", name, type);
1233         return EINA_FALSE;
1234      }
1235
1236    element->props = eina_inlist_append(element->props, EINA_INLIST_GET(p));
1237    return EINA_TRUE;
1238 }
1239
1240 static E_Connman_Array *
1241 _e_connman_element_iter_get_array(DBusMessageIter *itr, const char *key)
1242 {
1243    E_Connman_Array *array;
1244    DBusMessageIter e_itr;
1245
1246    array = malloc(sizeof(E_Connman_Array));
1247    if (!array)
1248      {
1249         ERR("could not create new e_connman array.");
1250         return NULL;
1251      }
1252
1253    array->array = eina_array_new(16);
1254    if (!(array->array))
1255      {
1256         ERR("could not create new eina array.");
1257         free(array);
1258         return NULL;
1259      }
1260
1261    dbus_message_iter_recurse(itr, &e_itr);
1262    array->type = dbus_message_iter_get_arg_type(&e_itr);
1263    if (array->type == DBUS_TYPE_INVALID)
1264      {
1265         DBG("array %s is of type 'invalid' (empty?)", key);
1266         eina_array_free(array->array);
1267         free(array);
1268         return NULL;
1269      }
1270
1271    do
1272      {
1273         switch (array->type)
1274           {
1275            case DBUS_TYPE_OBJECT_PATH:
1276            {
1277               const char *path;
1278
1279               dbus_message_iter_get_basic(&e_itr, &path);
1280               path = eina_stringshare_add(path);
1281               eina_array_push(array->array, path);
1282               _e_connman_element_item_register(key, path);
1283            }
1284            break;
1285
1286            case DBUS_TYPE_STRING:
1287            {
1288               const char *str;
1289
1290               dbus_message_iter_get_basic(&e_itr, &str);
1291               str = eina_stringshare_add(str);
1292               eina_array_push(array->array, str);
1293            }
1294            break;
1295
1296            case DBUS_TYPE_BYTE:
1297            {
1298               unsigned char byte;
1299               dbus_message_iter_get_basic(&e_itr, &byte);
1300               eina_array_push(array->array, (void *)(long)byte);
1301            }
1302            break;
1303
1304            case DBUS_TYPE_DICT_ENTRY:
1305            {
1306               E_Connman_Element_Dict_Entry *entry;
1307               entry = _e_connman_element_dict_entry_new(&e_itr);
1308               if (entry)
1309                  eina_array_push(array->array, entry);
1310            }
1311            break;
1312
1313            default:
1314               ERR("don't know how to build array '%s' of type %c (%d)",
1315                   key, array->type, array->type);
1316               eina_array_free(array->array);
1317               free(array);
1318               return NULL;
1319           }
1320      }
1321    while (dbus_message_iter_next(&e_itr));
1322    return array;
1323 }
1324
1325 static void
1326 _e_connman_element_get_properties_callback(void *user_data, DBusMessage *msg, DBusError *err)
1327 {
1328    E_Connman_Element *element = user_data;
1329    DBusMessageIter itr, s_itr;
1330    int t, changed;
1331
1332    DBG("get_properties msg=%p", msg);
1333
1334    if (!_dbus_callback_check_and_init(msg, &itr, err))
1335       return;
1336
1337    t = dbus_message_iter_get_arg_type(&itr);
1338    if (!_dbus_iter_type_check(t, DBUS_TYPE_ARRAY))
1339       return;
1340
1341    changed = 0;
1342    dbus_message_iter_recurse(&itr, &s_itr);
1343    do
1344      {
1345         DBusMessageIter e_itr, v_itr;
1346         const char *key;
1347         void *value = NULL;
1348         int r;
1349
1350         t = dbus_message_iter_get_arg_type(&s_itr);
1351         if (!_dbus_iter_type_check(t, DBUS_TYPE_DICT_ENTRY))
1352            continue;
1353
1354         dbus_message_iter_recurse(&s_itr, &e_itr);
1355
1356         t = dbus_message_iter_get_arg_type(&e_itr);
1357         if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
1358            continue;
1359
1360         dbus_message_iter_get_basic(&e_itr, &key);
1361         dbus_message_iter_next(&e_itr);
1362         t = dbus_message_iter_get_arg_type(&e_itr);
1363         if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
1364            continue;
1365
1366         dbus_message_iter_recurse(&e_itr, &v_itr);
1367         t = dbus_message_iter_get_arg_type(&v_itr);
1368         if (t == DBUS_TYPE_ARRAY)
1369           {
1370              value = _e_connman_element_iter_get_array(&v_itr, key);
1371           }
1372         else if (t != DBUS_TYPE_INVALID)
1373           {
1374              dbus_message_iter_get_basic(&v_itr, &value);
1375           }
1376         else
1377           {
1378              ERR("property has invalid type %s", key);
1379              continue;
1380           }
1381
1382         r = _e_connman_element_property_value_add(element, key, t, value);
1383         if (r < 0)
1384           {
1385              ERR("failed to add property value %s (%c)", key, t);
1386           }
1387         else if (r == 1)
1388           {
1389              INF("property value changed %s (%c)", key, t);
1390              changed = 1;
1391           }
1392      }
1393    while (dbus_message_iter_next(&s_itr));
1394
1395    if (changed)
1396       _e_connman_element_listeners_call(element);
1397 }
1398
1399 /**
1400  * Sync element properties with server.
1401  *
1402  * Call method GetProperties() at the given element on server in order to sync
1403  * them.
1404  *
1405  * @param element to call method on server.
1406  * @param cb function to call when server replies or some error happens.
1407  * @param data data to give to cb when it is called.
1408  *
1409  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1410  */
1411 Eina_Bool
1412 e_connman_element_sync_properties_full(E_Connman_Element *element, E_DBus_Method_Return_Cb cb, const void *data)
1413 {
1414    const char name[] = "GetProperties";
1415
1416    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1417    return e_connman_element_call_full
1418              (element, name, _e_connman_element_get_properties_callback,
1419              &element->_pending.properties_get, cb, data);
1420 }
1421
1422 /**
1423  * Sync element properties with server, simple version.
1424  *
1425  * Call method GetProperties() at the given element on server in order to sync
1426  * them. This is the simple version and there is no check of server reply
1427  * for errors.
1428  *
1429  * @param element to call method on server.
1430  *
1431  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1432  */
1433 Eina_Bool
1434 e_connman_element_properties_sync(E_Connman_Element *element)
1435 {
1436    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1437    return e_connman_element_sync_properties_full(element, NULL, NULL);
1438 }
1439
1440 /**
1441  * Call method SetProperty(prop, {key: value}) at the given element on server.
1442  *
1443  * This is a server call, not local, so it may fail and in that case
1444  * no property is updated locally. If the value was set the event
1445  * E_CONNMAN_EVENT_ELEMENT_UPDATED will be added to main loop.
1446  *
1447  * @param element to call method on server.
1448  * @param prop property name.
1449  * @param key dict key name.
1450  * @param type DBus type to use for value.
1451  * @param value pointer to value, just like regular DBus, see
1452  *        dbus_message_iter_append_basic().
1453  * @param cb function to call when server replies or some error happens.
1454  * @param data data to give to cb when it is called.
1455  *
1456  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1457  */
1458 Eina_Bool
1459 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)
1460 {
1461    const char name[] = "SetProperty";
1462    DBusMessage *msg;
1463    DBusMessageIter itr, variant, dict, entry;
1464    char typestr[32];
1465
1466    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1467    EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
1468
1469    msg = dbus_message_new_method_call
1470          (e_connman_system_bus_name_get(), element->path, element->interface, name);
1471
1472    if (!msg)
1473       return EINA_FALSE;
1474
1475    dbus_message_iter_init_append(msg, &itr);
1476    dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
1477
1478    if ((size_t)snprintf(typestr, sizeof(typestr),
1479                         (DBUS_TYPE_ARRAY_AS_STRING
1480                          DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1481                          DBUS_TYPE_STRING_AS_STRING
1482                          "%c"
1483                          DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
1484                         type) >= sizeof(typestr))
1485      {
1486         ERR("sizeof(typestr) is too small!");
1487         return EINA_FALSE;
1488      }
1489
1490    dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, typestr, &variant);
1491
1492    snprintf(typestr, sizeof(typestr),
1493             (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1494              DBUS_TYPE_STRING_AS_STRING
1495              "%c"
1496              DBUS_DICT_ENTRY_END_CHAR_AS_STRING),
1497             type);
1498
1499    dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, typestr, &dict);
1500    dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
1501
1502    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1503
1504    if ((type == DBUS_TYPE_STRING) || (type == DBUS_TYPE_OBJECT_PATH))
1505       dbus_message_iter_append_basic(&entry, type, &value);
1506    else
1507       dbus_message_iter_append_basic(&entry, type, value);
1508
1509    dbus_message_iter_close_container(&dict, &entry);
1510    dbus_message_iter_close_container(&variant, &dict);
1511    dbus_message_iter_close_container(&itr, &variant);
1512
1513    return e_connman_element_message_send
1514              (element, name, NULL, msg, &element->_pending.property_set, cb, data);
1515 }
1516
1517 /**
1518  * Call method SetProperty(prop, value) at the given element on server.
1519  *
1520  * This is a server call, not local, so it may fail and in that case
1521  * no property is updated locally. If the value was set the event
1522  * E_CONNMAN_EVENT_ELEMENT_UPDATED will be added to main loop.
1523  *
1524  * @param element to call method on server.
1525  * @param prop property name.
1526  * @param type DBus type to use for value.
1527  * @param value pointer to value, just like regular DBus, see
1528  *        dbus_message_iter_append_basic().
1529  * @param cb function to call when server replies or some error happens.
1530  * @param data data to give to cb when it is called.
1531  *
1532  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1533  */
1534 Eina_Bool
1535 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)
1536 {
1537    const char name[] = "SetProperty";
1538    char typestr[2];
1539    DBusMessage *msg;
1540
1541    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1542    EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
1543
1544    msg = dbus_message_new_method_call
1545          (e_connman_system_bus_name_get(), element->path, element->interface, name);
1546
1547    if (!msg)
1548       return EINA_FALSE;
1549
1550    DBusMessageIter itr, v;
1551    dbus_message_iter_init_append(msg, &itr);
1552    dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
1553
1554    typestr[0] = type;
1555    typestr[1] = '\0';
1556    dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, typestr, &v);
1557    if ((type == DBUS_TYPE_STRING) || (type == DBUS_TYPE_OBJECT_PATH))
1558      {
1559         dbus_message_iter_append_basic(&v, type, &value);
1560      }
1561    else if (type == DBUS_TYPE_BOOLEAN)
1562      {
1563         unsigned int b = *(char *)value;
1564         dbus_message_iter_append_basic(&v, type, &b);
1565      }
1566    else
1567      {
1568         dbus_message_iter_append_basic(&v, type, value);
1569      }
1570
1571    dbus_message_iter_close_container(&itr, &v);
1572
1573    return e_connman_element_message_send
1574              (element, name, NULL, msg, &element->_pending.property_set, cb, data);
1575 }
1576
1577 /**
1578  * Call method SetProperty(prop, value) at the given element on server, when
1579  * value is an array.
1580  *
1581  * This is a server call, not local, so it may fail and in that case
1582  * no property is updated locally. If the value was set the event
1583  * E_CONNMAN_EVENT_ELEMENT_UPDATED will be added to main loop.
1584  *
1585  * @param element to call method on server.
1586  * @param prop property name.
1587  * @param type DBus type to use for value.
1588  * @param value pointer to value, just like regular DBus, see
1589  *        dbus_message_iter_append_basic().
1590  * @param cb function to call when server replies or some error happens.
1591  * @param data data to give to cb when it is called.
1592  *
1593  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1594  */
1595 Eina_Bool
1596 e_connman_element_property_array_set_full(E_Connman_Element *element, const char *prop, int type, const Eina_List *values, E_DBus_Method_Return_Cb cb, const void *data)
1597 {
1598    const char name[] = "SetProperty";
1599    char type_sig[2] = { type, '\0'};
1600    char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
1601    DBusMessage *msg;
1602    DBusMessageIter itr, variant, array;
1603    const Eina_List *l;
1604    void *entry;
1605
1606    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1607    EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
1608
1609    msg = dbus_message_new_method_call
1610          (e_connman_system_bus_name_get(), element->path, element->interface, name);
1611
1612    if (!msg)
1613       return EINA_FALSE;
1614
1615    dbus_message_iter_init_append(msg, &itr);
1616    dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &prop);
1617
1618    dbus_message_iter_open_container(&itr, DBUS_TYPE_VARIANT, array_sig,
1619                                     &variant);
1620    dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, type_sig,
1621                                     &array);
1622
1623    if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH)
1624      {
1625         EINA_LIST_FOREACH(values, l, entry)
1626            dbus_message_iter_append_basic(&array, type, &entry);
1627      }
1628    else
1629      {
1630         EINA_LIST_FOREACH(values, l, entry)
1631            dbus_message_iter_append_basic(&array, type, entry);
1632      }
1633
1634    dbus_message_iter_close_container(&variant, &array);
1635    dbus_message_iter_close_container(&itr, &variant);
1636
1637    return e_connman_element_message_send(element, name, NULL, msg,
1638                                          &element->_pending.property_set,
1639                                          cb, data);
1640 }
1641
1642 /**
1643  * Call method SetProperty(prop, value) at the given element on server.
1644  *
1645  * This is the simple version and there is no check of server reply
1646  * for errors.
1647  *
1648  * @param element to call method on server.
1649  * @param prop property name.
1650  * @param type DBus type to use for value.
1651  * @param value pointer to value, just like regular DBus, see
1652  *        dbus_message_iter_append_basic().
1653  *
1654  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1655  */
1656 Eina_Bool
1657 e_connman_element_property_set(E_Connman_Element *element, const char *prop, int type, const void *value)
1658 {
1659    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1660    EINA_SAFETY_ON_NULL_RETURN_VAL(prop, EINA_FALSE);
1661    return e_connman_element_property_set_full
1662              (element, prop, type, value, NULL, NULL);
1663 }
1664
1665 Eina_Bool
1666 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)
1667 {
1668    DBusMessageIter itr;
1669    DBusMessage *msg;
1670
1671    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1672    EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
1673    EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
1674    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
1675
1676    msg = dbus_message_new_method_call
1677          (e_connman_system_bus_name_get(), element->path, element->interface,
1678          method_name);
1679
1680    if (!msg)
1681       return EINA_FALSE;
1682
1683    dbus_message_iter_init_append(msg, &itr);
1684    dbus_message_iter_append_basic(&itr, DBUS_TYPE_OBJECT_PATH, &string);
1685
1686    return e_connman_element_message_send
1687              (element, method_name, cb, msg, pending, user_cb, user_data);
1688 }
1689
1690 Eina_Bool
1691 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)
1692 {
1693    DBusMessageIter itr;
1694    DBusMessage *msg;
1695
1696    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1697    EINA_SAFETY_ON_NULL_RETURN_VAL(method_name, EINA_FALSE);
1698    EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE);
1699    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, EINA_FALSE);
1700
1701    msg = dbus_message_new_method_call
1702          (e_connman_system_bus_name_get(), element->path, element->interface,
1703          method_name);
1704
1705    if (!msg)
1706       return EINA_FALSE;
1707
1708    dbus_message_iter_init_append(msg, &itr);
1709    dbus_message_iter_append_basic(&itr, DBUS_TYPE_STRING, &string);
1710
1711    return e_connman_element_message_send
1712              (element, method_name, cb, msg, pending, user_cb, user_data);
1713 }
1714
1715 /**
1716  * Get property type.
1717  *
1718  * If @c EINA_FALSE is returned, then this call failed and parameter-returned
1719  * values shall be considered invalid.
1720  *
1721  * @param element which element to get the property
1722  * @param name property name, must be previously stringshared
1723  * @param type will contain the value type.
1724  *
1725  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1726  */
1727 Eina_Bool
1728 e_connman_element_property_type_get_stringshared(const E_Connman_Element *element, const char *name, int *type)
1729 {
1730    const E_Connman_Element_Property *p;
1731
1732    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1733    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
1734    EINA_SAFETY_ON_NULL_RETURN_VAL(type, EINA_FALSE);
1735
1736    EINA_INLIST_FOREACH(element->props, p)
1737    {
1738       if (p->name == name)
1739         {
1740            *type = p->type;
1741            return EINA_TRUE;
1742         }
1743    }
1744
1745    WRN("element %s (%p) has no property with name \"%s\".",
1746        element->path, element, name);
1747    return EINA_FALSE;
1748 }
1749
1750 /**
1751  * Get property type.
1752  *
1753  * If @c EINA_FALSE is returned, then this call failed and parameter-returned
1754  * values shall be considered invalid.
1755  *
1756  * @param element which element to get the property
1757  * @param name property name
1758  * @param type will contain the value type.
1759  *
1760  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1761  */
1762 Eina_Bool
1763 e_connman_element_property_type_get(const E_Connman_Element *element, const char *name, int *type)
1764 {
1765    Eina_Bool ret;
1766    name = eina_stringshare_add(name);
1767    ret = e_connman_element_property_type_get_stringshared(element, name, type);
1768    eina_stringshare_del(name);
1769    return ret;
1770 }
1771
1772 void
1773 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)
1774 {
1775    const E_Connman_Element_Property *p;
1776
1777    EINA_SAFETY_ON_NULL_RETURN(element);
1778    EINA_SAFETY_ON_NULL_RETURN(cb);
1779
1780    EINA_INLIST_FOREACH(element->props, p)
1781    {
1782       const void *value = NULL;
1783
1784       switch (p->type)
1785         {
1786          case DBUS_TYPE_STRING:
1787             value = &p->value.str;
1788             break;
1789
1790          case DBUS_TYPE_OBJECT_PATH:
1791             value = &p->value.path;
1792             break;
1793
1794          case DBUS_TYPE_BOOLEAN:
1795             value = (void *)&p->value.boolean;
1796             break;
1797
1798          case DBUS_TYPE_UINT16:
1799             value = &p->value.u16;
1800             break;
1801
1802          case DBUS_TYPE_UINT32:
1803             value = &p->value.u32;
1804             break;
1805
1806          default:
1807             ERR("unsupported type %c", p->type);
1808         }
1809
1810       if (!cb((void *)data, element, p->name, p->type, value))
1811          return;
1812    }
1813 }
1814
1815 /**
1816  * Get dict value given its key inside a dict property.
1817  *
1818  * This will look into properties for one of type dict that contains
1819  * the given key, to find the property.  If no property is found then
1820  * @c EINA_FALSE is returned.
1821  *
1822  * If @c EINA_FALSE is returned, then this call failed and parameter-returned
1823  * values shall be considered invalid.
1824  *
1825  * @param element which element to get the property
1826  * @param dict_name property name, must be previously stringshared
1827  * @param key key inside dict, must be previously stringshared
1828  * @param type if provided it will contain the value type.
1829  * @param value where to store the property value, must be a pointer to the
1830  *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
1831  *
1832  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
1833  */
1834 Eina_Bool
1835 e_connman_element_property_dict_get_stringshared(const E_Connman_Element *element, const char *dict_name, const char *key, int *type, void *value)
1836 {
1837    const E_Connman_Element_Property *p;
1838
1839    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1840    EINA_SAFETY_ON_NULL_RETURN_VAL(dict_name, EINA_FALSE);
1841    EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
1842    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
1843
1844    EINA_INLIST_FOREACH(element->props, p)
1845    {
1846       E_Connman_Element_Dict_Entry *entry;
1847       E_Connman_Array *array;
1848
1849       if (p->name != dict_name)
1850          continue;
1851
1852       if (p->type != DBUS_TYPE_ARRAY)
1853         {
1854            WRN("element %s (%p) has property \"%s\" is not an array: %c (%d)",
1855                element->path, element, dict_name, p->type, p->type);
1856            return EINA_FALSE;
1857         }
1858
1859       array = p->value.array;
1860       if ((!array) || (array->type != DBUS_TYPE_DICT_ENTRY))
1861         {
1862            int t = array ? array->type : DBUS_TYPE_INVALID;
1863            WRN("element %s (%p) has property \"%s\" is not a dict: %c (%d)",
1864                element->path, element, dict_name, t, t);
1865            return EINA_FALSE;
1866         }
1867
1868       entry = _e_connman_element_array_dict_find_stringshared(array, key);
1869       if (!entry)
1870         {
1871            WRN("element %s (%p) has no dict property with name \"%s\" with "
1872                "key \"%s\".",
1873                element->path, element, dict_name, key);
1874            return EINA_FALSE;
1875         }
1876
1877       if (type)
1878          *type = entry->type;
1879
1880       switch (entry->type)
1881         {
1882          case DBUS_TYPE_BOOLEAN:
1883             *(Eina_Bool *)value = entry->value.boolean;
1884             return EINA_TRUE;
1885
1886          case DBUS_TYPE_BYTE:
1887             *(unsigned char *)value = entry->value.byte;
1888             return EINA_TRUE;
1889
1890          case DBUS_TYPE_UINT16:
1891             *(unsigned short *)value = entry->value.u16;
1892             return EINA_TRUE;
1893
1894          case DBUS_TYPE_UINT32:
1895             *(unsigned int *)value = entry->value.u32;
1896             return EINA_TRUE;
1897
1898          case DBUS_TYPE_STRING:
1899             *(const char **)value = entry->value.str;
1900             return EINA_TRUE;
1901
1902          case DBUS_TYPE_OBJECT_PATH:
1903             *(const char **)value = entry->value.path;
1904             return EINA_TRUE;
1905
1906          case DBUS_TYPE_ARRAY:
1907             *(E_Connman_Array **)value = entry->value.array;
1908             return EINA_TRUE;
1909
1910          default:
1911             ERR("don't know how to get property %s, key %s type %c (%d)",
1912                 dict_name, key, entry->type, entry->type);
1913             return EINA_FALSE;
1914         }
1915    }
1916
1917    DBG("element %s (%p) has no property with name \"%s\".",
1918        element->path, element, dict_name);
1919    return EINA_FALSE;
1920 }
1921
1922 Eina_Bool
1923 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)
1924 {
1925    const char **ret, **p;
1926    Eina_Array_Iterator iterator;
1927    E_Connman_Array *array;
1928    unsigned int i;
1929    int type;
1930    void *item;
1931
1932    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
1933    EINA_SAFETY_ON_NULL_RETURN_VAL(dict_name, EINA_FALSE);
1934    EINA_SAFETY_ON_NULL_RETURN_VAL(key, EINA_FALSE);
1935    EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
1936    EINA_SAFETY_ON_NULL_RETURN_VAL(strings, EINA_FALSE);
1937
1938    *count = 0;
1939    *strings = NULL;
1940
1941    if (!e_connman_element_property_dict_get_stringshared(element, dict_name,
1942                                                          key, &type, &array))
1943       return EINA_FALSE;
1944
1945    if (type != DBUS_TYPE_ARRAY)
1946      {
1947         ERR("property %s.%s is not an array!", dict_name, key);
1948         return EINA_FALSE;
1949      }
1950
1951    if ((!array) || (!array->array) || (array->type == DBUS_TYPE_INVALID))
1952       return EINA_FALSE;
1953
1954    if (array->type != DBUS_TYPE_STRING)
1955      {
1956         ERR("property %s.%s is not an array of strings!", dict_name, key);
1957         return EINA_FALSE;
1958      }
1959
1960    *count = eina_array_count_get(array->array);
1961    ret = malloc(*count * sizeof(char *));
1962    if (!ret)
1963      {
1964         ERR("could not allocate return array of %d strings: %s",
1965             *count, strerror(errno));
1966         *count = 0;
1967         return EINA_FALSE;
1968      }
1969
1970    p = ret;
1971
1972    EINA_ARRAY_ITER_NEXT(array->array, i, item, iterator)
1973      {
1974         if (!item)
1975            continue;
1976
1977         *p = item;
1978         p++;
1979      }
1980    *count = p - ret;
1981    *strings = ret;
1982    return EINA_TRUE;
1983 }
1984
1985 /**
1986  * Get property value given its name.
1987  *
1988  * This will look into properties, to find the property.
1989  * If no property is found then @c EINA_FALSE is returned.
1990  *
1991  * If @c EINA_FALSE is returned, then this call failed and parameter-returned
1992  * values shall be considered invalid.
1993  *
1994  * @param element which element to get the property
1995  * @param name property name, must be previously stringshared
1996  * @param type if provided it will contain the value type.
1997  * @param value where to store the property value, must be a pointer to the
1998  *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
1999  *
2000  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
2001  */
2002 Eina_Bool
2003 e_connman_element_property_get_stringshared(const E_Connman_Element *element, const char *name, int *type, void *value)
2004 {
2005    const E_Connman_Element_Property *p;
2006
2007    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
2008    EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
2009    EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
2010
2011    EINA_INLIST_FOREACH(element->props, p)
2012    {
2013       if (p->name != name)
2014          continue;
2015
2016       if (type)
2017          *type = p->type;
2018
2019       switch (p->type)
2020         {
2021          case DBUS_TYPE_BOOLEAN:
2022             *(Eina_Bool *)value = p->value.boolean;
2023             return EINA_TRUE;
2024
2025          case DBUS_TYPE_BYTE:
2026             *(unsigned char *)value = p->value.byte;
2027             return EINA_TRUE;
2028
2029          case DBUS_TYPE_UINT16:
2030             *(unsigned short *)value = p->value.u16;
2031             return EINA_TRUE;
2032
2033          case DBUS_TYPE_UINT32:
2034             *(unsigned int *)value = p->value.u32;
2035             return EINA_TRUE;
2036
2037          case DBUS_TYPE_STRING:
2038             *(const char **)value = p->value.str;
2039             return EINA_TRUE;
2040
2041          case DBUS_TYPE_OBJECT_PATH:
2042             *(const char **)value = p->value.path;
2043             return EINA_TRUE;
2044
2045          case DBUS_TYPE_ARRAY:
2046             *(E_Connman_Array **)value = p->value.array;
2047             return EINA_TRUE;
2048
2049          default:
2050             ERR("don't know how to get property type %c (%d)",
2051                 p->type, p->type);
2052             return EINA_FALSE;
2053         }
2054    }
2055
2056    WRN("element %s (%p) has no property with name \"%s\".",
2057        element->path, element, name);
2058    return EINA_FALSE;
2059 }
2060
2061 /**
2062  * Get property value given its name.
2063  *
2064  * This will look into properties, to find the property.
2065  * If no property is found then @c EINA_FALSE is returned.
2066  *
2067  * If @c EINA_FALSE is returned, then this call failed and parameter-returned
2068  * values shall be considered invalid.
2069  *
2070  * @param element which element to get the property
2071  * @param name property name
2072  * @param type if provided it will contain the value type.
2073  * @param value where to store the property value, must be a pointer to the
2074  *        exact type, (Eina_Bool *) for booleans, (char **) for strings, and so on.
2075  *
2076  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
2077  */
2078 Eina_Bool
2079 e_connman_element_property_get(const E_Connman_Element *element, const char *name, int *type, void *value)
2080 {
2081    Eina_Bool ret;
2082    name = eina_stringshare_add(name);
2083    ret = e_connman_element_property_get_stringshared
2084          (element, name, type, value);
2085    eina_stringshare_del(name);
2086    return ret;
2087 }
2088
2089 struct e_connman_elements_for_each_data
2090 {
2091    Eina_Hash_Foreach cb;
2092    void             *data;
2093 };
2094
2095 static Eina_Bool
2096 _e_connman_elements_for_each(Eina_Hash *hash __UNUSED__, const char *key, void *data, void *fdata)
2097 {
2098    struct e_connman_elements_for_each_data *each_data = fdata;
2099
2100    each_data->cb(elements, key, data, each_data->data);
2101    return EINA_TRUE;
2102 }
2103
2104 /**
2105  * Call the given function for each existing element.
2106  *
2107  * @param cb function to call for each element. It will get as parameters,
2108  *        in order: the element pointer and the given @a user_data.
2109  * @param user_data data to give to @a cb for each element.
2110  */
2111 void
2112 e_connman_elements_for_each(Eina_Hash_Foreach cb, const void *user_data)
2113 {
2114    struct e_connman_elements_for_each_data data = {cb, (void *)user_data};
2115
2116    EINA_SAFETY_ON_NULL_RETURN(cb);
2117
2118    eina_hash_foreach(elements, (Eina_Hash_Foreach)_e_connman_elements_for_each,
2119                      &data);
2120 }
2121
2122 static Eina_Bool
2123 _e_connman_elements_get_allocate(unsigned int *count, E_Connman_Element ***p_elements)
2124 {
2125    *count = eina_hash_population(elements);
2126    if (*count == 0)
2127      {
2128         *p_elements = NULL;
2129         return EINA_TRUE;
2130      }
2131
2132    *p_elements = malloc(*count * sizeof(E_Connman_Element *));
2133    if (!*p_elements)
2134      {
2135         ERR("could not allocate return array of %d elements: %s",
2136             *count, strerror(errno));
2137         *count = 0;
2138         return EINA_FALSE;
2139      }
2140
2141    return EINA_TRUE;
2142 }
2143
2144 static Eina_Bool
2145 _e_connman_elements_get_all(Eina_Hash *hash __UNUSED__, const char *key __UNUSED__, void *data, void *fdata)
2146 {
2147    E_Connman_Element *element = data;
2148    E_Connman_Element ***p_ret = fdata;
2149
2150    **p_ret = element;
2151    (*p_ret)++;
2152    return EINA_TRUE;
2153 }
2154
2155 /**
2156  * Get all known elements.
2157  *
2158  * No reference is added to these elements, since there are no threads
2159  * in the system, you are free to add references yourself right after
2160  * the return of this call without race condition, elements by the
2161  * system (ie: elementRemoved signal)could only be touched on the next
2162  * main loop iteration.
2163  *
2164  * @param count return the number of elements in array.
2165  * @param p_elements array with all elements, these are not referenced
2166  *        and in no particular order, just set if return is @c EINA_TRUE.
2167  *
2168  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
2169  */
2170 Eina_Bool
2171 e_connman_elements_get_all(unsigned int *count, E_Connman_Element ***p_elements)
2172 {
2173    E_Connman_Element **p;
2174
2175    EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
2176    EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
2177
2178    if (!_e_connman_elements_get_allocate(count, p_elements))
2179       return EINA_FALSE;
2180
2181    p = *p_elements;
2182    eina_hash_foreach(elements, (Eina_Hash_Foreach)_e_connman_elements_get_all,
2183                      &p);
2184    return EINA_TRUE;
2185 }
2186
2187 struct e_connman_elements_get_all_str_data
2188 {
2189    E_Connman_Element **elements;
2190    int                 count;
2191    const char         *str;
2192 };
2193
2194 static Eina_Bool
2195 _e_connman_elements_get_all_type(Eina_Hash *hash __UNUSED__, const char *key __UNUSED__, void *e, void *user_data)
2196 {
2197    struct e_connman_elements_get_all_str_data *data = user_data;
2198    E_Connman_Element *element = e;
2199
2200    if ((data->str) && (element->interface != data->str))
2201       return EINA_TRUE;
2202
2203    data->elements[data->count] = element;
2204    data->count++;
2205    return EINA_TRUE;
2206 }
2207
2208 /**
2209  * Get all known elements of type.
2210  *
2211  * No reference is added to these elements, since there are no threads
2212  * in the system, you are free to add references yourself right after
2213  * the return of this call without race condition, elements by the
2214  * system (ie: ElementRemoved signal) could only be touched on the next
2215  * main loop iteration.
2216  *
2217  * @param type type to filter, or NULL to get all.
2218  * @param count return the number of elements in array.
2219  * @param p_elements array with all elements, these are not referenced
2220  *        and in no particular order, just set if return is @c EINA_TRUE.
2221  *
2222  * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
2223  *
2224  * @see e_connman_elements_get_all()
2225  */
2226 Eina_Bool
2227 e_connman_elements_get_all_type(const char *type, unsigned int *count, E_Connman_Element ***p_elements)
2228 {
2229    struct e_connman_elements_get_all_str_data data;
2230
2231    EINA_SAFETY_ON_NULL_RETURN_VAL(count, EINA_FALSE);
2232    EINA_SAFETY_ON_NULL_RETURN_VAL(p_elements, EINA_FALSE);
2233
2234    if (!_e_connman_elements_get_allocate(count, p_elements))
2235       return EINA_FALSE;
2236
2237    data.elements = *p_elements;
2238    data.count = 0;
2239    data.str = eina_stringshare_add(type);
2240    eina_hash_foreach(elements,
2241                      (Eina_Hash_Foreach)_e_connman_elements_get_all_type,
2242                      &data);
2243
2244    eina_stringshare_del(data.str);
2245    *count = data.count;
2246    return EINA_TRUE;
2247 }
2248
2249 /**
2250  * Get the element registered at given path.
2251  *
2252  * @param path the path to query for registered object.
2253  *
2254  * @return element pointer if found, NULL otherwise. No references are added.
2255  */
2256 E_Connman_Element *
2257 e_connman_element_get(const char *path)
2258 {
2259    E_Connman_Element *element;
2260
2261    EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
2262    element = eina_hash_find(elements, path);
2263
2264    return element;
2265 }
2266
2267 static void
2268 _e_connman_element_property_changed_callback(void *data, DBusMessage *msg)
2269 {
2270    E_Connman_Element *element = (E_Connman_Element *)data;
2271    DBusMessageIter itr, v_itr;
2272    int t, r, changed = 0;
2273    const char *name = NULL;
2274    void *value = NULL;
2275
2276    DBG("Property changed in element %s", element->path);
2277
2278    if (!_dbus_callback_check_and_init(msg, &itr, NULL))
2279       return;
2280
2281    t = dbus_message_iter_get_arg_type(&itr);
2282    if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
2283      {
2284         ERR("missing name in property changed signal");
2285         return;
2286      }
2287
2288    dbus_message_iter_get_basic(&itr, &name);
2289
2290    dbus_message_iter_next(&itr);
2291    t = dbus_message_iter_get_arg_type(&itr);
2292    if (!_dbus_iter_type_check(t, DBUS_TYPE_VARIANT))
2293      {
2294         ERR("missing value in property changed signal");
2295         return;
2296      }
2297
2298    dbus_message_iter_recurse(&itr, &v_itr);
2299    t = dbus_message_iter_get_arg_type(&v_itr);
2300
2301    if (t == DBUS_TYPE_ARRAY)
2302      {
2303         value = _e_connman_element_iter_get_array(&v_itr, name);
2304      }
2305    else if (t != DBUS_TYPE_INVALID)
2306      {
2307         dbus_message_iter_get_basic(&v_itr, &value);
2308      }
2309    else
2310      {
2311         ERR("property has invalid type %s", name);
2312         return;
2313      }
2314
2315    r = _e_connman_element_property_value_add(element, name, t, value);
2316    if (r < 0)
2317      {
2318         ERR("failed to add property value %s (%c)", name, t);
2319      }
2320    else if (r == 1)
2321      {
2322         INF("property value changed %s (%c)", name, t);
2323         changed = 1;
2324      }
2325
2326    if (changed)
2327       _e_connman_element_listeners_call(element);
2328 }
2329
2330 /**
2331  * Register the given path, possible creating and element and return it.
2332  *
2333  * This will check if path is already registered, in that case the
2334  * exiting element is returned. If it was not registered yet, a new
2335  * element is created, registered and returned.
2336  *
2337  * This call will not add extra references to the object.
2338  *
2339  * @param path the path to register the element
2340  *
2341  * @return the registered object, no references are added.
2342  */
2343 E_Connman_Element *
2344 e_connman_element_register(const char *path, const char *interface)
2345 {
2346    E_Connman_Element *element;
2347
2348    EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
2349    EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL);
2350
2351    element = eina_hash_find(elements, path);
2352    if (element)
2353       return element;
2354
2355    element = e_connman_element_new(path, interface);
2356    if (!element)
2357       return NULL;
2358
2359    if (!eina_hash_add(elements, element->path, element))
2360      {
2361         ERR("could not add element %s to hash, delete it.", path);
2362         e_connman_element_free(element);
2363         return NULL;
2364      }
2365
2366    element->signal_handler =
2367       e_dbus_signal_handler_add
2368          (e_connman_conn, e_connman_system_bus_name_get(),
2369          element->path, element->interface, "PropertyChanged",
2370          _e_connman_element_property_changed_callback, element);
2371
2372    e_connman_element_event_add(E_CONNMAN_EVENT_ELEMENT_ADD, element);
2373
2374    return element;
2375 }
2376
2377 static void
2378 _e_connman_element_event_unregister_and_free(void *data __UNUSED__, void *ev)
2379 {
2380    E_Connman_Element *element = ev;
2381    e_connman_element_unref(element);
2382 }
2383
2384 static void
2385 _e_connman_element_unregister_internal(E_Connman_Element *element)
2386 {
2387    if (element->signal_handler)
2388      {
2389         e_dbus_signal_handler_del(e_connman_conn, element->signal_handler);
2390         element->signal_handler = NULL;
2391      }
2392
2393    ecore_event_add(E_CONNMAN_EVENT_ELEMENT_DEL, element,
2394                    _e_connman_element_event_unregister_and_free, NULL);
2395 }
2396
2397 /**
2398  * Forget about the given element.
2399  *
2400  * This will remove the element from the pool of known objects, then
2401  * add an E_CONNMAN_EVENT_ELEMENT_DEL and after that will unreference it,
2402  * possible freeing it.
2403  *
2404  * @param element element to forget about. Its reference will be removed.
2405  */
2406 void
2407 e_connman_element_unregister(E_Connman_Element *element)
2408 {
2409    if (!element)
2410       return;
2411
2412    if (elements)
2413       eina_hash_del_by_key(elements, element->path);
2414 }
2415
2416 /**
2417  * Remove all known elements.
2418  *
2419  * This will remove all known elements but will NOT add any
2420  * E_CONNMAN_EVENT_ELEMENT_DEL to main loop.
2421  *
2422  * This is just useful to make sure next e_connman_manager_sync_elements()
2423  * will not leave any stale elements. This is unlikely to happen, as
2424  * E_Connman is supposed to catch all required events to avoid stale elements.
2425  */
2426 void
2427 e_connman_manager_clear_elements(void)
2428 {
2429    e_connman_elements_shutdown();
2430    e_connman_elements_init();
2431 }
2432
2433 /**
2434  * Creates elements hash.
2435  *
2436  * This has no init counter since its already guarded by other code.
2437  * @internal
2438  */
2439 void
2440 e_connman_elements_init(void)
2441 {
2442    EINA_SAFETY_ON_FALSE_RETURN(!elements);
2443    elements =
2444       eina_hash_string_superfast_new(EINA_FREE_CB
2445                                         (_e_connman_element_unregister_internal));
2446 }
2447
2448 void
2449 e_connman_elements_shutdown(void)
2450 {
2451    EINA_SAFETY_ON_FALSE_RETURN(!!elements);
2452    eina_hash_free(elements);
2453    elements = NULL;
2454 }
2455
2456 static inline Eina_Bool
2457 _e_connman_element_is(const E_Connman_Element *element, const char *interface)
2458 {
2459    return element->interface == interface;
2460 }
2461
2462 Eina_Bool
2463 e_connman_element_is_manager(const E_Connman_Element *element)
2464 {
2465    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
2466    return _e_connman_element_is(element, e_connman_iface_manager);
2467 }
2468
2469 Eina_Bool
2470 e_connman_element_is_profile(const E_Connman_Element *element)
2471 {
2472    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
2473    return _e_connman_element_is(element, e_connman_iface_profile);
2474 }
2475
2476 Eina_Bool
2477 e_connman_element_is_service(const E_Connman_Element *element)
2478 {
2479    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
2480    return _e_connman_element_is(element, e_connman_iface_service);
2481 }
2482
2483 Eina_Bool
2484 e_connman_element_is_technology(const E_Connman_Element *element)
2485 {
2486    EINA_SAFETY_ON_NULL_RETURN_VAL(element, EINA_FALSE);
2487    return _e_connman_element_is(element, e_connman_iface_technology);
2488 }
2489