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