4 #include <Elementary.h>
8 #include <contacts-ug.h>
13 #include "contacts-ofono-efl.h"
16 typedef struct _Contacts {
18 Eina_Bool contacts_on;
19 Ecore_Timer *reconnect;
20 struct ui_gadget *ug_all;
21 Eina_Hash *numbers, *hash_ids;
23 * hash_ids is a pair (tizen_db_id, Contact_Info)
24 * So we won't create a duplicated Contact_Info when dealing
29 typedef struct _Contact_Number {
31 unsigned int numberlen;
36 typedef struct _Contact_Name_Search {
39 } Contact_Name_Search;
41 typedef struct _Contact_Number_Entry {
44 } Contact_Number_Entry;
46 struct _Contact_Info {
48 const char *first_name;
49 const char *last_name;
50 const char *full_name;
54 Eina_Inlist *on_del_cbs;
57 Eina_Inlist *listeners;
63 typedef struct _Contact_Info_On_Del_Ctx {
65 void (*cb)(void *, const Contact_Info *);
67 } Contact_Info_On_Del_Ctx;
69 typedef struct _Contact_Info_On_Changed_Ctx {
71 void (*cb)(void *, Contact_Info *);
74 } Contact_Info_On_Changed_Ctx;
76 struct _Contact_Partial_Match
78 const Contact_Info *info;
80 Eina_Bool name_match : 1;
83 typedef struct _Partial_Match_Search
86 const Contacts *contacts;
87 } Partial_Match_Search;
90 static void _contact_number_entry_add(const char *number, Contact_Info *c_info);
92 static const char *phone_type_get(contact_number_h number);
93 static void _contact_info_free(Contact_Info *c_info);
95 static void _contact_number_add(char *number,
97 contact_number_h number_h);
99 const char *contact_info_number_check(const Contact_Info *c,
102 static void _partial_match_add(Eina_List **p_list, const char *type,
103 const Contact_Info *c_info,
104 Eina_Bool name_match)
106 Contact_Partial_Match *pm = malloc(sizeof(Contact_Partial_Match));
107 EINA_SAFETY_ON_NULL_RETURN(pm);
110 pm->name_match = name_match;
111 *p_list = eina_list_append(*p_list, pm);
114 static void _partial_number_match_add(Eina_List **p_list, const char *type,
115 const Contact_Info *c_info)
117 _partial_match_add(p_list, type, c_info, EINA_FALSE);
120 static bool _number_partial_search(contact_query_number_s *query, void *data)
122 Partial_Match_Search *pm_search = data;
123 const Contacts *contacts = pm_search->contacts;
127 contact_number_iterator_h it;
128 contact_number_h number_h;
129 Contact_Info *c_info;
132 c_info = eina_hash_find(contacts->hash_ids, &query->contact_db_id);
137 c_info = calloc(1, sizeof(Contact_Info));
138 EINA_SAFETY_ON_NULL_RETURN_VAL(c_info, true);
139 c_info->first_name = eina_stringshare_add(query->first_name);
140 c_info->last_name = eina_stringshare_add(query->last_name);
141 c_info->picture = eina_stringshare_add(query->contact_image_path);
142 c_info->id = query->contact_db_id;
143 if (contact_get_from_db(c_info->id, &tizen_c) != CONTACTS_ERROR_NONE)
146 if (contact_get_number_iterator(tizen_c, &it) !=
150 while (contact_number_iterator_has_next(it)) {
151 if (contact_number_iterator_next(&it, &number_h) !=
154 if (contact_number_get_number(number_h, &n) !=
157 _contact_number_add(n, c_info, number_h);
160 contact_destroy(tizen_c);
163 c_info->contacts = (Contacts *)contacts;
164 eina_hash_add(contacts->hash_ids, &c_info->id, c_info);
165 EINA_INLIST_FOREACH(c_info->numbers, cn)
166 _contact_number_entry_add(cn->number, c_info);
169 type = contact_info_number_check(c_info, query->phone_number);
170 _partial_number_match_add(&pm_search->matches, type,
176 static bool _name_partial_search(contact_query_name_s *query, void *data)
178 Partial_Match_Search *pm_search = data;
179 const Contacts *contacts = pm_search->contacts;
182 contact_number_iterator_h it;
183 contact_number_h number_h;
184 Contact_Info *c_info;
186 Eina_Bool c_info_new = EINA_FALSE;
189 c_info = eina_hash_find(contacts->hash_ids, &query->contact_db_id);
194 c_info = calloc(1, sizeof(Contact_Info));
195 EINA_SAFETY_ON_NULL_RETURN_VAL(c_info, true);
196 c_info->first_name = eina_stringshare_add(query->first_name);
197 c_info->last_name = eina_stringshare_add(query->last_name);
198 c_info->picture = eina_stringshare_add(query->contact_image_path);
199 c_info->id = query->contact_db_id;
200 if (contact_get_from_db(c_info->id, &tizen_c) != CONTACTS_ERROR_NONE)
203 if (contact_get_number_iterator(tizen_c, &it) !=
207 while (contact_number_iterator_has_next(it)) {
208 if (contact_number_iterator_next(&it, &number_h) !=
211 if (contact_number_get_number(number_h, &n) !=
214 _contact_number_add(n, c_info, number_h);
217 contact_destroy(tizen_c);
220 c_info->contacts = (Contacts *)contacts;
221 eina_hash_add(contacts->hash_ids, &c_info->id, c_info);
222 c_info_new = EINA_TRUE;
224 EINA_INLIST_FOREACH(c_info->numbers, cn) {
226 _contact_number_entry_add(cn->number, c_info);
227 _partial_match_add(&pm_search->matches, cn->type, c_info,
233 Eina_List *contact_partial_match_search(Evas_Object *obj, const char *query)
236 const Contacts *contacts;
238 Eina_Bool name_search = EINA_FALSE;
240 Partial_Match_Search pm_search;
242 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
243 EINA_SAFETY_ON_NULL_RETURN_VAL(query, NULL);
244 contacts = evas_object_data_get(obj, "contacts.ctx");
245 EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
247 if (!contacts->contacts_on)
250 /* Check if it is numeric */
251 query_number = alloca(strlen(query) + 1);
252 EINA_SAFETY_ON_NULL_RETURN_VAL(query_number, NULL);
253 for (i = 0, j = 0; query[i] != '\0'; i++) {
254 if (isalpha(query[i])) {
255 name_search = EINA_TRUE;
257 } else if (isdigit(query[i]))
258 query_number[j++] = query[i];
261 pm_search.contacts = contacts;
262 pm_search.matches = NULL;
265 if (contact_query_contact_by_name(_name_partial_search, query,
267 ERR("Could not search in contacts DB the name: %s",
272 query_number[j] = '\0';
273 if (contact_query_contact_by_number(_number_partial_search,
276 ERR("Could not search in contacts DB the number: %s",
282 return pm_search.matches;
285 void contact_partial_match_search_free(Eina_List *results)
287 Contact_Partial_Match *pm;
288 EINA_LIST_FREE(results, pm)
292 const char *contact_partial_match_type_get(const Contact_Partial_Match *pm)
294 EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL);
298 const Contact_Info *contact_partial_match_info_get(const Contact_Partial_Match *pm)
300 EINA_SAFETY_ON_NULL_RETURN_VAL(pm, NULL);
304 Eina_Bool contact_partial_match_name_match_get(const Contact_Partial_Match *pm)
306 EINA_SAFETY_ON_NULL_RETURN_VAL(pm, EINA_FALSE);
307 return pm->name_match;
310 Eina_List *contact_info_all_numbers_get(const Contact_Info *c)
315 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
317 EINA_INLIST_FOREACH(c->numbers, cn)
318 l = eina_list_append(l, cn->number);
323 static void _contact_number_entry_add(const char *number,
324 Contact_Info *c_info)
326 Contact_Number_Entry *e = eina_hash_find(c_info->contacts->numbers,
329 size_t numberlen = strlen(number);
330 e = calloc(1, sizeof(Contact_Number_Entry) + numberlen + 1);
331 EINA_SAFETY_ON_NULL_RETURN(e);
332 memcpy(e->number, number, numberlen + 1);
333 eina_hash_direct_add(c_info->contacts->numbers, e->number, e);
335 e->contacts = eina_list_append(e->contacts, c_info);
338 static void _contact_number_entry_del(const char *number,
339 Contact_Info *c_info)
341 Eina_Hash *numbers = c_info->contacts->numbers;
342 Contact_Number_Entry *e = eina_hash_find(numbers, number);
343 EINA_SAFETY_ON_NULL_RETURN(e);
344 e->contacts = eina_list_remove(e->contacts, c_info);
347 eina_hash_del_by_key(numbers, e->number);
348 /* hash's free callback will free "e" for me */
351 static Eina_Bool _is_alias(Contact_Number *cn, const char *alias)
353 unsigned int aliaslen = strlen(alias);
354 unsigned int suffix = cn->numberlen - aliaslen;
355 if (cn->numberlen < aliaslen)
358 return memcmp(cn->number + suffix, alias, aliaslen) == 0;
361 static Eina_Bool _contact_number_is_equal(Contact_Number *cn,
364 unsigned int numberlen = strlen(number);
365 if (cn->numberlen == numberlen &&
366 memcmp(cn->number, number, numberlen) == 0)
372 static void _alias_delete(Contact_Number *cn, Contact_Info *c_info)
374 Contact_Number *alias;
375 Eina_List *deleted_list = NULL;
377 EINA_INLIST_FOREACH(c_info->alias, alias) {
378 if (_is_alias(cn, alias->number))
379 deleted_list = eina_list_append(deleted_list, alias);
382 EINA_LIST_FREE(deleted_list, alias) {
383 c_info->alias = eina_inlist_remove(c_info->alias,
384 EINA_INLIST_GET(alias));
385 _contact_number_entry_del(alias->number, c_info);
390 static Eina_Bool _contact_phone_changed(Contact_Info *c_info,
394 Eina_Bool ret = EINA_FALSE;
395 Eina_List *deleted_list = NULL;
397 /* Looking for deleted phones */
398 EINA_INLIST_FOREACH(c_info->numbers, cn) {
399 Eina_Bool deleted = EINA_TRUE;
400 contact_number_iterator_h it;
401 contact_number_h number_h;
403 if (contact_get_number_iterator(contact, &it) !=
406 while (contact_number_iterator_has_next(it)) {
407 if (contact_number_iterator_next(&it, &number_h) !=
410 if (contact_number_get_number(number_h, &number) !=
413 Eina_Bool equal = _contact_number_is_equal(cn, number);
416 deleted = EINA_FALSE;
422 _contact_number_entry_del(cn->number, c_info);
423 deleted_list = eina_list_append(deleted_list, cn);
427 contact_number_iterator_h it;
428 if (contact_get_number_iterator(contact, &it) != CONTACTS_ERROR_NONE)
431 /* Looking for new phones */
432 while (contact_number_iterator_has_next(it)) {
433 Eina_Bool added = EINA_TRUE;
434 contact_number_h number_h;
436 if (contact_number_iterator_next(&it, &number_h) !=
439 if (contact_number_get_number(number_h, &number) !=
442 EINA_INLIST_FOREACH(c_info->numbers, cn) {
443 if (_contact_number_is_equal(cn, number)) {
449 _contact_number_add(number, c_info, number_h);
453 EINA_LIST_FREE(deleted_list, cn) {
454 c_info->numbers = eina_inlist_remove(c_info->numbers,
455 EINA_INLIST_GET(cn));
456 _alias_delete(cn, c_info);
463 static void _contact_info_on_del_dispatch(Contact_Info *c)
465 Eina_Inlist *lst = c->on_del_cbs;
466 c->on_del_cbs = NULL; /* avoid contact_info_on_del_callback_del() */
468 Contact_Info_On_Del_Ctx *ctx = EINA_INLIST_CONTAINER_GET
469 (lst, Contact_Info_On_Del_Ctx);
471 lst = eina_inlist_remove(lst, lst);
473 ctx->cb((void *)ctx->data, c);
478 static void _contact_info_on_changed_dispatch(Contact_Info *c)
480 Contact_Info_On_Changed_Ctx *ctx;
482 c->on_changed_cbs.walking++;
483 EINA_INLIST_FOREACH(c->on_changed_cbs.listeners, ctx) {
486 ctx->cb((void *)ctx->data, c);
488 c->on_changed_cbs.walking--;
490 if (c->on_changed_cbs.walking <= 0) {
491 EINA_LIST_FREE(c->on_changed_cbs.deleted, ctx) {
492 c->on_changed_cbs.listeners = eina_inlist_remove(
493 c->on_changed_cbs.listeners,
494 EINA_INLIST_GET(ctx));
500 static Eina_Bool _hash_foreach(const Eina_Hash *hash __UNUSED__,
501 const void *key __UNUSED__, void *data,
504 Eina_List **deleted = fdata;
505 Eina_Bool disp = EINA_FALSE;
506 Contact_Info *c_info = data;
507 contact_h contact = NULL;
508 contact_name_h name_h = NULL;
509 char *f_name = NULL, *l_name = NULL, *img = NULL;
511 contact_get_from_db(c_info->id, &contact);
512 /* Contact no longer exists. */
515 contact_get_name(contact, &name_h);
516 EINA_SAFETY_ON_NULL_GOTO(name_h, err_contact);
518 contact_name_get_detail(name_h, CONTACT_NAME_DETAIL_FIRST, &f_name);
519 contact_name_get_detail(name_h, CONTACT_NAME_DETAIL_LAST, &l_name);
520 contact_get_image(contact, &img);
522 if (eina_stringshare_replace(&c_info->first_name, f_name)) {
524 eina_stringshare_del(c_info->full_name);
525 c_info->full_name = NULL;
528 if (eina_stringshare_replace(&c_info->last_name, l_name)) {
530 eina_stringshare_del(c_info->full_name);
531 c_info->full_name = NULL;
534 disp |= eina_stringshare_replace(&c_info->picture, img);
536 disp |= _contact_phone_changed(c_info, contact);
539 _contact_info_on_changed_dispatch(c_info);
545 contact_destroy(contact);
549 *deleted = eina_list_append(*deleted, c_info);
553 static void _contact_db_changed(void *data)
555 Contacts *contacts = data;
556 Contact_Info *c_info;
557 Eina_List *deleted = NULL;
559 EINA_SAFETY_ON_NULL_RETURN(contacts);
560 eina_hash_foreach(contacts->hash_ids, _hash_foreach, &deleted);
562 EINA_LIST_FREE(deleted, c_info) {
564 /* _contact_info_free() will free the lists for me */
565 EINA_INLIST_FOREACH(c_info->alias, cn)
566 _contact_number_entry_del(cn->number, c_info);
567 EINA_INLIST_FOREACH(c_info->numbers, cn)
568 _contact_number_entry_del(cn->number, c_info);
569 eina_hash_del_by_key(contacts->hash_ids, &c_info->id);
573 static void _contact_number_add(char *number,
574 Contact_Info *c_info,
575 contact_number_h number_h)
577 unsigned int numberlen = strlen(number);
578 Contact_Number *cn = malloc(sizeof(Contact_Number) + numberlen + 1);
579 EINA_SAFETY_ON_NULL_RETURN(cn);
580 memcpy(cn->number, number, numberlen);
581 cn->numberlen = numberlen;
582 cn->number[numberlen] = '\0';
583 cn->type = phone_type_get(number_h);
584 c_info->numbers = eina_inlist_append(c_info->numbers,
585 EINA_INLIST_GET(cn));
588 bool _search_cb(contact_query_number_s *query, void *data)
590 Contact_Info **c_info = data;
593 contact_number_iterator_h it;
594 contact_number_h number_h;
596 *c_info = calloc(1, sizeof(Contact_Info));
597 EINA_SAFETY_ON_NULL_RETURN_VAL((*c_info), false);
598 (*c_info)->first_name = eina_stringshare_add(query->first_name);
599 (*c_info)->last_name = eina_stringshare_add(query->last_name);
600 (*c_info)->picture = eina_stringshare_add(query->contact_image_path);
601 (*c_info)->id = query->contact_db_id;
602 if (contact_get_from_db((*c_info)->id, &tizen_c) != CONTACTS_ERROR_NONE)
605 if (contact_get_number_iterator(tizen_c, &it) !=
609 while (contact_number_iterator_has_next(it)) {
610 if (contact_number_iterator_next(&it, &number_h) !=
613 if (contact_number_get_number(number_h, &n) !=
616 _contact_number_add(n, (*c_info), number_h);
619 contact_destroy(tizen_c);
623 static const char *phone_type_get(contact_number_h number)
625 contact_number_type_e type_e;
627 if (contact_number_get_type(number, &type_e) < 0)
631 case CONTACT_NUMBER_TYPE_NONE:
633 case CONTACT_NUMBER_TYPE_HOME:
635 case CONTACT_NUMBER_TYPE_WORK:
637 case CONTACT_NUMBER_TYPE_VOICE:
639 case CONTACT_NUMBER_TYPE_FAX:
641 case CONTACT_NUMBER_TYPE_MSG:
643 case CONTACT_NUMBER_TYPE_CELL:
645 case CONTACT_NUMBER_TYPE_PAGER:
647 case CONTACT_NUMBER_TYPE_BBS:
648 return "Bulletin board";
649 case CONTACT_NUMBER_TYPE_MODEM:
651 case CONTACT_NUMBER_TYPE_CAR:
653 case CONTACT_NUMBER_TYPE_ISDN:
655 case CONTACT_NUMBER_TYPE_VIDEO:
656 return "Video conference";
657 case CONTACT_NUMBER_TYPE_PCS:
658 return "Personal communicatior";
659 case CONTACT_NUMBER_TYPE_ASSISTANT:
660 return "Assistant telephone";
661 case CONTACT_NUMBER_TYPE_CUSTOM:
668 static const char *_alias_phone_type_match(Contact_Info *c_info,
672 EINA_INLIST_FOREACH(c_info->numbers, cn) {
673 if (_is_alias(cn, alias))
679 static Eina_Bool _alias_create(Contact_Info *c_info, const char *number)
681 unsigned int numberlen = strlen(number);
682 Contact_Number *cn = malloc(sizeof(Contact_Number) + numberlen + 1);
683 EINA_SAFETY_ON_NULL_RETURN_VAL(cn, EINA_FALSE);
684 memcpy(cn->number, number, numberlen);
685 cn->numberlen = numberlen;
686 cn->number[numberlen] = '\0';
687 cn->type = _alias_phone_type_match(c_info, number);
688 c_info->alias = eina_inlist_append(
689 c_info->alias, EINA_INLIST_GET(cn));
690 _contact_number_entry_add(cn->number, c_info);
694 Contact_Info *contact_search(Evas_Object *obj, const char *number,
697 Contact_Info *c_info = NULL, *found;
699 Contact_Number_Entry *entry;
701 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
702 EINA_SAFETY_ON_NULL_RETURN_VAL(number, NULL);
703 contacts = evas_object_data_get(obj, "contacts.ctx");
704 EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
706 if (!contacts->contacts_on)
709 entry = eina_hash_find(contacts->numbers, number);
712 c_info = eina_list_data_get(entry->contacts);
713 EINA_SAFETY_ON_NULL_RETURN_VAL(c_info, NULL);
717 if (contact_query_contact_by_number(_search_cb, number, &c_info) < 0) {
718 ERR("Could not fetch phone number: %s from DB", number);
725 /* Do we have this contact already ? */
726 found = eina_hash_find(contacts->hash_ids, &c_info->id);
729 _contact_info_free(c_info);
731 /* The user enterer an alias */
733 r = _alias_create(c_info, number);
734 EINA_SAFETY_ON_FALSE_RETURN_VAL(r, NULL);
737 c_info->contacts = contacts;
738 eina_hash_add(contacts->hash_ids, &c_info->id, c_info);
740 EINA_INLIST_FOREACH(c_info->numbers, cn)
741 _contact_number_entry_add(cn->number, c_info);
746 *type = contact_info_number_check(c_info, number);
750 const char *contact_info_picture_get(const Contact_Info *c)
752 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
756 const char *contact_info_full_name_get(const Contact_Info *c)
759 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
761 c2 = (Contact_Info *)c;
762 c2->full_name = eina_stringshare_printf("%s %s", c->first_name,
768 const char *contact_info_first_name_get(const Contact_Info *c)
770 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
771 return c->first_name;
774 const char *contact_info_last_name_get(const Contact_Info *c)
776 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
780 const char *contact_info_detail_get(const Contact_Info *c,
783 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
784 EINA_SAFETY_ON_NULL_RETURN_VAL(type, NULL);
786 /* Do not check in the alias list. Because here we want in fact a
789 EINA_INLIST_FOREACH(c->numbers, cn) {
790 if (strcmp(cn->type, type) == 0)
796 const char *contact_info_number_check(const Contact_Info *c,
799 EINA_SAFETY_ON_NULL_RETURN_VAL(c, NULL);
800 EINA_SAFETY_ON_NULL_RETURN_VAL(number, NULL);
803 EINA_INLIST_FOREACH(c->numbers, cn) {
804 if (_contact_number_is_equal(cn, number))
807 /* It could be an alias */
808 EINA_INLIST_FOREACH(c->alias, cn) {
809 if (_contact_number_is_equal(cn, number))
815 Eina_Bool contact_info_picture_set(Contact_Info *c __UNUSED__,
816 const char *filename __UNUSED__)
822 Eina_Bool contact_info_first_name_set(Contact_Info *c __UNUSED__,
823 const char *name __UNUSED__)
829 Eina_Bool contact_info_last_name_set(Contact_Info *c __UNUSED__,
830 const char *name __UNUSED__)
836 Eina_Bool contact_info_detail_set(Contact_Info *c __UNUSED__,
837 const char *type __UNUSED__,
838 const char *number __UNUSED__)
844 void contact_info_on_changed_callback_add(Contact_Info *c,
845 void (*cb)(void *data, Contact_Info *c),
848 Contact_Info_On_Changed_Ctx *ctx;
850 EINA_SAFETY_ON_NULL_RETURN(c);
851 EINA_SAFETY_ON_NULL_RETURN(cb);
853 ctx = calloc(1, sizeof(Contact_Info_On_Changed_Ctx));
854 EINA_SAFETY_ON_NULL_RETURN(ctx);
858 c->on_changed_cbs.listeners = eina_inlist_append(
859 c->on_changed_cbs.listeners, EINA_INLIST_GET(ctx));
862 void contact_info_on_changed_callback_del(Contact_Info *c,
863 void (*cb)(void *data, Contact_Info *c),
867 Contact_Info_On_Changed_Ctx *ctx, *found = NULL;
868 EINA_SAFETY_ON_NULL_RETURN(c);
869 EINA_SAFETY_ON_NULL_RETURN(cb);
871 EINA_INLIST_FOREACH(c->on_changed_cbs.listeners, ctx) {
872 if (ctx->cb == cb && ctx->data == data) {
881 if (c->on_changed_cbs.walking > 0) {
882 found->deleted = EINA_TRUE;
883 c->on_changed_cbs.deleted = eina_list_append(
884 c->on_changed_cbs.deleted, found);
888 c->on_changed_cbs.listeners = eina_inlist_remove(
889 c->on_changed_cbs.listeners, EINA_INLIST_GET(found));
893 void contact_info_on_del_callback_add(Contact_Info *c,
894 void (*cb)(void *data, const Contact_Info *c),
898 Contact_Info_On_Del_Ctx *ctx;
900 EINA_SAFETY_ON_NULL_RETURN(c);
901 EINA_SAFETY_ON_NULL_RETURN(cb);
903 ctx = calloc(1, sizeof(Contact_Info_On_Del_Ctx));
904 EINA_SAFETY_ON_NULL_RETURN(ctx);
908 c->on_del_cbs = eina_inlist_append(c->on_del_cbs, EINA_INLIST_GET(ctx));
911 void contact_info_on_del_callback_del(Contact_Info *c,
912 void (*cb)(void *data, const Contact_Info *c),
916 Contact_Info_On_Del_Ctx *ctx, *found = NULL;
917 EINA_SAFETY_ON_NULL_RETURN(c);
918 EINA_SAFETY_ON_NULL_RETURN(cb);
920 EINA_INLIST_FOREACH(c->on_del_cbs, ctx) {
921 if (ctx->cb == cb && ctx->data == data) {
930 c->on_del_cbs = eina_inlist_remove(c->on_del_cbs,
931 EINA_INLIST_GET(found));
936 void contact_info_del(Contact_Info *c_info __UNUSED__)
941 static void _contacts_ug_layout_create(struct ui_gadget *ug,
942 enum ug_mode mode __UNUSED__,
945 Contacts *contacts = priv;
946 EINA_SAFETY_ON_NULL_RETURN(ug);
947 elm_object_part_content_set(contacts->self, "elm.swallow.genlist",
951 static void _contact_info_free(Contact_Info *c_info)
954 _contact_info_on_del_dispatch(c_info);
955 EINA_SAFETY_ON_FALSE_RETURN(c_info->on_changed_cbs.walking == 0);
957 if (c_info->on_changed_cbs.deleted) {
958 ERR("contact still have changed deleted listeners: %p %s %s",
959 c_info, c_info->first_name, c_info->last_name);
960 eina_list_free(c_info->on_changed_cbs.deleted);
963 if (c_info->on_changed_cbs.listeners) {
964 while (c_info->on_changed_cbs.listeners) {
965 Contact_Info_On_Changed_Ctx *ctx;
967 ctx = EINA_INLIST_CONTAINER_GET(
968 c_info->on_changed_cbs.listeners,
969 Contact_Info_On_Changed_Ctx);
970 c_info->on_changed_cbs.listeners = eina_inlist_remove
971 (c_info->on_changed_cbs.listeners,
972 c_info->on_changed_cbs.listeners);
977 while (c_info->numbers) {
978 cn = EINA_INLIST_CONTAINER_GET(c_info->numbers,
980 c_info->numbers = eina_inlist_remove(c_info->numbers,
985 while (c_info->alias) {
986 cn = EINA_INLIST_CONTAINER_GET(c_info->alias,
988 c_info->alias = eina_inlist_remove(c_info->alias,
993 eina_stringshare_del(c_info->first_name);
994 eina_stringshare_del(c_info->last_name);
995 eina_stringshare_del(c_info->full_name);
996 eina_stringshare_del(c_info->picture);
1000 void _hash_elements_free(void *data)
1002 Contact_Info *c = data;
1003 _contact_info_free(c);
1006 void _numbers_hash_elements_free(void *data)
1008 Contact_Number_Entry *e = data;
1009 /*Contact_Info will be deleted by hash_ids */
1010 eina_list_free(e->contacts);
1014 static void _on_del(void *data, Evas *e __UNUSED__,
1015 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
1017 Contacts *contacts = data;
1018 eina_hash_free(contacts->hash_ids);
1019 eina_hash_free(contacts->numbers);
1020 ug_destroy(contacts->ug_all);
1021 if (contacts->reconnect)
1022 ecore_timer_del(contacts->reconnect);
1024 contacts_disconnect();
1027 static void _create_contacts_ug(Contacts *contacts)
1031 struct ui_gadget *ug;
1034 cbs.priv = contacts;
1035 cbs.layout_cb = _contacts_ug_layout_create;
1036 cbs.result_cb = NULL;
1037 cbs.destroy_cb = NULL;
1039 bd = bundle_create();
1040 EINA_SAFETY_ON_NULL_RETURN(bd);
1042 snprintf(buf, sizeof(buf), "%d", CT_UG_REQUEST_DETAIL);
1043 bundle_add(bd, CT_UG_BUNDLE_TYPE, buf);
1044 snprintf(buf, sizeof(buf), "%d", 1);
1045 bundle_add(bd, CT_UG_BUNDLE_ID, buf);
1047 ug = ug_create(NULL, UG_CONTACTS_LIST, UG_MODE_FRAMEVIEW, bd, &cbs);
1048 EINA_SAFETY_ON_NULL_GOTO(ug, err_ug);
1050 contacts->ug_all = ug;
1051 evas_object_data_set(contacts->self, "contacts.ctx", contacts);
1057 static Eina_Bool _contacts_reconnect(void *data)
1059 Contacts *contacts = data;
1061 if (contacts_connect() != CONTACTS_ERROR_NONE)
1062 return ECORE_CALLBACK_RENEW;
1064 contacts->contacts_on = EINA_TRUE;
1065 contacts->reconnect = NULL;
1066 contacts_add_contact_db_changed_cb(_contact_db_changed, contacts);
1067 _create_contacts_ug(contacts);
1068 return ECORE_CALLBACK_DONE;
1071 Evas_Object *contacts_add(Evas_Object *parent)
1075 contacts = calloc(1, sizeof(Contacts));
1076 EINA_SAFETY_ON_NULL_RETURN_VAL(contacts, NULL);
1077 contacts->self = layout_add(parent, "contacts_bg");
1078 EINA_SAFETY_ON_NULL_GOTO(contacts->self, err_layout);
1079 evas_object_event_callback_add(contacts->self, EVAS_CALLBACK_DEL,
1082 if (contacts_connect() != CONTACTS_ERROR_NONE) {
1083 WRN("Could not connect to the contacts DB");
1084 contacts->contacts_on = EINA_FALSE;
1085 contacts->reconnect = ecore_timer_add(1.0, _contacts_reconnect,
1088 contacts_add_contact_db_changed_cb(_contact_db_changed,
1090 contacts->contacts_on = EINA_TRUE;
1091 _create_contacts_ug(contacts);
1094 contacts->numbers = eina_hash_string_superfast_new(
1095 _numbers_hash_elements_free);
1096 EINA_SAFETY_ON_NULL_GOTO(contacts->numbers, err_hash);
1098 contacts->hash_ids = eina_hash_int32_new(_hash_elements_free);
1099 EINA_SAFETY_ON_NULL_GOTO(contacts->hash_ids, err_hash_id);
1101 return contacts->self;
1104 eina_hash_free(contacts->numbers);
1106 evas_object_del(contacts->self);
1107 if (contacts->reconnect)
1108 ecore_timer_del(contacts->reconnect);