Adding history infrastructure.
[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
10 #include "ofono.h"
11 #include "log.h"
12
13 #define HISTORY_ENTRY "history"
14
15 typedef struct _Call_Info_List {
16         Eina_List *list;
17 } Call_Info_List;
18
19 typedef struct _History {
20         Eet_File *log;
21         Eet_Data_Descriptor *edd;
22         Eet_Data_Descriptor *edd_list;
23         Call_Info_List *calls;
24 } History;
25
26 typedef struct _Call_Info {
27         int state;
28         long long start_time;
29         long long end_time;
30         const char *line_id;
31         const char *name;
32 } Call_Info;
33
34 static OFono_Callback_List_Call_Node *callback_node_call_removed = NULL;
35 static OFono_Callback_List_Call_Node *callback_node_call_changed = NULL;
36
37 static Call_Info *_history_call_info_list_search(Eina_List *list,
38                                                         const char *line_id) {
39         Call_Info *call_info;
40         Eina_List *l;
41
42         EINA_LIST_FOREACH (list, l, call_info)
43                 if (!strcmp(call_info->line_id, line_id))
44                         return call_info;
45
46         return NULL;
47 }
48
49 static void _history_call_changed(void *data, OFono_Call *call) {
50         History *history = data;
51         const char *line_id = ofono_call_line_id_get(call);
52         Call_Info *call_info;
53         OFono_Call_State state = ofono_call_state_get(call);
54
55         call_info =
56                 _history_call_info_list_search(history->calls->list, line_id);
57
58         if (call_info) {
59                 /* Otherwise I missed the call or the person didn't
60                  * awnser my call!
61                  */
62                 if ((call_info->state == OFONO_CALL_STATE_INCOMING ||
63                         call_info->state == OFONO_CALL_STATE_DIALING) &&
64                         state != OFONO_CALL_STATE_DISCONNECTED)
65                         call_info->state = state;
66                 return;
67         }
68         call_info = calloc(1, sizeof(Call_Info));
69         EINA_SAFETY_ON_NULL_RETURN(call_info);
70
71         call_info->state = state;
72         call_info->start_time = time(NULL);
73         call_info->line_id = eina_stringshare_add(line_id);
74         call_info->name = eina_stringshare_add(ofono_call_name_get(call));
75         history->calls->list =
76                 eina_list_prepend(history->calls->list, call_info);
77 }
78
79 static void _history_call_log_save(History *history) {
80         if (!(eet_data_write(history->log,
81                                 history->edd_list, HISTORY_ENTRY,
82                                 history->calls, EET_COMPRESSION_DEFAULT)))
83                 ERR("Could in the history log file");
84 }
85
86 static void _history_call_removed(void *data, OFono_Call *call) {
87         History *history = data;
88         const char *line_id = ofono_call_line_id_get(call);
89         Call_Info *call_info;
90         time_t start;
91         char *tm;
92
93         call_info =
94                 _history_call_info_list_search(history->calls->list, line_id);
95         EINA_SAFETY_ON_NULL_RETURN(call_info);
96         start = call_info->start_time;
97         tm = ctime(&start);
98
99         if (call_info->state == OFONO_CALL_STATE_INCOMING)
100                 INF("Missed call - Id: %s - time: %s", line_id, tm);
101         else if (call_info->state == OFONO_CALL_STATE_DIALING)
102                 INF("Call not answered - Id: %s - time: %s", line_id, tm);
103         else
104                 INF("A call has ended - Id: %s - time: %s", line_id, tm);
105
106         call_info->end_time = time(NULL);
107         _history_call_log_save(history);
108 }
109
110 static void _call_info_free(Call_Info *call_info) {
111         eina_stringshare_del(call_info->line_id);
112         eina_stringshare_del(call_info->name);
113         free(call_info);
114 }
115
116 static void _on_del(void *data, Evas *e __UNUSED__,
117                         Evas_Object *obj __UNUSED__, void *event __UNUSED__) {
118         History *history = data;
119         Call_Info *call_info;
120         ofono_call_removed_cb_del(callback_node_call_removed);
121         ofono_call_changed_cb_del(callback_node_call_changed);
122         eet_close(history->log);
123         eet_data_descriptor_free(history->edd);
124         eet_data_descriptor_free(history->edd_list);
125         EINA_LIST_FREE(history->calls->list, call_info) {
126                 _call_info_free(call_info);
127         }
128         free(history->calls);
129         free(history);
130         eet_shutdown();
131 }
132
133 static void _history_call_info_descriptor_init(Eet_Data_Descriptor **edd,
134                                                 Eet_Data_Descriptor **edd_list) {
135         Eet_Data_Descriptor_Class eddc;
136
137         EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Call_Info);
138         *edd = eet_data_descriptor_stream_new(&eddc);
139
140         EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Call_Info_List);
141         *edd_list = eet_data_descriptor_stream_new(&eddc);
142
143         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
144                                         "state", state, EET_T_INT);
145         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
146                                         "start_time", start_time, EET_T_LONG_LONG);
147         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
148                                         "end_time", end_time, EET_T_LONG_LONG);
149         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
150                                         "line_id", line_id, EET_T_STRING);
151         EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
152                                         "name", name, EET_T_STRING);
153
154         EET_DATA_DESCRIPTOR_ADD_LIST(*edd_list, Call_Info_List, "list", list,
155                                         *edd);
156 }
157
158 static void _history_call_log_read(History *history) {
159         Call_Info *call_info;
160         Eina_List *l;
161         history->calls = eet_data_read(history->log, history->edd_list,
162                                                         HISTORY_ENTRY);
163
164         EINA_SAFETY_ON_NULL_GOTO(history->calls, calls_list_alloc);
165
166         EINA_LIST_FOREACH (history->calls->list, l, call_info) {
167                 if (!call_info)
168                         continue;
169
170                 DBG("Line id: %s", call_info->line_id);
171                 DBG("Name: %s", call_info->name);
172                 DBG("Start time: %s", ctime((time_t *)&call_info->start_time));
173                 DBG("End time: %s", ctime((time_t *)&call_info->end_time));
174                 DBG("State: %d", call_info->state);
175         }
176         return;
177
178 calls_list_alloc:
179         history->calls = calloc(1, sizeof(Call_Info_List));
180 }
181
182 Evas_Object *history_add(Evas_Object *parent) {
183         History *history;
184         Evas_Object *obj = elm_label_add(parent);
185         const char *config_path;
186         char path[PATH_MAX];
187
188         eet_init();
189         history = calloc(1, sizeof(History));
190         EINA_SAFETY_ON_NULL_RETURN_VAL(history, NULL);
191
192         config_path = efreet_config_home_get();
193         snprintf(path, sizeof(path), "%s%s", config_path, PACKAGE_NAME);
194         ecore_file_mkpath(path);
195         snprintf(path, sizeof(path), "%s%s/history.eet", config_path,
196                         PACKAGE_NAME);
197         history->log = eet_open(path, EET_FILE_MODE_READ_WRITE);
198         EINA_SAFETY_ON_NULL_RETURN_VAL(history->log, NULL);
199
200         _history_call_info_descriptor_init(&history->edd, &history->edd_list);
201         _history_call_log_read(history);
202         EINA_SAFETY_ON_NULL_RETURN_VAL(history->calls, NULL);
203         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _on_del,
204                                         history);
205         callback_node_call_changed =
206                 ofono_call_changed_cb_add(_history_call_changed, history);
207         callback_node_call_removed =
208                 ofono_call_removed_cb_add(_history_call_removed, history);
209         return obj;
210 }