[accounts-dialog] Improve async handling of user creating/deletion



commit a22e79bd22d80b84e413e38cd8d632208fc56521
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Jan 24 15:48:15 2010 -0500

    Improve async handling of user creating/deletion
    
    Use the GAsyncResult pattern, translate errors that are returned,
    don't show an error dialog if authentication failed/was canceled,
    select newly created users, etc, etc.

 TODO                    |    1 -
 src/main.c              |  106 ++++++++++++++++-----
 src/um-account-dialog.c |   69 ++++++++++++--
 src/um-account-dialog.h |   10 ++-
 src/um-user-manager.c   |  238 +++++++++++++++++++++++++++++++++++++++++-----
 src/um-user-manager.h   |   40 +++++++--
 6 files changed, 394 insertions(+), 70 deletions(-)
---
diff --git a/TODO b/TODO
index e4dfb25..514725d 100644
--- a/TODO
+++ b/TODO
@@ -3,7 +3,6 @@ Dialog
 - add supervisor user to supervised accounts
 - move 'disable account' to restrictions
 - more async ?
-- select new user after creating
 - find a place to point to for safe password tips, or include them
 - review text in acount type dialog
 - hide unimplemented parts
diff --git a/src/main.c b/src/main.c
index 42bd368..6f5f0e1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -259,10 +259,67 @@ user_changed (UmUserManager *um, UmUser *user, UserAccountDialog *d)
 }
 
 static void
+select_created_user (UmUser *user, UserAccountDialog *d)
+{
+        GtkTreeView *tv;
+        GtkTreeModel *model;
+        GtkTreeSelection *selection;
+        GtkTreeIter iter;
+        UmUser *current;
+        GtkTreePath *path;
+
+        tv = (GtkTreeView *)get_widget (d, "list-treeview");
+        model = gtk_tree_view_get_model (tv);
+        selection = gtk_tree_view_get_selection (tv);
+
+        gtk_tree_model_get_iter_first (model, &iter);
+        do {
+                gtk_tree_model_get (model, &iter, USER_COL, &current, -1);
+                if (user == current) {
+                        path = gtk_tree_model_get_path (model, &iter);
+                        gtk_tree_view_scroll_to_cell (tv, path, NULL, FALSE, 0.0, 0.0);
+                        gtk_tree_selection_select_path (selection, path);
+                        gtk_tree_path_free (path);
+                        break;
+                }
+        } while (gtk_tree_model_iter_next (model, &iter));
+}
+
+static void
 add_user (GtkButton *button, UserAccountDialog *d)
 {
         um_account_dialog_show (d->account_dialog,
-                                GTK_WINDOW (get_widget (d, "user-account-window")));
+                                GTK_WINDOW (get_widget (d, "user-account-window")),
+                                (UserCreatedCallback)select_created_user, d);
+}
+
+static void
+delete_user_done (UmUserManager     *manager,
+                  GAsyncResult      *res,
+                  UserAccountDialog *d)
+{
+        GError *error;
+
+        error = NULL;
+        if (!um_user_manager_delete_user_finish (manager, res, &error)) {
+                if (!g_error_matches (error, UM_USER_MANAGER_ERROR, UM_USER_MANAGER_ERROR_PERMISSION_DENIED)) {
+                        GtkWidget *dialog;
+
+                        dialog = gtk_message_dialog_new (gtk_window_get_transient_for (GTK_WINDOW (d->main_window)),
+                                                         GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                         GTK_MESSAGE_ERROR,
+                                                         GTK_BUTTONS_CLOSE,
+                                                         _("Failed to delete user"));
+
+                        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                                                  "%s", error->message);
+
+                        g_signal_connect (G_OBJECT (dialog), "response",
+                                          G_CALLBACK (gtk_widget_destroy), NULL);
+                        gtk_window_present (GTK_WINDOW (dialog));
+                }
+                g_error_free (error);
+        }
 }
 
 static void
@@ -271,24 +328,25 @@ delete_user_response (GtkWidget         *dialog,
                       UserAccountDialog *d)
 {
         UmUser *user;
+        gboolean remove_files;
 
         gtk_widget_destroy (dialog);
 
         user = get_selected_user (d);
 
-        switch (response_id) {
-        case GTK_RESPONSE_NO:
-                g_debug ("Goodbye, %s. Your files are toast.\n",
-                         um_user_get_real_name (user));
-                um_user_manager_delete_user (d->um, user, TRUE);
-                break;
-        case GTK_RESPONSE_YES:
-                g_debug ("Goodbye, %s. Your files are safe.\n",
-                         um_user_get_real_name (user));
-                um_user_manager_delete_user (d->um, user, FALSE);
-                break;
-        default: ;
+        if (response_id == GTK_RESPONSE_NO) {
+                remove_files = TRUE;
         }
+        else {
+                remove_files = FALSE;
+        }
+
+        um_user_manager_delete_user (d->um,
+                                     user,
+                                     remove_files,
+                                     (GAsyncReadyCallback)delete_user_done,
+                                     d,
+                                     NULL);
 
         g_object_unref (user);
 }
@@ -469,7 +527,7 @@ update_data_change_buttons (GObject           *source,
         gboolean is_authorized;
 
         error = NULL;
-	is_authorized = FALSE;
+        is_authorized = FALSE;
         result = polkit_authority_check_authorization_finish (d->authority,
                                                               res,
                                                               &error);
@@ -515,10 +573,10 @@ update_account_type_change_buttons (GObject           *source,
         PolkitAuthorizationResult *result;
         gboolean is_authorized;
         gboolean can_change_password;
-	UmUser *user;
+        UmUser *user;
 
         error = NULL;
-	is_authorized = FALSE;
+        is_authorized = FALSE;
         result = polkit_authority_check_authorization_finish (d->authority,
                                                               res,
                                                               &error);
@@ -544,11 +602,11 @@ update_account_type_change_buttons (GObject           *source,
 
         user = get_selected_user (d);
         if (um_user_get_uid (user) == geteuid ()) {
-		can_change_password = TRUE;
-	}
-	else {
-		can_change_password = is_authorized;
-	}
+                can_change_password = TRUE;
+        }
+        else {
+                can_change_password = is_authorized;
+        }
 
         if (can_change_password) {
                 gtk_widget_show (get_widget (d, "change-password-button"));
@@ -603,7 +661,7 @@ update_create_buttons_cb (GObject           *source,
         UmUser *user;
 
         error = NULL;
- 	is_authorized = FALSE;
+        is_authorized = FALSE;
         result = polkit_authority_check_authorization_finish (d->authority,
                                                               res,
                                                               &error);
@@ -629,9 +687,9 @@ update_create_buttons_cb (GObject           *source,
                 if (user && um_user_get_uid (user) == getuid ()) {
                         gtk_widget_set_sensitive (get_widget (d, "delete-user-button"), FALSE);
                 }
-		else {
+                else {
                         gtk_widget_set_sensitive (get_widget (d, "delete-user-button"), TRUE);
-		}
+                }
         }
         else {
                 gtk_widget_hide (get_widget (d, "add-delete-buttonbox"));
diff --git a/src/um-account-dialog.c b/src/um-account-dialog.c
index 8edc623..c2b545b 100644
--- a/src/um-account-dialog.c
+++ b/src/um-account-dialog.c
@@ -22,6 +22,8 @@
 #include "config.h"
 
 #include <stdlib.h>
+#include <sys/types.h>
+#include <pwd.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -40,6 +42,9 @@ struct _UmAccountDialog {
 
         gboolean valid_name;
         gboolean valid_shortname;
+
+        UserCreatedCallback user_created_callback;
+        gpointer            user_created_data;
 };
 
 static void
@@ -50,6 +55,40 @@ cancel_account_dialog (GtkButton       *button,
 }
 
 static void
+create_user_done (UmUserManager   *manager,
+                  GAsyncResult    *res,
+                  UmAccountDialog *um)
+{
+        UmUser *user;
+        GError *error;
+
+        error = NULL;
+        if (!um_user_manager_create_user_finish (manager, res, &user, &error)) {
+
+                if (!g_error_matches (error, UM_USER_MANAGER_ERROR, UM_USER_MANAGER_ERROR_PERMISSION_DENIED)) {
+                        GtkWidget *dialog;
+
+                        dialog = gtk_message_dialog_new (gtk_window_get_transient_for (GTK_WINDOW (um->dialog)),
+                                                         GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                         GTK_MESSAGE_ERROR,
+                                                         GTK_BUTTONS_CLOSE,
+                                                         _("Failed to create user"));
+
+                        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                                                  "%s", error->message);
+
+                        g_signal_connect (G_OBJECT (dialog), "response",
+                                          G_CALLBACK (gtk_widget_destroy), NULL);
+                        gtk_window_present (GTK_WINDOW (dialog));
+                }
+                g_error_free (error);
+        }
+        else {
+                um->user_created_callback (user, um->user_created_data);
+        }
+}
+
+static void
 accept_account_dialog (GtkButton       *button,
                        UmAccountDialog *um)
 {
@@ -67,7 +106,13 @@ accept_account_dialog (GtkButton       *button,
         gtk_tree_model_get (model, &iter, 1, &account_type, -1);
 
         manager = um_user_manager_ref_default ();
-        um_user_manager_create_user (manager, shortname, name, account_type);
+        um_user_manager_create_user (manager,
+                                     shortname,
+                                     name,
+                                     account_type,
+                                     (GAsyncReadyCallback)create_user_done,
+                                     um,
+                                     NULL);
         g_object_unref (manager);
 
         gtk_widget_hide (um->dialog);
@@ -76,14 +121,11 @@ accept_account_dialog (GtkButton       *button,
 static gboolean
 is_shortname_used (const gchar *shortname)
 {
-        UmUserManager *manager;
-        UmUser *user;
+        struct passwd *pwent;
 
-        manager = um_user_manager_ref_default ();
-        user = um_user_manager_get_user (manager, shortname);
-        g_object_unref (manager);
+        pwent = getpwnam (shortname);
 
-        return user != NULL;
+        return pwent != NULL;
 }
 
 static void
@@ -422,11 +464,17 @@ um_account_dialog_free (UmAccountDialog *um)
 }
 
 void
-um_account_dialog_show (UmAccountDialog *um,
-                        GtkWindow       *parent)
+um_account_dialog_show (UmAccountDialog     *um,
+                        GtkWindow           *parent,
+                        UserCreatedCallback  user_created_callback,
+                        gpointer             user_created_data)
 {
+        GtkTreeModel *model;
+
         gtk_entry_set_text (GTK_ENTRY (um->name_entry), "");
         gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (um->shortname_combo))), "");
+        model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->shortname_combo));
+        gtk_list_store_clear (GTK_LIST_STORE (model));
         gtk_combo_box_set_active (GTK_COMBO_BOX (um->account_type_combo), 0);
 
         gtk_window_set_transient_for (GTK_WINDOW (um->dialog), parent);
@@ -434,6 +482,9 @@ um_account_dialog_show (UmAccountDialog *um,
         gtk_widget_grab_focus (um->name_entry);
 
         um->valid_name = um->valid_shortname = TRUE;
+
+        um->user_created_callback = user_created_callback;
+        um->user_created_data = user_created_data;
 }
 
 
diff --git a/src/um-account-dialog.h b/src/um-account-dialog.h
index 3d4a8f2..e3b2ebc 100644
--- a/src/um-account-dialog.h
+++ b/src/um-account-dialog.h
@@ -29,10 +29,14 @@ G_BEGIN_DECLS
 
 typedef struct _UmAccountDialog UmAccountDialog;
 
+typedef void (*UserCreatedCallback) (UmUser *user, gpointer data);
+
 UmAccountDialog *um_account_dialog_new      (void);
-void             um_account_dialog_free     (UmAccountDialog *dialog);
-void             um_account_dialog_show     (UmAccountDialog *dialog,
-                                             GtkWindow       *parent);
+void             um_account_dialog_free     (UmAccountDialog     *dialog);
+void             um_account_dialog_show     (UmAccountDialog     *dialog,
+                                             GtkWindow           *parent,
+                                             UserCreatedCallback  user_created,
+                                             gpointer             data);
 
 G_END_DECLS
 
diff --git a/src/um-user-manager.c b/src/um-user-manager.c
index 7330e91..f611051 100644
--- a/src/um-user-manager.c
+++ b/src/um-user-manager.c
@@ -117,7 +117,7 @@ remove_user_from_dupe_ring (UmUserManager *manager,
 
         um_user_show_short_display_name (user);
 
-        dupes = g_object_get_data (user, "dupes");
+        dupes = g_object_get_data (G_OBJECT (user), "dupes");
 
         if (dupes == NULL) {
                 return;
@@ -129,7 +129,7 @@ remove_user_from_dupe_ring (UmUserManager *manager,
                 g_signal_emit (manager, signals[USER_CHANGED], 0, dup);
 
                 g_list_free_1 (dupes->next);
-                g_object_set_data (dup, "dupes", NULL);
+                g_object_set_data (G_OBJECT (dup), "dupes", NULL);
         }
         else {
                 dupes->next->prev = dupes->prev;
@@ -137,7 +137,7 @@ remove_user_from_dupe_ring (UmUserManager *manager,
         }
 
         g_list_free_1 (dupes);
-        g_object_set_data (user, "dupes", NULL);
+        g_object_set_data (G_OBJECT (user), "dupes", NULL);
 }
 
 static gboolean
@@ -165,17 +165,17 @@ add_user_to_dupe_ring (UmUserManager *manager,
 
         um_user_show_full_display_name (user);
 
-        dupes = g_object_get_data (dup, "dupes");
+        dupes = g_object_get_data (G_OBJECT (dup), "dupes");
         if (!dupes) {
                 um_user_show_full_display_name (dup);
                 g_signal_emit (manager, signals[USER_CHANGED], 0, dup);
                 dupes = g_list_append (NULL, dup);
-                g_object_set_data (dup, "dupes", dupes);
+                g_object_set_data (G_OBJECT (dup), "dupes", dupes);
                 dupes->next = dupes->prev = dupes;
         }
 
         l = g_list_append (NULL, user);
-        g_object_set_data (user, "dupes", l);
+        g_object_set_data (G_OBJECT (user), "dupes", l);
         l->prev = dupes->prev;
         dupes->prev->next = l;
         l->next = dupes;
@@ -333,11 +333,11 @@ clear_dup (gpointer key,
         /* don't bother maintaining the ring, we're destroying the
          * entire hash table anyway
          */
-        dupes = g_object_get_data (value, "dupes");
+        dupes = g_object_get_data (G_OBJECT (value), "dupes");
 
         if (dupes) {
                 g_list_free_1 (dupes);
-                g_object_set_data (value, "dupes", NULL);
+                g_object_set_data (G_OBJECT (value), "dupes", NULL);
         }
 }
 
@@ -369,30 +369,210 @@ um_user_manager_ref_default (void)
         return UM_USER_MANAGER (user_manager_object);
 }
 
+typedef struct {
+        UmUserManager       *manager;
+        gchar               *user_name;
+        GAsyncReadyCallback  callback;
+        gpointer             data;
+        GDestroyNotify       destroy;
+}  AsyncUserOpData;
+
+static void
+async_user_op_data_free (gpointer d)
+{
+        AsyncUserOpData *data = d;
+
+        g_object_unref (data->manager);
+
+        g_free (data->user_name);
+
+        if (data->destroy)
+                data->destroy (data->data);
+
+        g_free (data);
+}
+
+static void
+create_user_done (DBusGProxy     *proxy,
+                  DBusGProxyCall *call_id,
+                  gpointer        user_data)
+{
+        AsyncUserOpData *data = user_data;
+        gchar *path;
+        GError *error;
+        GSimpleAsyncResult *res;
+
+        res = g_simple_async_result_new (G_OBJECT (data->manager),
+                                         data->callback,
+                                         data->data,
+                                         um_user_manager_create_user);
+        error = NULL;
+        if (!dbus_g_proxy_end_call (proxy,
+                                    call_id,
+                                    &error,
+                                    DBUS_TYPE_G_OBJECT_PATH, &path,
+                                    G_TYPE_INVALID)) {
+                /* dbus-glib fail:
+                 * We have to translate the errors manually here, since
+                 * calling dbus_g_error_has_name on the error returned in
+                 * um_user_manager_create_user_finish doesn't work.
+                 */
+                if (dbus_g_error_has_name (error, "org.freedesktop.Accounts.Error.PermissionDenied")) {
+                        g_simple_async_result_set_error (res,
+                                                         UM_USER_MANAGER_ERROR,
+                                                         UM_USER_MANAGER_ERROR_PERMISSION_DENIED,
+                                                         "Not authorized");
+                }
+                else if (dbus_g_error_has_name (error, "org.freedesktop.Accounts.Error.UserExists")) {
+                        g_simple_async_result_set_error (res,
+                                                         UM_USER_MANAGER_ERROR,
+                                                         UM_USER_MANAGER_ERROR_USER_EXISTS,
+                                                         _("A user with name '%s' already exists."),
+                                                         data->user_name);
+                }
+                else {
+                        g_simple_async_result_set_from_error (res, error);
+                }
+                g_error_free (error);
+        }
+        else {
+                g_simple_async_result_set_op_res_gpointer (res, path, g_free);
+        }
+
+        data->callback (G_OBJECT (data->manager), G_ASYNC_RESULT (res), data->data);
+}
+
+gboolean
+um_user_manager_create_user_finish (UmUserManager  *manager,
+                                    GAsyncResult   *result,
+                                    UmUser        **user,
+                                    GError        **error)
+{
+        gchar *path;
+        GSimpleAsyncResult *res;
+
+        res = G_SIMPLE_ASYNC_RESULT (result);
+
+        *user = NULL;
+
+        if (g_simple_async_result_propagate_error (res, error)) {
+                return FALSE;
+        }
+
+        path = g_simple_async_result_get_op_res_gpointer (res);
+        *user = g_hash_table_lookup (manager->user_by_object_path, path);
+
+        return TRUE;
+}
+
 void
-um_user_manager_create_user (UmUserManager *manager,
-                             const char    *user_name,
-                             const char    *real_name,
-                             gint           account_type)
+um_user_manager_create_user (UmUserManager       *manager,
+                             const char          *user_name,
+                             const char          *real_name,
+                             gint                 account_type,
+                             GAsyncReadyCallback  done,
+                             gpointer             done_data,
+                             GDestroyNotify       destroy)
+{
+        AsyncUserOpData *data;
+
+        data = g_new0 (AsyncUserOpData, 1);
+        data->manager = g_object_ref (manager);
+        data->user_name = g_strdup (user_name);
+        data->callback = done;
+        data->data = done_data;
+        data->destroy = destroy;
+
+        dbus_g_proxy_begin_call (manager->proxy,
+                                 "CreateUser",
+                                 create_user_done,
+                                 data,
+                                 async_user_op_data_free,
+                                 G_TYPE_STRING, user_name,
+                                 G_TYPE_STRING, real_name,
+                                 G_TYPE_INT, account_type,
+                                 G_TYPE_INVALID);
+}
+
+static void
+delete_user_done (DBusGProxy     *proxy,
+                  DBusGProxyCall *call_id,
+                  gpointer        user_data)
+{
+        AsyncUserOpData *data = user_data;
+        GError *error;
+        GSimpleAsyncResult *res;
+
+        res = g_simple_async_result_new (G_OBJECT (data->manager),
+                                         data->callback,
+                                         data->data,
+                                         um_user_manager_delete_user);
+        error = NULL;
+        if (!dbus_g_proxy_end_call (proxy,
+                                    call_id,
+                                    &error,
+                                    G_TYPE_INVALID)) {
+                if (dbus_g_error_has_name (error, "org.freedesktop.Accounts.Error.PermissionDenied")) {
+                        g_simple_async_result_set_error (res,
+                                                         UM_USER_MANAGER_ERROR,
+                                                         UM_USER_MANAGER_ERROR_PERMISSION_DENIED,
+                                                         "Not authorized");
+                }
+                else if (dbus_g_error_has_name (error, "org.freedesktop.Accounts.Error.UserDoesntExists")) {
+                        g_simple_async_result_set_error (res,
+                                                         UM_USER_MANAGER_ERROR,
+                                                         UM_USER_MANAGER_ERROR_USER_DOES_NOT_EXIST,
+                                                         _("This user does not exist."));
+                }
+                else {
+                        g_simple_async_result_set_from_error (res, error);
+                        g_error_free (error);
+                }
+        }
+
+        data->callback (G_OBJECT (data->manager), G_ASYNC_RESULT (res), data->data);
+}
+
+gboolean
+um_user_manager_delete_user_finish (UmUserManager  *manager,
+                                    GAsyncResult   *result,
+                                    GError        **error)
 {
-        dbus_g_proxy_call_no_reply (manager->proxy,
-                                    "CreateUser",
-                                    G_TYPE_STRING, user_name,
-                                    G_TYPE_STRING, real_name,
-                                    G_TYPE_INT, account_type,
-                                    G_TYPE_INVALID);
+        GSimpleAsyncResult *res;
+
+        res = G_SIMPLE_ASYNC_RESULT (result);
+
+        if (g_simple_async_result_propagate_error (res, error)) {
+                return FALSE;
+        }
+
+        return TRUE;
 }
 
 void
-um_user_manager_delete_user (UmUserManager *manager,
-                             UmUser        *user,
-                             gboolean       remove_files)
+um_user_manager_delete_user (UmUserManager       *manager,
+                             UmUser              *user,
+                             gboolean             remove_files,
+                             GAsyncReadyCallback  done,
+                             gpointer             done_data,
+                             GDestroyNotify       destroy)
 {
-        dbus_g_proxy_call_no_reply (manager->proxy,
-                                    "DeleteUser",
-                                    G_TYPE_INT64, um_user_get_uid (user),
-                                    G_TYPE_BOOLEAN, remove_files,
-                                    G_TYPE_INVALID);
+        AsyncUserOpData *data;
+
+        data = g_new0 (AsyncUserOpData, 1);
+        data->manager = g_object_ref (manager);
+        data->callback = done;
+        data->data = done_data;
+        data->destroy = destroy;
+
+        dbus_g_proxy_begin_call (manager->proxy,
+                                 "DeleteUser",
+                                 delete_user_done,
+                                 data,
+                                 async_user_op_data_free,
+                                 G_TYPE_INT64, um_user_get_uid (user),
+                                 G_TYPE_BOOLEAN, remove_files,
+                                 G_TYPE_INVALID);
 }
 
 GSList *
@@ -436,3 +616,9 @@ um_user_manager_no_service (UmUserManager *manager)
 {
         return manager->no_service;
 }
+
+GQuark
+um_user_manager_error_quark (void)
+{
+        return g_quark_from_static_string ("um-user-manager-error-quark");
+}
diff --git a/src/um-user-manager.h b/src/um-user-manager.h
index a25b36a..b051a88 100644
--- a/src/um-user-manager.h
+++ b/src/um-user-manager.h
@@ -22,6 +22,7 @@
 #define __UM_USER_MANAGER__
 
 #include <glib-object.h>
+#include <gio/gio.h>
 #include <dbus/dbus-glib.h>
 
 #include "um-user.h"
@@ -62,6 +63,17 @@ typedef struct
 } UmUserManagerClass;
 
 
+typedef enum {
+        UM_USER_MANAGER_ERROR_FAILED,
+        UM_USER_MANAGER_ERROR_USER_EXISTS,
+        UM_USER_MANAGER_ERROR_USER_DOES_NOT_EXIST,
+        UM_USER_MANAGER_ERROR_PERMISSION_DENIED
+} UmUserManagerError;
+
+#define UM_USER_MANAGER_ERROR um_user_manager_error_quark ()
+
+GQuark             um_user_manager_error_quark (void);
+
 GType              um_user_manager_get_type              (void);
 
 UmUserManager *    um_user_manager_ref_default           (void);
@@ -73,13 +85,27 @@ UmUser *           um_user_manager_get_user              (UmUserManager *manager
                                                           const char    *user_name);
 UmUser *           um_user_manager_get_user_by_id        (UmUserManager *manager,
                                                           uid_t          uid);
-void               um_user_manager_create_user           (UmUserManager *manager,
-                                                          const char    *user_name,
-                                                          const char    *real_name,
-                                                          gint           account_type);
-void               um_user_manager_delete_user           (UmUserManager *manager,
-                                                          UmUser        *user,
-                                                          gboolean       remove_files);
+
+void               um_user_manager_create_user           (UmUserManager       *manager,
+                                                          const char          *user_name,
+                                                          const char          *real_name,
+                                                          gint                 account_type,
+                                                          GAsyncReadyCallback  done,
+                                                          gpointer             user_data,
+                                                          GDestroyNotify       destroy);
+gboolean           um_user_manager_create_user_finish    (UmUserManager       *manager,
+                                                          GAsyncResult        *result,
+                                                          UmUser             **user,
+                                                          GError             **error);
+void               um_user_manager_delete_user           (UmUserManager       *manager,
+                                                          UmUser              *user,
+                                                          gboolean             remove_files,
+                                                          GAsyncReadyCallback  done,
+                                                          gpointer             user_data,
+                                                          GDestroyNotify       destroy);
+gboolean           um_user_manager_delete_user_finish    (UmUserManager       *manager,
+                                                          GAsyncResult        *result,
+                                                          GError             **error);
 
 G_END_DECLS
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]