Fix static analysis issue
[platform/core/appfw/app-core.git] / src / base / appcore_base.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
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
18 #define _GNU_SOURCE
19
20 #include <stdbool.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <malloc.h>
28 #include <locale.h>
29 #include <libintl.h>
30 #include <linux/limits.h>
31 #include <glib.h>
32 #include <gio/gio.h>
33 #include <sys/time.h>
34 #include <dlfcn.h>
35 #include <vconf.h>
36 #include <aul.h>
37 #include <bundle_internal.h>
38 #include <sensor_internal.h>
39 #include "appcore_base.h"
40 #include "appcore_base_private.h"
41
42 #define PATH_LOCALE "locale"
43 #define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
44 #define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer"
45 #define RESOURCED_FREEZER_SIGNAL "FreezerState"
46
47 typedef struct _appcore_base_context {
48         appcore_base_ops ops;
49         void *data;
50         int argc;
51         char **argv;
52         unsigned int tid;
53         bool suspended_state;
54         bool allowed_bg;
55         bool dirty;
56 } appcore_base_context;
57
58 typedef struct _appcore_base_event_node {
59         int type;
60         appcore_base_event_cb cb;
61         void *data;
62 } appcore_base_event_node;
63
64 typedef struct _appcore_base_rotation {
65         int conn;
66         int lock;
67         int ref;
68         enum appcore_base_rm rm;
69 } appcore_base_rotation;
70
71 struct lang_info_s {
72         char *parent;
73         GList *list;
74 };
75
76 static appcore_base_context __context;
77 static GList *__events;
78 static GDBusConnection *__bus;
79 static guint __suspend_dbus_handler_initialized;
80 static char *__locale_dir;
81 static appcore_base_rotation __rotation;
82
83 static void __invoke_callback(void *event, int type)
84 {
85         GList *iter = __events;
86
87         while (iter) {
88                 appcore_base_event_node *node = iter->data;
89
90                 if (node->type == type)
91                         node->cb(event, node->data);
92                 iter = g_list_next(iter);
93         }
94 }
95
96 static bool __exist_callback(int type)
97 {
98         GList *iter = __events;
99
100         while (iter) {
101                 appcore_base_event_node *node = iter->data;
102
103                 if (node->type == type)
104                         return true;
105
106                 iter = g_list_next(iter);
107         }
108
109         return false;
110 }
111
112 static enum appcore_base_rm __get_rm(sensor_data_t data)
113 {
114         int event;
115         enum appcore_base_rm rm;
116
117         if (data.value_count <= 0) {
118                 _ERR("Failed to get sensor data");
119                 return APPCORE_BASE_RM_UNKNOWN;
120         }
121
122         event = data.values[0];
123         switch (event) {
124         case AUTO_ROTATION_DEGREE_0:
125                 rm = APPCORE_BASE_RM_PORTRAIT_NORMAL;
126                 break;
127         case AUTO_ROTATION_DEGREE_90:
128                 rm = APPCORE_BASE_RM_LANDSCAPE_NORMAL;
129                 break;
130         case AUTO_ROTATION_DEGREE_180:
131                 rm = APPCORE_BASE_RM_PORTRAIT_REVERSE;
132                 break;
133         case AUTO_ROTATION_DEGREE_270:
134                 rm = APPCORE_BASE_RM_LANDSCAPE_REVERSE;
135                 break;
136         default:
137                 rm = APPCORE_BASE_RM_UNKNOWN;
138                 break;
139         }
140
141         return rm;
142 }
143
144 static void __lock_cb(keynode_t *node, void *user_data)
145 {
146         bool r;
147         sensor_data_t data;
148         enum appcore_base_rm rm;
149
150         __rotation.lock = !vconf_keynode_get_bool(node);
151         if (__rotation.lock) {
152                 _DBG("Rotation locked");
153                 rm = APPCORE_BASE_RM_PORTRAIT_NORMAL;
154         } else {
155                 _DBG("Rotation unlocked");
156                 r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data);
157                 if (!r) {
158                         _ERR("Failed to get sensor data");
159                         return;
160                 }
161
162                 rm = __get_rm(data);
163                 if (rm == APPCORE_BASE_RM_UNKNOWN) {
164                         _ERR("Unknown mode");
165                         return;
166                 }
167         }
168
169         if (__rotation.rm == rm)
170                 return;
171
172         _DBG("Rotation: %d -> %d", __rotation.rm, rm);
173         __rotation.rm = rm;
174         __invoke_callback((void *)&__rotation.rm, APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED);
175 }
176
177 static void __auto_rotation_changed_cb(sensor_t sensor, unsigned int event_type,
178                 sensor_data_t *data, void *user_data)
179 {
180         enum appcore_base_rm rm;
181
182         if (data == NULL)
183                 return;
184
185         if (__rotation.lock)
186                 return;
187
188         if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
189                 return;
190
191         rm = __get_rm(*data);
192         if (rm == APPCORE_BASE_RM_UNKNOWN) {
193                 _ERR("Unknown mode");
194                 return;
195         }
196
197         _DBG("Rotation: %d -> %d", __rotation.rm, rm);
198         __rotation.rm = rm;
199         __invoke_callback((void *)&__rotation.rm, APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED);
200 }
201
202 static void __unregister_rotation_changed_event(void)
203 {
204         if (!__rotation.ref)
205                 return;
206
207         __rotation.ref--;
208         if (__rotation.ref > 1)
209                 return;
210
211         vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, __lock_cb);
212         sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
213         sensord_stop(__rotation.conn);
214         sensord_disconnect(__rotation.conn);
215
216         __rotation.lock = 0;
217         __rotation.ref = 0;
218 }
219
220 static void __register_rotation_changed_event(void)
221 {
222         sensor_t sensor;
223         int lock;
224         bool r;
225
226         if (__rotation.ref) {
227                 __rotation.ref++;
228                 return;
229         }
230
231         sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
232         __rotation.conn = sensord_connect(sensor);
233         if (__rotation.conn < 0) {
234                 _ERR("Failed to connect sensord");
235                 return;
236         }
237
238         r = sensord_register_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT,
239                         SENSOR_INTERVAL_NORMAL, 0, __auto_rotation_changed_cb, NULL);
240         if (!r) {
241                 _ERR("Failed to register auto rotation change event");
242                 sensord_disconnect(__rotation.conn);
243                 return;
244         }
245
246         r = sensord_start(__rotation.conn, 0);
247         if (!r) {
248                 _ERR("Failed to start sensord");
249                 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
250                 sensord_disconnect(__rotation.conn);
251                 return;
252         }
253
254         lock = 0;
255         vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
256         vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, __lock_cb, NULL);
257
258         __rotation.lock = !lock;
259         __rotation.ref++;
260 }
261
262 static void __on_low_memory(keynode_t *key, void *data)
263 {
264         int val;
265
266         val = vconf_keynode_get_int(key);
267
268         if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
269                 __invoke_callback(&val, APPCORE_BASE_EVENT_LOW_MEMORY);
270                 malloc_trim(0);
271         }
272 }
273
274 static void __on_low_battery(keynode_t *key, void *data)
275 {
276         int val;
277
278         val = vconf_keynode_get_int(key);
279
280         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
281                 __invoke_callback(&val, APPCORE_BASE_EVENT_LOW_BATTERY);
282 }
283
284 static void __destroy_lang_info(gpointer data)
285 {
286         struct lang_info_s *info = (struct lang_info_s *)data;
287
288         if (info == NULL)
289                 return;
290
291         if (info->list)
292                 g_list_free_full(info->list, free);
293         if (info->parent)
294                 free(info->parent);
295         free(info);
296 }
297
298 static struct lang_info_s *__create_lang_info(const char *lang)
299 {
300         struct lang_info_s *info;
301
302         info = calloc(1, sizeof(struct lang_info_s));
303         if (info == NULL) {
304                 _ERR("Out of memory");
305                 return NULL;
306         }
307
308         info->parent = strdup(lang);
309         if (info->parent == NULL) {
310                 _ERR("Out of memory");
311                 free(info);
312                 return NULL;
313         }
314
315         return info;
316 }
317
318 static gint __compare_langs(gconstpointer a, gconstpointer b)
319 {
320         if (!a || !b)
321                 return -1;
322
323         return strcmp(a, b);
324 }
325
326 static char *__get_string_before(const char *str, const char *delim)
327 {
328         char *new_str;
329         char *dup_str;
330         char *token;
331
332         dup_str = strdup(str);
333         if (dup_str == NULL)
334                 return NULL;
335
336         token = strtok(dup_str, delim);
337         if (token == NULL) {
338                 free(dup_str);
339                 return NULL;
340         }
341
342         new_str = strdup(token);
343         free(dup_str);
344
345         return new_str;
346 }
347
348 static GHashTable *__get_lang_table(void)
349 {
350         GHashTable *table;
351         DIR *dp;
352         struct dirent *dentry;
353         char buf[PATH_MAX];
354         struct stat stat_buf;
355         int ret;
356         char *parent_lang;
357         struct lang_info_s *info;
358
359         if (__locale_dir == NULL || __locale_dir[0] == '\0')
360                 return NULL;
361
362         table = g_hash_table_new_full(g_str_hash, g_str_equal,
363                         NULL, __destroy_lang_info);
364         if (table == NULL) {
365                 _ERR("Out of memory");
366                 return NULL;
367         }
368
369         dp = opendir(__locale_dir);
370         if (dp == NULL) {
371                 g_hash_table_destroy(table);
372                 return NULL;
373         }
374
375         while ((dentry = readdir(dp)) != NULL) {
376                 if (!strcmp(dentry->d_name, ".") ||
377                                 !strcmp(dentry->d_name, ".."))
378                         continue;
379
380                 snprintf(buf, sizeof(buf), "%s/%s",
381                                 __locale_dir, dentry->d_name);
382                 ret = stat(buf, &stat_buf);
383                 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
384                         continue;
385
386                 parent_lang = __get_string_before(dentry->d_name, "_");
387                 if (parent_lang == NULL) {
388                         _ERR("Out of memory");
389                         break;
390                 }
391
392                 info = g_hash_table_lookup(table, parent_lang);
393                 if (info == NULL) {
394                         info = __create_lang_info(parent_lang);
395                         if (info == NULL) {
396                                 free(parent_lang);
397                                 break;
398                         }
399                         g_hash_table_insert(table, info->parent, info);
400                 }
401                 info->list = g_list_append(info->list, strdup(dentry->d_name));
402                 free(parent_lang);
403         }
404         closedir(dp);
405
406         return table;
407 }
408
409 static GList *__append_langs(const char *lang, GList *list, GHashTable *table)
410 {
411         struct lang_info_s *info;
412         GList *found;
413         char *parent_lang = NULL;
414         char *extract_lang;
415
416         if (lang == NULL)
417                 return list;
418
419         extract_lang = __get_string_before(lang, ".");
420         if (extract_lang == NULL)
421                 return list;
422
423         found = g_list_find_custom(list, extract_lang, __compare_langs);
424         if (found) {
425                 list = g_list_remove_link(list, found);
426                 list = g_list_concat(list, found);
427                 goto end;
428         }
429
430         parent_lang = __get_string_before(extract_lang, "_");
431         if (parent_lang == NULL)
432                 goto end;
433
434         info = g_hash_table_lookup(table, parent_lang);
435         if (info == NULL)
436                 goto end;
437
438         found = g_list_find_custom(info->list, extract_lang, __compare_langs);
439         if (found) {
440                 info->list = g_list_remove_link(info->list, found);
441                 list = g_list_concat(list, found);
442                 goto end;
443         }
444
445         found = g_list_find_custom(info->list, parent_lang, __compare_langs);
446         if (found) {
447                 info->list = g_list_remove_link(info->list, found);
448                 list = g_list_concat(list, found);
449                 goto end;
450         }
451
452         found = g_list_first(info->list);
453         if (found) {
454                 info->list = g_list_remove_link(info->list, found);
455                 list = g_list_concat(list, found);
456         }
457
458 end:
459         if (extract_lang)
460                 free(extract_lang);
461         if (parent_lang)
462                 free(parent_lang);
463
464         return list;
465 }
466
467 static GList *__split_language(const char *lang)
468 {
469         GList *list = NULL;
470         char *dup_lang;
471         char *token;
472
473         dup_lang = strdup(lang);
474         if (dup_lang == NULL) {
475                 _ERR("Out of memory");
476                 return NULL;
477         }
478
479         token = strtok(dup_lang, ":");
480         while (token != NULL) {
481                 list = g_list_append(list, strdup(token));
482                 token = strtok(NULL, ":");
483         }
484         free(dup_lang);
485
486         return list;
487 }
488
489 static GList *__append_default_langs(GList *list)
490 {
491         const char *langs[] = {"en_US", "en_GB", "en"};
492         unsigned int i;
493         GList *found;
494
495         for (i = 0; i < (sizeof(langs) / sizeof(langs[0])); i++) {
496                 found = g_list_find_custom(list, langs[i], __compare_langs);
497                 if (found == NULL)
498                         list = g_list_append(list, strdup(langs[i]));
499         }
500
501         return list;
502 }
503
504 static char *__get_language(const char *lang)
505 {
506         GHashTable *table;
507         GList *list;
508         GList *lang_list = NULL;
509         GList *iter;
510         char *language;
511         char buf[LINE_MAX] = {'\0'};
512         size_t n;
513
514         list = __split_language(lang);
515         if (list == NULL)
516                 return NULL;
517
518         table = __get_lang_table();
519         if (table == NULL) {
520                 g_list_free_full(list, free);
521                 return NULL;
522         }
523
524         iter = g_list_first(list);
525         while (iter) {
526                 language = (char *)iter->data;
527                 lang_list = __append_langs(language, lang_list, table);
528                 iter = g_list_next(iter);
529         }
530         g_list_free_full(list, free);
531         g_hash_table_destroy(table);
532
533         lang_list = __append_default_langs(lang_list);
534         iter = g_list_first(lang_list);
535         while (iter) {
536                 language = (char *)iter->data;
537                 if (language) {
538                         if (buf[0] == '\0') {
539                                 snprintf(buf, sizeof(buf), "%s", language);
540                         } else {
541                                 n = sizeof(buf) - strlen(buf) - 1;
542                                 strncat(buf, ":", n);
543                                 n = sizeof(buf) - strlen(buf) - 1;
544                                 strncat(buf, language, n);
545                         }
546                 }
547                 iter = g_list_next(iter);
548         }
549         g_list_free_full(lang_list, free);
550
551         return strdup(buf);
552 }
553
554 static void __update_lang(void)
555 {
556         char *language;
557         char *lang;
558         char *r;
559
560         lang = vconf_get_str(VCONFKEY_LANGSET);
561         if (lang) {
562                 /* TODO: Use VCONFKEY_SETAPPL_LANGUAGES key */
563                 language = __get_language(lang);
564                 if (language) {
565                         _DBG("*****language(%s)", language);
566                         setenv("LANGUAGE", language, 1);
567                         free(language);
568                 } else {
569                         setenv("LANGUAGE", lang, 1);
570                 }
571                 setenv("LANG", lang, 1);
572                 setenv("LC_MESSAGES", lang, 1);
573                 r = setlocale(LC_ALL, "");
574                 if (r == NULL) {
575                         r = setlocale(LC_ALL, lang);
576                         if (r != NULL)
577                                 _DBG("*****appcore setlocale=%s\n", r);
578                 }
579                 free(lang);
580         }
581 }
582
583 static void __update_region(void)
584 {
585         char *region;
586         char *r;
587
588         region = vconf_get_str(VCONFKEY_REGIONFORMAT);
589         if (region) {
590                 setenv("LC_CTYPE", region, 1);
591                 setenv("LC_NUMERIC", region, 1);
592                 setenv("LC_TIME", region, 1);
593                 setenv("LC_COLLATE", region, 1);
594                 setenv("LC_MONETARY", region, 1);
595                 setenv("LC_PAPER", region, 1);
596                 setenv("LC_NAME", region, 1);
597                 setenv("LC_ADDRESS", region, 1);
598                 setenv("LC_TELEPHONE", region, 1);
599                 setenv("LC_MEASUREMENT", region, 1);
600                 setenv("LC_IDENTIFICATION", region, 1);
601                 r = setlocale(LC_ALL, "");
602                 if (r != NULL)
603                         _DBG("*****appcore setlocale=%s\n", r);
604
605                 free(region);
606         }
607 }
608
609 static void __on_language_change(keynode_t *key, void *data)
610 {
611         char *val;
612
613         val = vconf_keynode_get_str(key);
614
615         __update_lang();
616         __invoke_callback((void *)val, APPCORE_BASE_EVENT_LANG_CHANGE);
617 }
618
619 static void __on_region_change(keynode_t *key, void *data)
620 {
621         char *val = NULL;
622         const char *name;
623
624         name = vconf_keynode_get_name(key);
625         if (name && !strcmp(name, VCONFKEY_REGIONFORMAT))
626                 val = vconf_keynode_get_str(key);
627
628         __update_region();
629         __invoke_callback((void *)val, APPCORE_BASE_EVENT_REGION_CHANGE);
630 }
631
632 static gboolean __flush_memory(gpointer data)
633 {
634         int suspend = APPCORE_BASE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
635
636         appcore_base_flush_memory();
637         __context.tid = 0;
638
639         if (!__context.allowed_bg && !__context.suspended_state) {
640                 _DBG("[__SUSPEND__] flush case");
641                 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
642                 __context.suspended_state = true;
643         }
644
645         return FALSE;
646 }
647
648 static void __add_suspend_timer(void)
649 {
650         __context.tid = g_timeout_add_seconds(5, __flush_memory, NULL);
651 }
652
653 static void __remove_suspend_timer(void)
654 {
655         if (__context.tid > 0) {
656                 g_source_remove(__context.tid);
657                 __context.tid = 0;
658         }
659 }
660
661 static void __on_receive_suspend_signal(GDBusConnection *connection,
662                                         const gchar *sender_name,
663                                         const gchar *object_path,
664                                         const gchar *interface_name,
665                                         const gchar *signal_name,
666                                         GVariant *parameters,
667                                         gpointer user_data)
668 {
669         gint suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
670         gint pid;
671         gint status;
672
673         if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
674                 g_variant_get(parameters, "(ii)", &status, &pid);
675                 if (pid == getpid() && status == 0) {
676                         if (!__context.allowed_bg && __context.suspended_state) {
677                                 __remove_suspend_timer();
678                                 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
679                                 __context.suspended_state = false;
680                                 __add_suspend_timer();
681                         }
682                 }
683         }
684 }
685
686 static int __init_suspend_dbus_handler(void)
687 {
688         GError *err = NULL;
689
690         if (__suspend_dbus_handler_initialized)
691                 return 0;
692
693         if (!__bus) {
694                 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
695                 if (!__bus) {
696                         _ERR("Failed to connect to the D-BUS daemon: %s",
697                                                 err->message);
698                         g_error_free(err);
699                         return -1;
700                 }
701         }
702
703         __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
704                                                 __bus,
705                                                 NULL,
706                                                 RESOURCED_FREEZER_INTERFACE,
707                                                 RESOURCED_FREEZER_SIGNAL,
708                                                 RESOURCED_FREEZER_PATH,
709                                                 NULL,
710                                                 G_DBUS_SIGNAL_FLAGS_NONE,
711                                                 __on_receive_suspend_signal,
712                                                 NULL,
713                                                 NULL);
714         if (__suspend_dbus_handler_initialized == 0) {
715                 _ERR("g_dbus_connection_signal_subscribe() is failed.");
716                 return -1;
717         }
718
719         _DBG("[__SUSPEND__] suspend signal initialized");
720
721         return 0;
722 }
723
724 static void __fini_suspend_dbus_handler(void)
725 {
726         if (__bus == NULL)
727                 return;
728
729         if (__suspend_dbus_handler_initialized) {
730                 g_dbus_connection_signal_unsubscribe(__bus,
731                                 __suspend_dbus_handler_initialized);
732                 __suspend_dbus_handler_initialized = 0;
733         }
734
735         g_object_unref(__bus);
736         __bus = NULL;
737 }
738
739 static int __get_locale_resource_dir(char *locale_dir, int size)
740 {
741         const char *res_path;
742
743         res_path = aul_get_app_resource_path();
744         if (res_path == NULL) {
745                 _ERR("Failed to get resource path");
746                 return -1;
747         }
748
749         snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path);
750         if (access(locale_dir, R_OK) != 0)
751                 _DBG("%s does not exist", locale_dir);
752
753         return 0;
754 }
755
756 static int __get_app_name(const char *appid, char **name)
757 {
758         char *name_token = NULL;
759
760         if (appid == NULL)
761                 return -1;
762
763         /* com.vendor.name -> name */
764         name_token = strrchr(appid, '.');
765         if (name_token == NULL)
766                 return -1;
767
768         name_token++;
769
770         *name = strdup(name_token);
771         if (*name == NULL)
772                 return -1;
773
774         return 0;
775 }
776
777 static int __set_i18n(const char *domain, const char *dir)
778 {
779         char *r;
780         char *lan;
781
782         if (domain == NULL) {
783                 errno = EINVAL;
784                 return -1;
785         }
786
787         if (dir) {
788                 if (__locale_dir)
789                         free(__locale_dir);
790                 __locale_dir = strdup(dir);
791         }
792
793         __update_lang();
794         __update_region();
795
796         r = setlocale(LC_ALL, "");
797         /* if locale is not set properly, try again to set as language base */
798         if (r == NULL) {
799                 lan = vconf_get_str(VCONFKEY_LANGSET);
800                 if (lan != NULL) {
801                         r = setlocale(LC_ALL, lan);
802                         _DBG("*****appcore setlocale=%s\n", r);
803                         free(lan);
804                 }
805         }
806         if (r == NULL)
807                 _ERR("appcore: setlocale() error");
808
809         r = bindtextdomain(domain, dir);
810         if (r == NULL)
811                 _ERR("appcore: bindtextdomain() error");
812
813         r = textdomain(domain);
814         if (r == NULL)
815                 _ERR("appcore: textdomain() error");
816
817         return 0;
818 }
819
820 EXPORT_API int appcore_base_on_set_i18n(void)
821 {
822         int r;
823         char locale_dir[PATH_MAX];
824         char appid[PATH_MAX];
825         char *name = NULL;
826
827         r = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
828         if (r < 0)
829                 return -1;
830
831         r = __get_app_name(appid, &name);
832         if (r < 0)
833                 return -1;
834
835         r = __get_locale_resource_dir(locale_dir, sizeof(locale_dir));
836         if (r < 0) {
837                 free(name);
838                 return -1;
839         }
840
841         r = __set_i18n(name, locale_dir);
842         if (r < 0) {
843                 free(name);
844                 return -1;
845         }
846
847         free(name);
848
849         return 0;
850 }
851
852 EXPORT_API int appcore_base_set_i18n(const char *domain_name, const char *dir_name)
853 {
854         return __set_i18n(domain_name, dir_name);
855 }
856
857 EXPORT_API int appcore_base_init(appcore_base_ops ops, int argc, char **argv, void *data)
858 {
859         int i;
860
861         __context.ops = ops;
862         __context.argc = argc;
863         __context.argv = argv;
864         __context.data = data;
865         __context.tid = 0;
866         __context.suspended_state = false;
867         __context.allowed_bg = false;
868
869         if (__context.ops.set_i18n)
870                 __context.ops.set_i18n(__context.data);
871
872         __init_suspend_dbus_handler();
873
874         if (!__context.dirty) {
875                 __context.dirty = true;
876
877                 for (i = APPCORE_BASE_EVENT_START + 1; i < APPCORE_BASE_EVENT_MAX; i++) {
878                         if (__exist_callback(i)) {
879                                 if (__context.ops.set_event)
880                                         __context.ops.set_event(i, __context.data);
881                         }
882                 }
883         }
884
885         if (__context.ops.create && __context.ops.create(__context.data) < 0) {
886                 aul_status_update(STATUS_DYING);
887                 return 0;
888         }
889
890         if (__context.ops.run)
891                 __context.ops.run(__context.data);
892
893         return 0;
894 }
895
896 EXPORT_API void appcore_base_fini(void)
897 {
898         int i;
899
900         aul_status_update(STATUS_DYING);
901         if (__context.ops.terminate)
902                 __context.ops.terminate(__context.data);
903
904         for (i = APPCORE_BASE_EVENT_START + 1; i < APPCORE_BASE_EVENT_MAX; i++) {
905                 if (__exist_callback(i)) {
906                         if (__context.ops.unset_event)
907                                 __context.ops.unset_event(i, __context.data);
908                 }
909         }
910
911         g_list_free_full(__events, free);
912         __events = NULL;
913         __fini_suspend_dbus_handler();
914
915         if (__locale_dir) {
916                 free(__locale_dir);
917                 __locale_dir = NULL;
918         }
919
920         __context.dirty = false;
921 }
922
923 EXPORT_API int appcore_base_flush_memory(void)
924 {
925         malloc_trim(0);
926         return 0;
927 }
928
929 EXPORT_API int appcore_base_on_receive(aul_type type, bundle *b)
930 {
931         int ret;
932         const char **tep_path;
933         int len = 0;
934         int i;
935         const char *bg;
936         int dummy = 0;
937
938         switch (type) {
939         case AUL_START:
940                 _DBG("[APP %d]     AUL event: AUL_START", getpid());
941                 tep_path = bundle_get_str_array(b, AUL_TEP_PATH, &len);
942                 if (tep_path) {
943                         for (i = 0; i < len; i++) {
944                                 ret = aul_check_tep_mount(tep_path[i]);
945                                 if (ret == -1) {
946                                         _ERR("mount request not completed within 1 sec");
947                                         exit(-1);
948                                 }
949                         }
950                 }
951
952                 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
953                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
954                         _DBG("[__SUSPEND__] allowed background");
955                         __context.allowed_bg = true;
956                         __remove_suspend_timer();
957                 }
958
959                 if (__context.ops.control)
960                        __context.ops.control(b, __context.data);
961                 break;
962         case AUL_RESUME:
963                 _DBG("[APP %d]     AUL event: AUL_RESUME", getpid());
964                 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
965                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
966                         _DBG("[__SUSPEND__] allowed background");
967                         __context.allowed_bg = true;
968                         __remove_suspend_timer();
969                 }
970                 break;
971         case AUL_TERMINATE:
972                 _DBG("[APP %d]     AUL event: AUL_TERMINATE", getpid());
973                 aul_status_update(STATUS_DYING);
974                 if (!__context.allowed_bg)
975                         __remove_suspend_timer();
976
977                 if (__context.ops.exit)
978                         __context.ops.exit(__context.data);
979                 break;
980         case AUL_TERMINATE_BGAPP:
981                 _DBG("[APP %d]     AUL event: AUL_TERMINATE_BGAPP", getpid());
982                 if (!__context.allowed_bg)
983                         __remove_suspend_timer();
984                 break;
985         case AUL_WAKE:
986                 _DBG("[APP %d]     AUL event: AUL_WAKE", getpid());
987                 if (!__context.allowed_bg && __context.suspended_state) {
988                         int suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
989                         __remove_suspend_timer();
990                         __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
991                         __context.suspended_state = false;
992                 }
993                 break;
994         case AUL_SUSPEND:
995                 _DBG("[APP %d]     AUL event: AUL_SUSPEND", getpid());
996                 if (!__context.allowed_bg && !__context.suspended_state) {
997                         __remove_suspend_timer();
998                         __flush_memory(NULL);
999                 }
1000                 break;
1001         case AUL_UPDATE_REQUESTED:
1002                 _DBG("[APP %d]     AUL event: AUL_UPDATE_REQUESTED", getpid());
1003                 __invoke_callback((void *)&dummy, APPCORE_BASE_EVENT_UPDATE_REQUESTED);
1004                 break;
1005         default:
1006                 _DBG("[APP %d]     AUL event: %d", getpid(), type);
1007                 /* do nothing */
1008                 break;
1009         }
1010
1011         return 0;
1012 }
1013
1014 EXPORT_API int appcore_base_on_create(void)
1015 {
1016         int r;
1017         r = aul_launch_init(__context.ops.receive, NULL);
1018         if (r < 0) {
1019                 _ERR("Aul init failed: %d", r);
1020                 return -1;
1021         }
1022
1023         r = aul_launch_argv_handler(__context.argc, __context.argv);
1024         if (r < 0) {
1025                 _ERR("Aul argv handler failed: %d", r);
1026                 return -1;
1027         }
1028
1029         return 0;
1030 }
1031
1032 EXPORT_API int appcore_base_on_control(bundle *b)
1033 {
1034         return 0;
1035 }
1036
1037 EXPORT_API int appcore_base_on_terminate()
1038 {
1039         aul_finalize();
1040         if (__context.ops.exit)
1041                 __context.ops.exit(__context.data);
1042
1043         return 0;
1044 }
1045
1046 EXPORT_API void appcore_base_on_set_event(enum appcore_base_event event)
1047 {
1048         int r;
1049
1050         switch (event) {
1051         case APPCORE_BASE_EVENT_LOW_MEMORY:
1052                 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory, NULL);
1053                 break;
1054         case APPCORE_BASE_EVENT_LOW_BATTERY:
1055                 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery, NULL);
1056                 break;
1057         case APPCORE_BASE_EVENT_LANG_CHANGE:
1058                 vconf_notify_key_changed(VCONFKEY_LANGSET, __on_language_change, NULL);
1059                 break;
1060         case APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED:
1061                 __register_rotation_changed_event();
1062                 break;
1063         case APPCORE_BASE_EVENT_REGION_CHANGE:
1064                 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change, NULL);
1065                 if (r < 0)
1066                         break;
1067
1068                 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __on_region_change, NULL);
1069                 break;
1070         case APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE:
1071                 break;
1072
1073         default:
1074                 break;
1075         }
1076
1077 }
1078
1079 EXPORT_API void appcore_base_on_unset_event(enum appcore_base_event event)
1080 {
1081         int r;
1082
1083         switch (event) {
1084         case APPCORE_BASE_EVENT_LOW_MEMORY:
1085                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory);
1086                 break;
1087         case APPCORE_BASE_EVENT_LOW_BATTERY:
1088                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery);
1089                 break;
1090         case APPCORE_BASE_EVENT_LANG_CHANGE:
1091                 vconf_ignore_key_changed(VCONFKEY_LANGSET, __on_language_change);
1092                 break;
1093         case APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED:
1094                 __unregister_rotation_changed_event();
1095                 break;
1096         case APPCORE_BASE_EVENT_REGION_CHANGE:
1097                 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change);
1098                 if (r < 0)
1099                         break;
1100                 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __on_region_change);
1101                 break;
1102         case APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE:
1103                 break;
1104         default:
1105                 break;
1106         }
1107 }
1108
1109 EXPORT_API appcore_base_event_h appcore_base_add_event(enum appcore_base_event event,
1110                 appcore_base_event_cb cb, void *data)
1111 {
1112         appcore_base_event_node *node;
1113
1114         if (__context.dirty && !__exist_callback(event)) {
1115                 if (__context.ops.set_event)
1116                         __context.ops.set_event(event, __context.data);
1117         }
1118
1119         node = malloc(sizeof(appcore_base_event_node));
1120
1121         if (node == NULL)
1122                 return NULL;
1123
1124         node->cb = cb;
1125         node->type = event;
1126         node->data = data;
1127         __events = g_list_append(__events, node);
1128
1129         return node;
1130 }
1131
1132 EXPORT_API int appcore_base_remove_event(appcore_base_event_h handle)
1133 {
1134         appcore_base_event_node *node = handle;
1135         enum appcore_base_event event;
1136
1137         event = node->type;
1138         __events = g_list_remove(__events, node);
1139         free(node);
1140         if (__context.dirty && !__exist_callback(event)) {
1141                 if (__context.ops.unset_event)
1142                         __context.ops.unset_event(event, __context.data);
1143         }
1144
1145         return 0;
1146 }
1147
1148 EXPORT_API int appcore_base_raise_event(void *event, enum appcore_base_event type)
1149 {
1150         __invoke_callback(event, type);
1151         return 0;
1152 }
1153
1154 EXPORT_API int appcore_base_get_rotation_state(enum appcore_base_rm *curr)
1155 {
1156         if (curr == NULL)
1157                 return -1;
1158
1159         if (!__rotation.ref)
1160                 return -1;
1161
1162         *curr = __rotation.rm;
1163         return 0;
1164 }
1165
1166 EXPORT_API bool appcore_base_is_bg_allowed(void)
1167 {
1168         return __context.allowed_bg;
1169 }
1170
1171 EXPORT_API bool appcore_base_is_suspended(void)
1172 {
1173         return __context.suspended_state;
1174 }
1175
1176 EXPORT_API void appcore_base_toggle_suspended_state(void)
1177 {
1178         __context.suspended_state ^= __context.suspended_state;
1179 }
1180
1181 static int __on_receive(aul_type type, bundle *b, void *data)
1182 {
1183         return appcore_base_on_receive(type, b);
1184 }
1185
1186 static int __on_create(void *data)
1187 {
1188         return appcore_base_on_create();
1189 }
1190
1191 static int __on_control(bundle *b, void *data)
1192 {
1193         return appcore_base_on_control(b);
1194 }
1195
1196 static int __on_terminate(void *data)
1197 {
1198         return appcore_base_on_terminate();
1199 }
1200
1201 static int __on_set_i18n(void *data)
1202 {
1203         return appcore_base_on_set_i18n();
1204 }
1205
1206 static void __on_set_event(enum appcore_base_event event, void *data)
1207 {
1208         return appcore_base_on_set_event(event);
1209 }
1210
1211 static void __on_unset_event(enum appcore_base_event event, void *data)
1212 {
1213         return appcore_base_on_unset_event(event);
1214 }
1215
1216 EXPORT_API appcore_base_ops appcore_base_get_default_ops(void)
1217 {
1218         appcore_base_ops ops;
1219
1220         ops.create = __on_create;
1221         ops.control = __on_control;
1222         ops.terminate = __on_terminate;
1223         ops.receive = __on_receive;
1224         ops.set_i18n = __on_set_i18n;
1225         ops.run = NULL;
1226         ops.exit = NULL;
1227         ops.set_event = __on_set_event;
1228         ops.unset_event = __on_unset_event;
1229
1230         return ops;
1231 }
1232
1233