+/*
+ * pkgmgr-info
+ *
+ * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Junghyun Yeon(jungh.yeon@samsung.com>,
+ * Jongmyeong Ko(jongmyeong.ko@samsung.com>, Sangyoon Jang(s89.jang@samsung.com>
+ *
+ * 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.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdbool.h>
+#include <ctype.h>
+
+#include <sqlite3.h>
+#include <glib.h>
+
+#include "pkgmgrinfo_basic.h"
+#include "pkgmgrinfo_private.h"
+#include "pkgmgrinfo_debug.h"
+#include "pkgmgr-info.h"
+
+static void __free_update_info(gpointer data)
+{
+ updateinfo_x *update_info = (updateinfo_x *)data;
+ if (update_info == NULL)
+ return;
+
+ if (update_info->pkgid)
+ free((void *)update_info->pkgid);
+ if (update_info->version)
+ free((void *)update_info->version);
+ free((void *)update_info);
+
+}
+
+static int __convert_update_type(const char *type, pkgmgrinfo_updateinfo_update_type *convert_type)
+{
+ if (strncasecmp(type, PMINFO_UPDATEINFO_TYPE_NONE,
+ strlen(PMINFO_UPDATEINFO_TYPE_NONE)) == 0)
+ *convert_type = PMINFO_UPDATEINFO_NONE;
+ else if (strncasecmp(type, PMINFO_UPDATEINFO_TYPE_FORCE,
+ strlen(PMINFO_UPDATEINFO_TYPE_FORCE)) == 0)
+ *convert_type = PMINFO_UPDATEINFO_FORCE;
+ else if (strncasecmp(type, PMINFO_UPDATEINFO_TYPE_OPTIONAL,
+ strlen(PMINFO_UPDATEINFO_TYPE_OPTIONAL)) == 0)
+ *convert_type = PMINFO_UPDATEINFO_OPTIONAL;
+ else
+ return -1;
+ return 0;
+}
+
+API int pkgmgrinfo_updateinfo_create(
+ pkgmgrinfo_updateinfo_h *updateinfo_handle)
+{
+ updateinfo_x *update_info;
+
+ retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
+ "Update handle output parameter is NULL\n");
+
+ update_info = (updateinfo_x *)calloc(
+ 1, sizeof(updateinfo_x));
+ if (update_info == NULL) {
+ _LOGE("Out of memory");
+ return PMINFO_R_ERROR;
+ }
+
+ *updateinfo_handle = update_info;
+
+ return PMINFO_R_OK;
+}
+
+API int pkgmgrinfo_updateinfo_destroy(
+ pkgmgrinfo_updateinfo_h updateinfo_handle)
+{
+ retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
+ "Update info handle parameter is NULL\n");
+
+ __free_update_info(updateinfo_handle);
+ return PMINFO_R_OK;
+}
+
+API int pkgmgrinfo_updateinfo_set_pkgid(
+ pkgmgrinfo_updateinfo_h updateinfo_handle, const char *pkgid)
+{
+ updateinfo_x *updateinfo;
+
+ retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
+ "Update info handle parameter is NULL\n");
+ retvm_if(pkgid == NULL, PMINFO_R_EINVAL,
+ "pkgid parameter is NULL\n");
+
+ updateinfo = (updateinfo_x *)updateinfo_handle;
+ if (updateinfo->pkgid)
+ free(updateinfo->pkgid);
+
+ updateinfo->pkgid = strdup(pkgid);
+ if (updateinfo->pkgid == NULL) {
+ _LOGE("Out of memory");
+ return PMINFO_R_ERROR;
+ }
+
+ return PMINFO_R_OK;
+}
+
+API int pkgmgrinfo_updateinfo_set_version(
+ pkgmgrinfo_updateinfo_h updateinfo_handle, const char *version)
+{
+ updateinfo_x *updateinfo;
+
+ retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
+ "Update info handle parameter is NULL\n");
+ retvm_if(version == NULL, PMINFO_R_EINVAL,
+ "pkgid parameter is NULL\n");
+
+ updateinfo = (updateinfo_x *)updateinfo_handle;
+ if (updateinfo->version)
+ free(updateinfo->version);
+
+ updateinfo->version = strdup(version);
+ if (updateinfo->version == NULL) {
+ _LOGE("Out of memory");
+ return PMINFO_R_ERROR;
+ }
+
+ return PMINFO_R_OK;
+}
+
+API int pkgmgrinfo_updateinfo_set_type(
+ pkgmgrinfo_updateinfo_h updateinfo_handle,
+ pkgmgrinfo_updateinfo_update_type type)
+{
+ updateinfo_x *updateinfo;
+
+ retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
+ "Update info handle parameter is NULL\n");
+
+ updateinfo = (updateinfo_x *)updateinfo_handle;
+ updateinfo->type = type;
+ return PMINFO_R_OK;
+}
+
+API int pkgmgrinfo_updateinfo_get_pkgid(
+ pkgmgrinfo_updateinfo_h updateinfo_handle, char **pkgid)
+{
+ updateinfo_x *update_info;
+
+ retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
+ "Update info node parameter is NULL\n");
+
+ update_info = (updateinfo_x *)updateinfo_handle;
+ if (update_info->pkgid == NULL)
+ return PMINFO_R_ERROR;
+
+ *pkgid = update_info->pkgid;
+ return PMINFO_R_OK;
+}
+
+API int pkgmgrinfo_updateinfo_get_version(
+ pkgmgrinfo_updateinfo_h updateinfo_handle, char **version)
+{
+ updateinfo_x *update_info;
+
+ retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
+ "Update info node parameter is NULL\n");
+
+ update_info = (updateinfo_x *)updateinfo_handle;
+ if (update_info->version == NULL)
+ return PMINFO_R_ERROR;
+
+ *version = update_info->version;
+ return PMINFO_R_OK;
+}
+
+API int pkgmgrinfo_updateinfo_get_update_type(
+ pkgmgrinfo_updateinfo_h updateinfo_handle,
+ pkgmgrinfo_updateinfo_update_type *type)
+{
+ updateinfo_x *update_info;
+
+ retvm_if(updateinfo_handle == NULL, PMINFO_R_EINVAL,
+ "Update info node parameter is NULL\n");
+
+ update_info = (updateinfo_x *)updateinfo_handle;
+ *type = update_info->type;
+
+ return PMINFO_R_OK;
+}
+
+static int _get_pkg_updateinfo_from_db(const char *pkgid,
+ GSList **update_info_list, uid_t uid)
+{
+ char *dbpath;
+ char *type;
+ char query[MAX_QUERY_LEN] = { '\0' };
+ int ret;
+ int idx;
+ sqlite3 *db;
+ sqlite3_stmt *stmt;
+ updateinfo_x *update_info = NULL;
+ pkgmgrinfo_updateinfo_update_type convert_type;
+
+ dbpath = getUserPkgParserDBPathUID(uid);
+ if (dbpath == NULL)
+ return PMINFO_R_ERROR;
+
+ ret = __open_db(dbpath, &db, SQLITE_OPEN_READONLY);
+ if (ret != SQLITE_OK) {
+ _LOGD("failed to open db: %d", ret);
+ free(dbpath);
+ return -1;
+ }
+
+ if (pkgid == NULL)
+ sqlite3_snprintf(MAX_QUERY_LEN, query,
+ "SELECT package, update_version, update_type " \
+ "FROM package_update_info");
+ else
+ sqlite3_snprintf(MAX_QUERY_LEN, query,
+ "SELECT package, update_version, update_type " \
+ "FROM package_update_info WHERE package=%Q",
+ pkgid);
+
+ ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ _LOGE("Don't execute query = %s error message = %s\n", query,
+ sqlite3_errmsg(db));
+ free(dbpath);
+ return -1;
+ }
+
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ update_info = calloc(1, sizeof(updateinfo_x));
+ if (update_info == NULL) {
+ _LOGE("Out of memory");
+ free(dbpath);
+ sqlite3_finalize(stmt);
+ sqlite3_close_v2(db);
+ return -1;
+ }
+ idx = 0;
+ _save_column_str(stmt, idx++, &update_info->pkgid);
+ _save_column_str(stmt, idx++, &update_info->version);
+ _save_column_str(stmt, idx, &type);
+ ret = __convert_update_type(type, &convert_type);
+ if (ret != 0) {
+ __free_update_info(update_info);
+ free(dbpath);
+ sqlite3_finalize(stmt);
+ sqlite3_close_v2(db);
+ return -1;
+ }
+ update_info->type = convert_type;
+ *update_info_list = g_slist_append(*update_info_list, update_info);
+ }
+
+ free(dbpath);
+ sqlite3_finalize(stmt);
+ sqlite3_close_v2(db);
+
+ return 0;
+}
+
+API int pkgmgrinfo_updateinfo_get_usr_updateinfo(const char *pkgid,
+ pkgmgrinfo_updateinfo_h *update_handle, uid_t uid)
+{
+ int ret;
+ pkgmgrinfo_pkginfo_h pkginfo = NULL;
+ bool is_global_pkg;
+ updateinfo_x *update_info;
+ GSList *info_list = NULL;
+
+ if (update_handle == NULL || pkgid == NULL)
+ return PMINFO_R_EINVAL;
+
+ update_info = calloc(1, sizeof(updateinfo_x));
+ if (update_info == NULL) {
+ _LOGE("Out of memory");
+ return PMINFO_R_ERROR;
+ }
+
+ ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, uid, &pkginfo);
+ if (ret != PMINFO_R_OK) {
+ free(update_info);
+ return ret;
+ }
+ ret = pkgmgrinfo_pkginfo_is_global(pkginfo, &is_global_pkg);
+ if (ret != PMINFO_R_OK) {
+ free(update_info);
+ pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
+ return ret;
+ }
+ pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
+
+ ret = _get_pkg_updateinfo_from_db(pkgid, &info_list,
+ (is_global_pkg) ? GLOBAL_USER : uid);
+
+ if (ret != PMINFO_R_OK) {
+ g_slist_free_full(info_list, __free_update_info);
+ return PMINFO_R_ERROR;
+ }
+ *update_handle = (pkgmgrinfo_updateinfo_h)info_list->data;
+ g_slist_free(info_list);
+
+ return ret;
+}
+
+API int pkgmgrinfo_updateinfo_get_updateinfo(const char *pkgid,
+ pkgmgrinfo_updateinfo_h *update_handle)
+{
+ return pkgmgrinfo_updateinfo_get_usr_updateinfo(pkgid, update_handle, _getuid());
+}
+
+API int pkgmgrinfo_updateinfo_usr_foreach_updateinfo(uid_t uid,
+ pkgmgrinfo_foreach_updateinfo_cb callback, void *user_data)
+{
+ int ret;
+ GSList *info_list;
+ GSList *tmp_list;
+
+ if (callback == NULL)
+ return PMINFO_R_EINVAL;
+
+ info_list = calloc(1, sizeof(updateinfo_x));
+ if (info_list == NULL) {
+ _LOGE("Out of memory");
+ return PMINFO_R_ERROR;
+ }
+
+ ret = _get_pkg_updateinfo_from_db(NULL, &info_list, uid);
+ if (ret != 0) {
+ _LOGE("Failed to get pkg update info for user[%d]", (int)uid);
+ pkgmgrinfo_updateinfo_destroy(info_list);
+ return PMINFO_R_ERROR;
+ }
+
+ ret = _get_pkg_updateinfo_from_db(NULL, &info_list, GLOBAL_USER);
+ if (ret != 0) {
+ _LOGE("Failed to get pkg update info for user[%d]",
+ (int)GLOBAL_USER);
+ pkgmgrinfo_updateinfo_destroy(info_list);
+ return PMINFO_R_ERROR;
+ }
+
+ for (tmp_list = info_list; tmp_list; tmp_list = g_slist_next(tmp_list)) {
+ ret = callback((pkgmgrinfo_updateinfo_h)tmp_list->data, user_data);
+ if (ret < 0)
+ break;
+ }
+
+ g_slist_free_full(info_list, __free_update_info);
+ return PMINFO_R_OK;
+}
+
+API int pkgmgrinfo_updateinfo_foreach_updateinfo(
+ pkgmgrinfo_foreach_updateinfo_cb callback, void *user_data)
+{
+ return pkgmgrinfo_updateinfo_usr_foreach_updateinfo(_getuid(),
+ callback, user_data);
+}