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