Add engine-parser 35/182635/2
authorsooyeon.kim <sooyeon.kim@samsung.com>
Tue, 26 Jun 2018 13:08:16 +0000 (22:08 +0900)
committerSooyeon Kim <sooyeon.kim@samsung.com>
Wed, 27 Jun 2018 01:43:54 +0000 (01:43 +0000)
Change-Id: Ib3789585acd459938a507fc2a102089e8130e460
Signed-off-by: sooyeon.kim <sooyeon.kim@samsung.com>
CMakeLists.txt
common/vc_config_mgr.c
common/vc_config_parser.c
common/vc_config_parser.h
common/vc_defs.h
engine-parser/CMakeLists.txt [new file with mode: 0644]
engine-parser/src/vc-engine-parser.c [new file with mode: 0644]
packaging/voice-control.spec

index 51c98b0..8819be3 100644 (file)
@@ -43,12 +43,12 @@ INCLUDE(FindPkgConfig)
 IF("${_TV_PRODUCT}" STREQUAL "TRUE")
 pkg_check_modules(pkgs REQUIRED
     aul capi-appfw-app-control capi-appfw-app-manager capi-base-common capi-media-audio-io capi-media-sound-manager ecore-wayland
-    capi-network-bluetooth capi-network-bluetooth-tv capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libtzplatform-config libxml-2.0 sqlite3 vconf msfapi
+    capi-network-bluetooth capi-network-bluetooth-tv capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 sqlite3 vconf msfapi
 )
 ELSE()
 pkg_check_modules(pkgs REQUIRED
     aul capi-appfw-app-control capi-appfw-app-manager capi-base-common capi-media-audio-io capi-media-sound-manager ecore-wayland
-    capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libtzplatform-config libxml-2.0 sqlite3 vconf
+    capi-system-info cynara-client cynara-session dbus-1 db-util dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 sqlite3 vconf
 )
 ENDIF()
 
@@ -62,6 +62,9 @@ ADD_SUBDIRECTORY(client)
 ## Server daemon ##
 ADD_SUBDIRECTORY(server)
 
+## Engine Parser ##
+ADD_SUBDIRECTORY(engine-parser)
+
 ## config ##
 INSTALL(FILES ${CMAKE_SOURCE_DIR}/vc-config.xml DESTINATION ${TZ_SYS_RO_SHARE}/voice/vc/1.0)
 
index 296e88a..5c33189 100755 (executable)
@@ -41,6 +41,12 @@ typedef struct {
        vc_config_enabled_cb            enabled_cb;
 } vc_config_client_s;
 
+/* for engine directory monitoring */
+typedef struct {
+       Ecore_Fd_Handler* dir_fd_handler;
+       int dir_fd;
+       int dir_wd;
+} vc_engine_inotify_s;
 
 const char* vc_config_tag()
 {
@@ -58,10 +64,14 @@ static Ecore_Fd_Handler* g_fd_handler_lang = NULL;
 static int g_fd_lang;
 static int g_wd_lang;
 
+static GList* g_ino_list = NULL;
+
 static pthread_mutex_t vc_config_mgr_mutex = PTHREAD_MUTEX_INITIALIZER;
 
-int __vc_config_mgr_print_engine_info();
+static int __vc_config_mgr_register_engine_config_updated_event(const char* path);
+static int __vc_config_mgr_unregister_engine_config_updated_event();
 
+int __vc_config_mgr_print_engine_info();
 int __vc_config_mgr_print_client_info();
 
 int vc_config_convert_error_code(vc_config_error_e code)
@@ -260,6 +270,295 @@ int __vc_config_mgr_select_lang(const char* engine_id, char** language)
        return VC_ERROR_OPERATION_FAILED;
 }
 
+int __vc_config_release_client(int uid)
+{
+       GSList *iter = NULL;
+       vc_config_client_s* temp_client = NULL;
+
+       if (0 < g_slist_length(g_config_client_list)) {
+               /* Check uid */
+               iter = g_slist_nth(g_config_client_list, 0);
+
+               while (NULL != iter) {
+                       temp_client = iter->data;
+
+                       if (NULL != temp_client) {
+                               if (uid == temp_client->uid) {
+                                       g_config_client_list = g_slist_remove(g_config_client_list, temp_client);
+                                       free(temp_client);
+                                       break;
+                               }
+                       }
+
+                       iter = g_slist_next(iter);
+               }
+       }
+
+       SLOG(LOG_DEBUG, vc_config_tag(), "Client count (%d)", g_slist_length(g_config_client_list));
+
+       return g_slist_length(g_config_client_list);
+}
+
+void __vc_config_release_engine()
+{
+       GSList *iter = NULL;
+       vc_engine_info_s *engine_info = NULL;
+
+       if (0 < g_slist_length(g_engine_list)) {
+
+               /* Get a first item */
+               iter = g_slist_nth(g_engine_list, 0);
+
+               while (NULL != iter) {
+                       engine_info = iter->data;
+
+                       if (NULL != engine_info) {
+                               g_engine_list = g_slist_remove(g_engine_list, engine_info);
+
+                               vc_parser_free_engine_info(engine_info);
+                       }
+
+                       iter = g_slist_nth(g_engine_list, 0);
+               }
+       }
+
+       return;
+}
+
+int __vc_config_mgr_get_engine_info()
+{
+       DIR *dp = NULL;
+       struct dirent *dirp = NULL;
+
+       char filepath[512] = {'\0',};
+       int filesize;
+       vc_engine_info_s* info = NULL;
+
+       __vc_config_release_engine();
+       g_engine_list = NULL;
+       __vc_config_mgr_unregister_engine_config_updated_event();
+
+       /* Copy default info directory to download directory */
+       dp  = opendir(VC_DEFAULT_ENGINE_INFO);
+       if (NULL == dp) {
+               SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] No default directory : %s", VC_DEFAULT_ENGINE_INFO);
+       } else {
+               do {
+                       dirp = readdir(dp);
+
+                       if (NULL != dirp) {
+                               if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name))
+                                       continue;
+
+                               filesize = strlen(VC_DEFAULT_ENGINE_INFO) + strlen(dirp->d_name) + 2;
+                               if (filesize >= 512) {
+                                       SECURE_SLOG(LOG_ERROR, vc_config_tag(), "[CONFIG ERROR] File path is too long : %s", dirp->d_name);
+                                       closedir(dp);
+                                       return -1;
+                               }
+
+                               memset(filepath, '\0', 512);
+                               snprintf(filepath, 512, "%s/%s", VC_DEFAULT_ENGINE_INFO, dirp->d_name);
+
+                               SECURE_SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] Filepath(%s)", filepath);
+
+                               char dest[512] = {'\0',};
+                               snprintf(dest, 512, "%s/%s", VC_DOWNLOAD_ENGINE_INFO, dirp->d_name);
+
+                               if (0 != access(dest, F_OK)) {
+                                       if (0 != vc_parser_copy_xml(filepath, dest)) {
+                                               SLOG(LOG_ERROR, vc_config_tag(), "[CONFIG ERROR] Fail to copy engine info");
+                                       }
+                               }
+                       }
+               } while (NULL != dirp);
+
+               closedir(dp);
+       }
+
+       /* Get engine info from default engine directory */
+       dp  = opendir(VC_DOWNLOAD_ENGINE_INFO);
+       if (NULL == dp) {
+               SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] No downloadable directory : %s", VC_DOWNLOAD_ENGINE_INFO);
+       } else {
+               do {
+                       dirp = readdir(dp);
+
+                       if (NULL != dirp) {
+                               if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name))
+                                       continue;
+
+                               filesize = strlen(VC_DOWNLOAD_ENGINE_INFO) + strlen(dirp->d_name) + 2;
+                               if (filesize >= 512) {
+                                       SECURE_SLOG(LOG_ERROR, vc_config_tag(), "[CONFIG ERROR] File path is too long : %s", dirp->d_name);
+                                       closedir(dp);
+                                       return -1;
+                               }
+
+                               memset(filepath, '\0', 512);
+                               snprintf(filepath, 512, "%s/%s", VC_DOWNLOAD_ENGINE_INFO, dirp->d_name);
+
+                               SECURE_SLOG(LOG_DEBUG, vc_config_tag(), "[CONFIG] Filepath(%s)", filepath);
+
+                               if (0 == vc_parser_get_engine_info(filepath, &info)) {
+                                       g_engine_list = g_slist_append(g_engine_list, info);
+                                       if (0 != __vc_config_mgr_register_engine_config_updated_event(filepath)) {
+                                               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to register engine config updated event");
+                                       }
+                               }
+                       }
+               } while (NULL != dirp);
+
+               closedir(dp);
+       }
+
+       if (0 >= g_slist_length(g_engine_list)) {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] No engine");
+               return -1;
+       }
+
+       return 0;
+}
+
+static Eina_Bool __vc_config_mgr_engine_config_inotify_event_callback(void* data, Ecore_Fd_Handler *fd_handler)
+{
+       SLOG(LOG_DEBUG, vc_config_tag(), "@@@ Engine config updated callback event");
+
+       vc_engine_inotify_s *ino = (vc_engine_inotify_s *)data;
+       int dir_fd = ino->dir_fd;
+
+       int length;
+       struct inotify_event event;
+       memset(&event, '\0', sizeof(struct inotify_event));
+
+       length = read(dir_fd, &event, sizeof(struct inotify_event));
+       if (0 > length) {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Empty Inotify event");
+               SLOG(LOG_DEBUG, vc_config_tag(), "@@@");
+               return ECORE_CALLBACK_DONE;
+       }
+
+       if (IN_CLOSE_WRITE == event.mask) {
+               int ret = __vc_config_mgr_get_engine_info();
+               if (0 != ret) {
+                       SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get engine info when config updated");
+               }
+               __vc_config_mgr_print_engine_info();
+               bool support = vc_config_check_default_language_is_valid(g_config_info->language);
+               if (false == support) {
+                       SLOG(LOG_DEBUG, vc_config_tag(), "[ERROR] Default language is valid");
+                       char* temp_lang = NULL;
+                       ret = __vc_config_mgr_select_lang(g_config_info->engine_id, &temp_lang);
+                       if (0 != ret) {
+                               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get language");
+                       }
+
+                       ret = vc_config_mgr_set_default_language(temp_lang);
+                       if (0 != ret) {
+                               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to set language");
+                       } else {
+                               SLOG(LOG_DEBUG, vc_config_tag(), "[DEBUG] Saved default language : lang(%s)", g_config_info->language);
+                       }
+                       if (NULL != temp_lang) {
+                               free(temp_lang);
+                               temp_lang = NULL;
+                       }
+               }
+       } else {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Undefined event");
+       }
+
+       SLOG(LOG_DEBUG, vc_config_tag(), "@@@");
+
+       return ECORE_CALLBACK_PASS_ON;
+}
+
+static int __vc_config_mgr_register_engine_config_updated_event(const char* path)
+{
+       if (NULL == path) {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Path is NULL");
+               return -1;
+       }
+
+       /* For engine directory monitoring */
+       vc_engine_inotify_s *ino = (vc_engine_inotify_s *)calloc(1, sizeof(vc_engine_inotify_s));
+       if (NULL == ino) {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to allocate memory");
+               return -1;
+       }
+
+       ino->dir_fd = inotify_init();
+       if (ino->dir_fd < 0) {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to init inotify");
+               free(ino);
+               ino = NULL;
+
+               return -1;
+       }
+
+       ino->dir_wd = inotify_add_watch(ino->dir_fd, path, IN_CLOSE_WRITE);
+       SLOG(LOG_DEBUG, vc_config_tag(), "Add inotify watch(%s)", path);
+       if (ino->dir_wd < 0) {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to add watch");
+               free(ino);
+               ino = NULL;
+               return -1;
+       }
+
+       ino->dir_fd_handler = ecore_main_fd_handler_add(ino->dir_fd, ECORE_FD_READ, (Ecore_Fd_Cb)__vc_config_mgr_engine_config_inotify_event_callback, (void *)ino, NULL, NULL);
+       if (NULL == ino->dir_fd_handler) {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to add fd handler");
+               free(ino);
+               ino = NULL;
+               return -1;
+       }
+
+       /* Set non-blocking mode of file */
+       int value;
+       value = fcntl(ino->dir_fd, F_GETFL, 0);
+       value |= O_NONBLOCK;
+
+       if (0 > fcntl(ino->dir_fd, F_SETFL, value)) {
+               SLOG(LOG_WARN, vc_config_tag(), "[WARNING] Fail to set non-block mode");
+       }
+
+       g_ino_list = g_list_append(g_ino_list, ino);
+
+       return 0;
+}
+
+static int __vc_config_mgr_unregister_engine_config_updated_event()
+{
+       /* delete all inotify variable */
+       if (0 < g_list_length(g_ino_list)) {
+               GList *iter = NULL;
+               iter = g_list_first(g_ino_list);
+
+               while (NULL != iter) {
+                       vc_engine_inotify_s *tmp = iter->data;
+
+                       if (NULL != tmp) {
+                               ecore_main_fd_handler_del(tmp->dir_fd_handler);
+                               inotify_rm_watch(tmp->dir_fd, tmp->dir_wd);
+                               close(tmp->dir_fd);
+
+                               free(tmp);
+                               tmp = NULL;
+                       }
+
+                       g_ino_list = g_list_remove_link(g_ino_list, iter);
+
+                       iter = g_list_first(g_ino_list);
+               }
+       }
+
+       return 0;
+}
+
+
+
+
+
 Eina_Bool vc_config_mgr_inotify_event_cb(void* data, Ecore_Fd_Handler *fd_handler)
 {
        SLOG(LOG_DEBUG, vc_config_tag(), "@@@ Config changed callback event");
@@ -529,14 +828,12 @@ int vc_config_mgr_initialize(int uid)
        }
 
        /* Get file name from default engine directory */
-       DIR *dp = NULL;
-       struct dirent *dirp;
-
        g_engine_list = NULL;
 
        if (0 != access(VC_CONFIG_BASE, F_OK)) {
                if (0 != mkdir(VC_CONFIG_BASE, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
                        SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_CONFIG_BASE);
+                       __vc_config_release_client(uid);
                        pthread_mutex_unlock(&vc_config_mgr_mutex);
                        return -1;
                } else {
@@ -546,6 +843,7 @@ int vc_config_mgr_initialize(int uid)
        if (0 != access(VC_RUNTIME_INFO_ROOT, F_OK)) {
                if (0 != mkdir(VC_RUNTIME_INFO_ROOT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
                        SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_RUNTIME_INFO_ROOT);
+                       __vc_config_release_client(uid);
                        pthread_mutex_unlock(&vc_config_mgr_mutex);
                        return -1;
                } else {
@@ -553,55 +851,49 @@ int vc_config_mgr_initialize(int uid)
                }
        }
 
-       dp  = opendir(VC_DEFAULT_ENGINE_INFO);
-       if (NULL != dp) {
-               do {
-                       dirp = readdir(dp);
-
-                       if (NULL != dirp) {
-                               if (!strcmp(".", dirp->d_name) || !strcmp("..", dirp->d_name))
-                                       continue;
-
-                               vc_engine_info_s* info = NULL;
-                               char* filepath = NULL;
-                               int filesize = 0;
-
-                               filesize = strlen(VC_DEFAULT_ENGINE_INFO) + strlen(dirp->d_name) + 5;
-                               filepath = (char*)calloc(filesize, sizeof(char));
-
-                               if (NULL != filepath) {
-                                       snprintf(filepath, filesize, "%s/%s", VC_DEFAULT_ENGINE_INFO, dirp->d_name);
-                               } else {
-                                       SLOG(LOG_ERROR, vc_config_tag(), "[Engine Agent ERROR] Memory not enough!!");
-                                       continue;
-                               }
-
-                               if (0 == vc_parser_get_engine_info(filepath, &info)) {
-                                       g_engine_list = g_slist_append(g_engine_list, info);
-                               }
-
-                               if (NULL != filepath) {
-                                       free(filepath);
-                                       filepath = NULL;
-                               }
-                       }
-               } while (NULL != dirp);
+       if (0 != access(VC_DOWNLOAD_BASE, F_OK)) {
+               if (0 != mkdir(VC_DOWNLOAD_BASE, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
+                       SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_DOWNLOAD_BASE);
+                       __vc_config_release_client(uid);
+                       pthread_mutex_unlock(&vc_config_mgr_mutex);
+                       return -1;
+               } else {
+                       SLOG(LOG_DEBUG, vc_config_tag(), "Success to make directory : %s", VC_DOWNLOAD_BASE);
+               }
+       }
+       if (0 != access(VC_DOWNLOAD_ENGINE_INFO, F_OK)) {
+               if (0 != mkdir(VC_DOWNLOAD_ENGINE_INFO, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
+                       SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to make directory : %s", VC_DOWNLOAD_ENGINE_INFO);
+                       __vc_config_release_client(uid);
+                       pthread_mutex_unlock(&vc_config_mgr_mutex);
+                       return -1;
+               } else {
+                       SLOG(LOG_DEBUG, vc_config_tag(), "Success to make directory : %s", VC_DOWNLOAD_ENGINE_INFO);
+               }
+       }
 
-               closedir(dp);
-       } else {
-               SLOG(LOG_WARN, vc_config_tag(), "[Engine Agent WARNING] Fail to open default directory");
+       if (0 != __vc_config_mgr_get_engine_info()) {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get engine info");
+               __vc_config_release_client(uid);
+               __vc_config_release_engine();
+               pthread_mutex_unlock(&vc_config_mgr_mutex);
+               return VC_CONFIG_ERROR_ENGINE_NOT_FOUND;
        }
 
        __vc_config_mgr_print_engine_info();
 
        if (0 != vc_parser_load_config(&g_config_info)) {
                SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse configure information");
+               __vc_config_release_client(uid);
+               __vc_config_release_engine();
                pthread_mutex_unlock(&vc_config_mgr_mutex);
                return -1;
        }
 
        if (0 != __vc_config_mgr_check_engine_is_valid(g_config_info->engine_id)) {
                SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to get default engine");
+               __vc_config_release_client(uid);
+               __vc_config_release_engine();
                vc_parser_unload_config(g_config_info);
                pthread_mutex_unlock(&vc_config_mgr_mutex);
                return VC_CONFIG_ERROR_ENGINE_NOT_FOUND;
@@ -616,6 +908,8 @@ int vc_config_mgr_initialize(int uid)
                        char* tmp_language;
                        if (0 != __vc_config_mgr_select_lang(g_config_info->engine_id, &tmp_language)) {
                                SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to select language");
+                               __vc_config_release_client(uid);
+                               __vc_config_release_engine();
                                vc_parser_unload_config(g_config_info);
                                pthread_mutex_unlock(&vc_config_mgr_mutex);
                                return -1;
@@ -630,6 +924,8 @@ int vc_config_mgr_initialize(int uid)
                                if (0 != vc_parser_set_language(tmp_language)) {
                                        free(tmp_language);
                                        SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to save config");
+                                       __vc_config_release_client(uid);
+                                       __vc_config_release_engine();
                                        vc_parser_unload_config(g_config_info);
                                        pthread_mutex_unlock(&vc_config_mgr_mutex);
                                        return -1;
@@ -655,6 +951,8 @@ int vc_config_mgr_initialize(int uid)
        temp_client = (vc_config_client_s*)calloc(1, sizeof(vc_config_client_s));
        if (NULL == temp_client) {
                SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to allocate memory");
+               __vc_config_release_client(uid);
+               __vc_config_release_engine();
                vc_parser_unload_config(g_config_info);
                pthread_mutex_unlock(&vc_config_mgr_mutex);
                return VC_ERROR_OUT_OF_MEMORY;
@@ -676,62 +974,22 @@ int vc_config_mgr_initialize(int uid)
 
 int vc_config_mgr_finalize(int uid)
 {
-       GSList *iter = NULL;
-       vc_config_client_s* temp_client = NULL;
-
        SLOG(LOG_INFO, vc_config_tag(), "[WARNING] Enter critical section");
-       pthread_mutex_lock(&vc_config_mgr_mutex);
 
-       if (0 < g_slist_length(g_config_client_list)) {
-               /* Check uid */
-               iter = g_slist_nth(g_config_client_list, 0);
-
-               while (NULL != iter) {
-                       temp_client = iter->data;
-
-                       if (NULL != temp_client) {
-                               if (uid == temp_client->uid) {
-                                       g_config_client_list = g_slist_remove(g_config_client_list, temp_client);
-                                       free(temp_client);
-                                       break;
-                               }
-                       }
-
-                       iter = g_slist_next(iter);
-               }
-       }
+       pthread_mutex_lock(&vc_config_mgr_mutex);
 
-       if (0 < g_slist_length(g_config_client_list)) {
-               SLOG(LOG_DEBUG, vc_config_tag(), "Client count (%d)", g_slist_length(g_config_client_list));
+       if (0 < __vc_config_release_client(uid)) {
                pthread_mutex_unlock(&vc_config_mgr_mutex);
-
+               SLOG(LOG_DEBUG, vc_config_tag(), "[WARNING] Leave critical section");
+               
                if (0 != pthread_mutex_destroy(&vc_config_mgr_mutex)) {
                        SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to destroy vc_config_mgr_mutex.");
                }
-
                return 0;
        }
 
-       vc_engine_info_s *engine_info = NULL;
-
-       if (0 < g_slist_length(g_engine_list)) {
-
-               /* Get a first item */
-               iter = g_slist_nth(g_engine_list, 0);
-
-               while (NULL != iter) {
-                       engine_info = iter->data;
-
-                       if (NULL != engine_info) {
-                               g_engine_list = g_slist_remove(g_engine_list, engine_info);
-
-                               vc_parser_free_engine_info(engine_info);
-                       }
-
-                       iter = g_slist_nth(g_engine_list, 0);
-               }
-       }
-
+       __vc_config_release_engine();
+       
        vconf_ignore_key_changed(VCONFKEY_LANGSET, __vc_config_language_changed_cb);
 
        vc_parser_unload_config(g_config_info);
index ac89c5a..a862549 100644 (file)
@@ -302,12 +302,12 @@ int vc_parser_load_config(vc_config_s** config_info)
        bool is_default_open = false;
 
        if (0 != access(VC_CONFIG, F_OK)) {
-               doc = xmlParseFile(VC_CONFIG_DEFAULT);
+               doc = xmlParseFile(VC_DEFAULT_CONFIG);
                if (doc == NULL) {
-                       SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_CONFIG_DEFAULT);
+                       SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_DEFAULT_CONFIG);
                        return -1;
                }
-               SLOG(LOG_DEBUG, vc_config_tag(), "Use default config : %s", VC_CONFIG_DEFAULT);
+               SLOG(LOG_DEBUG, vc_config_tag(), "Use default config : %s", VC_DEFAULT_CONFIG);
                is_default_open = true;
        } else {
                int retry_count = 0;
@@ -322,9 +322,9 @@ int vc_parser_load_config(vc_config_s** config_info)
 
                        if (VC_RETRY_COUNT == retry_count) {
                                SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_CONFIG);
-                               doc = xmlParseFile(VC_CONFIG_DEFAULT);
+                               doc = xmlParseFile(VC_DEFAULT_CONFIG);
                                if (NULL == doc) {
-                                       SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_CONFIG_DEFAULT);
+                                       SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", VC_DEFAULT_CONFIG);
                                        xmlCleanupParser();
                                        return -1;
                                }
@@ -760,6 +760,56 @@ int vc_parser_find_config_changed(int* auto_lang, char** language, int* enabled)
        return 0;
 }
 
+int vc_parser_copy_xml(const char* original, const char* destination)
+{
+       if (NULL == original || NULL == destination) {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Input parameter is NULL");
+               return -1;
+       }
+
+       xmlDocPtr doc = NULL;
+       if (0 == access(original, F_OK)) {
+               SLOG(LOG_DEBUG, vc_config_tag(), "[DEBUG] Success to access to %s", original);
+               doc = xmlParseFile(original);
+               if (doc == NULL) {
+                       SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to parse file error : %s", original);
+                       return -1;
+               }
+       } else {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to access to %s", original);
+               return -1;
+       }
+
+       int ret = xmlSaveFile(destination, doc);
+       if (0 > ret) {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Save result : %d", ret);
+       } else {
+               static FILE* pFile;
+               pFile = fopen(destination, "r");
+               int fd = -1;
+               if (NULL == pFile) {
+                       SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to open file %s", destination);
+               } else {
+                        fd = fileno(pFile);
+                        fsync(fd);
+                        fclose(pFile);
+                        SLOG(LOG_INFO, vc_config_tag(), "[DEBUG] Success to fsync %s", destination);
+                }
+                SLOG(LOG_ERROR, vc_config_tag(), "[DEBUG] Success to save %s", destination);
+       }
+
+       /* Set mode */
+       if (0 > chmod(destination, 0600)) {
+               SLOG(LOG_ERROR, vc_config_tag(), "[ERROR] Fail to change file mode : %d", ret);
+       }
+
+       xmlFreeDoc(doc);
+       doc = NULL;
+       SLOG(LOG_DEBUG, vc_config_tag(), "[SUCCESS] Copying xml");
+
+       return 0;
+}
+
 int vc_parser_set_foreground(int pid, bool value)
 {
        int cur_pid = 0;
index 253aa11..15635f0 100644 (file)
@@ -61,6 +61,8 @@ int vc_parser_set_enabled(bool value);
 
 int vc_parser_find_config_changed(int* auto_lang, char** language, int* enabled);
 
+int vc_parser_copy_xml(const char* original, const char* destination);
+
 
 /* Set / Get foreground info */
 int vc_parser_set_foreground(int pid, bool value);
index 096aa4f..d58ed69 100644 (file)
@@ -179,7 +179,7 @@ extern "C" {
 
 #define VC_DAEMON_PATH                 tzplatform_mkpath(tzplatform_getid("TZ_SYS_BIN"), "vc-daemon")
 
-#define VC_CONFIG_DEFAULT              tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "voice/vc/1.0/vc-config.xml")
+#define VC_DEFAULT_CONFIG              tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "voice/vc/1.0/vc-config.xml")
 
 #define VC_DEFAULT_BASE                        tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "voice/vc/1.0")
 
@@ -207,6 +207,10 @@ extern "C" {
 
 #define VC_RUNTIME_INFO_CLIENT         tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "share/.voice/vc/vc-client-info.xml")
 
+#define VC_DOWNLOAD_BASE               tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "/share/.voice/vc/1.0")
+
+#define VC_DOWNLOAD_ENGINE_INFO                tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "/share/.voice/vc/1.0/engine-info")
+
 #define VC_NO_FOREGROUND_PID           -1
 #define VC_BASE_LANGUAGE               "en_US"
 #define VC_RETRY_COUNT                 5
diff --git a/engine-parser/CMakeLists.txt b/engine-parser/CMakeLists.txt
new file mode 100644 (file)
index 0000000..84dafbe
--- /dev/null
@@ -0,0 +1,37 @@
+pkg_check_modules(parser-pkgs REQUIRED
+       capi-base-common
+       dlog
+       glib-2.0
+       libxml-2.0
+       pkgmgr-info
+       pkgmgr-installer
+       capi-appfw-app-manager
+       libtzplatform-config
+)
+
+FOREACH(flag ${parser-pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET (SRCS
+       src/vc-engine-parser.c
+)
+
+SET(EXTRA_CFLAGS  "${EXTRA_CFLAGS} -Wall" )
+SET(extapi "-fvisibility=hidden")
+
+## SET C COMPILER FLAGS
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} ${extapi}")
+
+## SET CPP COMPILER FLAGS
+#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
+#SET(CMAKE_CXX_FLAGS "${OSP_DEBUG_FLAGS} ${OSP_OPT_FLAGS} ${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} ${OSP_COMPILER_FLAGS}")
+
+## SET LINKER FLAGS
+SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed")
+
+## Create Library
+ADD_LIBRARY ("${PROJECT_NAME}-engine-parser" SHARED ${SRCS})
+TARGET_LINK_LIBRARIES("${PROJECT_NAME}-engine-parser" ${parser-pkgs_LDFLAGS} )
+
+INSTALL(TARGETS "${PROJECT_NAME}-engine-parser" DESTINATION "/etc/package-manager/parserlib/metadata")
diff --git a/engine-parser/src/vc-engine-parser.c b/engine-parser/src/vc-engine-parser.c
new file mode 100644 (file)
index 0000000..0e4a92a
--- /dev/null
@@ -0,0 +1,883 @@
+//
+// Copyright (c) 2016 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <app_manager.h>
+#include <dlog.h>
+#include <errno.h>
+#include <glib.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <pkgmgr-info.h>
+#include <pkgmgr_installer_info.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <tzplatform_config.h>
+#include <systemd/sd-login.h>
+
+#include <gum/gum-user.h>
+#include <gum/gum-user-service.h>
+#include <gum/common/gum-user-types.h>
+
+/* Define EXPORT_API */
+#ifndef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "vc-engine-parser"
+
+#define VC_TAG_ENGINE_BASE                     "voice-control-engine"
+#define VC_TAG_ENGINE_NAME                     "name"
+#define VC_TAG_ENGINE_ID                       "id"
+#define VC_TAG_ENGINE_SETTING          "setting"
+#define VC_TAG_ENGINE_LANGUAGE_SET             "languages"
+#define VC_TAG_ENGINE_LANGUAGE                 "lang"
+#define VC_TAG_ENGINE_NON_FIXED_SUPPORT        "non-fixed-support"
+#define VC_TAG_ENGINE_CREDENTIAL               "credential"
+
+#define VC_CONFIG_BASE         tzplatform_mkpath(TZ_USER_HOME, "share/.voice")
+#define VC_HOME                tzplatform_mkpath(TZ_USER_HOME, "share/.voice/vc")
+#define VC_ENGINE_BASE         tzplatform_mkpath(TZ_USER_HOME, "share/.voice/vc/1.0")
+#define VC_ENGINE_INFO         tzplatform_mkpath(TZ_USER_SHARE, ".voice/vc/1.0/engine-info")
+
+#define VC_GLOBAL_CONFIG_BASE          "/etc/skel/share/.voice"
+#define VC_GLOBAL_HOME         "/etc/skel/share/.voice/vc"
+#define VC_GLOBAL_ENGINE_BASE          "/etc/skel/share/.voice/vc/1.0"
+#define VC_GLOBAL_ENGINE_INFO          "/etc/skel/share/.voice/vc/1.0/engine-info"
+
+#define VC_METADATA_LANGUAGE                   "http://tizen.org/metadata/vc-engine/language"
+#define VC_METADATA_NON_FIXED_SUPPORT          "http://tizen.org/metadata/vc-engine/non-fixed-support"
+#define VC_METADATA_CREDENTIAL_REQUIRED        "http://tizen.org/metadata/vc-engine/credential-required"
+#define VC_METADATA_ENGINE_SETTING             "http://tizen.org/metadata/vc-engine/setting"
+#define VC_METADATA_ENGINE_NAME                "http://tizen.org/metadata/vc-engine/name"
+
+/* Define Macro */
+#define FREE(x)        { if (NULL != x)        { free(x);      x = NULL; } }
+#define G_FREE(x)      { if (NULL != x) { g_free(x);   x = NULL; } }
+
+typedef struct metadata {
+       const char *key;
+       const char *value;
+} metadata;
+
+static xmlDocPtr g_doc;
+GumUser *g_guser = NULL;
+uid_t g_uid = 301;     // app_fw
+gid_t g_gid = 301;     // app_fw
+GumUserType g_ut = GUM_USERTYPE_NONE;
+gchar *g_user_type = NULL;
+
+char *g_dir_config_base = NULL;
+char *g_dir_home = NULL;
+char *g_dir_engine_base = NULL;
+char *g_dir_engine_info = NULL;
+
+
+static int __create_engine_info_xml(const char *pkgid)
+{
+       LOGD("=== Create engine info doc");
+       g_doc = xmlNewDoc((xmlChar*)"1.0");
+       if (NULL == g_doc) {
+               LOGE("[ERROR] Fail to new doc");
+               return -1;
+       }
+       LOGD("===");
+       return 0;
+}
+
+static int __save_engine_info_xml(const char *pkgid, gchar *ut, uid_t uid, gid_t gid)
+{
+       LOGD("=== Save engine info doc");
+       char *dir_config_base = NULL;
+       char *dir_home = NULL;
+       char *dir_engine_base = NULL;
+       char *dir_engine_info = NULL;
+
+       if (NULL == ut || (NULL != ut && 0 == strcmp(ut, "none"))) {
+               LOGE("[ERROR] Usertype is NONE");
+               return -1;
+       }
+
+       uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
+       uid_t tmp_uid = 0;
+       gid_t tmp_gid = 0;
+       LOGD("uid(%d)", uid);
+
+       if (globalapp_uid == uid) {
+               /* Global app */
+               dir_config_base = strdup(VC_GLOBAL_CONFIG_BASE);
+               dir_home = strdup(VC_GLOBAL_HOME);
+               dir_engine_base = strdup(VC_GLOBAL_ENGINE_BASE);
+               dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO);
+               tmp_uid = 301;  // app_fw
+               tmp_gid = 301;  // app_fw
+       } else {
+               /* User app, Guest app, Security app */
+               if (NULL != g_dir_config_base)
+                       dir_config_base = strdup(g_dir_config_base);
+               if (NULL != g_dir_home)
+                       dir_home = strdup(g_dir_home);
+               if (NULL != g_dir_engine_base)
+                       dir_engine_base = strdup(g_dir_engine_base);
+               if (NULL != g_dir_engine_info)
+                       dir_engine_info = strdup(g_dir_engine_info);
+               tmp_uid = uid;
+               tmp_gid = gid;
+       }
+
+       if (NULL == dir_config_base || NULL == dir_home || NULL == dir_engine_base || NULL == dir_engine_info) {
+               LOGE("[ERROR] Fail to allocate memory");
+               FREE(dir_config_base)
+               FREE(dir_home)
+               FREE(dir_engine_base)
+               FREE(dir_engine_info)
+               return -1;
+       }
+
+       LOGD("[DEBUG] dir_engine_info(%s)", dir_engine_info);
+
+       /* Make directories */
+       int fd = -1;
+//     if (0 != access(dir_config_base, F_OK)) {
+       fd = open(dir_config_base, O_DIRECTORY);
+       if (-1 == fd) {
+               LOGE("[INFO] No directory : %s, errno : %d", dir_config_base, errno);
+               if (0 != mkdir(dir_config_base, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
+                       LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_config_base, errno);
+                       FREE(dir_config_base)
+                       FREE(dir_home)
+                       FREE(dir_engine_base)
+                       FREE(dir_engine_info)
+                       return -1;
+               } else {
+                       LOGD("Success to make directory : %s", dir_config_base);
+                       if (0 != chown(dir_config_base, tmp_uid, tmp_gid)) {
+                               LOGD("[ERROR] Fail to change user and group, errno : %d", errno);
+                       } else {
+                               LOGD("[DEBUG] Success to change user and group");
+                       }
+               }
+       } else {
+               close(fd);
+       }
+
+//     if (0 != access(dir_home, F_OK)) {
+       fd = open(dir_home, O_DIRECTORY);
+       if (-1 == fd) {
+               LOGE("[INFO] No directory : %s, errno : %d", dir_home, errno);
+               if (0 != mkdir(dir_home, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
+                       LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_home, errno);
+                       FREE(dir_config_base)
+                       FREE(dir_home)
+                       FREE(dir_engine_base)
+                       FREE(dir_engine_info)
+                       return -1;
+               } else {
+                       LOGD("Success to make directory : %s", dir_home);
+                       if (0 != chown(dir_home, tmp_uid, tmp_gid)) {
+                               LOGD("[ERROR] Fail to change user and group, errno : %d", errno);
+                       } else {
+                               LOGD("[DEBUG] Success to change user and group");
+                       }
+               }
+       } else {
+               close(fd);
+       }
+
+//     if (0 != access(dir_engine_base, F_OK)) {
+       fd = open(dir_engine_base, O_DIRECTORY);
+       if (-1 == fd) {
+               LOGE("[INFO] No directory : %s, errno : %d", dir_engine_base, errno);
+               if (0 != mkdir(dir_engine_base, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
+                       LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_engine_base, errno);
+                       FREE(dir_config_base)
+                       FREE(dir_home)
+                       FREE(dir_engine_base)
+                       FREE(dir_engine_info)
+                       return -1;
+               } else {
+                       LOGD("Success to make directory : %s", dir_engine_base);
+                       if (0 != chown(dir_engine_base, tmp_uid, tmp_gid)) {
+                               LOGD("[ERROR] Fail to change user and group, errno : %d", errno);
+                       } else {
+                               LOGD("[DEBUG] Success to change user and group");
+                       }
+               }
+       } else {
+               close(fd);
+       }
+
+//     if (0 != access(dir_engine_info, F_OK)) {
+       fd = open(dir_engine_info, O_DIRECTORY);
+       if (-1 == fd) {
+               LOGE("[INFO] No directory : %s, errno : %d", dir_engine_info, errno);
+               if (0 != mkdir(dir_engine_info, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
+                       LOGE("[ERROR] Fail to make directory : %s, errno : %d", dir_engine_info, errno);
+                       FREE(dir_config_base)
+                       FREE(dir_home)
+                       FREE(dir_engine_base)
+                       FREE(dir_engine_info)
+                       return -1;
+               } else {
+                       LOGD("Success to make directory : %s", dir_engine_info);
+                       if (0 != chown(dir_engine_info, tmp_uid, tmp_gid)) {
+                               LOGD("[ERROR] Fail to change user and group, errno : %d", errno);
+                       } else {
+                               LOGD("[DEBUG] Success to change user and group");
+                       }
+               }
+       } else {
+               close(fd);
+       }
+
+       char path[256] = {'\0',};
+       snprintf(path, 256, "%s/%s.xml", dir_engine_info, pkgid);
+       int ret = xmlSaveFormatFile(path, g_doc, 1);
+       LOGD("xmlSaveFile (%d)", ret);
+       if (0 == ret) {
+               if (0 != chown(path, tmp_uid, tmp_gid)) {
+                       LOGD("[ERROR] Fail to change user and group");
+               } else {
+                       LOGD("[DEBUG] Success to change user and group");
+               }
+       }
+
+       FREE(dir_config_base)
+       FREE(dir_home)
+       FREE(dir_engine_base)
+       FREE(dir_engine_info)
+
+       LOGD("===");
+
+       return 0;
+}
+
+static int __remove_engine_info_xml(const char *pkgid, gchar *ut, uid_t uid)
+{
+       LOGD("=== Remove engine info doc");
+       char *dir_engine_info = NULL;
+
+       if (NULL == ut || (NULL != ut && 0 == strcmp(ut, "none"))) {
+               LOGE("[ERROR] Usertype is NONE");
+               return -1;
+       }
+
+       uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
+
+       LOGD("uid(%d)", uid);
+
+       if (globalapp_uid == uid) {
+               /* Global app */
+               dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO);
+       } else {
+               /* User app, Guest app, Security app */
+               if (NULL != g_dir_engine_info)
+                       dir_engine_info = strdup(g_dir_engine_info);
+       }
+
+       if (NULL == dir_engine_info) {
+               LOGE("[ERROR] Fail to allocate memory");
+               return -1;
+       }
+
+       LOGD("[DEBUG] dir_engine_info(%s)", dir_engine_info);
+
+       char path[256] = {'\0',};
+       snprintf(path, 256, "%s/%s.xml", dir_engine_info, pkgid);
+       if (0 == access(path, F_OK)) {
+               LOGD("Remove engine info xml(%s)", path);
+               if (0 != remove(path)) {
+                       LOGE("[ERROR] Fail to emove engine info xml(%s)", path);
+               }
+       }
+
+       FREE(dir_engine_info)
+
+       LOGD("===");
+
+       return 0;
+}
+
+static void __insert_language_from_metadata(xmlNodePtr root, const char *language)
+{
+       LOGD("==== Insert language");
+       char* lang = NULL;
+
+       if (NULL == root || NULL == language) {
+               LOGE("Invalid parameter, root(%p), language(%s)", root, language);
+               return;
+       }
+
+       char *tmp_lang, *tmp_free;
+       tmp_free = tmp_lang = strdup(language);
+       xmlNodePtr languages_node = NULL;
+       xmlNodePtr lang_node = NULL;
+
+       languages_node = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_LANGUAGE_SET);
+
+       lang = strsep(&tmp_lang, ",");
+       while (NULL != lang) {
+               LOGD("lang (%s)", lang);
+               lang_node = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_LANGUAGE);
+               xmlNodeSetContent(lang_node, (const xmlChar*)lang);
+               xmlAddChild(languages_node, lang_node);
+               lang = strsep(&tmp_lang, ",");
+       }
+       xmlAddChild(root, languages_node);
+
+       FREE(tmp_free)
+}
+
+static int __write_metadata_inxml(const char *pkgid, const char *appid, GList *list)
+{
+       GList *iter = NULL;
+       metadata *md = NULL;
+
+       __create_engine_info_xml(pkgid);
+
+       xmlNodePtr root = NULL;
+       xmlNodePtr cur = NULL;
+
+       root = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_BASE);
+
+       if (NULL == root) {
+               LOGE("[ERROR] Fail to get new node");
+//             xmlFreeDoc(g_doc);
+               return -1;
+       }
+       xmlDocSetRootElement(g_doc, root);
+
+       iter = g_list_first(list);
+       while (NULL != iter) {
+               md = (metadata *)iter->data;
+               if (NULL != md && NULL != md->key && NULL != md->value) {
+                       LOGD(" - key(%s) value(%s)", md->key, md->value);
+                       if (!strcmp(md->key, VC_METADATA_LANGUAGE)) {
+                               __insert_language_from_metadata(root, md->value);
+                       } else if (!strcmp(md->key, VC_METADATA_NON_FIXED_SUPPORT)) {
+                               cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_NON_FIXED_SUPPORT);
+                               xmlNodeSetContent(cur, (const xmlChar*)md->value);
+                               xmlAddChild(root, cur);
+                       } else if (!strcmp(md->key, VC_METADATA_CREDENTIAL_REQUIRED)) {
+                               cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_CREDENTIAL);
+                               xmlNodeSetContent(cur, (const xmlChar*)md->value);
+                               xmlAddChild(root, cur);
+                       } else if (!strcmp(md->key, VC_METADATA_ENGINE_SETTING)) {
+                               cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_SETTING);
+                               xmlNodeSetContent(cur, (const xmlChar*)md->value);
+                               xmlAddChild(root, cur);
+                       } else if (!strcmp(md->key, VC_METADATA_ENGINE_NAME)) {
+                               cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_NAME);
+                               xmlNodeSetContent(cur, (const xmlChar*)md->value);
+                               xmlAddChild(root, cur);
+                       } else {
+                               LOGW("[WARNING] Unknown metadata type");
+                       }
+               }
+               iter = g_list_next(iter);
+       }
+
+       cur = xmlNewNode(NULL, (const xmlChar*)VC_TAG_ENGINE_ID);
+       xmlNodeSetContent(cur, (const xmlChar*)appid);
+       xmlAddChild(root, cur);
+
+       LOGD("");
+       return 0;
+}
+
+EXPORT_API
+int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgid, const char *appid, GList *list)
+{
+       LOGD("METADATA INSTALL");
+       LOGD("pkgid(%s) appid(%s) list(%d)", pkgid, appid, g_list_length(list));
+
+       int ret = -1;
+       ret = pkgmgr_installer_info_get_target_uid(&g_uid);
+       if (ret < 0) {
+               LOGE("[ERROR] Fail to get target uid");
+               return 0;
+       } else {
+               LOGD("uid(%d)", g_uid);
+               printf("[Parser Debug][DEBUG] uid(%d)", g_uid);
+       }
+
+       uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
+       if (globalapp_uid == g_uid) {
+               g_user_type = g_strdup("admin");
+       } else {
+               g_guser = gum_user_get_sync(g_uid, FALSE);
+               if (NULL == g_guser) {
+                       LOGE("[ERROR] g_guser is NULL");
+                       return -1;
+               }
+
+               g_object_get(G_OBJECT(g_guser), "gid", &g_gid, NULL);
+               g_object_get(G_OBJECT(g_guser), "usertype", &g_ut, NULL);
+               g_user_type = g_strdup(gum_user_type_to_string(g_ut));
+       }
+
+       if (NULL == g_user_type) {
+               LOGE("[ERROR] Fail to allocate memory");
+               if (NULL != g_guser) {
+                       g_object_unref(g_guser);
+                       g_guser = NULL;
+               }
+               return -1;
+       }
+
+       if (0 == strcmp(g_user_type, "none")) {
+               /* GUM_USERTYPE_NONE */
+               LOGE("[ERROR] Fail to get target uid");
+               g_object_unref(g_guser);
+               g_guser = NULL;
+               G_FREE(g_user_type)
+               return -1;
+       }
+
+       if (globalapp_uid == g_uid) {
+               /* global directory */
+               LOGD("[DEBUG] usertype: %s", g_user_type);
+               if (0 >= g_list_length(list)) {
+                       LOGE("[ERROR] No Engine Metadata");
+                       G_FREE(g_user_type)
+                       return 0;
+               }
+
+               if (0 != __write_metadata_inxml(pkgid, appid, list)) {
+                       LOGE("[ERROR] Fail to write metadata in the xml");
+                       xmlFreeDoc(g_doc);
+                       G_FREE(g_user_type)
+                       return -1;
+               }
+
+               /* Save in /etc/skel/share/ */
+               g_dir_config_base = strdup(VC_GLOBAL_CONFIG_BASE);
+               g_dir_home = strdup(VC_GLOBAL_HOME);
+               g_dir_engine_base = strdup(VC_GLOBAL_ENGINE_BASE);
+               g_dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO);
+
+               if (NULL == g_dir_config_base || NULL == g_dir_home || NULL == g_dir_engine_base || NULL == g_dir_engine_info) {
+                       LOGE("[ERROR] Fail to allocate memory");
+                       FREE(g_dir_config_base)
+                       FREE(g_dir_home)
+                       FREE(g_dir_engine_base)
+                       FREE(g_dir_engine_info)
+                       xmlFreeDoc(g_doc);
+                       G_FREE(g_user_type)
+                       return -1;
+               }
+
+               if (0 != __save_engine_info_xml(pkgid, g_user_type, g_uid, g_gid)) {
+                       LOGE("[ERROR] Fail to make engine info file");
+                       xmlFreeDoc(g_doc);
+                       G_FREE(g_user_type)
+                       return -1;
+               }
+
+               /* Get user data by using libgum */
+
+               GumUserService *gus = NULL;
+               GumUserList *users = NULL;
+               GumUserList *iter = NULL;
+               GumUser *user = NULL;
+               gchar **query;
+               GumUserType gumut = GUM_USERTYPE_NONE;
+               gchar *user_type = NULL;
+
+               uid_t uid;
+               gid_t gid;
+               gchar *home_dir = NULL;
+
+               gus = gum_user_service_create_sync(TRUE);
+               if (!gus) {
+                       LOGE("Failed to create gum user service");
+                       G_FREE(g_user_type)
+                       return -1;
+               }
+
+               query = g_strsplit("admin,normal", ",", -1);
+
+               users = gum_user_service_get_user_list_sync(gus, (const gchar *const *)query);
+               g_strfreev(query);
+
+               if (!users) {
+                       LOGD("NO users");
+                       g_object_unref(gus);
+                       gus = NULL;
+                       G_FREE(g_user_type)
+                       return 0;
+               }
+
+               /* Make new user list */
+
+               iter = users;
+               while (iter != NULL) {
+                       user = (GumUser*) iter->data;
+                       g_object_get(G_OBJECT(user), "uid", &uid, NULL);
+                       G_FREE(home_dir)
+
+                       g_object_get(G_OBJECT(user), "gid", &gid, NULL);
+                       g_object_get(G_OBJECT(user), "homedir", &home_dir, NULL);
+                       g_object_get(G_OBJECT(user), "usertype", &gumut, NULL);
+                       user_type = g_strdup(gum_user_type_to_string(gumut));
+                       if (NULL == user_type) {
+                               gum_user_service_list_free(users);
+                               G_FREE(home_dir)
+                               g_object_unref(gus);
+                               gus = NULL;
+                               return -1;
+                       }
+
+                       LOGD("[DEBUG] user info");
+                       if (NULL != home_dir) {
+                               LOGD("[DEBUG] uid(%d), gid(%d), user_type(%s), home_dir(%s)", uid, gid, user_type, home_dir);
+
+                               g_dir_config_base = (char*)calloc(strlen(home_dir) + 14, sizeof(char));
+                               g_dir_home = (char*)calloc(strlen(home_dir) + 17, sizeof(char));
+                               g_dir_engine_base = (char*)calloc(strlen(home_dir) + 21, sizeof(char));
+                               g_dir_engine_info = (char*)calloc(strlen(home_dir) + 33, sizeof(char));
+
+                               if (NULL == g_dir_config_base || NULL == g_dir_home || NULL == g_dir_engine_base || NULL == g_dir_engine_info) {
+                                       LOGE("[ERROR] Fail to allocate memory");
+                                       FREE(g_dir_config_base)
+                                       FREE(g_dir_home)
+                                       FREE(g_dir_engine_base)
+                                       FREE(g_dir_engine_info)
+                                       gum_user_service_list_free(users);
+                                       g_object_unref(gus);
+                                       gus = NULL;
+                                       G_FREE(user_type)
+                                       G_FREE(home_dir)
+                                       return -1;
+                               }
+                               snprintf(g_dir_config_base, strlen(home_dir) + 14, "%s/share/.voice", home_dir);
+                               snprintf(g_dir_home, strlen(home_dir) + 17, "%s/share/.voice/vc", home_dir);
+                               snprintf(g_dir_engine_base, strlen(home_dir) + 21, "%s/share/.voice/vc/1.0", home_dir);
+                               snprintf(g_dir_engine_info, strlen(home_dir) + 33, "%s/share/.voice/vc/1.0/engine-info", home_dir);
+
+                               LOGD("[DEBUG] g_dir_engine_info(%s)", g_dir_engine_info);
+
+                               if (0 != __save_engine_info_xml(pkgid, user_type, uid, gid)) {
+                                       LOGE("[ERROR] Fail to make engine info file");
+                               }
+
+                               FREE(g_dir_config_base)
+                               FREE(g_dir_home)
+                               FREE(g_dir_engine_base)
+                               FREE(g_dir_engine_info)
+
+                               G_FREE(home_dir)
+                       }
+
+                       G_FREE(user_type)
+                       iter = g_list_next(iter);
+               }
+
+               gum_user_service_list_free(users);
+               g_object_unref(gus);
+               gus = NULL;
+       } else {
+               /* user directory */
+               LOGD("[DEBUG] usertype: %s", g_user_type);
+
+               ret = tzplatform_set_user(g_uid);
+               if (ret < 0) {
+                       LOGE("[ERROR] Invalid uid");
+                       g_object_unref(g_guser);
+                       g_guser = NULL;
+                       G_FREE(g_user_type)
+                       return 0;
+               } else {
+                       LOGD("TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/"));
+                       printf("[Parser Debug][DEBUG] TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/"));
+               }
+
+               if (0 >= g_list_length(list)) {
+                       LOGE("[ERROR] No Engine Metadata");
+                       g_object_unref(g_guser);
+                       g_guser = NULL;
+                       G_FREE(g_user_type)
+                       return 0;
+               }
+
+               if (0 != __write_metadata_inxml(pkgid, appid, list)) {
+                       LOGE("[ERROR] Fail to write metadata in the xml");
+                       xmlFreeDoc(g_doc);
+                       g_object_unref(g_guser);
+                       g_guser = NULL;
+                       G_FREE(g_user_type)
+                       return -1;
+               }
+
+               g_dir_config_base = strdup(VC_CONFIG_BASE);
+               g_dir_home = strdup(VC_HOME);
+               g_dir_engine_base = strdup(VC_ENGINE_BASE);
+               g_dir_engine_info = strdup(VC_ENGINE_INFO);
+
+               if (NULL == g_dir_config_base || NULL == g_dir_home || NULL == g_dir_engine_base || NULL == g_dir_engine_info) {
+                       LOGE("[ERROR] Fail to allocate memory");
+                       FREE(g_dir_config_base)
+                       FREE(g_dir_home)
+                       FREE(g_dir_engine_base)
+                       FREE(g_dir_engine_info)
+                       xmlFreeDoc(g_doc);
+                       g_object_unref(g_guser);
+                       g_guser = NULL;
+                       G_FREE(g_user_type)
+                       return -1;
+               }
+
+               if (0 != __save_engine_info_xml(pkgid, g_user_type, g_uid, g_gid)) {
+                       LOGE("[ERROR] Fail to make engine info file");
+                       xmlFreeDoc(g_doc);
+                       if (NULL != g_guser) {
+                               g_object_unref(g_guser);
+                               g_guser = NULL;
+                       }
+                       G_FREE(g_user_type)
+                       return -1;
+               }
+       }
+
+       xmlFreeDoc(g_doc);
+       if (NULL != g_guser) {
+               g_object_unref(g_guser);
+               g_guser = NULL;
+       }
+       G_FREE(g_user_type)
+
+       FREE(g_dir_config_base)
+       FREE(g_dir_home)
+       FREE(g_dir_engine_base)
+       FREE(g_dir_engine_info)
+
+       return 0;
+}
+
+EXPORT_API
+int PKGMGR_MDPARSER_PLUGIN_UNINSTALL(const char *pkgid, const char *appid, GList *list)
+{
+       LOGD("METADATA UNINSTALL");
+       LOGD("pkgid(%s) appid(%s) list(%d)", pkgid, appid, g_list_length(list));
+
+       int ret = -1;
+       ret = pkgmgr_installer_info_get_target_uid(&g_uid);
+       if (ret < 0) {
+               LOGE("[ERROR] Fail to get target uid");
+               return 0;
+       } else {
+               LOGD("uid(%d)", g_uid);
+               printf("[Parser Debug][DEBUG] uid(%d)", g_uid);
+       }
+
+       uid_t globalapp_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
+       if (globalapp_uid == g_uid) {
+               g_user_type = g_strdup("admin");
+       } else {
+               g_guser = gum_user_get_sync(g_uid, FALSE);
+               if (NULL == g_guser) {
+                       LOGE("[ERROR] g_guser is NULL");
+                       return -1;
+               }
+
+               g_object_get(G_OBJECT(g_guser), "usertype", &g_ut, NULL);
+               g_user_type = g_strdup(gum_user_type_to_string(g_ut));
+       }
+
+       if (NULL == g_user_type) {
+               LOGE("[ERROR] Fail to allocate memory");
+               if (NULL != g_guser) {
+                       g_object_unref(g_guser);
+                       g_guser = NULL;
+               }
+               return -1;
+       }
+
+       if (0 == strcmp(g_user_type, "none")) {
+               /* GUM_USERTYPE_NONE */
+               LOGE("[ERROR] Fail to get target uid");
+               g_object_unref(g_guser);
+               g_guser = NULL;
+               G_FREE(g_user_type)
+               return -1;
+       }
+
+       if (globalapp_uid == g_uid) {
+               /* global directory */
+               LOGD("[DEBUG] usertype: %s", g_user_type);
+
+               /* Remove files in /etc/skel/share/ */
+               g_dir_engine_info = strdup(VC_GLOBAL_ENGINE_INFO);
+               if (NULL == g_dir_engine_info) {
+                       LOGE("[ERROR] Fail to allocate memory");
+                       G_FREE(g_user_type)
+                       return -1;
+               }
+
+               if (0 != __remove_engine_info_xml(pkgid, g_user_type, g_uid)) {
+                       LOGE("[ERROR] Fail to remove engine info file");
+               }
+
+               /* Get user data by using libgum */
+
+               GumUserService *gus = NULL;
+               GumUserList *users = NULL;
+               GumUserList *iter = NULL;
+               GumUser *user = NULL;
+               gchar **query;
+               GumUserType gumut = GUM_USERTYPE_NONE;
+               gchar *user_type = NULL;
+
+               uid_t uid;
+               gchar *home_dir = NULL;
+
+               GList *md_iter = NULL;
+               metadata *md = NULL;
+
+               gus = gum_user_service_create_sync(TRUE);
+               if (!gus) {
+                       LOGE("Failed to create gum user service");
+                       G_FREE(g_user_type)
+                       return -1;
+               }
+
+               query = g_strsplit("admin,normal", ",", -1);
+
+               users = gum_user_service_get_user_list_sync(gus, (const gchar *const *)query);
+               g_strfreev(query);
+
+               if (!users) {
+                       LOGD("NO users");
+                       g_object_unref(gus);
+                       gus = NULL;
+                       G_FREE(g_user_type)
+                       return 0;
+               }
+
+               /* Make new user list */
+
+               iter = users;
+               while (iter != NULL) {
+                       user = (GumUser*) iter->data;
+                       g_object_get(G_OBJECT(user), "uid", &uid, NULL);
+                       G_FREE(home_dir)
+                       g_object_get(G_OBJECT(user), "homedir", &home_dir, NULL);
+                       g_object_get(G_OBJECT(user), "usertype", &gumut, NULL);
+                       user_type = g_strdup(gum_user_type_to_string(gumut));
+                       if (NULL == user_type) {
+                               gum_user_service_list_free(users);
+                               G_FREE(home_dir)
+                               g_object_unref(gus);
+                               gus = NULL;
+                               return -1;
+                       }
+
+                       if (NULL != home_dir) {
+                               g_dir_engine_info = (char*)calloc(strlen(home_dir) + 33, sizeof(char));
+                               if (NULL == g_dir_engine_info) {
+                                       gum_user_service_list_free(users);
+                                       G_FREE(home_dir)
+                                       g_object_unref(gus);
+                                       gus = NULL;
+                                       G_FREE(user_type)
+                                       return -1;
+                               }
+
+                               snprintf(g_dir_engine_info, strlen(home_dir) + 33, "%s/share/.voice/vc/1.0/engine-info", home_dir);
+
+                               md_iter = g_list_first(list);
+                               while (NULL != md_iter) {
+                                       md = (metadata *)md_iter->data;
+                                       LOGD(" - key(%s) value(%s)", md->key, md->value);
+                                       md_iter = g_list_next(md_iter);
+                               }
+
+                               if (0 != __remove_engine_info_xml(pkgid, user_type, uid)) {
+                                       LOGE("[ERROR] Fail to remove engine info file");
+                               }
+
+                               G_FREE(home_dir)
+                               G_FREE(g_dir_engine_info)
+                       }
+                       G_FREE(user_type)
+
+                       LOGD("Finish release memory");
+                       iter = g_list_next(iter);
+                       LOGD("Finish next iter");
+               }
+
+               gum_user_service_list_free(users);
+               g_object_unref(gus);
+               gus = NULL;
+       } else {
+               /* user directory */
+               LOGD("[DEBUG] usertype: %s", g_user_type);
+
+               ret = tzplatform_set_user(g_uid);
+               if (ret < 0) {
+                       LOGE("[ERROR] Invalid uid");
+                       g_object_unref(g_guser);
+                       g_guser = NULL;
+                       G_FREE(g_user_type)
+                       return -1;
+               } else {
+                       LOGD("TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/"));
+                       printf("[Parser Debug][DEBUG] TZ_USER_HOME: %s", tzplatform_mkstr(TZ_USER_HOME, "/"));
+               }
+
+               g_dir_engine_info = strdup(VC_ENGINE_INFO);
+               if (NULL == g_dir_engine_info) {
+                       LOGE("[ERROR] Fail to allocate memory");
+                       g_object_unref(g_guser);
+                       g_guser = NULL;
+                       G_FREE(g_user_type)
+                       return -1;
+               }
+
+               if (0 != __remove_engine_info_xml(pkgid, g_user_type, g_uid)) {
+                       LOGE("[ERROR] Fail to remove engine info file");
+               }
+
+       }
+
+       if (NULL != g_guser) {
+               g_object_unref(g_guser);
+               g_guser = NULL;
+       }
+       G_FREE(g_user_type)
+
+       FREE(g_dir_engine_info)
+
+       LOGD("");
+       return 0;
+}
+
+EXPORT_API
+int PKGMGR_MDPARSER_PLUGIN_UPGRADE(const char *pkgid, const char *appid, GList *list)
+{
+       LOGD("METADATA UPGRADE");
+       LOGD("pkgid(%s) appid(%s) list(%d)", pkgid, appid, g_list_length(list));
+
+       PKGMGR_MDPARSER_PLUGIN_UNINSTALL(pkgid, appid, list);
+       PKGMGR_MDPARSER_PLUGIN_INSTALL(pkgid, appid, list);
+
+       LOGD("");
+       return 0;
+}
index 278936c..6d0cc6d 100644 (file)
@@ -26,9 +26,12 @@ BuildRequires:  pkgconfig(ecore)
 BuildRequires:  pkgconfig(ecore-wayland)
 BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(json-glib-1.0)
+BuildRequires:  pkgconfig(libgum)
 BuildRequires:  pkgconfig(libtzplatform-config)
 BuildRequires:  pkgconfig(libxml-2.0)
 BuildRequires:  pkgconfig(sqlite3)
+BuildRequires:  pkgconfig(pkgmgr-info)
+BuildRequires:  pkgconfig(pkgmgr-installer)
 %if "%{tizen_profile_name}" == "tv"
 BuildRequires:  pkgconfig(capi-network-bluetooth)
 BuildRequires:  pkgconfig(capi-network-bluetooth-tv)
@@ -128,6 +131,7 @@ mkdir -p %{_libdir}/voice/vc
 %{_libdir}/libvc_engine.so
 %{TZ_SYS_RO_SHARE}/voice/vc/1.0/vc-config.xml
 %{TZ_SYS_RO_SHARE}/dbus-1/services/org.tizen.voice*
+%{TZ_SYS_RO_ETC}/package-manager/parserlib/metadata/libvc-engine-parser.so*
 /etc/dbus-1/session.d/vc-server.conf
 
 %files devel