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