/* * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * 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 #include #include #include #include #include #include #include #include #include #include "data_user.h" #include "datamgr.h" #include "defs.h" #include "utils.h" #define ADDRESS_BUF_MAX 128 #define USER_SWITCH_TLM_SEAT_ID "seat0" #define USER_SWITCH_DBUS_SOCKET_PATH "/var/run/tlm/" #define USER_SWITCH_TLM_BUS_NAME "org.O1.Tlm.Login" #define USER_SWITCH_TLM_INTERFACE USER_SWITCH_TLM_BUS_NAME #define USER_SWITCH_TLM_OBJECT_PATH "/org/O1/Tlm/Login" #define USER_SWITCH_METHOD "switchUser" #define PINCODE "tizen" static GVariant *_build_env_param(const char *username, const char *password) { GVariantBuilder *builder; GVariant *param, *env; builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); if (!builder) { _ERR("failed to new builder"); return NULL; } g_variant_builder_add(builder, "{ss}", "", ""); env = g_variant_builder_end(builder); g_variant_builder_unref(builder); param = g_variant_new("(sss@a{ss})", USER_SWITCH_TLM_SEAT_ID, username, password, env); return param; } static GDBusConnection *_get_bus_connection(GError **error) { gchar address[ADDRESS_BUF_MAX]; g_snprintf(address, ADDRESS_BUF_MAX - 1, "unix:path=%s%s-%u", USER_SWITCH_DBUS_SOCKET_PATH, USER_SWITCH_TLM_SEAT_ID, getuid()); return g_dbus_connection_new_for_address_sync(address, G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, NULL, error); } static int _switch(char *name, char *password) { GDBusConnection *conn; GError *error; GVariant *param; GDBusMessage *msg, *res; guint32 serial; if (!name || !password) return ITEM_SELECT_ERROR_INVALID_PARAMETER; error = NULL; conn = _get_bus_connection(&error); if (!conn) { _ERR("failed to get connection, %s", error ? error->message : ""); g_error_free(error); return ITEM_SELECT_ERROR_INVALID_OPERATION; } param = _build_env_param(name, password); if (!param) { _ERR("failed to build env param"); g_object_unref(conn); g_error_free(error); return ITEM_SELECT_ERROR_INVALID_OPERATION; } msg = g_dbus_message_new_method_call(USER_SWITCH_TLM_BUS_NAME, USER_SWITCH_TLM_OBJECT_PATH, USER_SWITCH_TLM_INTERFACE, USER_SWITCH_METHOD); g_dbus_message_set_body(msg, param); res = g_dbus_connection_send_message_with_reply_sync(conn, msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 1000, &serial, NULL, &error); if (!res) { _ERR("failed to send message, %s", error ? error->message : ""); g_object_unref(msg); g_object_unref(conn); g_error_free(error); return ITEM_SELECT_ERROR_SWITCH; } g_object_unref(res); g_object_unref(msg); g_object_unref(conn); viewmgr_hide_view(VIEW_USER); return ITEM_SELECT_ERROR_NONE; } static int _update(struct datamgr_item *di) { GumUser *user; gboolean r; char *exist_icon; user = gum_user_get_by_name_sync(di->title, FALSE); if (!user) { _ERR("failed to get user"); return ITEM_SELECT_ERROR_INVALID_OPERATION; } g_object_get(G_OBJECT(user), GUM_ATTR_ICON, &exist_icon, NULL); if (strcmp(di->icon, exist_icon)) { g_object_set(G_OBJECT(user), GUM_ATTR_ICON, di->icon, NULL); r = gum_user_update_sync(user); if (!r) { _ERR("failed to update user"); g_object_unref(user); free(exist_icon); return ITEM_SELECT_ERROR_INVALID_OPERATION; } } g_object_unref(user); free(exist_icon); return ITEM_SELECT_ERROR_NONE; } static int _delete(struct datamgr_item *di) { GumUser *user; gboolean r; user = gum_user_get_by_name_sync(di->title, FALSE); if (!user) { _ERR("failed to get user"); return ITEM_SELECT_ERROR_INVALID_OPERATION; } r = gum_user_delete_sync(user, FALSE); if (!r) { _ERR("failed to delete user"); g_object_unref(user); return ITEM_SELECT_ERROR_INVALID_OPERATION; } g_object_unref(user); return ITEM_SELECT_ERROR_NONE; } static int _select(struct datamgr_item *di) { int r; if (!di) { _ERR("Invalid argument"); return ITEM_SELECT_ERROR_INVALID_PARAMETER; } r = ITEM_SELECT_ERROR_INVALID_OPERATION; switch (di->action) { case ITEM_SELECT_ACTION_SWITCH: /* FIXME: set pincode "tizen" */ r = _switch(di->title, PINCODE); break; case ITEM_SELECT_ACTION_PUSH: if (viewmgr_push_view(di->parameter)) r = ITEM_SELECT_ERROR_NONE; break; case ITEM_SELECT_ACTION_POP: if (viewmgr_pop_view()) r = ITEM_SELECT_ERROR_NONE; break; case ITEM_SELECT_ACTION_UPDATE: r = _update(di); break; case ITEM_SELECT_ACTION_DELETE: r = _delete(di); break; default: _ERR("Invalid state"); break; } return r; } static void _unload_user(struct datamgr *dm) { struct datamgr_item *di; EINA_LIST_FREE(dm->list, di) { free(di->title); free(di->icon); free(di->focus_icon); free(di->parameter); free(di); } dm->list = NULL; } static struct datamgr_item *_pack_user(char *name, char *icon, char *focus_icon, enum datamgr_item_select_action action, char *parameter, int type) { struct datamgr_item *di; di = calloc(1, sizeof(*di)); if (!di) { _ERR("failed calloc user item"); return false; } if (!icon || strlen(icon) == 0) icon = IMAGE_USER_DEFAULT; if (!focus_icon || strlen(focus_icon) == 0) focus_icon = IMAGE_USER_DEFAULT_FOCUS; if (name) di->title = strdup(name); if (parameter) di->parameter = strdup(parameter); di->icon = strdup(icon); di->focus_icon = strdup(focus_icon); di->action = action; di->type = type; return di; } static bool _load_login_user(Eina_List **list) { struct datamgr_item *di; GumUser *user; uid_t uid; char *name, *icon; GumUserType type; uid = getuid(); user = gum_user_get_sync(uid, FALSE); if (!user) { _ERR("failed to get user service"); return false; } name = NULL; icon = NULL; g_object_get(G_OBJECT(user), GUM_ATTR_NAME, &name, GUM_ATTR_ICON, &icon, GUM_ATTR_USERTYPE, &type, NULL); di = _pack_user(name, icon, (char *)utils_get_focus_icon_from_icon(icon), ITEM_SELECT_ACTION_POP, NULL, type); if (!di) { g_free(name); g_free(icon); g_object_unref(user); return false; } *list = eina_list_append(*list, di); g_free(name); g_free(icon); g_object_unref(user); return true; } static bool _load_users(Eina_List **list) { GumUserList *ulist; GumUser *user; GumUserService *service; GumUserType type; struct datamgr_item *di; char *name, *icon; uid_t uid, user_uid; int i; static const gchar * const strv[] = { GUM_LIST_USERTYPE_NORMAL, GUM_LIST_USERTYPE_ADMIN, NULL }; service = gum_user_service_create_sync(FALSE); if (!service) { _ERR("failed to create service"); return false; } ulist = gum_user_service_get_user_list_sync(service, strv); if (!ulist) { _ERR("failed to get user list"); g_object_unref(service); return false; } user_uid = getuid(); for (i = 0; i < g_list_length(ulist); i++) { user = g_list_nth_data(ulist, i); if (!user) continue; g_object_get(G_OBJECT(user), GUM_ATTR_NAME, &name, GUM_ATTR_ICON, &icon, GUM_ATTR_UID, &uid, GUM_ATTR_USERTYPE, &type, NULL); if (uid == user_uid) { g_free(name); g_free(icon); continue; } di = _pack_user(name, icon, (char *)utils_get_focus_icon_from_icon(icon), ITEM_SELECT_ACTION_SWITCH, NULL, type); g_free(name); g_free(icon); if (!di) continue; *list = eina_list_append(*list, di); } gum_user_service_list_free(ulist); g_object_unref(service); return true; } static bool _load_add_user(Eina_List **list) { struct datamgr_item *di; di = _pack_user(NULL, IMAGE_USER_ADD, IMAGE_USER_ADD_FOCUS, ITEM_SELECT_ACTION_PUSH, VIEW_USER_EDIT, 1); if (!di) return false; *list = eina_list_append(*list, di); return true; } static bool _load_user(struct datamgr *dm) { if (!_load_login_user(&dm->list)) { _ERR("failed to load login user"); return false; } if (!_load_users(&dm->list)) _ERR("failed to load users"); if (!_load_add_user(&dm->list)) _ERR("failed to load add user"); return true; } static Eina_List *_get_items(struct datamgr *dm) { if (!dm) { _ERR("Invalid argument"); return NULL; } _unload_user(dm); _load_user(dm); return dm->list; } static void _fini(struct datamgr *dm) { if (!dm) { _ERR("Invalid argument"); return; } _unload_user(dm); } static bool _init(struct datamgr *dm) { if (!dm) { _ERR("Invalid argument"); return false; } return _load_user(dm); } static int _add(struct datamgr *dm, const char *title, const char *icon, const char *parameter) { GumUser *user; GumUser *exist = NULL; gboolean r; if (!dm || !title || !icon) { _ERR("Invalid argument"); return USER_ADD_ERROR_INVALID_OPERATION; } exist = gum_user_get_by_name_sync(title, FALSE); if (!exist) { user = gum_user_create_sync(FALSE); if (!user) { _ERR("failed to get user"); return USER_ADD_ERROR_INVALID_OPERATION; } } else { g_object_unref(exist); return USER_ADD_ERROR_EXIST_ALREADY; } /* FIXME: set pincode "tizen" */ parameter = PINCODE; g_object_set(G_OBJECT(user), GUM_ATTR_NAME, title, GUM_ATTR_ICON, icon, GUM_ATTR_PASSWORD, parameter, GUM_ATTR_USERTYPE, GUM_USERTYPE_NORMAL, NULL); r = gum_user_add_sync(user); if (!r) { _ERR("failed to add user"); g_object_unref(user); return USER_ADD_ERROR_INVALID_OPERATION; } g_object_unref(user); return USER_ADD_ERROR_NONE; } static struct data_class dclass = { .init = _init, .fini = _fini, .get_items = _get_items, .select = _select, .add = _add }; struct data_class *datamgr_user_get_dclass(void) { return &dclass; }