Adds support the icon property 00/38400/1
authorMinkyu Kang <mk7.kang@samsung.com>
Mon, 16 Feb 2015 05:58:07 +0000 (14:58 +0900)
committerHurnjoo Lee <hurnjoo.lee@samsung.com>
Mon, 20 Apr 2015 11:01:44 +0000 (20:01 +0900)
The Icon property will be saved at /var/lib/gumd/user/[uid] file
This file follow .ini file format

[User]
Icon=/usr/share/icons/user.png

So if we need to add new properties, this file can be expanded easily

Change-Id: I17f8ce3eb5f8a0e834678c3cca74a2a69cd87a97
Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
data/tizen/etc/gumd/gumd-tizen-common.conf
include/gum/common/gum-config-general.h
packaging/gumd.spec
src/common/dbus/interfaces/org.O1.SecurityAccounts.gUserManagement.User.xml
src/daemon/core/gumd-daemon-user.c
src/lib/gum-user.c
src/utils/gumd-utils.c

index a915ad4..71826d4 100644 (file)
@@ -65,6 +65,9 @@ DEFAULT_USR_GROUPS=audio,video,display
 # environment variable.
 SKEL_DIR=/etc/skel
 
+# Path to user information folder.
+USERINFO_DIR=/var/lib/gumd/user/
+
 # Minimum value for the automatic uid selection. Default value is: 1000
 UID_MIN=5001
 
index 1ee49bb..7a8f3f2 100644 (file)
                                               "/SKEL_DIR"
 
 /**
+ * GUM_CONFIG_GENERAL_USERINFO_DIR:
+ *
+ * Path to user information folder.
+ */
+#define GUM_CONFIG_GENERAL_USERINFO_DIR         GUM_CONFIG_GENERAL \
+                                              "/USERINFO_DIR"
+
+/**
  * GUM_CONFIG_GENERAL_UID_MIN:
  *
  * Minimum value for the automatic uid selection. Default value is: 2000
index be72810..c3bc696 100644 (file)
@@ -108,6 +108,7 @@ install -d -m 755 %{_sysconfdir}/%{name}/useradd.d
 install -d -m 755 %{_sysconfdir}/%{name}/userdel.d
 install -d -m 755 %{_sysconfdir}/%{name}/groupadd.d
 install -d -m 755 %{_sysconfdir}/%{name}/groupdel.d
+install -d -m 755 %{_localstatedir}/lib/%{name}/user
 
 
 %postun -p /sbin/ldconfig
index 4aa2e42..f2ebab0 100644 (file)
             </tp:docstring>
         </property>
 
+        <property name="icon" tp:name-for-bindings="icon"
+         type="s" access="readwrite">
+            <tp:docstring>path of the user icon
+            </tp:docstring>
+        </property>
+
     </interface>
 </node>
index 24fcbb7..3805c9f 100644 (file)
@@ -32,6 +32,8 @@
 #include <gio/gio.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
 
 #include "gumd-daemon-user.h"
 #include "gumd-daemon-group.h"
 #include "common/gum-error.h"
 #include "common/gum-utils.h"
 
+struct _userinfo {
+    char *icon;
+};
+
 struct _GumdDaemonUserPrivate
 {
     GumConfig *config;
@@ -63,6 +69,11 @@ struct _GumdDaemonUserPrivate
      * account_expiry_date:reserved_field
      */
     struct spwd *shadow;
+
+    /* user info file entries format:
+     * icon:
+     */
+    struct _userinfo *info;
 };
 
 G_DEFINE_TYPE (GumdDaemonUser, gumd_daemon_user, G_TYPE_OBJECT)
@@ -71,6 +82,7 @@ G_DEFINE_TYPE (GumdDaemonUser, gumd_daemon_user, G_TYPE_OBJECT)
         GUMD_TYPE_DAEMON_USER, GumdDaemonUserPrivate)
 
 #define GUMD_DAY (24L*3600L)
+#define GUMD_STR_LEN 4096
 
 enum
 {
@@ -89,6 +101,7 @@ enum
     PROP_HOMEPHONE,
     PROP_HOMEDIR,
     PROP_SHELL,
+    PROP_ICON,
 
     N_PROPERTIES
 };
@@ -131,6 +144,15 @@ _free_shadow_entry (
     }
 }
 
+static void
+_free_info_entry (
+        struct _userinfo *info)
+{
+    if (info) {
+        g_free (info->icon);
+    }
+}
+
 static GumUserType
 _get_usertype_from_gecos (
         struct passwd *pw)
@@ -344,6 +366,19 @@ _set_shell_property (
 }
 
 static void
+_set_icon_property (
+        GumdDaemonUser *self,
+        const gchar *value)
+{
+    if (g_strcmp0 (value, self->priv->info->icon) != 0 &&
+        gum_validate_db_string_entry (value, NULL)) {
+        GUM_STR_FREE (self->priv->info->icon);
+        self->priv->info->icon = g_strdup (value);
+        g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ICON]);
+    }
+}
+
+static void
 _set_property (
         GObject *object,
         guint property_id,
@@ -405,6 +440,10 @@ _set_property (
             _set_shell_property (self, g_value_get_string (value));
             break;
         }
+        case PROP_ICON: {
+            _set_icon_property (self, g_value_get_string (value));
+            break;
+        }
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -503,6 +542,10 @@ _get_property (
                 g_value_set_string (value, self->priv->pw->pw_shell);
             break;
         }
+        case PROP_ICON: {
+            g_value_set_string (value, self->priv->info->icon);
+            break;
+        }
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -537,6 +580,11 @@ _finalize (GObject *object)
         self->priv->pw = NULL;
     }
 
+    if (self->priv->info) {
+        _free_info_entry (self->priv->info);
+        self->priv->info = NULL;
+    }
+
     G_OBJECT_CLASS (gumd_daemon_user_parent_class)->finalize (object);
 }
 
@@ -551,6 +599,7 @@ gumd_daemon_user_init (
     self->priv->pw->pw_uid = GUM_USER_INVALID_UID;
     self->priv->pw->pw_gid = GUMD_DAEMON_GROUP_INVALID_GID;
     self->priv->shadow = g_malloc0 (sizeof (struct spwd));
+    self->priv->info = g_malloc0 (sizeof (struct _userinfo));
 }
 
 static void
@@ -664,6 +713,13 @@ gumd_daemon_user_class_init (
             G_PARAM_READWRITE |
             G_PARAM_STATIC_STRINGS);
 
+    properties[PROP_ICON] = g_param_spec_string ("icon",
+            "Icon",
+            "Icon path of User",
+            "" /* default value */,
+            G_PARAM_READWRITE |
+            G_PARAM_STATIC_STRINGS);
+
     g_object_class_install_properties (object_class, N_PROPERTIES,
             properties);
 
@@ -1237,6 +1293,137 @@ _finished:
     return deleted;
 }
 
+static gboolean
+_get_userinfo_path(GumdDaemonUser *self, gchar *path, gulong n)
+{
+    const gchar *str = NULL;
+
+    str = gum_config_get_string (self->priv->config, GUM_CONFIG_GENERAL_USERINFO_DIR);
+    if (!str) {
+        WARN("Failed to get userinfo file path");
+        return FALSE;
+    }
+
+    g_snprintf(path, n, "%s%d", str, self->priv->pw->pw_uid);
+
+    return TRUE;
+}
+
+static void
+_delete_userinfo(GumdDaemonUser *self)
+{
+    gchar path[GUMD_STR_LEN];
+
+    if (!_get_userinfo_path(self, path, sizeof(path)))
+        return;
+
+    g_remove(path);
+}
+
+static gboolean
+_add_userinfo(GumdDaemonUser *self)
+{
+    GKeyFile *key = NULL;
+    GError *error = NULL;
+    gchar path[GUMD_STR_LEN];
+
+    key = g_key_file_new();
+    if (!key)
+        return FALSE;
+
+    if (self->priv->info->icon)
+        g_key_file_set_string(key, "User", "Icon", self->priv->info->icon);
+
+    if (!_get_userinfo_path(self, path, sizeof(path)))
+        return FALSE;
+
+    if (!g_key_file_save_to_file(key, path, &error)) {
+        WARN("Key file save failure error %d:%s", error ? error->code : 0,
+                error ? error->message : "");
+        g_key_file_free(key);
+        g_clear_error(&error);
+        return FALSE;
+    }
+
+    g_key_file_free(key);
+
+    return TRUE;
+}
+
+static gboolean
+_update_userinfo(GumdDaemonUser *self, struct _userinfo *info)
+{
+    GKeyFile *key = NULL;
+    GError *error = NULL;
+    gchar path[GUMD_STR_LEN];
+
+    key = g_key_file_new();
+    if (!key)
+        return FALSE;
+
+    if (!_get_userinfo_path(self, path, sizeof(path)))
+        return FALSE;
+
+    g_key_file_load_from_file(key, path, G_KEY_FILE_NONE, NULL);
+
+    if (info->icon)
+        g_key_file_set_string(key, "User", "Icon", info->icon);
+
+    if (!g_key_file_save_to_file(key, path, &error)) {
+        WARN("Key file save failure error %d:%s", error ? error->code : 0,
+                error ? error->message : "");
+        g_key_file_free(key);
+        g_clear_error(&error);
+        return FALSE;
+    }
+
+    g_key_file_free(key);
+
+    return TRUE;
+}
+
+static gboolean
+_get_userinfo(GumdDaemonUser *self, struct _userinfo *info)
+{
+    GKeyFile *key = NULL;
+    GError *error = NULL;
+    gchar path[GUMD_STR_LEN];
+
+    key = g_key_file_new();
+    if (!key)
+        return FALSE;
+
+    if (!_get_userinfo_path(self, path, sizeof(path)))
+        return FALSE;
+
+    if (!g_key_file_load_from_file(key, path, G_KEY_FILE_NONE, &error)) {
+        g_key_file_free(key);
+        g_clear_error(&error);
+        return FALSE;
+    }
+
+    info->icon = g_key_file_get_string(key, "User", "Icon", NULL);
+    if (!info->icon)
+        info->icon = "";
+
+    g_key_file_free(key);
+
+    return TRUE;
+}
+
+static gboolean
+_copy_userinfo_struct (
+        struct _userinfo *src,
+        GumdDaemonUser *dest)
+{
+    if (!src || !dest)
+        return FALSE;
+
+    _set_icon_property (dest, src->icon);
+
+    return TRUE;
+}
+
 static struct passwd *
 _get_passwd (
         GumdDaemonUser *self,
@@ -1320,6 +1507,7 @@ _copy_passwd_data (
 {
     struct passwd *pent = NULL;
     struct spwd *spent = NULL;
+    struct _userinfo info = {0,};
     DBG("");
 
     if ((pent = _get_passwd (self, error)) == NULL) {
@@ -1331,6 +1519,7 @@ _copy_passwd_data (
         GUM_RETURN_WITH_ERROR (GUM_ERROR_USER_NOT_FOUND, "User not found",
                 error, FALSE);
     }
+    _get_userinfo (self, &info);
 
     /*passwd entry*/
     _copy_passwd_struct (pent, self);
@@ -1338,6 +1527,9 @@ _copy_passwd_data (
     /*shadow entry*/
     _copy_shadow_struct (spent, self->priv->shadow, FALSE);
 
+    /*userinfo entry*/
+    _copy_userinfo_struct (&info, self);
+
     return TRUE;
 }
 
@@ -1546,6 +1738,8 @@ gumd_daemon_user_add (
         return FALSE;
     }
 
+    _add_userinfo(self);
+
     if (!_set_default_groups (self, error) ||
         !_create_home_dir (self, error)) {
         gum_lock_pwdf_unlock ();
@@ -1568,6 +1762,7 @@ gumd_daemon_user_add (
     gum_utils_run_user_scripts (scrip_dir, self->priv->pw->pw_name,
             self->priv->pw->pw_uid, self->priv->pw->pw_gid,
             self->priv->pw->pw_dir, ut);
+
     g_free (ut);
     gum_lock_pwdf_unlock ();
     return TRUE;
@@ -1650,6 +1845,8 @@ gumd_daemon_user_delete (
             self->priv->pw->pw_uid, self->priv->pw->pw_gid,
             self->priv->pw->pw_dir, NULL);
 
+    _delete_userinfo(self);
+
     if (!gum_file_update (G_OBJECT (self), GUM_OPTYPE_DELETE,
             (GumFileUpdateCB)_update_passwd_entry,
             gum_config_get_string (self->priv->config,
@@ -1731,6 +1928,7 @@ gumd_daemon_user_update (
 {
     struct passwd *pw = NULL;
     struct spwd *shadow = NULL;
+    struct _userinfo info = {0,};
     gchar *old_name = NULL;
     gint change = 0;
 
@@ -1761,6 +1959,16 @@ gumd_daemon_user_update (
                 "User not found in Shadow", error, FALSE);
     }
 
+    /* userinfo entry */
+    _get_userinfo (self, &info);
+
+    if (self->priv->info->icon && g_strcmp0 (info.icon, self->priv->info->icon)) {
+        change++;
+        info.icon = self->priv->info->icon;
+    }
+    if (change)
+        _update_userinfo(self, &info);
+
     /* shadow entry */
     _copy_shadow_struct (shadow, self->priv->shadow, TRUE);
 
index ccb88b1..9313479 100644 (file)
@@ -144,6 +144,7 @@ enum
     PROP_HOMEDIR,
     PROP_SHELL,
     PROP_OFFLINE,
+    PROP_ICON,
 
     N_PROPERTIES
 };
@@ -521,6 +522,16 @@ gum_user_class_init (
             FALSE,
             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
 
+    /**
+     * GumUser:icon:
+     */
+    properties[PROP_ICON] = g_param_spec_string ("icon",
+            "Icon",
+            "Icon path of User",
+            "" /* default value */,
+            G_PARAM_READWRITE |
+            G_PARAM_STATIC_STRINGS);
+
     g_object_class_install_properties (object_class, N_PROPERTIES,
             properties);
 }
index 5ab3629..c18d03b 100644 (file)
@@ -53,6 +53,7 @@ typedef struct {
     gchar *home_dir;
     gchar *shell;
     gchar *secret;
+    gchar *icon;
 } InputUser;
 
 typedef struct {
@@ -94,6 +95,7 @@ _free_test_user (
                g_free (user->office); g_free (user->office_phone);
                g_free (user->home_phone); g_free (user->home_dir);
                g_free (user->shell); g_free (user->user_type);
+               g_free (user->icon);
                g_free (user);
        }
 }
@@ -133,6 +135,9 @@ _set_user_update_prop (
     if (user->secret) {
         g_object_set (G_OBJECT (guser), "secret", user->secret, NULL);
     }
+    if (user->icon) {
+        g_object_set (G_OBJECT (guser), "icon", user->icon, NULL);
+    }
 }
 
 static void
@@ -177,6 +182,7 @@ _print_user_prop (
     g_object_get (G_OBJECT (guser), "homephone", &user->home_phone, NULL);
     g_object_get (G_OBJECT (guser), "homedir", &user->home_dir, NULL);
     g_object_get (G_OBJECT (guser), "shell", &user->shell, NULL);
+    g_object_get (G_OBJECT (guser), "icon", &user->icon, NULL);
 
     INFO ("uid : %u", user->uid);
     INFO ("gid : %u", user->gid);
@@ -189,6 +195,7 @@ _print_user_prop (
                user->office_phone ? user->office_phone : "UNKNOWN");
     INFO ("homephone : %s", user->home_phone ? user->home_phone : "UNKNOWN");
     INFO ("homedir : %s", user->home_dir ? user->home_dir : "UNKNOWN");
+    INFO ("icon: %s", user->icon ? user->icon: "UNKNOWN");
     INFO ("shell : %s\n", user->shell ? user->shell : "UNKNOWN");
 
     _free_test_user (user);
@@ -610,8 +617,8 @@ main (int argc, char *argv[])
                 "delete user -- uid is mandatory", NULL},
         { "update-user", 'u', 0, G_OPTION_ARG_NONE, &is_user_up_op,
                 "update user -- uid is mandatory; possible props that can be "
-                "updated are secret, realname, office, officephone, homephone "
-                "and shell", NULL},
+                "updated are secret, realname, office, officephone, homephone, "
+                "icon and shell", NULL},
         { "get-user", 'b', 0, G_OPTION_ARG_NONE, &is_user_get_op, "get user"
                 " -- uid is mandatory", NULL},
         { "get-user-by-name", 'c', 0, G_OPTION_ARG_NONE,
@@ -686,6 +693,8 @@ main (int argc, char *argv[])
                 "dir"},
         { "shell", 0, 0, G_OPTION_ARG_STRING, &user->shell, "shell path",
                 "shell"},
+        { "icon", 0, 0, G_OPTION_ARG_STRING, &user->icon, "icon path",
+                "icon"},
         { NULL }
     };