#include <app_debug.h>
#include <Eina.h>
+#include <Evas.h>
#include <stdbool.h>
+#include <viewmgr.h>
+#include <stdlib.h>
+#include <gum/gum-user.h>
+#include <gum/gum-user-service.h>
+#include <gum/common/gum-user-types.h>
+#include <pwd.h>
+#include <gio/gio.h>
#include "data_user.h"
#include "datamgr.h"
+#include "defs.h"
+
+#define GUM_ATTR_NAME "username"
+#define GUM_ATTR_USERTYPE "usertype"
+#define GUM_ATTR_UID "uid"
+#define GUM_ATTR_ICON "icon"
+#define GUM_LIST_USERTYPE "normal"
+
+#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"
+
+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 void _switch(char *name, char *password)
+{
+ GDBusConnection *conn;
+ GError *error;
+ GVariant *param;
+ GDBusMessage *msg, *res;
+ guint32 serial;
+
+ if (!name || !password)
+ return;
+
+ error = NULL;
+ conn = _get_bus_connection(&error);
+ if (!conn) {
+ _ERR("failed to get connection, %s",
+ error ? error->message : "");
+ g_error_free(error);
+ return;
+ }
+
+ param = _build_env_param(name, password);
+ if (!param) {
+ _ERR("failed to build env param");
+ goto err;
+ }
+
+ 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);
+ goto err;
+ }
+
+ g_object_unref(res);
+ g_object_unref(msg);
+ g_object_unref(conn);
+err:
+ g_object_unref(conn);
+ g_error_free(error);
+ return;
+}
static void _select(struct datamgr_item *di)
{
- /* It should be implemented later */
+ if (!di)
+ return;
+
+ switch (di->action) {
+ case ITEM_SELECT_ACTION_SWITCH:
+ /* It should be implemented later */
+ _switch(di->title, "");
+ break;
+ case ITEM_SELECT_ACTION_PUSH:
+ viewmgr_push_view(di->parameter);
+ break;
+ case ITEM_SELECT_ACTION_POP:
+ viewmgr_pop_view();
+ break;
+ default:
+ _ERR("Invalid state");
+ return;
+ }
+}
+
+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)
+{
+ 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;
+
+ return di;
+}
+
+static bool _load_login_user(Eina_List **list)
+{
+ struct datamgr_item *di;
+ GumUser *user;
+ uid_t uid;
+ char *name, *icon;
+ struct passwd *passwd;
+
+ uid = getuid();
+ user = gum_user_get_sync(uid, FALSE);
+ if (!user) {
+ _ERR("failed to get user service");
+ passwd = getpwuid(uid);
+ di = _pack_user(passwd->pw_name, IMAGE_USER_DEFAULT,
+ IMAGE_USER_DEFAULT_FOCUS,
+ ITEM_SELECT_ACTION_POP, NULL);
+ if (!di)
+ return false;
+
+ *list = eina_list_append(*list, di);
+ return true;
+ }
+
+ name = NULL;
+ icon = NULL;
+ g_object_get(G_OBJECT(user), GUM_ATTR_NAME, &name, GUM_ATTR_ICON, &icon,
+ NULL);
+
+ di = _pack_user(name, icon, icon, ITEM_SELECT_ACTION_POP, NULL);
+ if (!di) {
+ g_object_unref(user);
+ return false;
+ }
+
+ *list = eina_list_append(*list, di);
+ g_object_unref(user);
+
+ return true;
+}
+
+static gchar **_append_string(gchar **src_strv, const gchar *string)
+{
+ gchar **dest_strv;
+ gint ind;
+ gint len;
+
+ if (src_strv)
+ len = g_strv_length(src_strv);
+
+ len = 0;
+ ind = 0;
+ dest_strv = NULL;
+
+ dest_strv = (gchar **)g_malloc0(sizeof(gchar *) * (len + 2));
+ if (src_strv) {
+ while (src_strv[ind]) {
+ dest_strv[ind] = g_strdup(src_strv[ind]);
+ ind++;
+ }
+ }
+
+ dest_strv[ind++] = g_strdup(string);
+ dest_strv[ind] = NULL;
+
+ return dest_strv;
+}
+
+static bool _load_users(Eina_List **list)
+{
+ GumUserList *ulist;
+ GumUser *user;
+ GumUserService *service;
+ struct datamgr_item *di;
+ char *name, *icon;
+ gchar **strv;
+ int i;
+
+ service = gum_user_service_create_sync(FALSE);
+ if (!service) {
+ _ERR("failed to create service");
+ return false;
+ }
+
+ strv = _append_string(NULL, GUM_LIST_USERTYPE);
+ ulist = gum_user_service_get_user_list_sync(service,
+ (const gchar *const *)strv);
+ g_strfreev(strv);
+ if (!ulist) {
+ _ERR("failed to get user list");
+ g_object_unref(service);
+ return false;
+ }
+
+ 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, NULL);
+ di = _pack_user(name, icon, icon, ITEM_SELECT_ACTION_SWITCH,
+ NULL);
+ 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);
+ 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");
+
+ 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)
return NULL;
}
+ _unload_user(dm);
+ _load_user(dm);
+
return dm->list;
}
static void _fini(struct datamgr *dm)
{
- /* It should be implemented later */
+ if (!dm) {
+ _ERR("Invalid argument");
+ return;
+ }
+
+ _unload_user(dm);
}
static bool _init(struct datamgr *dm)
{
- /* It should be implemented later */
+ if (!dm) {
+ _ERR("Invalid argument");
+ return false;
+ }
- return true;
+ return _load_user(dm);
}
static struct data_class dclass = {
{
return &dclass;
}
-