minor: fix -Wshadow warning regarding "time"
[profile/ivi/lemolo.git] / dialer / history.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include <Elementary.h>
5 #include <Eet.h>
6 #include <Eina.h>
7 #include <time.h>
8 #include <limits.h>
9 #include <string.h>
10
11 #include "ofono.h"
12 #include "log.h"
13 #include "util.h"
14
15 #define HISTORY_ENTRY "history"
16
17 typedef struct _Call_Info_List {
18         Eina_List *list;
19 } Call_Info_List;
20
21 typedef struct _History {
22         Eet_File *log;
23         Eet_Data_Descriptor *edd;
24         Eet_Data_Descriptor *edd_list;
25         Call_Info_List *calls;
26         Elm_Genlist_Item_Class *itc;
27         Evas_Object *genlist_all, *genlist_missed;
28         Elm_Object_Item *all, *missed;
29 } History;
30
31 typedef struct _Call_Info {
32         int state;
33         long long start_time;
34         long long end_time;
35         const char *line_id;
36         const char *name;
37 } Call_Info;
38
39 static OFono_Callback_List_Call_Node *callback_node_call_removed = NULL;
40 static OFono_Callback_List_Call_Node *callback_node_call_changed = NULL;
41
42 static Call_Info *_history_call_info_list_search(Eina_List *list,
43                                                         const char *line_id) {
44         Call_Info *call_info;
45         Eina_List *l;
46
47         EINA_LIST_FOREACH (list, l, call_info)
48                 if (!strcmp(call_info->line_id, line_id))
49                         return call_info;
50
51         return NULL;
52 }
53
54 static void _history_call_changed(void *data, OFono_Call *call) {
55         History *history = data;
56         const char *line_id = ofono_call_line_id_get(call);
57         Call_Info *call_info;
58         OFono_Call_State state = ofono_call_state_get(call);
59
60         call_info =
61                 _history_call_info_list_search(history->calls->list, line_id);
62
63         if (call_info) {
64                 /* Otherwise I missed the call or the person didn't
65                  * awnser my call!
66                  */
67                 if ((call_info->state == OFONO_CALL_STATE_INCOMING ||
68                         call_info->state == OFONO_CALL_STATE_DIALING) &&
69                         state != OFONO_CALL_STATE_DISCONNECTED)
70                         call_info->state = state;
71                 return;
72         }
73         call_info = calloc(1, sizeof(Call_Info));
74         EINA_SAFETY_ON_NULL_RETURN(call_info);
75
76         call_info->state = state;
77         call_info->start_time = time(NULL);
78         call_info->line_id = eina_stringshare_add(line_id);
79         call_info->name = eina_stringshare_add(ofono_call_name_get(call));
80         history->calls->list =
81                 eina_list_prepend(history->calls->list, call_info);
82 }
83
84 static void _history_call_log_save(History *history) {
85         if (!(eet_data_write(history->log,
86                                 history->edd_list, HISTORY_ENTRY,
87                                 history->calls, EET_COMPRESSION_DEFAULT)))
88                 ERR("Could in the history log file");
89 }
90
91 static void _history_call_removed(void *data, OFono_Call *call) {
92         History *history = data;
93         const char *line_id = ofono_call_line_id_get(call);
94         Call_Info *call_info;
95         time_t start;
96         char *tm;
97
98         call_info =
99                 _history_call_info_list_search(history->calls->list, line_id);
100         EINA_SAFETY_ON_NULL_RETURN(call_info);
101         start = call_info->start_time;
102         tm = ctime(&start);
103
104         if (call_info->state == OFONO_CALL_STATE_INCOMING) {
105                 INF("Missed call - Id: %s - time: %s", line_id, tm);
106                 elm_genlist_item_append(history->genlist_missed, history->itc,
107                                         call_info, NULL, ELM_GENLIST_ITEM_NONE,
108                                         NULL, NULL);
109         } else if (call_info->state == OFONO_CALL_STATE_DIALING)
110                 INF("Call not answered - Id: %s - time: %s", line_id, tm);
111         else
112                 INF("A call has ended - Id: %s - time: %s", line_id, tm);
113
114         call_info->end_time = time(NULL);
115         _history_call_log_save(history);
116         elm_genlist_item_append(history->genlist_all, history->itc, call_info,
117                                 NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
118 }
119
120 static void _call_info_free(Call_Info *call_info) {
121         eina_stringshare_del(call_info->line_id);
122         eina_stringshare_del(call_info->name);
123         free(call_info);
124 }
125
126 static void _on_del(void *data, Evas *e __UNUSED__,
127                         Evas_Object *obj __UNUSED__, void *event __UNUSED__) {
128         History *history = data;
129         Call_Info *call_info;
130         ofono_call_removed_cb_del(callback_node_call_removed);
131         ofono_call_changed_cb_del(callback_node_call_changed);
132         eet_close(history->log);
133         eet_data_descriptor_free(history->edd);
134         eet_data_descriptor_free(history->edd_list);
135         EINA_LIST_FREE(history->calls->list, call_info) {
136                 _call_info_free(call_info);
137         }
138         free(history->calls);
139         elm_genlist_item_class_free(history->itc);
140         free(history);
141         eet_shutdown();
142 }
143
144 static void _history_call_info_descriptor_init(Eet_Data_Descriptor **edd,
145                                                 Eet_Data_Descriptor **edd_list) {
146         Eet_Data_Descriptor_Class eddc;
147
148         EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Call_Info);
149         *edd = eet_data_descriptor_stream_new(&eddc);
150
151         EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Call_Info_List);
152         *edd_list = eet_data_descriptor_stream_new(&eddc);
153
154         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
155                                         "state", state, EET_T_INT);
156         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
157                                         "start_time", start_time, EET_T_LONG_LONG);
158         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
159                                         "end_time", end_time, EET_T_LONG_LONG);
160         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
161                                         "line_id", line_id, EET_T_STRING);
162         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
163                                         "name", name, EET_T_STRING);
164
165         EET_DATA_DESCRIPTOR_ADD_LIST(*edd_list, Call_Info_List, "list", list,
166                                         *edd);
167 }
168
169 static void _history_call_log_read(History *history) {
170         Call_Info *call_info;
171         Eina_List *l;
172         history->calls = eet_data_read(history->log, history->edd_list,
173                                                         HISTORY_ENTRY);
174
175         EINA_SAFETY_ON_NULL_GOTO(history->calls, calls_list_alloc);
176
177         EINA_LIST_FOREACH (history->calls->list, l, call_info) {
178                 if (!call_info)
179                         continue;
180                 elm_genlist_item_append(history->genlist_all, history->itc,
181                                         call_info, NULL, ELM_GENLIST_ITEM_NONE,
182                                         NULL, NULL);
183                 if (call_info->state == OFONO_CALL_STATE_INCOMING)
184                         elm_genlist_item_append(history->genlist_missed,
185                                                 history->itc, call_info, NULL,
186                                                 ELM_GENLIST_ITEM_NONE,
187                                                 NULL, NULL);
188         }
189         return;
190
191 calls_list_alloc:
192         history->calls = calloc(1, sizeof(Call_Info_List));
193 }
194
195 static char *_item_label_get(void *data, Evas_Object *obj, const char *part) {
196         Call_Info *call_info = data;
197         char *buf;
198         const char *name, *call_state;
199         char *t;
200
201         name = call_info->name;
202
203         if (!call_info->name || call_info->name[0] == '\0')
204                 name = call_info->line_id;
205
206         if (call_info->state == OFONO_CALL_STATE_INCOMING)
207                 call_state = "Missed";
208         else if (call_info->state == OFONO_CALL_STATE_DIALING)
209                 call_state = "Not Awnsered";
210         else
211                 call_state = "Completed";
212
213         t = date_format(call_info->end_time);
214
215         if (asprintf(&buf, "%s-%s-%s", name, call_state, t) < 0)
216                 buf = strdup("");
217
218         free(t);
219         return buf;
220 }
221
222 static void _btn_naviframe_next_click(void *data, Evas_Object *obj,
223                                         void *event_inf) {
224         History *history = data;
225         elm_naviframe_item_promote(history->missed);
226 }
227
228 static void _btn_naviframe_prev_click(void *data, Evas_Object *obj,
229                                         void *event_inf) {
230         History *history = data;
231         elm_naviframe_item_promote(history->all);
232 }
233
234 Evas_Object *history_add(Evas_Object *parent) {
235         History *history;
236         const char *config_path;
237         char path[PATH_MAX];
238         Elm_Genlist_Item_Class *itc;
239         Evas_Object *obj, *genlist_all, *genlist_missed, *btn;
240
241         eet_init();
242         history = calloc(1, sizeof(History));
243         EINA_SAFETY_ON_NULL_RETURN_VAL(history, NULL);
244
245         obj = elm_naviframe_add(parent);
246         EINA_SAFETY_ON_NULL_GOTO(obj, err_naviframe);
247         elm_naviframe_prev_btn_auto_pushed_set(obj, EINA_FALSE);
248
249         genlist_all = elm_genlist_add(obj);
250         EINA_SAFETY_ON_NULL_GOTO(genlist_all, err_object_new);
251
252         genlist_missed = elm_genlist_add(obj);
253         EINA_SAFETY_ON_NULL_GOTO(genlist_missed, err_object_new);
254
255         itc = elm_genlist_item_class_new();
256         EINA_SAFETY_ON_NULL_GOTO(itc, err_object_new);
257         itc->item_style = "default";
258         itc->func.text_get = _item_label_get;
259         itc->func.content_get = NULL;
260         itc->func.state_get = NULL;
261         itc->func.del = NULL;
262         history->genlist_all = genlist_all;
263         history->genlist_missed = genlist_missed;
264
265         btn = elm_button_add(obj);
266         EINA_SAFETY_ON_NULL_GOTO(btn, err_item_class);
267         elm_object_text_set(btn, "Missed");
268         evas_object_smart_callback_add(btn, "clicked",
269                                         _btn_naviframe_next_click, history);
270
271         Elm_Object_Item *all =
272                 elm_naviframe_item_push(obj, "All", NULL, btn, genlist_all,
273                                         NULL);
274         EINA_SAFETY_ON_NULL_GOTO(all, err_item_class);
275
276         btn = elm_button_add(obj);
277         EINA_SAFETY_ON_NULL_GOTO(btn, err_item_class);
278         elm_object_text_set(btn, "All");
279         evas_object_smart_callback_add(btn, "clicked",
280                                         _btn_naviframe_prev_click, history);
281
282         Elm_Object_Item *missed =
283                 elm_naviframe_item_push(obj, "Missed", btn, NULL,
284                                         genlist_missed, NULL);
285         EINA_SAFETY_ON_NULL_GOTO(missed, err_item_class);
286         elm_naviframe_item_promote(all);
287
288         history->all = all;
289         history->missed = missed;
290         history->itc = itc;
291
292         config_path = efreet_config_home_get();
293         snprintf(path, sizeof(path), "%s%s", config_path, PACKAGE_NAME);
294         ecore_file_mkpath(path);
295         snprintf(path, sizeof(path), "%s%s/history.eet", config_path,
296                         PACKAGE_NAME);
297         history->log = eet_open(path, EET_FILE_MODE_READ_WRITE);
298         EINA_SAFETY_ON_NULL_RETURN_VAL(history->log, NULL);
299
300         _history_call_info_descriptor_init(&history->edd, &history->edd_list);
301         _history_call_log_read(history);
302         EINA_SAFETY_ON_NULL_RETURN_VAL(history->calls, NULL);
303         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _on_del,
304                                         history);
305         callback_node_call_changed =
306                 ofono_call_changed_cb_add(_history_call_changed, history);
307         callback_node_call_removed =
308                 ofono_call_removed_cb_add(_history_call_removed, history);
309         return obj;
310
311 err_item_class:
312         elm_genlist_item_class_free(itc);
313 err_object_new:
314         free(obj);
315 err_naviframe:
316         free(history);
317         return NULL;
318 }