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