Initialize the project.
[apps/livebox/data-provider-master.git] / src / ctx_client.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.tizenopensource.org/license
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <unistd.h>
19
20 #include <Ecore.h>
21 #include <gio/gio.h>
22
23 #include <vconf.h>
24 #include <dlog.h>
25
26 #include <packet.h>
27
28 #include "debug.h"
29 #include "slave_life.h"
30 #include "slave_rpc.h"
31 #include "client_life.h"
32 #include "instance.h"
33 #include "client_rpc.h"
34 #include "package.h"
35 #include "group.h"
36 #include "conf.h"
37 #include "util.h"
38 #include "rpc_to_slave.h"
39 #include "setting.h"
40 #include "ctx_wrapper.h"
41 #include "xmonitor.h"
42
43 static struct info {
44         Eina_List *event_list;
45 } s_info = {
46         .event_list = NULL,
47 };
48
49 struct pended_ctx_info {
50         char *cluster;
51         char *category;
52         char *pkgname;
53 };
54
55 static inline void processing_ctx_event(const char *cluster, const char *category, const char *pkgname)
56 {
57         slave_rpc_request_update(pkgname, "", cluster, category);
58         if (util_free_space(IMAGE_PATH) > MINIMUM_SPACE) {
59                 if (client_nr_of_subscriber(cluster, category) > 0) {
60                         double timestamp;
61                         struct inst_info *inst;
62
63                         timestamp = util_timestamp();
64                         inst = instance_create(NULL, timestamp, pkgname, DEFAULT_CONTENT, cluster, category, DEFAULT_PERIOD, 0, 0);
65                         if (!inst)
66                                 ErrPrint("Failed to create an instance (%s / %s - %s)\n", cluster, category, pkgname);
67                 } else {
68                         DbgPrint("No subscribed clients. Ignore ctx event (%s / %s - %s)\n", cluster, category, pkgname);
69                 }
70         } else {
71                 ErrPrint("Not enough space\n");
72         }
73
74         DbgPrint("Context event is updated\n");
75 }
76
77 static inline int is_already_pended(const char *c_name, const char *s_name, const char *pkgname)
78 {
79         Eina_List *l;
80         struct pended_ctx_info *info;
81
82         EINA_LIST_FOREACH(s_info.event_list, l, info) {
83                 if (strcmp(pkgname, info->pkgname))
84                         continue;
85
86                 if (strcmp(s_name, info->category))
87                         continue;
88
89                 if (strcmp(c_name, info->cluster))
90                         continue;
91
92                 return 1;
93         }
94
95         return 0;
96 }
97
98 static inline void push_pended_item(const char *c_name, const char *s_name, const char *pkgname)
99 {
100         struct pended_ctx_info *pending_item;
101
102         if (eina_list_count(s_info.event_list) >= MAX_PENDED_CTX_EVENTS) {
103                 ErrPrint("Reach to count of a maximum pended ctx events\n");
104                 return;
105         }
106
107         pending_item = malloc(sizeof(*pending_item));
108         if (!pending_item) {
109                 ErrPrint("Heap: %s\n", strerror(errno));
110                 return;
111         }
112
113         pending_item->cluster = strdup(c_name);
114         if (!pending_item->cluster) {
115                 ErrPrint("Heap: %s\n", strerror(errno));
116                 DbgFree(pending_item);
117                 return;
118         }
119
120         pending_item->category = strdup(s_name);
121         if (!pending_item->category) {
122                 ErrPrint("Heap: %s\n", strerror(errno));
123                 DbgFree(pending_item->cluster);
124                 DbgFree(pending_item);
125                 return;
126         }
127
128         pending_item->pkgname = strdup(pkgname);
129         if (!pending_item->pkgname) {
130                 ErrPrint("Heap: %s\n", strerror(errno));
131                 DbgFree(pending_item->cluster);
132                 DbgFree(pending_item->category);
133                 DbgFree(pending_item);
134                 return;
135         }
136
137         s_info.event_list = eina_list_append(s_info.event_list, pending_item);
138         ErrPrint("Context event is pended (%s/%s - %s)\n", c_name, s_name, pkgname);
139 }
140
141 static int ctx_changed_cb(struct context_item *item, void *user_data)
142 {
143         const char *c_name;
144         const char *s_name;
145         const char *pkgname;
146         struct context_info *info;
147         struct category *category;
148
149         info = group_context_info_from_item(item);
150         if (!info) {
151                 ErrPrint("Context info is not valid (%p)\n", item);
152                 return 0;
153         }
154
155         category = group_category_from_context_info(info);
156         if (!category) {
157                 ErrPrint("Category info is not valid: %p\n", info);
158                 return 0;
159         }
160
161         c_name = group_cluster_name_by_category(category);
162         s_name = group_category_name(category);
163         pkgname = group_pkgname_from_context_info(info);
164
165         if (!c_name || !s_name || !pkgname) {
166                 ErrPrint("Name is not valid (%s/%s/%s)\n", c_name, s_name, pkgname);
167                 return 0;
168         }
169
170         if (xmonitor_is_paused()) {
171                 if (!is_already_pended(c_name, s_name, pkgname)) {
172                         push_pended_item(c_name, s_name, pkgname);
173                 } else {
174                         DbgPrint("Already pended event : %s %s / %s\n", c_name, s_name, pkgname);
175                 }
176         } else {
177                 processing_ctx_event(c_name, s_name, pkgname);
178         }
179
180         return 0;
181 }
182
183 static inline void enable_event_handler(struct context_info *info)
184 {
185         Eina_List *l;
186         Eina_List *item_list;
187         struct context_item *item;
188
189         item_list = group_context_item_list(info);
190         EINA_LIST_FOREACH(item_list, l, item) {
191                 void *handler;
192
193                 handler = group_context_item_data(item, "callback");
194                 if (handler) {
195                         ErrPrint("Already registered ctx callback\n");
196                         continue;
197                 }
198
199                 handler = ctx_wrapper_register_callback(item, ctx_changed_cb, NULL);
200                 if (group_context_item_add_data(item, "callback", handler) < 0)
201                         ctx_wrapper_unregister_callback(handler);
202         }
203 }
204
205 static inline void register_callbacks(void)
206 {
207         Eina_List *cluster_list;
208         Eina_List *l1;
209         struct cluster *cluster;
210
211         Eina_List *category_list;
212         Eina_List *l2;
213         struct category *category;
214
215         Eina_List *info_list;
216         Eina_List *l3;
217         struct context_info *info;
218
219         cluster_list = group_cluster_list();
220         EINA_LIST_FOREACH(cluster_list, l1, cluster) {
221                 category_list = group_category_list(cluster);
222                 EINA_LIST_FOREACH(category_list, l2, category) {
223                         info_list = group_context_info_list(category);
224                         EINA_LIST_FOREACH(info_list, l3, info) {
225                                 enable_event_handler(info);
226                         } // info
227                 } // category
228         } // cluster
229 }
230
231 HAPI int ctx_enable_event_handler(struct context_info *info)
232 {
233         int enabled;
234
235         if (vconf_get_int(SYS_CLUSTER_KEY, &enabled) < 0)
236                 enabled = 0;
237
238         if (!enabled) {
239                 DbgPrint("CTX in not enabled\n");
240                 return 0;
241         }
242
243         enable_event_handler(info);
244         return 0;
245 }
246
247 HAPI int ctx_disable_event_handler(struct context_info *info)
248 {
249         Eina_List *l;
250         Eina_List *item_list;
251         struct context_item *item;
252
253         item_list = group_context_item_list(info);
254         EINA_LIST_FOREACH(item_list, l, item) {
255                 void *handler;
256                 handler = group_context_item_del_data(item, "callback");
257                 if (handler)
258                         ctx_wrapper_unregister_callback(handler);
259         }
260
261         return 0;
262 }
263
264 static inline void unregister_callbacks(void)
265 {
266         Eina_List *cluster_list;
267         Eina_List *l1;
268         struct cluster *cluster;
269
270         Eina_List *category_list;
271         Eina_List *l2;
272         struct category *category;
273
274         Eina_List *info_list;
275         Eina_List *l3;
276         struct context_info *info;
277
278         cluster_list = group_cluster_list();
279         EINA_LIST_FOREACH(cluster_list, l1, cluster) {
280                 category_list = group_category_list(cluster);
281                 EINA_LIST_FOREACH(category_list, l2, category) {
282                         info_list = group_context_info_list(category);
283                         EINA_LIST_FOREACH(info_list, l3, info) {
284                                 ctx_disable_event_handler(info);
285                         } // info
286                 } // category
287         } // cluster
288 }
289
290 static void ctx_vconf_cb(keynode_t *node, void *data)
291 {
292         int enabled;
293
294         if (!node) {
295                 /*!< Enable this for default option */
296                 if (vconf_get_int(SYS_CLUSTER_KEY, &enabled) < 0)
297                         enabled = 0;
298         } else {
299                 enabled = vconf_keynode_get_int(node);
300         }
301
302         if (!enabled) {
303                 unregister_callbacks();
304                 ctx_wrapper_disable();
305                 return;
306         }
307
308         ctx_wrapper_enable();
309         register_callbacks();
310 }
311
312 static int xmonitor_pause_cb(void *data)
313 {
314         DbgPrint("XMonitor Paused: do nothing\n");
315         return 0;
316 }
317
318 static int xmonitor_resume_cb(void *data)
319 {
320         struct pended_ctx_info *item;
321
322         EINA_LIST_FREE(s_info.event_list, item) {
323                 DbgPrint("Pended ctx event for %s - %s / %s\n", item->cluster, item->category, item->pkgname);
324                 processing_ctx_event(item->cluster, item->category, item->pkgname);
325
326                 DbgFree(item->cluster);
327                 DbgFree(item->category);
328                 DbgFree(item->pkgname);
329                 DbgFree(item);
330         }
331
332         return 0;
333 }
334
335 HAPI int ctx_client_init(void)
336 {
337         int ret;
338
339         xmonitor_add_event_callback(XMONITOR_PAUSED, xmonitor_pause_cb, NULL);
340         xmonitor_add_event_callback(XMONITOR_RESUMED, xmonitor_resume_cb, NULL);
341
342         ret = vconf_notify_key_changed(SYS_CLUSTER_KEY, ctx_vconf_cb, NULL);
343         if (ret < 0)
344                 ErrPrint("Failed to register the system_cluster vconf\n");
345
346         ctx_vconf_cb(NULL, NULL);
347         return 0;
348 }
349
350 HAPI int ctx_client_fini(void)
351 {
352         vconf_ignore_key_changed(SYS_CLUSTER_KEY, ctx_vconf_cb);
353
354         xmonitor_del_event_callback(XMONITOR_PAUSED, xmonitor_pause_cb, NULL);
355         xmonitor_del_event_callback(XMONITOR_RESUMED, xmonitor_resume_cb, NULL);
356         return 0;
357 }
358
359 /* End of a file */