diff --git a/.gitignore b/.gitignore index 40934da..28d2b8f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ gdm-2.30.2.tar.bz2 /gdm-2.91.94.tar.bz2 /gdm-3.0.0.tar.bz2 /gdm-3.0.4.tar.bz2 +/gdm-3.1.2.tar.xz diff --git a/gdm-multistack.patch b/gdm-multistack.patch deleted file mode 100644 index 5fa4577..0000000 --- a/gdm-multistack.patch +++ /dev/null @@ -1,17709 +0,0 @@ -From e08d0004d437c92da33013ee9646d07f24d22876 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Thu, 22 Jul 2010 13:38:09 -0400 -Subject: [PATCH 01/20] Revert "Don't wait a mandatory 2 seconds when resetting greeter" - -This reverts commit 83552f19154bf5689b395a76c1a9931b2558f41b. - -This is a temporary fix so that error messages are displayed for -long enough. A better fix would belong in the greeter. ---- - daemon/gdm-simple-slave.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c -index f43ed64..05326dc 100644 ---- a/daemon/gdm-simple-slave.c -+++ b/daemon/gdm-simple-slave.c -@@ -285,7 +285,7 @@ queue_greeter_reset (GdmSimpleSlave *slave) - return; - } - -- slave->priv->greeter_reset_id = g_idle_add ((GSourceFunc)greeter_reset_timeout, slave); -+ slave->priv->greeter_reset_id = g_timeout_add_seconds (2, (GSourceFunc)greeter_reset_timeout, slave); - } - - static void --- -1.7.4.1 - - -From 15d20a69c728b87017b28c2c6518d4ffda210128 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 20 Feb 2009 14:05:20 -0500 -Subject: [PATCH 02/20] Add new api to ask when chooser widget is done loading items - ---- - gui/simple-greeter/gdm-chooser-widget.c | 8 ++++++++ - gui/simple-greeter/gdm-chooser-widget.h | 2 ++ - 2 files changed, 10 insertions(+), 0 deletions(-) - -diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c -index e81bd77..99fefa0 100644 ---- a/gui/simple-greeter/gdm-chooser-widget.c -+++ b/gui/simple-greeter/gdm-chooser-widget.c -@@ -99,6 +99,7 @@ struct GdmChooserWidgetPrivate - - guint32 should_hide_inactive_items : 1; - guint32 emit_activated_after_resize_animation : 1; -+ guint32 is_loaded : 1; - - GdmChooserWidgetPosition separator_position; - GdmChooserWidgetState state; -@@ -2839,9 +2840,16 @@ gdm_chooser_widget_propagate_pending_key_events (GdmChooserWidget *widget) - gdm_scrollable_widget_replay_queued_key_events (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget)); - } - -+gboolean -+gdm_chooser_widget_is_loaded (GdmChooserWidget *widget) -+{ -+ return widget->priv->is_loaded; -+} -+ - void - gdm_chooser_widget_loaded (GdmChooserWidget *widget) - { -+ widget->priv->is_loaded = TRUE; - g_signal_emit (widget, signals[LOADED], 0); - update_chooser_visibility (widget); - queue_move_cursor_to_top (widget); -diff --git a/gui/simple-greeter/gdm-chooser-widget.h b/gui/simple-greeter/gdm-chooser-widget.h -index 11a6456..3f6fea3 100644 ---- a/gui/simple-greeter/gdm-chooser-widget.h -+++ b/gui/simple-greeter/gdm-chooser-widget.h -@@ -142,6 +142,8 @@ int gdm_chooser_widget_get_number_of_items (GdmChooserWidget - void gdm_chooser_widget_activate_if_one_item (GdmChooserWidget *widget); - void gdm_chooser_widget_propagate_pending_key_events (GdmChooserWidget *widget); - -+gboolean gdm_chooser_widget_is_loaded (GdmChooserWidget *widget); -+ - /* Protected - */ - void gdm_chooser_widget_loaded (GdmChooserWidget *widget); --- -1.7.4.1 - - -From 950454a880c9084a50e8901801b60db99a3ee15e Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 16 Jan 2009 11:00:08 -0500 -Subject: [PATCH 03/20] Introduce new Conversation object - -We want to eventually support having multiple -simultaneous PAM conversations in one login -screen (so, e.g., username/password, smart card, and -fingerprint all work at the same time). - -This commit refactors the session code to be in terms -of a conversation object. With this change, it should -be easier later to have multiple conversation objects. - -The conversation is named by the pam service the login -screen is talking to. ---- - daemon/gdm-factory-slave.c | 5 +- - daemon/gdm-product-slave.c | 29 +++- - daemon/gdm-session-direct.c | 314 ++++++++++++++++++++++++--------------- - daemon/gdm-session-private.h | 3 +- - daemon/gdm-session-relay.c | 15 ++- - daemon/gdm-session-worker-job.c | 7 + - daemon/gdm-session-worker-job.h | 2 + - daemon/gdm-session.c | 12 +- - daemon/gdm-session.h | 9 +- - daemon/gdm-simple-slave.c | 3 - - daemon/test-session.c | 5 +- - 11 files changed, 260 insertions(+), 144 deletions(-) - -diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c -index 5727986..109271a 100644 ---- a/daemon/gdm-factory-slave.c -+++ b/daemon/gdm-factory-slave.c -@@ -181,7 +181,8 @@ on_session_secret_info_query (GdmSession *session, - - static void - on_session_conversation_started (GdmSession *session, -- GdmFactorySlave *slave) -+ GdmFactorySlave *slave, -+ const char *service_name) - { - g_debug ("GdmFactorySlave: session conversation started"); - -@@ -389,7 +390,7 @@ on_session_relay_connected (GdmSessionRelay *session, - { - g_debug ("GdmFactorySlave: Relay Connected"); - -- gdm_session_start_conversation (GDM_SESSION (slave->priv->session)); -+ gdm_session_start_conversation (GDM_SESSION (slave->priv->session), "gdm"); - } - - static void -diff --git a/daemon/gdm-product-slave.c b/daemon/gdm-product-slave.c -index 2d1109e..84d5c49 100644 ---- a/daemon/gdm-product-slave.c -+++ b/daemon/gdm-product-slave.c -@@ -246,19 +246,21 @@ relay_session_started (GdmProductSlave *slave, - } - - static void --relay_session_conversation_started (GdmProductSlave *slave) -+relay_session_conversation_started (GdmProductSlave *slave, -+ const char *service_name) - { -- send_dbus_void_method (slave->priv->session_relay_connection, -- "ConversationStarted"); -+ send_dbus_string_method (slave->priv->session_relay_connection, -+ "ConversationStarted", service_name); - } - - static void - on_session_conversation_started (GdmSession *session, -+ const char *service_name, - GdmProductSlave *slave) - { - g_debug ("GdmProductSlave: session conversation started"); - -- relay_session_conversation_started (slave); -+ relay_session_conversation_started (slave, service_name); - } - - static void -@@ -783,7 +785,24 @@ static void - on_relay_start_conversation (GdmProductSlave *slave, - DBusMessage *message) - { -- gdm_session_start_conversation (GDM_SESSION (slave->priv->session)); -+ DBusError error; -+ char *service_name; -+ dbus_bool_t res; -+ -+ dbus_error_init (&error); -+ res = dbus_message_get_args (message, -+ &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID); -+ if (res) { -+ g_debug ("GdmProductSlave: Started conversation with %s service", service_name); -+ gdm_session_start_conversation (GDM_SESSION (slave->priv->session), -+ service_name); -+ } else { -+ g_warning ("Unable to get arguments: %s", error.message); -+ } -+ -+ dbus_error_free (&error); - } - - static void -diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c -index c8361b4..39ff815 100644 ---- a/daemon/gdm-session-direct.c -+++ b/daemon/gdm-session-direct.c -@@ -67,6 +67,16 @@ - #define GDM_SESSION_DEFAULT_PATH "/usr/local/bin:/usr/bin:/bin" - #endif - -+typedef struct -+{ -+ GdmSessionDirect *session; -+ GdmSessionWorkerJob *job; -+ GPid worker_pid; -+ char *service_name; -+ DBusConnection *worker_connection; -+ DBusMessage *message_pending_reply; -+} GdmSessionConversation; -+ - struct _GdmSessionDirectPrivate - { - /* per open scope */ -@@ -77,8 +87,7 @@ struct _GdmSessionDirectPrivate - char *selected_user; - char *user_x11_authority_file; - -- DBusMessage *message_pending_reply; -- DBusConnection *worker_connection; -+ GdmSessionConversation *conversation; - - GdmSessionWorkerJob *job; - GPid session_pid; -@@ -121,39 +130,39 @@ G_DEFINE_TYPE_WITH_CODE (GdmSessionDirect, - gdm_session_iface_init)) - - static gboolean --send_dbus_message (DBusConnection *connection, -- DBusMessage *message) -+send_dbus_message (GdmSessionConversation *conversation, -+ DBusMessage *message) - { - gboolean is_connected; - gboolean sent; - - g_return_val_if_fail (message != NULL, FALSE); - -- if (connection == NULL) { -+ if (conversation->worker_connection == NULL) { - g_warning ("There is no valid connection"); - return FALSE; - } - -- is_connected = dbus_connection_get_is_connected (connection); -+ is_connected = dbus_connection_get_is_connected (conversation->worker_connection); - if (! is_connected) { - g_warning ("Not connected!"); - return FALSE; - } - -- sent = dbus_connection_send (connection, message, NULL); -+ sent = dbus_connection_send (conversation->worker_connection, message, NULL); - - return sent; - } - - static void --send_dbus_string_signal (GdmSessionDirect *session, -+send_dbus_string_signal (GdmSessionConversation *conversation, - const char *name, - const char *text) - { - DBusMessage *message; - DBusMessageIter iter; - -- g_return_if_fail (session != NULL); -+ g_return_if_fail (conversation != NULL); - - message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH, - GDM_SESSION_DBUS_INTERFACE, -@@ -162,7 +171,7 @@ send_dbus_string_signal (GdmSessionDirect *session, - dbus_message_iter_init_append (message, &iter); - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &text); - -- if (! send_dbus_message (session->priv->worker_connection, message)) { -+ if (! send_dbus_message (conversation, message)) { - g_debug ("GdmSessionDirect: Could not send %s signal", - name ? name : "(null)"); - } -@@ -171,18 +180,18 @@ send_dbus_string_signal (GdmSessionDirect *session, - } - - static void --send_dbus_void_signal (GdmSessionDirect *session, -- const char *name) -+send_dbus_void_signal (GdmSessionConversation *conversation, -+ const char *name) - { - DBusMessage *message; - -- g_return_if_fail (session != NULL); -+ g_return_if_fail (conversation != NULL); - - message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH, - GDM_SESSION_DBUS_INTERFACE, - name); - -- if (! send_dbus_message (session->priv->worker_connection, message)) { -+ if (! send_dbus_message (conversation, message)) { - g_debug ("GdmSessionDirect: Could not send %s signal", name); - } - -@@ -194,22 +203,32 @@ on_authentication_failed (GdmSession *session, - const char *message) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -- gdm_session_record_failed (impl->priv->session_pid, -- impl->priv->selected_user, -- impl->priv->display_hostname, -- impl->priv->display_name, -- impl->priv->display_device); -+ GdmSessionConversation *conversation; -+ -+ conversation = impl->priv->conversation; -+ if (conversation != NULL) { -+ gdm_session_record_failed (conversation->worker_pid, -+ impl->priv->selected_user, -+ impl->priv->display_hostname, -+ impl->priv->display_name, -+ impl->priv->display_device); -+ } - } - - static void - on_session_started (GdmSession *session) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -- gdm_session_record_login (impl->priv->session_pid, -- impl->priv->selected_user, -- impl->priv->display_hostname, -- impl->priv->display_name, -- impl->priv->display_device); -+ GdmSessionConversation *conversation; -+ -+ conversation = impl->priv->conversation; -+ if (conversation != NULL) { -+ gdm_session_record_login (conversation->worker_pid, -+ impl->priv->selected_user, -+ impl->priv->display_hostname, -+ impl->priv->display_name, -+ impl->priv->display_device); -+ } - } - - static void -@@ -217,11 +236,16 @@ on_session_start_failed (GdmSession *session, - const char *message) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -- gdm_session_record_login (impl->priv->session_pid, -- impl->priv->selected_user, -- impl->priv->display_hostname, -- impl->priv->display_name, -- impl->priv->display_device); -+ GdmSessionConversation *conversation; -+ -+ conversation = impl->priv->conversation; -+ if (conversation != NULL) { -+ gdm_session_record_login (conversation->worker_pid, -+ impl->priv->selected_user, -+ impl->priv->display_hostname, -+ impl->priv->display_name, -+ impl->priv->display_device); -+ } - } - - static void -@@ -229,6 +253,7 @@ on_session_exited (GdmSession *session, - int exit_code) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -+ - gdm_session_record_logout (impl->priv->session_pid, - impl->priv->selected_user, - impl->priv->display_hostname, -@@ -765,54 +790,52 @@ gdm_session_direct_handle_username_changed (GdmSessionDirect *session, - } - - static void --cancel_pending_query (GdmSessionDirect *session) -+cancel_pending_query (GdmSessionConversation *conversation) - { - DBusMessage *reply; - -- if (session->priv->message_pending_reply == NULL) { -+ if (conversation->message_pending_reply == NULL) { - return; - } - - g_debug ("GdmSessionDirect: Cancelling pending query"); - -- reply = dbus_message_new_error (session->priv->message_pending_reply, -+ reply = dbus_message_new_error (conversation->message_pending_reply, - GDM_SESSION_DBUS_ERROR_CANCEL, - "Operation cancelled"); -- dbus_connection_send (session->priv->worker_connection, reply, NULL); -- dbus_connection_flush (session->priv->worker_connection); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); -+ dbus_connection_flush (conversation->worker_connection); - - dbus_message_unref (reply); -- dbus_message_unref (session->priv->message_pending_reply); -- session->priv->message_pending_reply = NULL; -+ dbus_message_unref (conversation->message_pending_reply); -+ conversation->message_pending_reply = NULL; - } - - static void --answer_pending_query (GdmSessionDirect *session, -- const char *answer) -+answer_pending_query (GdmSessionConversation *conversation, -+ const char *answer) - { - DBusMessage *reply; - DBusMessageIter iter; - -- g_assert (session->priv->message_pending_reply != NULL); -- -- reply = dbus_message_new_method_return (session->priv->message_pending_reply); -+ reply = dbus_message_new_method_return (conversation->message_pending_reply); - dbus_message_iter_init_append (reply, &iter); - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &answer); - -- dbus_connection_send (session->priv->worker_connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - -- dbus_message_unref (session->priv->message_pending_reply); -- session->priv->message_pending_reply = NULL; -+ dbus_message_unref (conversation->message_pending_reply); -+ conversation->message_pending_reply = NULL; - } - - static void --set_pending_query (GdmSessionDirect *session, -- DBusMessage *message) -+set_pending_query (GdmSessionConversation *conversation, -+ DBusMessage *message) - { -- g_assert (session->priv->message_pending_reply == NULL); -+ g_assert (conversation->message_pending_reply == NULL); - -- session->priv->message_pending_reply = dbus_message_ref (message); -+ conversation->message_pending_reply = dbus_message_ref (message); - } - - static DBusHandlerResult -@@ -822,6 +845,9 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session, - { - DBusError error; - const char *text; -+ GdmSessionConversation *conversation; -+ -+ conversation = session->priv->conversation; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -@@ -830,7 +856,7 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session, - g_warning ("ERROR: %s", error.message); - } - -- set_pending_query (session, message); -+ set_pending_query (conversation, message); - - g_debug ("GdmSessionDirect: Emitting 'info-query' signal"); - _gdm_session_info_query (GDM_SESSION (session), text); -@@ -845,6 +871,9 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session, - { - DBusError error; - const char *text; -+ GdmSessionConversation *conversation; -+ -+ conversation = session->priv->conversation; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -@@ -853,7 +882,7 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session, - g_warning ("ERROR: %s", error.message); - } - -- set_pending_query (session, message); -+ set_pending_query (conversation, message); - - g_debug ("GdmSessionDirect: Emitting 'secret-info-query' signal"); - _gdm_session_secret_info_query (GDM_SESSION (session), text); -@@ -893,9 +922,13 @@ gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session, - DBusMessage *message) - { - DBusMessage *reply; -+ GdmSessionConversation *conversation; - - g_debug ("GdmSessionDirect: worker cancelling pending query"); -- cancel_pending_query (session); -+ -+ conversation = session->priv->conversation; -+ -+ cancel_pending_query (conversation); - - reply = dbus_message_new_method_return (message); - dbus_connection_send (connection, reply, NULL); -@@ -1482,16 +1515,18 @@ handle_connection (DBusServer *server, - void *user_data) - { - GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data); -+ GdmSessionConversation *conversation; - - g_debug ("GdmSessionDirect: Handing new connection"); - -- if (session->priv->worker_connection == NULL) { -+ conversation = session->priv->conversation; -+ if (conversation->worker_connection == NULL) { - DBusObjectPathVTable vtable = { &session_unregister_handler, - &session_message_handler, - NULL, NULL, NULL, NULL - }; - -- session->priv->worker_connection = new_connection; -+ conversation->worker_connection = new_connection; - dbus_connection_ref (new_connection); - dbus_connection_setup_with_g_main (new_connection, NULL); - -@@ -1509,7 +1544,8 @@ handle_connection (DBusServer *server, - session); - - g_debug ("GdmSessionDirect: Emitting conversation-started signal"); -- _gdm_session_conversation_started (GDM_SESSION (session)); -+ _gdm_session_conversation_started (GDM_SESSION (session), -+ conversation->service_name); - } - } - -@@ -1579,8 +1615,6 @@ gdm_session_direct_init (GdmSessionDirect *session) - G_CALLBACK (on_session_exited), - NULL); - -- session->priv->session_pid = -1; -- - session->priv->environment = g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify) g_free, -@@ -1592,7 +1626,7 @@ gdm_session_direct_init (GdmSessionDirect *session) - - static void - worker_started (GdmSessionWorkerJob *job, -- GdmSessionDirect *session) -+ GdmSessionConversation *conversation) - { - g_debug ("GdmSessionDirect: Worker job started"); - } -@@ -1600,87 +1634,105 @@ worker_started (GdmSessionWorkerJob *job, - static void - worker_exited (GdmSessionWorkerJob *job, - int code, -- GdmSessionDirect *session) -+ GdmSessionConversation *conversation) - { - g_debug ("GdmSessionDirect: Worker job exited: %d", code); - -- if (session->priv->is_running) { -- _gdm_session_session_exited (GDM_SESSION (session), code); -+ if (conversation->session->priv->is_running) { -+ _gdm_session_session_exited (GDM_SESSION (conversation->session), code); - } - } - - static void - worker_died (GdmSessionWorkerJob *job, - int signum, -- GdmSessionDirect *session) -+ GdmSessionConversation *conversation) - { - g_debug ("GdmSessionDirect: Worker job died: %d", signum); - -- if (session->priv->is_running) { -- _gdm_session_session_died (GDM_SESSION (session), signum); -+ if (conversation->session->priv->is_running) { -+ _gdm_session_session_died (GDM_SESSION (conversation->session), signum); - } - } - --static gboolean --start_worker (GdmSessionDirect *session) -+static GdmSessionConversation * -+start_conversation (GdmSessionDirect *session, -+ const char *service_name) - { -- gboolean res; -+ GdmSessionConversation *conversation; - -- session->priv->job = gdm_session_worker_job_new (); -- gdm_session_worker_job_set_server_address (session->priv->job, session->priv->server_address); -- g_signal_connect (session->priv->job, -+ conversation = g_new0 (GdmSessionConversation, 1); -+ conversation->session = session; -+ conversation->service_name = g_strdup (service_name); -+ conversation->worker_pid = -1; -+ conversation->job = gdm_session_worker_job_new (); -+ gdm_session_worker_job_set_server_address (conversation->job, session->priv->server_address); -+ g_signal_connect (conversation->job, - "started", - G_CALLBACK (worker_started), -- session); -- g_signal_connect (session->priv->job, -+ conversation); -+ g_signal_connect (conversation->job, - "exited", - G_CALLBACK (worker_exited), -- session); -- g_signal_connect (session->priv->job, -+ conversation); -+ g_signal_connect (conversation->job, - "died", - G_CALLBACK (worker_died), -- session); -+ conversation); - -- res = gdm_session_worker_job_start (session->priv->job); -+ if (!gdm_session_worker_job_start (conversation->job)) { -+ g_object_unref (conversation->job); -+ g_free (conversation->service_name); -+ g_free (conversation); -+ return NULL; -+ } - -- return res; -+ conversation->worker_pid = gdm_session_worker_job_get_pid (conversation->job); -+ -+ return conversation; - } - - static void --stop_worker (GdmSessionDirect *session) -+stop_conversation (GdmSessionConversation *conversation) - { -- g_signal_handlers_disconnect_by_func (session->priv->job, -+ GdmSessionDirect *session; -+ -+ session = conversation->session; -+ -+ g_signal_handlers_disconnect_by_func (conversation->job, - G_CALLBACK (worker_started), -- session); -- g_signal_handlers_disconnect_by_func (session->priv->job, -+ conversation); -+ g_signal_handlers_disconnect_by_func (conversation->job, - G_CALLBACK (worker_exited), -- session); -- g_signal_handlers_disconnect_by_func (session->priv->job, -+ conversation); -+ g_signal_handlers_disconnect_by_func (conversation->job, - G_CALLBACK (worker_died), -- session); -+ conversation); - -- cancel_pending_query (session); -+ cancel_pending_query (conversation); - -- if (session->priv->worker_connection != NULL) { -- dbus_connection_close (session->priv->worker_connection); -- session->priv->worker_connection = NULL; -+ if (conversation->worker_connection != NULL) { -+ dbus_connection_close (conversation->worker_connection); -+ conversation->worker_connection = NULL; - } - -- gdm_session_worker_job_stop (session->priv->job); -- g_object_unref (session->priv->job); -- session->priv->job = NULL; -+ gdm_session_worker_job_stop (conversation->job); -+ g_object_unref (conversation->job); -+ g_free (conversation->service_name); -+ g_free (conversation); - } - - static void --gdm_session_direct_start_conversation (GdmSession *session) -+gdm_session_direct_start_conversation (GdmSession *session, -+ const char *service_name) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - - g_return_if_fail (session != NULL); - -- g_debug ("GdmSessionDirect: Starting conversation"); -+ g_debug ("GdmSessionDirect: starting conversation"); - -- start_worker (impl); -+ impl->priv->conversation = start_conversation (impl, service_name); - } - - static void -@@ -1693,6 +1745,7 @@ send_setup (GdmSessionDirect *session, - const char *display_device; - const char *display_hostname; - const char *display_x11_authority_file; -+ GdmSessionConversation *conversation; - - g_assert (service_name != NULL); - -@@ -1730,7 +1783,8 @@ send_setup (GdmSessionDirect *session, - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_hostname); - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file); - -- if (! send_dbus_message (session->priv->worker_connection, message)) { -+ conversation = session->priv->conversation; -+ if (! send_dbus_message (conversation, message)) { - g_debug ("GdmSessionDirect: Could not send %s signal", "Setup"); - } - -@@ -1748,6 +1802,7 @@ send_setup_for_user (GdmSessionDirect *session, - const char *display_hostname; - const char *display_x11_authority_file; - const char *selected_user; -+ GdmSessionConversation *conversation; - - g_assert (service_name != NULL); - -@@ -1791,7 +1846,8 @@ send_setup_for_user (GdmSessionDirect *session, - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file); - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &selected_user); - -- if (! send_dbus_message (session->priv->worker_connection, message)) { -+ conversation = session->priv->conversation; -+ if (! send_dbus_message (conversation, message)) { - g_debug ("GdmSessionDirect: Could not send %s signal", "SetupForUser"); - } - -@@ -1805,7 +1861,8 @@ gdm_session_direct_setup (GdmSession *session, - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - - g_return_if_fail (session != NULL); -- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->worker_connection)); -+ g_return_if_fail (impl->priv->conversation != NULL); -+ g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection)); - - send_setup (impl, service_name); - gdm_session_direct_defaults_changed (impl); -@@ -1819,7 +1876,8 @@ gdm_session_direct_setup_for_user (GdmSession *session, - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - - g_return_if_fail (session != NULL); -- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->worker_connection)); -+ g_return_if_fail (impl->priv->conversation != NULL); -+ g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection)); - g_return_if_fail (username != NULL); - - gdm_session_direct_select_user (session, username); -@@ -1832,22 +1890,28 @@ static void - gdm_session_direct_authenticate (GdmSession *session) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -+ GdmSessionConversation *conversation; - - g_return_if_fail (session != NULL); -- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->worker_connection)); -+ g_return_if_fail (impl->priv->conversation != NULL); -+ g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection)); - -- send_dbus_void_signal (impl, "Authenticate"); -+ conversation = impl->priv->conversation; -+ send_dbus_void_signal (conversation, "Authenticate"); - } - - static void - gdm_session_direct_authorize (GdmSession *session) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -+ GdmSessionConversation *conversation; - - g_return_if_fail (session != NULL); -- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->worker_connection)); -+ g_return_if_fail (impl->priv->conversation != NULL); -+ g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection)); - -- send_dbus_void_signal (impl, "Authorize"); -+ conversation = impl->priv->conversation; -+ send_dbus_void_signal (conversation, "Authorize"); - } - - static void -@@ -1855,16 +1919,19 @@ gdm_session_direct_accredit (GdmSession *session, - int cred_flag) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -+ GdmSessionConversation *conversation; - - g_return_if_fail (session != NULL); -- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->worker_connection)); -+ g_return_if_fail (impl->priv->conversation != NULL); -+ g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection)); - -+ conversation = impl->priv->conversation; - switch (cred_flag) { - case GDM_SESSION_CRED_ESTABLISH: -- send_dbus_void_signal (impl, "EstablishCredentials"); -+ send_dbus_void_signal (conversation, "EstablishCredentials"); - break; - case GDM_SESSION_CRED_REFRESH: -- send_dbus_void_signal (impl, "RefreshCredentials"); -+ send_dbus_void_signal (conversation, "RefreshCredentials"); - break; - default: - g_assert_not_reached (); -@@ -1878,6 +1945,7 @@ send_environment_variable (const char *key, - { - DBusMessage *message; - DBusMessageIter iter; -+ GdmSessionConversation *conversation; - - message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH, - GDM_SESSION_DBUS_INTERFACE, -@@ -1887,7 +1955,8 @@ send_environment_variable (const char *key, - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value); - -- if (! send_dbus_message (session->priv->worker_connection, message)) { -+ conversation = session->priv->conversation; -+ if (! send_dbus_message (conversation, message)) { - g_debug ("GdmSessionDirect: Could not send %s signal", "SetEnvironmentVariable"); - } - -@@ -2018,6 +2087,7 @@ static void - gdm_session_direct_start_session (GdmSession *session) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -+ GdmSessionConversation *conversation; - char *command; - char *program; - -@@ -2037,7 +2107,8 @@ gdm_session_direct_start_session (GdmSession *session) - setup_session_environment (impl); - send_environment (impl); - -- send_dbus_string_signal (impl, "StartProgram", program); -+ conversation = impl->priv->conversation; -+ send_dbus_string_signal (conversation, "StartProgram", program); - g_free (program); - } - -@@ -2050,16 +2121,12 @@ gdm_session_direct_close (GdmSession *session) - - g_debug ("GdmSessionDirect: Closing session"); - -- if (impl->priv->job != NULL) { -- if (impl->priv->is_running) { -- gdm_session_record_logout (impl->priv->session_pid, -- impl->priv->selected_user, -- impl->priv->display_hostname, -- impl->priv->display_name, -- impl->priv->display_device); -- } -- -- stop_worker (impl); -+ if (impl->priv->is_running) { -+ gdm_session_record_logout (impl->priv->session_pid, -+ impl->priv->selected_user, -+ impl->priv->display_hostname, -+ impl->priv->display_name, -+ impl->priv->display_device); - } - - g_free (impl->priv->selected_user); -@@ -2091,10 +2158,13 @@ gdm_session_direct_answer_query (GdmSession *session, - const char *text) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -+ GdmSessionConversation *conversation; - - g_return_if_fail (session != NULL); - -- answer_pending_query (impl, text); -+ conversation = impl->priv->conversation; -+ -+ answer_pending_query (conversation, text); - } - - static void -@@ -2104,7 +2174,7 @@ gdm_session_direct_cancel (GdmSession *session) - - g_return_if_fail (session != NULL); - -- cancel_pending_query (impl); -+ cancel_pending_query (impl->priv->conversation); - } - - char * -@@ -2176,6 +2246,7 @@ gdm_session_direct_select_session (GdmSession *session, - const char *text) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -+ GdmSessionConversation *conversation; - - g_free (impl->priv->selected_session); - -@@ -2185,7 +2256,8 @@ gdm_session_direct_select_session (GdmSession *session, - impl->priv->selected_session = g_strdup (text); - } - -- send_dbus_string_signal (impl, "SetSessionName", -+ conversation = impl->priv->conversation; -+ send_dbus_string_signal (conversation, "SetSessionName", - get_session_name (impl)); - } - -@@ -2194,6 +2266,7 @@ gdm_session_direct_select_language (GdmSession *session, - const char *text) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -+ GdmSessionConversation *conversation; - - g_free (impl->priv->selected_language); - -@@ -2203,7 +2276,8 @@ gdm_session_direct_select_language (GdmSession *session, - impl->priv->selected_language = g_strdup (text); - } - -- send_dbus_string_signal (impl, "SetLanguageName", -+ conversation = impl->priv->conversation; -+ send_dbus_string_signal (conversation, "SetLanguageName", - get_language_name (impl)); - } - -diff --git a/daemon/gdm-session-private.h b/daemon/gdm-session-private.h -index 88ac23c..34adff5 100644 ---- a/daemon/gdm-session-private.h -+++ b/daemon/gdm-session-private.h -@@ -27,7 +27,8 @@ - G_BEGIN_DECLS - - /* state changes */ --void _gdm_session_conversation_started (GdmSession *session); -+void _gdm_session_conversation_started (GdmSession *session, -+ const char *service_name); - void _gdm_session_setup_complete (GdmSession *session); - void _gdm_session_setup_failed (GdmSession *session, - const char *message); -diff --git a/daemon/gdm-session-relay.c b/daemon/gdm-session-relay.c -index 1ab4b05..d559c71 100644 ---- a/daemon/gdm-session-relay.c -+++ b/daemon/gdm-session-relay.c -@@ -180,10 +180,11 @@ send_dbus_void_signal (GdmSessionRelay *session_relay, - } - - static void --gdm_session_relay_start_conversation (GdmSession *session) -+gdm_session_relay_start_conversation (GdmSession *session, -+ const char *service_name) - { - GdmSessionRelay *impl = GDM_SESSION_RELAY (session); -- send_dbus_void_signal (impl, "StartConversation"); -+ send_dbus_string_signal (impl, "StartConversation", service_name); - } - - static void -@@ -720,8 +721,14 @@ handle_conversation_started (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - - dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } - - g_debug ("GdmSessionRelay: Conversation Started"); - -@@ -729,7 +736,7 @@ handle_conversation_started (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_conversation_started (GDM_SESSION (session_relay)); -+ _gdm_session_conversation_started (GDM_SESSION (session_relay), service_name); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -804,6 +811,7 @@ do_introspect (DBusConnection *connection, - xml = g_string_append (xml, - " \n" - " \n" -+ " \n" - " \n" - " \n" - " \n" -@@ -865,6 +873,7 @@ do_introspect (DBusConnection *connection, - " \n" - - " \n" -+ " \n" - " \n" - " \n" - " \n" -diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c -index 50bf4c0..f686002 100644 ---- a/daemon/gdm-session-worker-job.c -+++ b/daemon/gdm-session-worker-job.c -@@ -303,6 +303,13 @@ gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job) - return TRUE; - } - -+GPid -+gdm_session_worker_job_get_pid (GdmSessionWorkerJob *session_worker_job) -+{ -+ g_return_val_if_fail (GDM_IS_SESSION_WORKER_JOB (session_worker_job), 0); -+ return session_worker_job->priv->pid; -+} -+ - void - gdm_session_worker_job_set_server_address (GdmSessionWorkerJob *session_worker_job, - const char *address) -diff --git a/daemon/gdm-session-worker-job.h b/daemon/gdm-session-worker-job.h -index 5ad1c92..d24f025 100644 ---- a/daemon/gdm-session-worker-job.h -+++ b/daemon/gdm-session-worker-job.h -@@ -60,6 +60,8 @@ void gdm_session_worker_job_set_server_address (GdmSessionWor - gboolean gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job); - gboolean gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job); - -+GPid gdm_session_worker_job_get_pid (GdmSessionWorkerJob *session_worker_job); -+ - G_END_DECLS - - #endif /* __GDM_SESSION_WORKER_JOB_H */ -diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c -index d6baa22..6a87ddd 100644 ---- a/daemon/gdm-session.c -+++ b/daemon/gdm-session.c -@@ -79,11 +79,12 @@ gdm_session_get_type (void) - } - - void --gdm_session_start_conversation (GdmSession *session) -+gdm_session_start_conversation (GdmSession *session, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_SESSION (session)); - -- GDM_SESSION_GET_IFACE (session)->start_conversation (session); -+ GDM_SESSION_GET_IFACE (session)->start_conversation (session, service_name); - } - - void -@@ -210,7 +211,7 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, conversation_started), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, - 0); - signals [SETUP_COMPLETE] = -@@ -633,10 +634,11 @@ _gdm_session_session_died (GdmSession *session, - } - - void --_gdm_session_conversation_started (GdmSession *session) -+_gdm_session_conversation_started (GdmSession *session, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [CONVERSATION_STARTED], 0); -+ g_signal_emit (session, signals [CONVERSATION_STARTED], 0, service_name); - } - - void -diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h -index a1e885d..202da36 100644 ---- a/daemon/gdm-session.h -+++ b/daemon/gdm-session.h -@@ -45,7 +45,8 @@ struct _GdmSessionIface - GTypeInterface base_iface; - - /* Methods */ -- void (* start_conversation) (GdmSession *session); -+ void (* start_conversation) (GdmSession *session, -+ const char *service_name); - void (* setup) (GdmSession *session, - const char *service_name); - void (* setup_for_user) (GdmSession *session, -@@ -105,7 +106,8 @@ struct _GdmSessionIface - int exit_code); - void (* session_died) (GdmSession *session, - int signal_number); -- void (* conversation_started) (GdmSession *session); -+ void (* conversation_started) (GdmSession *session, -+ const char *service_name); - void (* closed) (GdmSession *session); - void (* selected_user_changed) (GdmSession *session, - const char *text); -@@ -118,7 +120,8 @@ struct _GdmSessionIface - - GType gdm_session_get_type (void) G_GNUC_CONST; - --void gdm_session_start_conversation (GdmSession *session); -+void gdm_session_start_conversation (GdmSession *session, -+ const char *service_name); - void gdm_session_setup (GdmSession *session, - const char *service_name); - void gdm_session_setup_for_user (GdmSession *session, -diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c -index 05326dc..5afb557 100644 ---- a/daemon/gdm-simple-slave.c -+++ b/daemon/gdm-simple-slave.c -@@ -243,7 +243,6 @@ reset_session (GdmSimpleSlave *slave) - { - destroy_session (slave); - create_new_session (slave); -- gdm_session_start_conversation (GDM_SESSION (slave->priv->session)); - } - - static gboolean -@@ -1043,8 +1042,6 @@ on_greeter_connected (GdmGreeterServer *greeter_server, - return; - } - -- gdm_session_start_conversation (GDM_SESSION (slave->priv->session)); -- - g_object_get (slave, - "display-is-local", &display_is_local, - NULL); -diff --git a/daemon/test-session.c b/daemon/test-session.c -index 8bed085..9bfda86 100644 ---- a/daemon/test-session.c -+++ b/daemon/test-session.c -@@ -34,11 +34,12 @@ static GMainLoop *loop; - - static void - on_conversation_started (GdmSession *session, -+ const char *service_name, - const char *username) - { - g_debug ("Got conversation started: calling setup..."); - -- gdm_session_setup (session, "gdm"); -+ gdm_session_setup (session, service_name); - } - - static void -@@ -267,7 +268,7 @@ main (int argc, - username = argv[1]; - } - -- gdm_session_start_conversation (GDM_SESSION (session)); -+ gdm_session_start_conversation (GDM_SESSION (session), "gdm"); - - g_signal_connect (session, - "conversation-started", --- -1.7.4.1 - - -From 136cceb2c899e5a59a892f82674b92e0b6927295 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 4 Feb 2009 10:55:03 -0500 -Subject: [PATCH 04/20] Rename session worker to the service it's managing - -This way when we're running multiple PAM conversations at once -it will be obvious which worker is managing which conversation. ---- - daemon/gdm-session-direct.c | 7 ++++- - daemon/gdm-session-worker-job.c | 63 ++++++++++++++++++++++++++++++-------- - daemon/gdm-session-worker-job.h | 3 +- - 3 files changed, 57 insertions(+), 16 deletions(-) - -diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c -index 39ff815..5b30ecd 100644 ---- a/daemon/gdm-session-direct.c -+++ b/daemon/gdm-session-direct.c -@@ -1660,6 +1660,7 @@ start_conversation (GdmSessionDirect *session, - const char *service_name) - { - GdmSessionConversation *conversation; -+ char *job_name; - - conversation = g_new0 (GdmSessionConversation, 1); - conversation->session = session; -@@ -1680,12 +1681,16 @@ start_conversation (GdmSessionDirect *session, - G_CALLBACK (worker_died), - conversation); - -- if (!gdm_session_worker_job_start (conversation->job)) { -+ job_name = g_strdup_printf ("pam: %s", service_name); -+ if (!gdm_session_worker_job_start (conversation->job, -+ job_name)) { - g_object_unref (conversation->job); - g_free (conversation->service_name); - g_free (conversation); -+ g_free (job_name); - return NULL; - } -+ g_free (job_name); - - conversation->worker_pid = gdm_session_worker_job_get_pid (conversation->job); - -diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c -index f686002..be85f30 100644 ---- a/daemon/gdm-session-worker-job.c -+++ b/daemon/gdm-session-worker-job.c -@@ -156,6 +156,37 @@ copy_environment_to_hash (GHashTable *hash) - } - - static GPtrArray * -+get_job_arguments (GdmSessionWorkerJob *job, -+ const char *name) -+{ -+ GPtrArray *args; -+ GError *error; -+ char **argv; -+ int i; -+ -+ args = NULL; -+ argv = NULL; -+ error = NULL; -+ if (! g_shell_parse_argv (job->priv->command, NULL, &argv, &error)) { -+ g_warning ("Could not parse command: %s", error->message); -+ g_error_free (error); -+ goto out; -+ } -+ -+ args = g_ptr_array_new (); -+ g_ptr_array_add (args, g_strdup (argv[0])); -+ g_ptr_array_add (args, g_strdup (name)); -+ for (i = 1; argv[i] != NULL; i++) { -+ g_ptr_array_add (args, g_strdup (argv[i])); -+ } -+ g_strfreev (argv); -+ -+ g_ptr_array_add (args, NULL); -+out: -+ return args; -+} -+ -+static GPtrArray * - get_job_environment (GdmSessionWorkerJob *job) - { - GPtrArray *env; -@@ -178,31 +209,31 @@ get_job_environment (GdmSessionWorkerJob *job) - } - - static gboolean --gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job) -+gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job, -+ const char *name) - { -- gchar **argv; - GError *error; - gboolean ret; -+ GPtrArray *args; - GPtrArray *env; - - ret = FALSE; - -- g_debug ("GdmSessionWorkerJob: Running session_worker_job process: %s", session_worker_job->priv->command); -+ g_debug ("GdmSessionWorkerJob: Running session_worker_job process: %s %s", -+ name != NULL? name : "", session_worker_job->priv->command); - -- argv = NULL; -- if (! g_shell_parse_argv (session_worker_job->priv->command, NULL, &argv, &error)) { -- g_warning ("Could not parse command: %s", error->message); -- g_error_free (error); -- goto out; -- } -+ args = get_job_arguments (session_worker_job, name); - -+ if (args == NULL) { -+ return FALSE; -+ } - env = get_job_environment (session_worker_job); - - error = NULL; - ret = g_spawn_async_with_pipes (NULL, -- argv, -+ (char **) args->pdata, - (char **)env->pdata, -- G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, -+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_FILE_AND_ARGV_ZERO, - (GSpawnChildSetupFunc)session_worker_job_child_setup, - session_worker_job, - &session_worker_job->priv->pid, -@@ -211,6 +242,9 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job) - NULL, - &error); - -+ g_ptr_array_foreach (args, (GFunc)g_free, NULL); -+ g_ptr_array_free (args, TRUE); -+ - g_ptr_array_foreach (env, (GFunc)g_free, NULL); - g_ptr_array_free (env, TRUE); - -@@ -227,7 +261,6 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job) - (GChildWatchFunc)session_worker_job_child_watch, - session_worker_job); - -- g_strfreev (argv); - out: - - return ret; -@@ -240,13 +273,14 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job) - * Starts a local X session_worker_job. Handles retries and fatal errors properly. - */ - gboolean --gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job) -+gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job, -+ const char *name) - { - gboolean res; - - g_debug ("GdmSessionWorkerJob: Starting worker..."); - -- res = gdm_session_worker_job_spawn (session_worker_job); -+ res = gdm_session_worker_job_spawn (session_worker_job, name); - - if (res) { - -@@ -294,6 +328,7 @@ gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job) - g_debug ("GdmSessionWorkerJob: Stopping job pid:%d", session_worker_job->priv->pid); - - res = gdm_signal_pid (session_worker_job->priv->pid, SIGTERM); -+ - if (res < 0) { - g_warning ("Unable to kill session worker process"); - } else { -diff --git a/daemon/gdm-session-worker-job.h b/daemon/gdm-session-worker-job.h -index d24f025..4833f23 100644 ---- a/daemon/gdm-session-worker-job.h -+++ b/daemon/gdm-session-worker-job.h -@@ -57,7 +57,8 @@ GType gdm_session_worker_job_get_type (void); - GdmSessionWorkerJob * gdm_session_worker_job_new (void); - void gdm_session_worker_job_set_server_address (GdmSessionWorkerJob *session_worker_job, - const char *server_address); --gboolean gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job); -+gboolean gdm_session_worker_job_start (GdmSessionWorkerJob *session_worker_job, -+ const char *name); - gboolean gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job); - - GPid gdm_session_worker_job_get_pid (GdmSessionWorkerJob *session_worker_job); --- -1.7.4.1 - - -From 8170e2dd9b62d3bad618f39e6bf9a6ac0361f72b Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 16 Jan 2009 13:01:48 -0500 -Subject: [PATCH 05/20] Make greeter/autologin session explicitly request PAM conversation - -Now the greeter (and also the autologin code) has to say what -PAM stack it wants the slave to run. When that stack is ready, -we emit the Ready signal as before, but now the Ready signal -carries a string argument saying which service is ready to -converse. - -When we support multiple PAM stacks, the greeter will call -StartConversation for each stack, and will keep the UI -associated with each stack disabled until the Ready signals -come back one-by-one. ---- - daemon/gdm-factory-slave.c | 3 +- - daemon/gdm-greeter-server.c | 53 ++++++++++++++++++++++++++++-- - daemon/gdm-greeter-server.h | 5 ++- - daemon/gdm-simple-slave.c | 39 +++++++++++++++++++++- - gui/simple-greeter/gdm-greeter-client.c | 18 ++++++---- - gui/simple-greeter/gdm-greeter-client.h | 4 ++- - gui/simple-greeter/gdm-greeter-session.c | 4 ++ - 7 files changed, 111 insertions(+), 15 deletions(-) - -diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c -index 109271a..9bae550 100644 ---- a/daemon/gdm-factory-slave.c -+++ b/daemon/gdm-factory-slave.c -@@ -186,7 +186,8 @@ on_session_conversation_started (GdmSession *session, - { - g_debug ("GdmFactorySlave: session conversation started"); - -- gdm_greeter_server_ready (slave->priv->greeter_server); -+ gdm_greeter_server_ready (slave->priv->greeter_server, -+ service_name); - } - - static void -diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c -index 6a021d1..463ba6a 100644 ---- a/daemon/gdm-greeter-server.c -+++ b/daemon/gdm-greeter-server.c -@@ -70,6 +70,7 @@ enum { - }; - - enum { -+ START_CONVERSATION, - BEGIN_AUTO_LOGIN, - BEGIN_VERIFICATION, - BEGIN_VERIFICATION_FOR_USER, -@@ -253,9 +254,10 @@ gdm_greeter_server_reset (GdmGreeterServer *greeter_server) - } - - gboolean --gdm_greeter_server_ready (GdmGreeterServer *greeter_server) -+gdm_greeter_server_ready (GdmGreeterServer *greeter_server, -+ const char *service_name) - { -- send_dbus_void_signal (greeter_server, "Ready"); -+ send_dbus_string_signal (greeter_server, "Ready", service_name); - return TRUE; - } - -@@ -323,6 +325,34 @@ generate_address (void) - } - - static DBusHandlerResult -+handle_start_conversation (GdmGreeterServer *greeter_server, -+ DBusConnection *connection, -+ DBusMessage *message) -+{ -+ DBusMessage *reply; -+ DBusError error; -+ const char *service_name; -+ -+ dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } -+ dbus_error_free (&error); -+ -+ g_debug ("GreeterServer: StartConversation"); -+ -+ reply = dbus_message_new_method_return (message); -+ dbus_connection_send (connection, reply, NULL); -+ dbus_message_unref (reply); -+ -+ g_signal_emit (greeter_server, signals [START_CONVERSATION], 0, service_name); -+ -+ return DBUS_HANDLER_RESULT_HANDLED; -+} -+ -+static DBusHandlerResult - handle_begin_verification (GdmGreeterServer *greeter_server, - DBusConnection *connection, - DBusMessage *message) -@@ -618,7 +648,9 @@ greeter_handle_child_message (DBusConnection *connection, - { - GdmGreeterServer *greeter_server = GDM_GREETER_SERVER (user_data); - -- if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "BeginVerification")) { -+ if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "StartConversation")) { -+ return handle_start_conversation (greeter_server, connection, message); -+ } else if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "BeginVerification")) { - return handle_begin_verification (greeter_server, connection, message); - } else if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "BeginVerificationForUser")) { - return handle_begin_verification_for_user (greeter_server, connection, message); -@@ -670,7 +702,11 @@ do_introspect (DBusConnection *connection, - /* interface */ - xml = g_string_append (xml, - " \n" -+ " \n" -+ " \n" -+ " \n" - " \n" -+ " \n" - " \n" - " \n" - " \n" -@@ -727,6 +763,7 @@ do_introspect (DBusConnection *connection, - " \n" - " \n" - " \n" -+ " \n" - " \n" - " \n" - " \n" -@@ -1091,6 +1128,16 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass) - "group name", - GDM_GROUPNAME, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); -+ signals [START_CONVERSATION] = -+ g_signal_new ("start-conversation", -+ G_OBJECT_CLASS_TYPE (object_class), -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmGreeterServerClass, start_conversation), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__STRING, -+ G_TYPE_NONE, -+ 1, G_TYPE_STRING); - signals [BEGIN_VERIFICATION] = - g_signal_new ("begin-verification", - G_OBJECT_CLASS_TYPE (object_class), -diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h -index 7872201..d4fc9dd 100644 ---- a/daemon/gdm-greeter-server.h -+++ b/daemon/gdm-greeter-server.h -@@ -45,6 +45,8 @@ typedef struct - { - GObjectClass parent_class; - -+ void (* start_conversation) (GdmGreeterServer *greeter_server, -+ const char *service_name); - void (* begin_auto_login) (GdmGreeterServer *greeter_server); - void (* begin_verification) (GdmGreeterServer *greeter_server); - void (* begin_verification_for_user)(GdmGreeterServer *greeter_server, -@@ -84,7 +86,8 @@ gboolean gdm_greeter_server_problem (GdmGreeterServer * - const char *text); - gboolean gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server); - gboolean gdm_greeter_server_reset (GdmGreeterServer *greeter_server); --gboolean gdm_greeter_server_ready (GdmGreeterServer *greeter_server); -+gboolean gdm_greeter_server_ready (GdmGreeterServer *greeter_server, -+ const char *service_name); - void gdm_greeter_server_selected_user_changed (GdmGreeterServer *greeter_server, - const char *text); - void gdm_greeter_server_default_language_name_changed (GdmGreeterServer *greeter_server, -diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c -index 5afb557..155680c 100644 ---- a/daemon/gdm-simple-slave.c -+++ b/daemon/gdm-simple-slave.c -@@ -616,6 +616,7 @@ on_session_secret_info_query (GdmSession *session, - - static void - on_session_conversation_started (GdmSession *session, -+ const char *service_name, - GdmSimpleSlave *slave) - { - gboolean res; -@@ -625,7 +626,8 @@ on_session_conversation_started (GdmSession *session, - - g_debug ("GdmSimpleSlave: session conversation started"); - if (slave->priv->greeter_server != NULL) { -- res = gdm_greeter_server_ready (slave->priv->greeter_server); -+ res = gdm_greeter_server_ready (slave->priv->greeter_server, -+ service_name); - if (! res) { - g_warning ("Unable to send ready"); - } -@@ -641,8 +643,10 @@ on_session_conversation_started (GdmSession *session, - gdm_greeter_server_request_timed_login (slave->priv->greeter_server, username, delay); - } else { - g_debug ("GdmSimpleSlave: begin auto login for user '%s'", username); -+ /* service_name will be "gdm-autologin" -+ */ - gdm_session_setup_for_user (GDM_SESSION (slave->priv->session), -- "gdm-autologin", -+ service_name, - username); - } - -@@ -686,6 +690,21 @@ on_default_session_name_changed (GdmSession *session, - } - - static void -+start_autologin_conversation_if_necessary (GdmSimpleSlave *slave) -+{ -+ gboolean enabled; -+ gdm_slave_get_timed_login_details (GDM_SLAVE (slave), &enabled, NULL, NULL); -+ -+ if (!enabled) { -+ return; -+ } -+ -+ g_debug ("GdmSimpleSlave: Starting automatic login conversation"); -+ gdm_session_start_conversation (GDM_SESSION (slave->priv->session), -+ "gdm-autologin"); -+} -+ -+static void - create_new_session (GdmSimpleSlave *slave) - { - gboolean display_is_local; -@@ -821,6 +840,8 @@ create_new_session (GdmSimpleSlave *slave) - "default-session-name-changed", - G_CALLBACK (on_default_session_name_changed), - slave); -+ -+ start_autologin_conversation_if_necessary (slave); - } - - static void -@@ -946,6 +967,16 @@ on_greeter_session_died (GdmGreeterSession *greeter, - } - - static void -+on_greeter_start_conversation (GdmGreeterServer *greeter_server, -+ const char *service_name, -+ GdmSimpleSlave *slave) -+{ -+ g_debug ("GdmSimpleSlave: starting conversation with '%s' pam service'", service_name); -+ gdm_session_start_conversation (GDM_SESSION (slave->priv->session), -+ service_name); -+} -+ -+static void - on_greeter_begin_verification (GdmGreeterServer *greeter_server, - GdmSimpleSlave *slave) - { -@@ -1159,6 +1190,10 @@ start_greeter (GdmSimpleSlave *slave) - - slave->priv->greeter_server = gdm_greeter_server_new (display_id); - g_signal_connect (slave->priv->greeter_server, -+ "start-conversation", -+ G_CALLBACK (on_greeter_start_conversation), -+ slave); -+ g_signal_connect (slave->priv->greeter_server, - "begin-auto-login", - G_CALLBACK (on_greeter_begin_auto_login), - slave); -diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c -index 10ba236..ae61eb1 100644 ---- a/gui/simple-greeter/gdm-greeter-client.c -+++ b/gui/simple-greeter/gdm-greeter-client.c -@@ -230,11 +230,7 @@ static void - on_ready (GdmGreeterClient *client, - DBusMessage *message) - { -- g_debug ("GdmGreeterClient: Ready"); -- -- g_signal_emit (client, -- gdm_greeter_client_signals[READY], -- 0); -+ emit_string_signal_for_message (client, "Ready", message, READY); - } - - static void -@@ -404,6 +400,14 @@ send_dbus_void_method (DBusConnection *connection, - } - - void -+gdm_greeter_client_call_start_conversation (GdmGreeterClient *client, -+ const char *service_name) -+{ -+ send_dbus_string_method (client->priv->connection, -+ "StartConversation", service_name); -+} -+ -+void - gdm_greeter_client_call_begin_auto_login (GdmGreeterClient *client, - const char *username) - { -@@ -875,9 +879,9 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass) - G_STRUCT_OFFSET (GdmGreeterClientClass, ready), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, G_TYPE_STRING); - - gdm_greeter_client_signals[RESET] = - g_signal_new ("reset", -diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h -index 7938046..5f92abe 100644 ---- a/gui/simple-greeter/gdm-greeter-client.h -+++ b/gui/simple-greeter/gdm-greeter-client.h -@@ -83,13 +83,15 @@ GQuark gdm_greeter_client_error_quark (void); - GdmGreeterClient * gdm_greeter_client_new (void); - - gboolean gdm_greeter_client_start (GdmGreeterClient *client, -- GError **error); -+ GError **error); - void gdm_greeter_client_stop (GdmGreeterClient *client); - - gboolean gdm_greeter_client_get_display_is_local (GdmGreeterClient *client); - - char * gdm_greeter_client_call_get_display_id (GdmGreeterClient *client); - -+void gdm_greeter_client_call_start_conversation (GdmGreeterClient *client, -+ const char *service_name); - void gdm_greeter_client_call_begin_auto_login (GdmGreeterClient *client, - const char *username); - void gdm_greeter_client_call_begin_verification (GdmGreeterClient *client); -diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c -index 7be5acd..ed20884 100644 ---- a/gui/simple-greeter/gdm-greeter-session.c -+++ b/gui/simple-greeter/gdm-greeter-session.c -@@ -89,6 +89,7 @@ on_problem (GdmGreeterClient *client, - - static void - on_ready (GdmGreeterClient *client, -+ const char *service_name, - GdmGreeterSession *session) - { - g_debug ("GdmGreeterSession: Ready"); -@@ -270,6 +271,7 @@ on_cancelled (GdmGreeterLoginWindow *login_window, - GdmGreeterSession *session) - { - gdm_greeter_client_call_cancel (session->priv->client); -+ gdm_greeter_client_call_start_conversation (session->priv->client, "gdm"); - } - - static void -@@ -423,6 +425,8 @@ gdm_greeter_session_start (GdmGreeterSession *session, - toggle_panel (session, TRUE); - toggle_login_window (session, TRUE); - -+ gdm_greeter_client_call_start_conversation (session->priv->client, "gdm"); -+ - gdm_profile_end (NULL); - - return res; --- -1.7.4.1 - - -From be38e34cfeca87d500705bfd033f820766264966 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 16 Jan 2009 15:18:31 -0500 -Subject: [PATCH 06/20] Store multiple conversations in the session - -We keep multiple conversations in the session now, keyed off of -PAM service is at the other end. Much of the guts still -only operate on the first conversation added though. ---- - daemon/gdm-factory-slave.c | 69 +++- - daemon/gdm-greeter-server.c | 134 ++++++-- - daemon/gdm-greeter-server.h | 19 +- - daemon/gdm-product-slave.c | 264 +++++++++++--- - daemon/gdm-session-direct.c | 599 +++++++++++++++++++++--------- - daemon/gdm-session-private.h | 28 ++- - daemon/gdm-session-relay.c | 135 ++++++-- - daemon/gdm-session-worker.c | 27 ++ - daemon/gdm-session.c | 203 +++++++---- - daemon/gdm-session.h | 60 +++- - daemon/gdm-simple-slave.c | 120 +++++-- - daemon/test-session.c | 22 +- - gui/simple-greeter/gdm-greeter-client.c | 188 ++++++++-- - gui/simple-greeter/gdm-greeter-client.h | 16 +- - gui/simple-greeter/gdm-greeter-session.c | 11 +- - 15 files changed, 1420 insertions(+), 475 deletions(-) - -diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c -index 9bae550..9e435f9 100644 ---- a/daemon/gdm-factory-slave.c -+++ b/daemon/gdm-factory-slave.c -@@ -144,45 +144,49 @@ on_greeter_session_died (GdmGreeterSession *greeter, - - static void - on_session_info (GdmSession *session, -+ const char *service_name, - const char *text, - GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: Info: %s", text); -- gdm_greeter_server_info (slave->priv->greeter_server, text); -+ gdm_greeter_server_info (slave->priv->greeter_server, service_name, text); - } - - static void - on_session_problem (GdmSession *session, -+ const char *service_name, - const char *text, - GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: Problem: %s", text); -- gdm_greeter_server_problem (slave->priv->greeter_server, text); -+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, text); - } - - static void - on_session_info_query (GdmSession *session, -+ const char *service_name, - const char *text, - GdmFactorySlave *slave) - { - - g_debug ("GdmFactorySlave: Info query: %s", text); -- gdm_greeter_server_info_query (slave->priv->greeter_server, text); -+ gdm_greeter_server_info_query (slave->priv->greeter_server, service_name, text); - } - - static void - on_session_secret_info_query (GdmSession *session, -+ const char *service_name, - const char *text, - GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: Secret info query: %s", text); -- gdm_greeter_server_secret_info_query (slave->priv->greeter_server, text); -+ gdm_greeter_server_secret_info_query (slave->priv->greeter_server, service_name, text); - } - - static void - on_session_conversation_started (GdmSession *session, -- GdmFactorySlave *slave, -- const char *service_name) -+ const char *service_name, -+ GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: session conversation started"); - -@@ -192,17 +196,19 @@ on_session_conversation_started (GdmSession *session, - - static void - on_session_setup_complete (GdmSession *session, -+ const char *service_name, - GdmFactorySlave *slave) - { -- gdm_session_authenticate (session); -+ gdm_session_authenticate (session, service_name); - } - - static void - on_session_setup_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmFactorySlave *slave) - { -- gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable to initialize login system")); -+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, _("Unable to initialize login system")); - - queue_greeter_reset (slave); - } -@@ -224,23 +230,26 @@ on_session_reset_failed (GdmSession *session, - - static void - on_session_authenticated (GdmSession *session, -+ const char *service_name, - GdmFactorySlave *slave) - { -- gdm_session_authorize (session); -+ gdm_session_authorize (session, service_name); - } - - static void - on_session_authentication_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmFactorySlave *slave) - { -- gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable to authenticate user")); -+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, _("Unable to authenticate user")); - - queue_greeter_reset (slave); - } - - static void - on_session_authorized (GdmSession *session, -+ const char *service_name, - GdmFactorySlave *slave) - { - int flag; -@@ -248,60 +257,65 @@ on_session_authorized (GdmSession *session, - /* FIXME: check for migration? */ - flag = GDM_SESSION_CRED_ESTABLISH; - -- gdm_session_accredit (session, flag); -+ gdm_session_accredit (session, service_name, flag); - } - - static void - on_session_authorization_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmFactorySlave *slave) - { -- gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable to authorize user")); -+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, _("Unable to authorize user")); - - queue_greeter_reset (slave); - } - - static void - on_session_accredited (GdmSession *session, -+ const char *service_name, - GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: session user verified"); - -- gdm_session_open_session (session); -+ gdm_session_open_session (session, service_name); - } - - static void - on_session_accreditation_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: could not successfully authenticate user: %s", - message); - -- gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable to establish credentials")); -+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, _("Unable to establish credentials")); - - queue_greeter_reset (slave); - } - - static void - on_session_opened (GdmSession *session, -+ const char *service_name, - GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: session opened"); - -- gdm_session_start_session (session); -+ gdm_session_start_session (session, service_name); - - gdm_greeter_server_reset (slave->priv->greeter_server); - } - - static void - on_session_open_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: could not open session: %s", message); - -- gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable to open session")); -+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, _("Unable to open session")); - - queue_greeter_reset (slave); - } -@@ -390,37 +404,48 @@ on_session_relay_connected (GdmSessionRelay *session, - GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: Relay Connected"); -+} -+ -+static void -+on_greeter_start_conversation (GdmGreeterServer *greeter_server, -+ const char *service_name, -+ GdmFactorySlave *slave) -+{ -+ g_debug ("GdmFactorySlave: start conversation"); - -- gdm_session_start_conversation (GDM_SESSION (slave->priv->session), "gdm"); -+ gdm_session_start_conversation (GDM_SESSION (slave->priv->session), service_name); - } - - static void - on_greeter_begin_verification (GdmGreeterServer *greeter_server, -+ const char *service_name, - GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: begin verification"); - gdm_session_setup (GDM_SESSION (slave->priv->session), -- "gdm"); -+ service_name); - } - - static void - on_greeter_begin_verification_for_user (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *username, - GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: begin verification for user"); - gdm_session_setup_for_user (GDM_SESSION (slave->priv->session), -- "gdm", -+ service_name, - username); - } - - static void - on_greeter_answer (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *text, - GdmFactorySlave *slave) - { - g_debug ("GdmFactorySlave: Greeter answer"); -- gdm_session_answer_query (GDM_SESSION (slave->priv->session), text); -+ gdm_session_answer_query (GDM_SESSION (slave->priv->session), service_name, text); - } - - static void -@@ -512,6 +537,10 @@ run_greeter (GdmFactorySlave *slave) - - slave->priv->greeter_server = gdm_greeter_server_new (display_id); - g_signal_connect (slave->priv->greeter_server, -+ "start-conversation", -+ G_CALLBACK (on_greeter_start_conversation), -+ slave); -+ g_signal_connect (slave->priv->greeter_server, - "begin-verification", - G_CALLBACK (on_greeter_begin_verification), - slave); -diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c -index 463ba6a..d9ecb1f 100644 ---- a/daemon/gdm-greeter-server.c -+++ b/daemon/gdm-greeter-server.c -@@ -44,6 +44,7 @@ - #include - - #include "gdm-common.h" -+#include "gdm-marshal.h" - #include "gdm-greeter-server.h" - - #define GDM_GREETER_SERVER_DBUS_PATH "/org/gnome/DisplayManager/GreeterServer" -@@ -156,6 +157,46 @@ send_dbus_string_and_int_signal (GdmGreeterServer *greeter_server, - } - - static void -+send_dbus_string_string_signal (GdmGreeterServer *greeter_server, -+ const char *name, -+ const char *text1, -+ const char *text2) -+{ -+ DBusMessage *message; -+ DBusMessageIter iter; -+ const char *str; -+ -+ g_return_if_fail (greeter_server != NULL); -+ -+ message = dbus_message_new_signal (GDM_GREETER_SERVER_DBUS_PATH, -+ GDM_GREETER_SERVER_DBUS_INTERFACE, -+ name); -+ -+ dbus_message_iter_init_append (message, &iter); -+ -+ if (text1 != NULL) { -+ str = text1; -+ } else { -+ str = ""; -+ } -+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &str); -+ -+ if (text2 != NULL) { -+ str = text2; -+ } else { -+ str = ""; -+ } -+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &str); -+ -+ g_debug ("GreeterServer: Sending %s (%s)", name, str); -+ if (! send_dbus_message (greeter_server->priv->greeter_connection, message)) { -+ g_debug ("GreeterServer: Could not send %s signal", name); -+ } -+ -+ dbus_message_unref (message); -+} -+ -+static void - send_dbus_string_signal (GdmGreeterServer *greeter_server, - const char *name, - const char *text) -@@ -208,34 +249,38 @@ send_dbus_void_signal (GdmGreeterServer *greeter_server, - - gboolean - gdm_greeter_server_info_query (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *text) - { -- send_dbus_string_signal (greeter_server, "InfoQuery", text); -+ send_dbus_string_string_signal (greeter_server, "InfoQuery", service_name, text); - - return TRUE; - } - - gboolean - gdm_greeter_server_secret_info_query (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *text) - { -- send_dbus_string_signal (greeter_server, "SecretInfoQuery", text); -+ send_dbus_string_string_signal (greeter_server, "SecretInfoQuery", service_name, text); - return TRUE; - } - - gboolean - gdm_greeter_server_info (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *text) - { -- send_dbus_string_signal (greeter_server, "Info", text); -+ send_dbus_string_string_signal (greeter_server, "Info", service_name, text); - return TRUE; - } - - gboolean - gdm_greeter_server_problem (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *text) - { -- send_dbus_string_signal (greeter_server, "Problem", text); -+ send_dbus_string_string_signal (greeter_server, "Problem", service_name, text); - return TRUE; - } - -@@ -261,6 +306,14 @@ gdm_greeter_server_ready (GdmGreeterServer *greeter_server, - return TRUE; - } - -+gboolean -+gdm_greeter_server_conversation_stopped (GdmGreeterServer *greeter_server, -+ const char *service_name) -+{ -+ send_dbus_string_signal (greeter_server, "ConversationStopped", service_name); -+ return TRUE; -+} -+ - void - gdm_greeter_server_selected_user_changed (GdmGreeterServer *greeter_server, - const char *username) -@@ -291,9 +344,10 @@ gdm_greeter_server_request_timed_login (GdmGreeterServer *greeter_server, - } - - void --gdm_greeter_server_user_authorized (GdmGreeterServer *greeter_server) -+gdm_greeter_server_user_authorized (GdmGreeterServer *greeter_server, -+ const char *service_name) - { -- send_dbus_void_signal (greeter_server, "UserAuthorized"); -+ send_dbus_string_signal (greeter_server, "UserAuthorized", service_name); - } - - /* Note: Use abstract sockets like dbus does by default on Linux. Abstract -@@ -358,6 +412,16 @@ handle_begin_verification (GdmGreeterServer *greeter_server, - DBusMessage *message) - { - DBusMessage *reply; -+ DBusError error; -+ const char *service_name; -+ -+ dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } -+ dbus_error_free (&error); - - g_debug ("GreeterServer: BeginVerification"); - -@@ -365,7 +429,7 @@ handle_begin_verification (GdmGreeterServer *greeter_server, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- g_signal_emit (greeter_server, signals [BEGIN_VERIFICATION], 0); -+ g_signal_emit (greeter_server, signals [BEGIN_VERIFICATION], 0, service_name); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -379,7 +443,6 @@ handle_begin_auto_login (GdmGreeterServer *greeter_server, - DBusError error; - const char *text; - -- - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, - DBUS_TYPE_STRING, &text, -@@ -406,13 +469,16 @@ handle_begin_verification_for_user (GdmGreeterServer *greeter_server, - DBusMessage *reply; - DBusError error; - const char *text; -+ const char *service_name; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) { - g_warning ("ERROR: %s", error.message); - } -+ dbus_error_free (&error); - - g_debug ("GreeterServer: BeginVerificationForUser for '%s'", text); - -@@ -420,7 +486,7 @@ handle_begin_verification_for_user (GdmGreeterServer *greeter_server, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- g_signal_emit (greeter_server, signals [BEGIN_VERIFICATION_FOR_USER], 0, text); -+ g_signal_emit (greeter_server, signals [BEGIN_VERIFICATION_FOR_USER], 0, service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -433,13 +499,16 @@ handle_answer_query (GdmGreeterServer *greeter_server, - DBusMessage *reply; - DBusError error; - const char *text; -+ const char *service_name; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) { - g_warning ("ERROR: %s", error.message); - } -+ dbus_error_free (&error); - - g_debug ("GreeterServer: AnswerQuery"); - -@@ -447,7 +516,7 @@ handle_answer_query (GdmGreeterServer *greeter_server, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- g_signal_emit (greeter_server, signals [QUERY_ANSWER], 0, text); -+ g_signal_emit (greeter_server, signals [QUERY_ANSWER], 0, service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -617,9 +686,11 @@ handle_start_session_when_ready (GdmGreeterServer *greeter_server, - DBusMessage *reply; - DBusError error; - gboolean should_start_session; -+ char *service_name; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, - DBUS_TYPE_BOOLEAN, &should_start_session, - DBUS_TYPE_INVALID)) { - g_warning ("ERROR: %s", error.message); -@@ -633,9 +704,9 @@ handle_start_session_when_ready (GdmGreeterServer *greeter_server, - dbus_message_unref (reply); - - if (should_start_session) { -- g_signal_emit (greeter_server, signals [START_SESSION_WHEN_READY], 0); -+ g_signal_emit (greeter_server, signals [START_SESSION_WHEN_READY], 0, service_name); - } else { -- g_signal_emit (greeter_server, signals [START_SESSION_LATER] ,0); -+ g_signal_emit (greeter_server, signals [START_SESSION_LATER] ,0, service_name); - } - - return DBUS_HANDLER_RESULT_HANDLED; -@@ -705,14 +776,20 @@ do_introspect (DBusConnection *connection, - " \n" - " \n" - " \n" -+ " \n" -+ " \n" -+ " \n" - " \n" -+ " \n" - " \n" - " \n" - " \n" - " \n" -+ " \n" - " \n" - " \n" - " \n" -+ " \n" - " \n" - " \n" - " \n" -@@ -735,18 +812,23 @@ do_introspect (DBusConnection *connection, - " \n" - " \n" - " \n" -+ " \n" - " \n" - " \n" - " \n" -+ " \n" - " \n" - " \n" - " \n" -+ " \n" - " \n" - " \n" - " \n" -+ " \n" - " \n" - " \n" - " \n" -+ " \n" - " \n" - " \n" - " \n" -@@ -765,11 +847,15 @@ do_introspect (DBusConnection *connection, - " \n" - " \n" - " \n" -+ " \n" -+ " \n" -+ " \n" - " \n" - " \n" - " \n" - " \n" - " \n" -+ " \n" - " \n" - " \n"); - -@@ -1145,9 +1231,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass) - G_STRUCT_OFFSET (GdmGreeterServerClass, begin_verification), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, G_TYPE_STRING); - signals [BEGIN_AUTO_LOGIN] = - g_signal_new ("begin-auto-login", - G_OBJECT_CLASS_TYPE (object_class), -@@ -1166,10 +1252,10 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass) - G_STRUCT_OFFSET (GdmGreeterServerClass, begin_verification_for_user), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - signals [QUERY_ANSWER] = - g_signal_new ("query-answer", - G_OBJECT_CLASS_TYPE (object_class), -@@ -1177,10 +1263,10 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass) - G_STRUCT_OFFSET (GdmGreeterServerClass, query_answer), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - signals [SESSION_SELECTED] = - g_signal_new ("session-selected", - G_OBJECT_CLASS_TYPE (object_class), -@@ -1263,9 +1349,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass) - G_STRUCT_OFFSET (GdmGreeterServerClass, start_session_when_ready), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, G_TYPE_STRING); - - signals [START_SESSION_LATER] = - g_signal_new ("start-session-later", -@@ -1274,9 +1360,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass) - G_STRUCT_OFFSET (GdmGreeterServerClass, start_session_later), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, G_TYPE_STRING); - } - - static void -diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h -index d4fc9dd..9015c26 100644 ---- a/daemon/gdm-greeter-server.h -+++ b/daemon/gdm-greeter-server.h -@@ -48,10 +48,13 @@ typedef struct - void (* start_conversation) (GdmGreeterServer *greeter_server, - const char *service_name); - void (* begin_auto_login) (GdmGreeterServer *greeter_server); -- void (* begin_verification) (GdmGreeterServer *greeter_server); -+ void (* begin_verification) (GdmGreeterServer *greeter_server, -+ const char *service_name); - void (* begin_verification_for_user)(GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *username); - void (* query_answer) (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *text); - void (* session_selected) (GdmGreeterServer *greeter_server, - const char *name); -@@ -64,7 +67,8 @@ typedef struct - void (* cancelled) (GdmGreeterServer *greeter_server); - void (* connected) (GdmGreeterServer *greeter_server); - void (* disconnected) (GdmGreeterServer *greeter_server); -- void (* start_session_when_ready) (GdmGreeterServer *greeter_server); -+ void (* start_session_when_ready) (GdmGreeterServer *greeter_server, -+ const char *service_name); - void (* start_session_later) (GdmGreeterServer *greeter_server); - } GdmGreeterServerClass; - -@@ -75,19 +79,24 @@ gboolean gdm_greeter_server_start (GdmGreeterServer * - gboolean gdm_greeter_server_stop (GdmGreeterServer *greeter_server); - char * gdm_greeter_server_get_address (GdmGreeterServer *greeter_server); - -- - gboolean gdm_greeter_server_info_query (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *text); - gboolean gdm_greeter_server_secret_info_query (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *text); - gboolean gdm_greeter_server_info (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *text); - gboolean gdm_greeter_server_problem (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *text); - gboolean gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server); - gboolean gdm_greeter_server_reset (GdmGreeterServer *greeter_server); - gboolean gdm_greeter_server_ready (GdmGreeterServer *greeter_server, - const char *service_name); -+gboolean gdm_greeter_server_conversation_stopped (GdmGreeterServer *greeter_server, -+ const char *service_name); - void gdm_greeter_server_selected_user_changed (GdmGreeterServer *greeter_server, - const char *text); - void gdm_greeter_server_default_language_name_changed (GdmGreeterServer *greeter_server, -@@ -98,8 +107,8 @@ void gdm_greeter_server_default_session_name_changed (GdmGreeterS - void gdm_greeter_server_request_timed_login (GdmGreeterServer *greeter_server, - const char *username, - int delay); --void gdm_greeter_server_user_authorized (GdmGreeterServer *greeter_server); -- -+void gdm_greeter_server_user_authorized (GdmGreeterServer *greeter_server, -+ const char *service_name); - - G_END_DECLS - -diff --git a/daemon/gdm-product-slave.c b/daemon/gdm-product-slave.c -index 84d5c49..af1c480 100644 ---- a/daemon/gdm-product-slave.c -+++ b/daemon/gdm-product-slave.c -@@ -79,6 +79,8 @@ struct GdmProductSlavePrivate - - DBusGProxy *product_display_proxy; - DBusGConnection *connection; -+ -+ char *start_session_service_name; - }; - - enum { -@@ -93,6 +95,68 @@ static void gdm_product_slave_finalize (GObject *object); - G_DEFINE_TYPE (GdmProductSlave, gdm_product_slave, GDM_TYPE_SLAVE) - - static gboolean -+send_dbus_string_string_method (DBusConnection *connection, -+ const char *method, -+ const char *payload1, -+ const char *payload2) -+{ -+ DBusError error; -+ DBusMessage *message; -+ DBusMessage *reply; -+ DBusMessageIter iter; -+ const char *str; -+ -+ g_debug ("GdmProductSlave: Calling %s", method); -+ message = dbus_message_new_method_call (NULL, -+ RELAY_SERVER_DBUS_PATH, -+ RELAY_SERVER_DBUS_INTERFACE, -+ method); -+ if (message == NULL) { -+ g_warning ("Couldn't allocate the D-Bus message"); -+ return FALSE; -+ } -+ -+ dbus_message_iter_init_append (message, &iter); -+ -+ if (payload1 != NULL) { -+ str = payload1; -+ } else { -+ str = ""; -+ } -+ dbus_message_iter_append_basic (&iter, -+ DBUS_TYPE_STRING, -+ &str); -+ if (payload2 != NULL) { -+ str = payload2; -+ } else { -+ str = ""; -+ } -+ dbus_message_iter_append_basic (&iter, -+ DBUS_TYPE_STRING, -+ &str); -+ dbus_error_init (&error); -+ reply = dbus_connection_send_with_reply_and_block (connection, -+ message, -+ -1, -+ &error); -+ -+ dbus_message_unref (message); -+ -+ if (dbus_error_is_set (&error)) { -+ g_warning ("%s %s raised: %s\n", -+ method, -+ error.name, -+ error.message); -+ return FALSE; -+ } -+ if (reply != NULL) { -+ dbus_message_unref (reply); -+ } -+ dbus_connection_flush (connection); -+ -+ return TRUE; -+} -+static gboolean - send_dbus_string_method (DBusConnection *connection, - const char *method, - const char *payload) -@@ -356,7 +420,8 @@ setup_session (GdmProductSlave *slave) - g_free (display_device); - g_free (auth_file); - -- gdm_session_start_session (GDM_SESSION (slave->priv->session)); -+ gdm_session_start_session (GDM_SESSION (slave->priv->session), -+ slave->priv->start_session_service_name); - - return TRUE; - } -@@ -508,114 +573,133 @@ on_session_reset_failed (GdmSession *session, - - static void - on_session_authenticated (GdmSession *session, -+ const char *service_name, - GdmProductSlave *slave) - { -- send_dbus_void_method (slave->priv->session_relay_connection, -- "Authenticated"); -+ send_dbus_string_method (slave->priv->session_relay_connection, -+ "Authenticated", service_name); - } - - static void - on_session_authentication_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmProductSlave *slave) - { -- send_dbus_string_method (slave->priv->session_relay_connection, -- "AuthenticationFailed", -- message); -+ send_dbus_string_string_method (slave->priv->session_relay_connection, -+ "AuthenticationFailed", -+ service_name, -+ message); - } - - static void - on_session_authorized (GdmSession *session, -+ const char *service_name, - GdmProductSlave *slave) - { -- send_dbus_void_method (slave->priv->session_relay_connection, -- "Authorized"); -+ send_dbus_string_method (slave->priv->session_relay_connection, -+ "Authorized", service_name); - } - - static void - on_session_authorization_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmProductSlave *slave) - { -- send_dbus_string_method (slave->priv->session_relay_connection, -- "AuthorizationFailed", -- message); -+ send_dbus_string_string_method (slave->priv->session_relay_connection, -+ "AuthorizationFailed", -+ service_name, -+ message); - } - - static void - on_session_accredited (GdmSession *session, -+ const char *service_name, - GdmProductSlave *slave) - { -- send_dbus_void_method (slave->priv->session_relay_connection, -- "Accredited"); -+ send_dbus_string_method (slave->priv->session_relay_connection, -+ "Accredited", service_name); - } - - static void - on_session_accreditation_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmProductSlave *slave) - { -- send_dbus_string_method (slave->priv->session_relay_connection, -- "AccreditationFailed", -- message); -+ send_dbus_string_string_method (slave->priv->session_relay_connection, -+ "AccreditationFailed", -+ service_name, -+ message); - } - - static void - on_session_opened (GdmSession *session, -+ const char *service_name, - GdmProductSlave *slave) - { -- send_dbus_void_method (slave->priv->session_relay_connection, -- "SessionOpened"); -+ send_dbus_string_method (slave->priv->session_relay_connection, -+ "SessionOpened", service_name); - } - - static void - on_session_open_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmProductSlave *slave) - { -- send_dbus_string_method (slave->priv->session_relay_connection, -- "SessionOpenFailed", -- message); -+ send_dbus_string_string_method (slave->priv->session_relay_connection, -+ "SessionOpenFailed", -+ service_name, -+ message); - } - - static void - on_session_info (GdmSession *session, -+ const char *service_name, - const char *text, - GdmProductSlave *slave) - { -- send_dbus_string_method (slave->priv->session_relay_connection, -- "Info", -- text); -+ send_dbus_string_string_method (slave->priv->session_relay_connection, -+ "Info", -+ service_name, -+ text); - } - - static void - on_session_problem (GdmSession *session, -+ const char *service_name, - const char *text, - GdmProductSlave *slave) - { -- send_dbus_string_method (slave->priv->session_relay_connection, -- "Problem", -- text); -+ send_dbus_string_string_method (slave->priv->session_relay_connection, -+ "Problem", -+ service_name, -+ text); - } - - static void - on_session_info_query (GdmSession *session, -+ const char *service_name, - const char *text, - GdmProductSlave *slave) - { -- send_dbus_string_method (slave->priv->session_relay_connection, -- "InfoQuery", -- text); -+ send_dbus_string_string_method (slave->priv->session_relay_connection, -+ "InfoQuery", -+ service_name, text); - } - - static void - on_session_secret_info_query (GdmSession *session, -+ const char *service_name, - const char *text, - GdmProductSlave *slave) - { -- send_dbus_string_method (slave->priv->session_relay_connection, -- "SecretInfoQuery", -- text); -+ send_dbus_string_string_method (slave->priv->session_relay_connection, -+ "SecretInfoQuery", -+ service_name, -+ text); - } - - static void -@@ -676,36 +760,92 @@ static void - on_relay_authenticate (GdmProductSlave *slave, - DBusMessage *message) - { -- g_debug ("GdmProductSlave: Relay Authenticate"); -+ DBusError error; -+ char *service_name; -+ dbus_bool_t res; - -- gdm_session_authenticate (GDM_SESSION (slave->priv->session)); -+ dbus_error_init (&error); -+ res = dbus_message_get_args (message, -+ &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID); -+ if (res) { -+ g_debug ("GdmProductSlave: Relay Authenticate"); -+ gdm_session_authenticate (GDM_SESSION (slave->priv->session), service_name); -+ } else { -+ g_warning ("Unable to get arguments: %s", error.message); -+ dbus_error_free (&error); -+ } -+ dbus_error_free (&error); - } - - static void - on_relay_authorize (GdmProductSlave *slave, - DBusMessage *message) - { -- g_debug ("GdmProductSlave: Relay Authorize"); -+ DBusError error; -+ char *service_name; -+ dbus_bool_t res; - -- gdm_session_authorize (GDM_SESSION (slave->priv->session)); -+ dbus_error_init (&error); -+ res = dbus_message_get_args (message, -+ &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID); -+ if (res) { -+ g_debug ("GdmProductSlave: Relay Authorize"); -+ gdm_session_authorize (GDM_SESSION (slave->priv->session), service_name); -+ } else { -+ g_warning ("Unable to get arguments: %s", error.message); -+ dbus_error_free (&error); -+ } -+ dbus_error_free (&error); - } - - static void - on_relay_establish_credentials (GdmProductSlave *slave, - DBusMessage *message) - { -- g_debug ("GdmProductSlave: Relay EstablishCredentials"); -+ DBusError error; -+ char *service_name; -+ dbus_bool_t res; - -- gdm_session_accredit (GDM_SESSION (slave->priv->session), GDM_SESSION_CRED_ESTABLISH); -+ dbus_error_init (&error); -+ res = dbus_message_get_args (message, -+ &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID); -+ if (res) { -+ g_debug ("GdmProductSlave: Relay EstablishCredentials"); -+ gdm_session_accredit (GDM_SESSION (slave->priv->session), service_name, GDM_SESSION_CRED_ESTABLISH); -+ } else { -+ g_warning ("Unable to get arguments: %s", error.message); -+ dbus_error_free (&error); -+ } -+ dbus_error_free (&error); - } - - static void - on_relay_refresh_credentials (GdmProductSlave *slave, - DBusMessage *message) - { -- g_debug ("GdmProductSlave: Relay RefreshCredentials"); -+ DBusError error; -+ char *service_name; -+ dbus_bool_t res; - -- gdm_session_accredit (GDM_SESSION (slave->priv->session), GDM_SESSION_CRED_REFRESH); -+ dbus_error_init (&error); -+ res = dbus_message_get_args (message, -+ &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID); -+ if (res) { -+ g_debug ("GdmProductSlave: Relay RefreshCredentials"); -+ gdm_session_accredit (GDM_SESSION (slave->priv->session), service_name, GDM_SESSION_CRED_REFRESH); -+ } else { -+ g_warning ("Unable to get arguments: %s", error.message); -+ dbus_error_free (&error); -+ } -+ dbus_error_free (&error); - } - - static void -@@ -714,16 +854,18 @@ on_relay_answer_query (GdmProductSlave *slave, - { - DBusError error; - const char *text; -+ const char *service_name; - dbus_bool_t res; - - dbus_error_init (&error); - res = dbus_message_get_args (message, - &error, -+ DBUS_TYPE_STRING, &service_name, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID); - if (res) { - g_debug ("GdmProductSlave: Relay AnswerQuery"); -- gdm_session_answer_query (GDM_SESSION (slave->priv->session), text); -+ gdm_session_answer_query (GDM_SESSION (slave->priv->session), service_name, text); - } else { - g_warning ("Unable to get arguments: %s", error.message); - dbus_error_free (&error); -@@ -809,14 +951,48 @@ static void - on_relay_open_session (GdmProductSlave *slave, - DBusMessage *message) - { -- gdm_session_open_session (GDM_SESSION (slave->priv->session)); -+ DBusError error; -+ const char *text; -+ dbus_bool_t res; -+ -+ dbus_error_init (&error); -+ res = dbus_message_get_args (message, -+ &error, -+ DBUS_TYPE_STRING, &text, -+ DBUS_TYPE_INVALID); -+ if (res) { -+ g_debug ("GdmProductSlave: open session %s", text); -+ gdm_session_open_session (GDM_SESSION (slave->priv->session), -+ text); -+ } else { -+ g_warning ("Unable to get arguments: %s", error.message); -+ dbus_error_free (&error); -+ } - } - - static void - on_relay_start_session (GdmProductSlave *slave, - DBusMessage *message) - { -- gdm_product_slave_create_server (slave); -+ DBusError error; -+ const char *service_name; -+ dbus_bool_t res; -+ -+ dbus_error_init (&error); -+ -+ res = dbus_message_get_args (message, -+ &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID); -+ if (res) { -+ g_debug ("GdmProductSlave: Relay StartSession"); -+ g_free (slave->priv->start_session_service_name); -+ slave->priv->start_session_service_name = g_strdup (service_name); -+ gdm_product_slave_create_server (slave); -+ } else { -+ g_warning ("Unable to get arguments: %s", error.message); -+ dbus_error_free (&error); -+ } - } - - static void -diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c -index 5b30ecd..15a018f 100644 ---- a/daemon/gdm-session-direct.c -+++ b/daemon/gdm-session-direct.c -@@ -87,9 +87,10 @@ struct _GdmSessionDirectPrivate - char *selected_user; - char *user_x11_authority_file; - -- GdmSessionConversation *conversation; -+ GHashTable *conversations; -+ -+ GList *pending_connections; - -- GdmSessionWorkerJob *job; - GPid session_pid; - guint32 is_running : 1; - -@@ -198,14 +199,30 @@ send_dbus_void_signal (GdmSessionConversation *conversation, - dbus_message_unref (message); - } - -+static GdmSessionConversation * -+find_conversation_by_name (GdmSessionDirect *session, -+ const char *service_name) -+{ -+ GdmSessionConversation *conversation; -+ -+ conversation = g_hash_table_lookup (session->priv->conversations, service_name); -+ -+ if (conversation == NULL) { -+ g_warning ("Tried to look up non-existent conversation %s", service_name); -+ } -+ -+ return conversation; -+} -+ - static void - on_authentication_failed (GdmSession *session, -+ const char *service_name, - const char *message) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - GdmSessionConversation *conversation; - -- conversation = impl->priv->conversation; -+ conversation = find_conversation_by_name (impl, service_name); - if (conversation != NULL) { - gdm_session_record_failed (conversation->worker_pid, - impl->priv->selected_user, -@@ -216,12 +233,13 @@ on_authentication_failed (GdmSession *session, - } - - static void --on_session_started (GdmSession *session) -+on_session_started (GdmSession *session, -+ const char *service_name) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - GdmSessionConversation *conversation; - -- conversation = impl->priv->conversation; -+ conversation = find_conversation_by_name (impl, service_name); - if (conversation != NULL) { - gdm_session_record_login (conversation->worker_pid, - impl->priv->selected_user, -@@ -233,12 +251,13 @@ on_session_started (GdmSession *session) - - static void - on_session_start_failed (GdmSession *session, -+ const char *service_name, - const char *message) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - GdmSessionConversation *conversation; - -- conversation = impl->priv->conversation; -+ conversation = find_conversation_by_name (impl, service_name); - if (conversation != NULL) { - gdm_session_record_login (conversation->worker_pid, - impl->priv->selected_user, -@@ -263,7 +282,7 @@ on_session_exited (GdmSession *session, - - static DBusHandlerResult - gdm_session_direct_handle_setup_complete (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -271,17 +290,17 @@ gdm_session_direct_handle_setup_complete (GdmSessionDirect *session, - g_debug ("GdmSessionDirect: Emitting 'setup-complete' signal"); - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_setup_complete (GDM_SESSION (session)); -+ _gdm_session_setup_complete (GDM_SESSION (session), conversation->service_name); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_setup_failed (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -296,12 +315,12 @@ gdm_session_direct_handle_setup_failed (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'setup-failed' signal"); - -- _gdm_session_setup_failed (GDM_SESSION (session), text); -+ _gdm_session_setup_failed (GDM_SESSION (session), conversation->service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -309,7 +328,7 @@ gdm_session_direct_handle_setup_failed (GdmSessionDirect *session, - - static DBusHandlerResult - gdm_session_direct_handle_reset_complete (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -317,7 +336,7 @@ gdm_session_direct_handle_reset_complete (GdmSessionDirect *session, - g_debug ("GdmSessionDirect: Emitting 'reset-complete' signal"); - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - _gdm_session_reset_complete (GDM_SESSION (session)); -@@ -327,7 +346,7 @@ gdm_session_direct_handle_reset_complete (GdmSessionDirect *session, - - static DBusHandlerResult - gdm_session_direct_handle_reset_failed (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -342,7 +361,7 @@ gdm_session_direct_handle_reset_failed (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'reset-failed' signal"); -@@ -354,7 +373,7 @@ gdm_session_direct_handle_reset_failed (GdmSessionDirect *session, - - static DBusHandlerResult - gdm_session_direct_handle_authenticated (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -362,17 +381,17 @@ gdm_session_direct_handle_authenticated (GdmSessionDirect *session, - g_debug ("GdmSessionDirect: Emitting 'authenticated' signal"); - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_authenticated (GDM_SESSION (session)); -+ _gdm_session_authenticated (GDM_SESSION (session), conversation->service_name); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_authentication_failed (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -387,19 +406,19 @@ gdm_session_direct_handle_authentication_failed (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'authentication-failed' signal"); - -- _gdm_session_authentication_failed (GDM_SESSION (session), text); -+ _gdm_session_authentication_failed (GDM_SESSION (session), conversation->service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_authorized (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -407,17 +426,17 @@ gdm_session_direct_handle_authorized (GdmSessionDirect *session, - g_debug ("GdmSessionDirect: Emitting 'authorized' signal"); - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_authorized (GDM_SESSION (session)); -+ _gdm_session_authorized (GDM_SESSION (session), conversation->service_name); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_authorization_failed (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -432,19 +451,19 @@ gdm_session_direct_handle_authorization_failed (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'authorization-failed' signal"); - -- _gdm_session_authorization_failed (GDM_SESSION (session), text); -+ _gdm_session_authorization_failed (GDM_SESSION (session), conversation->service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_accredited (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -452,17 +471,17 @@ gdm_session_direct_handle_accredited (GdmSessionDirect *session, - g_debug ("GdmSessionDirect: Emitting 'accredited' signal"); - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_accredited (GDM_SESSION (session)); -+ _gdm_session_accredited (GDM_SESSION (session), conversation->service_name); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_accreditation_failed (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -477,12 +496,12 @@ gdm_session_direct_handle_accreditation_failed (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'accreditation-failed' signal"); - -- _gdm_session_accreditation_failed (GDM_SESSION (session), text); -+ _gdm_session_accreditation_failed (GDM_SESSION (session), conversation->service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -758,7 +777,7 @@ gdm_session_direct_select_user (GdmSession *session, - - static DBusHandlerResult - gdm_session_direct_handle_username_changed (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -773,7 +792,7 @@ gdm_session_direct_handle_username_changed (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: changing username from '%s' to '%s'", -@@ -840,14 +859,11 @@ set_pending_query (GdmSessionConversation *conversation, - - static DBusHandlerResult - gdm_session_direct_handle_info_query (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusError error; - const char *text; -- GdmSessionConversation *conversation; -- -- conversation = session->priv->conversation; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -@@ -859,21 +875,18 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session, - set_pending_query (conversation, message); - - g_debug ("GdmSessionDirect: Emitting 'info-query' signal"); -- _gdm_session_info_query (GDM_SESSION (session), text); -+ _gdm_session_info_query (GDM_SESSION (session), conversation->service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusError error; - const char *text; -- GdmSessionConversation *conversation; -- -- conversation = session->priv->conversation; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -@@ -885,14 +898,14 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session, - set_pending_query (conversation, message); - - g_debug ("GdmSessionDirect: Emitting 'secret-info-query' signal"); -- _gdm_session_secret_info_query (GDM_SESSION (session), text); -+ _gdm_session_secret_info_query (GDM_SESSION (session), conversation->service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_info (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -907,31 +920,28 @@ gdm_session_direct_handle_info (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'info' signal"); -- _gdm_session_info (GDM_SESSION (session), text); -+ _gdm_session_info (GDM_SESSION (session), conversation->service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -- GdmSessionConversation *conversation; - - g_debug ("GdmSessionDirect: worker cancelling pending query"); - -- conversation = session->priv->conversation; -- - cancel_pending_query (conversation); - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - return DBUS_HANDLER_RESULT_HANDLED; -@@ -939,7 +949,7 @@ gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session, - - static DBusHandlerResult - gdm_session_direct_handle_problem (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -954,18 +964,18 @@ gdm_session_direct_handle_problem (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'problem' signal"); -- _gdm_session_problem (GDM_SESSION (session), text); -+ _gdm_session_problem (GDM_SESSION (session), conversation->service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_session_opened (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -980,10 +990,10 @@ gdm_session_direct_handle_session_opened (GdmSessionDirect *session, - - g_debug ("GdmSessionDirect: Emitting 'session-opened' signal"); - -- _gdm_session_session_opened (GDM_SESSION (session)); -+ _gdm_session_session_opened (GDM_SESSION (session), conversation->service_name); - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - return DBUS_HANDLER_RESULT_HANDLED; -@@ -991,7 +1001,7 @@ gdm_session_direct_handle_session_opened (GdmSessionDirect *session, - - static DBusHandlerResult - gdm_session_direct_handle_open_failed (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -1006,18 +1016,18 @@ gdm_session_direct_handle_open_failed (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'session-open-failed' signal"); -- _gdm_session_session_open_failed (GDM_SESSION (session), text); -+ _gdm_session_session_open_failed (GDM_SESSION (session), conversation->service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_session_started (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -1036,7 +1046,7 @@ gdm_session_direct_handle_session_started (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'session-started' signal with pid '%d'", -@@ -1045,14 +1055,14 @@ gdm_session_direct_handle_session_started (GdmSessionDirect *session, - session->priv->session_pid = pid; - session->priv->is_running = TRUE; - -- _gdm_session_session_started (GDM_SESSION (session), pid); -+ _gdm_session_session_started (GDM_SESSION (session), conversation->service_name, pid); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_start_failed (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -1067,18 +1077,18 @@ gdm_session_direct_handle_start_failed (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'session-start-failed' signal"); -- _gdm_session_session_start_failed (GDM_SESSION (session), text); -+ _gdm_session_session_start_failed (GDM_SESSION (session), conversation->service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } - - static DBusHandlerResult - gdm_session_direct_handle_session_exited (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -1093,7 +1103,7 @@ gdm_session_direct_handle_session_exited (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'session-exited' signal with exit code '%d'", -@@ -1107,7 +1117,7 @@ gdm_session_direct_handle_session_exited (GdmSessionDirect *session, - - static DBusHandlerResult - gdm_session_direct_handle_session_died (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -1122,7 +1132,7 @@ gdm_session_direct_handle_session_died (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - g_debug ("GdmSessionDirect: Emitting 'session-died' signal with signal number '%d'", -@@ -1136,7 +1146,7 @@ gdm_session_direct_handle_session_died (GdmSessionDirect *session, - - static DBusHandlerResult - gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -1151,7 +1161,7 @@ gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - if (strcmp (language_name, -@@ -1169,7 +1179,7 @@ gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session, - - static DBusHandlerResult - gdm_session_direct_handle_saved_session_name_read (GdmSessionDirect *session, -- DBusConnection *connection, -+ GdmSessionConversation *conversation, - DBusMessage *message) - { - DBusMessage *reply; -@@ -1184,7 +1194,7 @@ gdm_session_direct_handle_saved_session_name_read (GdmSessionDirect *session, - } - - reply = dbus_message_new_method_return (message); -- dbus_connection_send (connection, reply, NULL); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); - dbus_message_unref (reply); - - if (! get_session_command_for_name (session_name, NULL)) { -@@ -1212,56 +1222,59 @@ session_worker_message (DBusConnection *connection, - DBusMessage *message, - void *user_data) - { -- GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data); -+ GdmSessionConversation *conversation = user_data; -+ GdmSessionDirect *session; -+ -+ session = conversation->session; - - if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "InfoQuery")) { -- return gdm_session_direct_handle_info_query (session, connection, message); -+ return gdm_session_direct_handle_info_query (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SecretInfoQuery")) { -- return gdm_session_direct_handle_secret_info_query (session, connection, message); -+ return gdm_session_direct_handle_secret_info_query (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Info")) { -- return gdm_session_direct_handle_info (session, connection, message); -+ return gdm_session_direct_handle_info (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Problem")) { -- return gdm_session_direct_handle_problem (session, connection, message); -+ return gdm_session_direct_handle_problem (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "CancelPendingQuery")) { -- return gdm_session_direct_handle_cancel_pending_query (session, connection, message); -+ return gdm_session_direct_handle_cancel_pending_query (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupComplete")) { -- return gdm_session_direct_handle_setup_complete (session, connection, message); -+ return gdm_session_direct_handle_setup_complete (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupFailed")) { -- return gdm_session_direct_handle_setup_failed (session, connection, message); -+ return gdm_session_direct_handle_setup_failed (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "ResetComplete")) { -- return gdm_session_direct_handle_reset_complete (session, connection, message); -+ return gdm_session_direct_handle_reset_complete (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "ResetFailed")) { -- return gdm_session_direct_handle_reset_failed (session, connection, message); -+ return gdm_session_direct_handle_reset_failed (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Authenticated")) { -- return gdm_session_direct_handle_authenticated (session, connection, message); -+ return gdm_session_direct_handle_authenticated (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "AuthenticationFailed")) { -- return gdm_session_direct_handle_authentication_failed (session, connection, message); -+ return gdm_session_direct_handle_authentication_failed (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Authorized")) { -- return gdm_session_direct_handle_authorized (session, connection, message); -+ return gdm_session_direct_handle_authorized (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "AuthorizationFailed")) { -- return gdm_session_direct_handle_authorization_failed (session, connection, message); -+ return gdm_session_direct_handle_authorization_failed (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Accredited")) { -- return gdm_session_direct_handle_accredited (session, connection, message); -+ return gdm_session_direct_handle_accredited (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "AccreditationFailed")) { -- return gdm_session_direct_handle_accreditation_failed (session, connection, message); -+ return gdm_session_direct_handle_accreditation_failed (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "UsernameChanged")) { -- return gdm_session_direct_handle_username_changed (session, connection, message); -+ return gdm_session_direct_handle_username_changed (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionOpened")) { -- return gdm_session_direct_handle_session_opened (session, connection, message); -+ return gdm_session_direct_handle_session_opened (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "OpenFailed")) { -- return gdm_session_direct_handle_open_failed (session, connection, message); -+ return gdm_session_direct_handle_open_failed (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionStarted")) { -- return gdm_session_direct_handle_session_started (session, connection, message); -+ return gdm_session_direct_handle_session_started (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "StartFailed")) { -- return gdm_session_direct_handle_start_failed (session, connection, message); -+ return gdm_session_direct_handle_start_failed (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionExited")) { -- return gdm_session_direct_handle_session_exited (session, connection, message); -+ return gdm_session_direct_handle_session_exited (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SessionDied")) { -- return gdm_session_direct_handle_session_died (session, connection, message); -+ return gdm_session_direct_handle_session_died (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SavedLanguageNameRead")) { -- return gdm_session_direct_handle_saved_language_name_read (session, connection, message); -+ return gdm_session_direct_handle_saved_language_name_read (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SavedSessionNameRead")) { -- return gdm_session_direct_handle_saved_session_name_read (session, connection, message); -+ return gdm_session_direct_handle_saved_session_name_read (session, conversation, message); - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -@@ -1495,6 +1508,27 @@ session_unregister_handler (DBusConnection *connection, - g_debug ("session_unregister_handler"); - } - -+static GdmSessionConversation * -+find_conversation_by_pid (GdmSessionDirect *session, -+ GPid pid) -+{ -+ GHashTableIter iter; -+ gpointer key, value; -+ -+ g_hash_table_iter_init (&iter, session->priv->conversations); -+ while (g_hash_table_iter_next (&iter, &key, &value)) { -+ GdmSessionConversation *conversation; -+ -+ conversation = (GdmSessionConversation *) value; -+ -+ if (conversation->worker_pid == pid) { -+ return conversation; -+ } -+ } -+ -+ return NULL; -+} -+ - static dbus_bool_t - allow_user_function (DBusConnection *connection, - unsigned long uid, -@@ -1509,44 +1543,110 @@ allow_user_function (DBusConnection *connection, - return FALSE; - } - --static void --handle_connection (DBusServer *server, -- DBusConnection *new_connection, -- void *user_data) -+static gboolean -+register_worker (GdmSessionDirect *session, -+ DBusConnection *connection) - { -- GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data); - GdmSessionConversation *conversation; -+ DBusObjectPathVTable vtable = { &session_unregister_handler, -+ &session_message_handler, -+ NULL, NULL, NULL, NULL }; -+ GList *connection_node; -+ gulong pid; - -- g_debug ("GdmSessionDirect: Handing new connection"); -+ g_debug ("GdmSessionDirect: Authenticating new connection"); - -- conversation = session->priv->conversation; -- if (conversation->worker_connection == NULL) { -- DBusObjectPathVTable vtable = { &session_unregister_handler, -- &session_message_handler, -- NULL, NULL, NULL, NULL -- }; -+ connection_node = g_list_find (session->priv->pending_connections, connection); - -- conversation->worker_connection = new_connection; -- dbus_connection_ref (new_connection); -- dbus_connection_setup_with_g_main (new_connection, NULL); -+ if (connection_node == NULL) { -+ g_debug ("GdmSessionDirect: Ignoring connection that we aren't tracking"); -+ return FALSE; -+ } - -- g_debug ("GdmSessionDirect: worker connection is %p", new_connection); -- dbus_connection_set_exit_on_disconnect (new_connection, FALSE); -+ session->priv->pending_connections = -+ g_list_delete_link (session->priv->pending_connections, -+ connection_node); - -- dbus_connection_set_unix_user_function (new_connection, -- allow_user_function, -- session, -- NULL); -+ if (!dbus_connection_get_unix_process_id (connection, &pid)) { -+ g_warning ("GdmSessionDirect: Unable to read pid on new worker connection"); -+ dbus_connection_unref (connection); -+ return FALSE; -+ } - -- dbus_connection_register_object_path (new_connection, -- GDM_SESSION_DBUS_PATH, -- &vtable, -- session); -+ conversation = find_conversation_by_pid (session, (GPid) pid); - -- g_debug ("GdmSessionDirect: Emitting conversation-started signal"); -- _gdm_session_conversation_started (GDM_SESSION (session), -- conversation->service_name); -+ if (conversation == NULL) { -+ g_warning ("GdmSessionDirect: New worker connection is from unknown source"); -+ dbus_connection_unref (connection); -+ return FALSE; - } -+ -+ conversation->worker_connection = connection; -+ -+ g_debug ("GdmSessionDirect: worker connection is %p", connection); -+ -+ dbus_connection_register_object_path (connection, -+ GDM_SESSION_DBUS_PATH, -+ &vtable, -+ conversation); -+ -+ g_debug ("GdmSessionDirect: Emitting conversation-started signal"); -+ _gdm_session_conversation_started (GDM_SESSION (session), -+ conversation->service_name); -+ -+ g_debug ("GdmSessionDirect: Conversation started"); -+ -+ return TRUE; -+} -+ -+static DBusHandlerResult -+on_message (DBusConnection *connection, -+ DBusMessage *message, -+ void *user_data) -+{ -+ GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data); -+ -+ g_debug ("GdmSessionDirect: got message"); -+ -+ if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Hello")) { -+ DBusMessage *reply; -+ -+ if (register_worker (session, connection)) { -+ reply = dbus_message_new_method_return (message); -+ } else { -+ reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, ""); -+ } -+ -+ dbus_connection_send (connection, reply, NULL); -+ return DBUS_HANDLER_RESULT_HANDLED; -+ } -+ -+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -+} -+ -+static void -+handle_connection (DBusServer *server, -+ DBusConnection *new_connection, -+ void *user_data) -+{ -+ GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data); -+ g_debug ("GdmSessionDirect: Handing new connection"); -+ -+ /* add to the list of pending connections. We won't be able to -+ * associate it with a specific worker conversation until we have -+ * authenticated the connection (from the Hello handler). -+ */ -+ session->priv->pending_connections = -+ g_list_prepend (session->priv->pending_connections, -+ dbus_connection_ref (new_connection)); -+ dbus_connection_setup_with_g_main (new_connection, NULL); -+ dbus_connection_set_exit_on_disconnect (new_connection, FALSE); -+ -+ dbus_connection_set_unix_user_function (new_connection, -+ allow_user_function, -+ session, -+ NULL); -+ dbus_connection_add_filter (new_connection, on_message, session, NULL); - } - - static gboolean -@@ -1592,6 +1692,17 @@ setup_server (GdmSessionDirect *session) - } - - static void -+free_conversation (GdmSessionConversation *conversation) -+{ -+ if (conversation->job != NULL) { -+ g_warning ("Freeing conversation '%s' with active job", conversation->service_name); -+ } -+ -+ g_free (conversation->service_name); -+ g_free (conversation); -+} -+ -+static void - gdm_session_direct_init (GdmSessionDirect *session) - { - session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, -@@ -1615,6 +1726,11 @@ gdm_session_direct_init (GdmSessionDirect *session) - G_CALLBACK (on_session_exited), - NULL); - -+ session->priv->conversations = g_hash_table_new_full (g_str_hash, -+ g_str_equal, -+ (GDestroyNotify) g_free, -+ (GDestroyNotify) -+ free_conversation); - session->priv->environment = g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify) g_free, -@@ -1638,9 +1754,15 @@ worker_exited (GdmSessionWorkerJob *job, - { - g_debug ("GdmSessionDirect: Worker job exited: %d", code); - -+ g_object_ref (conversation->job); - if (conversation->session->priv->is_running) { - _gdm_session_session_exited (GDM_SESSION (conversation->session), code); - } -+ -+ g_debug ("GdmSessionDirect: Emitting conversation-stopped signal"); -+ _gdm_session_conversation_stopped (GDM_SESSION (conversation->session), -+ conversation->service_name); -+ g_object_unref (conversation->job); - } - - static void -@@ -1650,9 +1772,15 @@ worker_died (GdmSessionWorkerJob *job, - { - g_debug ("GdmSessionDirect: Worker job died: %d", signum); - -+ g_object_ref (conversation->job); - if (conversation->session->priv->is_running) { - _gdm_session_session_died (GDM_SESSION (conversation->session), signum); - } -+ -+ g_debug ("GdmSessionDirect: Emitting conversation-stopped signal"); -+ _gdm_session_conversation_stopped (GDM_SESSION (conversation->session), -+ conversation->service_name); -+ g_object_unref (conversation->job); - } - - static GdmSessionConversation * -@@ -1714,17 +1842,21 @@ stop_conversation (GdmSessionConversation *conversation) - G_CALLBACK (worker_died), - conversation); - -- cancel_pending_query (conversation); -- - if (conversation->worker_connection != NULL) { -+ dbus_connection_remove_filter (conversation->worker_connection, on_message, session); -+ - dbus_connection_close (conversation->worker_connection); - conversation->worker_connection = NULL; - } - - gdm_session_worker_job_stop (conversation->job); -+ - g_object_unref (conversation->job); -- g_free (conversation->service_name); -- g_free (conversation); -+ conversation->job = NULL; -+ -+ g_debug ("GdmSessionDirect: Emitting conversation-stopped signal"); -+ _gdm_session_conversation_stopped (GDM_SESSION (session), -+ conversation->service_name); - } - - static void -@@ -1732,12 +1864,35 @@ gdm_session_direct_start_conversation (GdmSession *session, - const char *service_name) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -+ GdmSessionConversation *conversation; -+ -+ g_return_if_fail (session != NULL); -+ -+ g_debug ("GdmSessionDirect: starting conversation %s", service_name); -+ -+ conversation = start_conversation (impl, service_name); -+ -+ g_hash_table_insert (impl->priv->conversations, -+ g_strdup (service_name), conversation); -+} -+ -+static void -+gdm_session_direct_stop_conversation (GdmSession *session, -+ const char *service_name) -+{ -+ GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -+ GdmSessionConversation *conversation; - - g_return_if_fail (session != NULL); - -- g_debug ("GdmSessionDirect: starting conversation"); -+ g_debug ("GdmSessionDirect: stopping conversation %s", service_name); -+ -+ conversation = find_conversation_by_name (impl, service_name); - -- impl->priv->conversation = start_conversation (impl, service_name); -+ if (conversation != NULL) { -+ stop_conversation (conversation); -+ g_hash_table_remove (impl->priv->conversations, service_name); -+ } - } - - static void -@@ -1788,8 +1943,8 @@ send_setup (GdmSessionDirect *session, - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_hostname); - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file); - -- conversation = session->priv->conversation; -- if (! send_dbus_message (conversation, message)) { -+ conversation = find_conversation_by_name (session, service_name); -+ if (conversation != NULL && ! send_dbus_message (conversation, message)) { - g_debug ("GdmSessionDirect: Could not send %s signal", "Setup"); - } - -@@ -1851,8 +2006,8 @@ send_setup_for_user (GdmSessionDirect *session, - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file); - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &selected_user); - -- conversation = session->priv->conversation; -- if (! send_dbus_message (conversation, message)) { -+ conversation = find_conversation_by_name (session, service_name); -+ if (conversation != NULL && ! send_dbus_message (conversation, message)) { - g_debug ("GdmSessionDirect: Could not send %s signal", "SetupForUser"); - } - -@@ -1866,8 +2021,6 @@ gdm_session_direct_setup (GdmSession *session, - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - - g_return_if_fail (session != NULL); -- g_return_if_fail (impl->priv->conversation != NULL); -- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection)); - - send_setup (impl, service_name); - gdm_session_direct_defaults_changed (impl); -@@ -1881,8 +2034,6 @@ gdm_session_direct_setup_for_user (GdmSession *session, - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - - g_return_if_fail (session != NULL); -- g_return_if_fail (impl->priv->conversation != NULL); -- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection)); - g_return_if_fail (username != NULL); - - gdm_session_direct_select_user (session, username); -@@ -1892,45 +2043,50 @@ gdm_session_direct_setup_for_user (GdmSession *session, - } - - static void --gdm_session_direct_authenticate (GdmSession *session) -+gdm_session_direct_authenticate (GdmSession *session, -+ const char *service_name) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - GdmSessionConversation *conversation; - - g_return_if_fail (session != NULL); -- g_return_if_fail (impl->priv->conversation != NULL); -- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection)); - -- conversation = impl->priv->conversation; -- send_dbus_void_signal (conversation, "Authenticate"); -+ conversation = find_conversation_by_name (impl, service_name); -+ if (conversation != NULL) { -+ send_dbus_void_signal (conversation, "Authenticate"); -+ } - } - - static void --gdm_session_direct_authorize (GdmSession *session) -+gdm_session_direct_authorize (GdmSession *session, -+ const char *service_name) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - GdmSessionConversation *conversation; - - g_return_if_fail (session != NULL); -- g_return_if_fail (impl->priv->conversation != NULL); -- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection)); - -- conversation = impl->priv->conversation; -- send_dbus_void_signal (conversation, "Authorize"); -+ conversation = find_conversation_by_name (impl, service_name); -+ if (conversation != NULL) { -+ send_dbus_void_signal (conversation, "Authorize"); -+ } - } - - static void - gdm_session_direct_accredit (GdmSession *session, -+ const char *service_name, - int cred_flag) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - GdmSessionConversation *conversation; - - g_return_if_fail (session != NULL); -- g_return_if_fail (impl->priv->conversation != NULL); -- g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection)); - -- conversation = impl->priv->conversation; -+ conversation = find_conversation_by_name (impl, service_name); -+ if (conversation == NULL) { -+ return; -+ } -+ - switch (cred_flag) { - case GDM_SESSION_CRED_ESTABLISH: - send_dbus_void_signal (conversation, "EstablishCredentials"); -@@ -1944,13 +2100,12 @@ gdm_session_direct_accredit (GdmSession *session, - } - - static void --send_environment_variable (const char *key, -- const char *value, -- GdmSessionDirect *session) -+send_environment_variable (const char *key, -+ const char *value, -+ GdmSessionConversation *conversation) - { - DBusMessage *message; - DBusMessageIter iter; -- GdmSessionConversation *conversation; - - message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH, - GDM_SESSION_DBUS_INTERFACE, -@@ -1960,7 +2115,6 @@ send_environment_variable (const char *key, - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key); - dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value); - -- conversation = session->priv->conversation; - if (! send_dbus_message (conversation, message)) { - g_debug ("GdmSessionDirect: Could not send %s signal", "SetEnvironmentVariable"); - } -@@ -1969,12 +2123,13 @@ send_environment_variable (const char *key, - } - - static void --send_environment (GdmSessionDirect *session) -+send_environment (GdmSessionDirect *session, -+ GdmSessionConversation *conversation) - { - - g_hash_table_foreach (session->priv->environment, - (GHFunc) send_environment_variable, -- session); -+ conversation); - } - - static const char * -@@ -2079,17 +2234,63 @@ setup_session_environment (GdmSessionDirect *session) - } - - static void --gdm_session_direct_open_session (GdmSession *session) -+gdm_session_direct_open_session (GdmSession *session, -+ const char *service_name) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -+ GdmSessionConversation *conversation; - - g_return_if_fail (session != NULL); - -- send_dbus_void_signal (impl, "OpenSession"); -+ conversation = find_conversation_by_name (impl, service_name); -+ -+ send_dbus_string_signal (conversation, "OpenSession", service_name); - } - - static void --gdm_session_direct_start_session (GdmSession *session) -+stop_all_other_conversations (GdmSessionDirect *session, -+ GdmSessionConversation *conversation_to_keep) -+{ -+ GHashTableIter iter; -+ gpointer key, value; -+ -+ if (session->priv->conversations == NULL) { -+ return; -+ } -+ -+ if (conversation_to_keep == NULL) { -+ g_debug ("GdmSessionDirect: Stopping all conversations"); -+ } else { -+ g_debug ("GdmSessionDirect: Stopping all conversations " -+ "except for %s", conversation_to_keep->service_name); -+ } -+ -+ g_hash_table_iter_init (&iter, session->priv->conversations); -+ while (g_hash_table_iter_next (&iter, &key, &value)) { -+ GdmSessionConversation *conversation; -+ -+ conversation = (GdmSessionConversation *) value; -+ -+ if (conversation == conversation_to_keep) { -+ g_hash_table_iter_steal (&iter); -+ g_free (key); -+ } else { -+ stop_conversation (conversation); -+ } -+ } -+ -+ g_hash_table_remove_all (session->priv->conversations); -+ -+ if (conversation_to_keep != NULL) { -+ g_hash_table_insert (session->priv->conversations, -+ g_strdup (conversation_to_keep->service_name), -+ conversation_to_keep); -+ } -+} -+ -+static void -+gdm_session_direct_start_session (GdmSession *session, -+ const char *service_name) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); - GdmSessionConversation *conversation; -@@ -2099,6 +2300,16 @@ gdm_session_direct_start_session (GdmSession *session) - g_return_if_fail (session != NULL); - g_return_if_fail (impl->priv->is_running == FALSE); - -+ conversation = find_conversation_by_name (impl, service_name); -+ -+ if (conversation == NULL) { -+ g_warning ("GdmSessionDirect: Tried to start session of " -+ "nonexistent conversation %s", service_name); -+ return; -+ } -+ -+ stop_all_other_conversations (impl, conversation); -+ - command = get_session_command (impl); - - if (gdm_session_direct_bypasses_xsession (impl)) { -@@ -2110,14 +2321,19 @@ gdm_session_direct_start_session (GdmSession *session) - g_free (command); - - setup_session_environment (impl); -- send_environment (impl); -+ send_environment (impl, conversation); - -- conversation = impl->priv->conversation; - send_dbus_string_signal (conversation, "StartProgram", program); - g_free (program); - } - - static void -+stop_all_conversations (GdmSessionDirect *session) -+{ -+ stop_all_other_conversations (session, NULL); -+} -+ -+static void - gdm_session_direct_close (GdmSession *session) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -@@ -2134,6 +2350,13 @@ gdm_session_direct_close (GdmSession *session) - impl->priv->display_device); - } - -+ stop_all_conversations (impl); -+ -+ g_list_foreach (impl->priv->pending_connections, -+ (GFunc) dbus_connection_unref, NULL); -+ g_list_free (impl->priv->pending_connections); -+ impl->priv->pending_connections = NULL; -+ - g_free (impl->priv->selected_user); - impl->priv->selected_user = NULL; - -@@ -2160,6 +2383,7 @@ gdm_session_direct_close (GdmSession *session) - - static void - gdm_session_direct_answer_query (GdmSession *session, -+ const char *service_name, - const char *text) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -@@ -2167,7 +2391,7 @@ gdm_session_direct_answer_query (GdmSession *session, - - g_return_if_fail (session != NULL); - -- conversation = impl->priv->conversation; -+ conversation = find_conversation_by_name (impl, service_name); - - answer_pending_query (conversation, text); - } -@@ -2175,11 +2399,9 @@ gdm_session_direct_answer_query (GdmSession *session, - static void - gdm_session_direct_cancel (GdmSession *session) - { -- GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -- - g_return_if_fail (session != NULL); - -- cancel_pending_query (impl->priv->conversation); -+ stop_all_conversations (GDM_SESSION_DIRECT (session)); - } - - char * -@@ -2251,7 +2473,8 @@ gdm_session_direct_select_session (GdmSession *session, - const char *text) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -- GdmSessionConversation *conversation; -+ GHashTableIter iter; -+ gpointer key, value; - - g_free (impl->priv->selected_session); - -@@ -2261,9 +2484,15 @@ gdm_session_direct_select_session (GdmSession *session, - impl->priv->selected_session = g_strdup (text); - } - -- conversation = impl->priv->conversation; -- send_dbus_string_signal (conversation, "SetSessionName", -- get_session_name (impl)); -+ g_hash_table_iter_init (&iter, impl->priv->conversations); -+ while (g_hash_table_iter_next (&iter, &key, &value)) { -+ GdmSessionConversation *conversation; -+ -+ conversation = (GdmSessionConversation *) value; -+ -+ send_dbus_string_signal (conversation, "SetSessionName", -+ get_session_name (impl)); -+ } - } - - static void -@@ -2271,7 +2500,8 @@ gdm_session_direct_select_language (GdmSession *session, - const char *text) - { - GdmSessionDirect *impl = GDM_SESSION_DIRECT (session); -- GdmSessionConversation *conversation; -+ GHashTableIter iter; -+ gpointer key, value; - - g_free (impl->priv->selected_language); - -@@ -2281,9 +2511,15 @@ gdm_session_direct_select_language (GdmSession *session, - impl->priv->selected_language = g_strdup (text); - } - -- conversation = impl->priv->conversation; -- send_dbus_string_signal (conversation, "SetLanguageName", -- get_language_name (impl)); -+ g_hash_table_iter_init (&iter, impl->priv->conversations); -+ while (g_hash_table_iter_next (&iter, &key, &value)) { -+ GdmSessionConversation *conversation; -+ -+ conversation = (GdmSessionConversation *) value; -+ -+ send_dbus_string_signal (conversation, "SetLanguageName", -+ get_language_name (impl)); -+ } - } - - static void -@@ -2543,6 +2779,7 @@ static void - gdm_session_iface_init (GdmSessionIface *iface) - { - iface->start_conversation = gdm_session_direct_start_conversation; -+ iface->stop_conversation = gdm_session_direct_stop_conversation; - iface->setup = gdm_session_direct_setup; - iface->setup_for_user = gdm_session_direct_setup_for_user; - iface->authenticate = gdm_session_direct_authenticate; -diff --git a/daemon/gdm-session-private.h b/daemon/gdm-session-private.h -index 34adff5..e15b7dd 100644 ---- a/daemon/gdm-session-private.h -+++ b/daemon/gdm-session-private.h -@@ -29,27 +29,41 @@ G_BEGIN_DECLS - /* state changes */ - void _gdm_session_conversation_started (GdmSession *session, - const char *service_name); --void _gdm_session_setup_complete (GdmSession *session); -+void _gdm_session_conversation_stopped (GdmSession *session, -+ const char *service_name); -+void _gdm_session_setup_complete (GdmSession *session, -+ const char *service_name); - void _gdm_session_setup_failed (GdmSession *session, -+ const char *service_name, - const char *message); - void _gdm_session_reset_complete (GdmSession *session); - void _gdm_session_reset_failed (GdmSession *session, - const char *message); --void _gdm_session_authenticated (GdmSession *session); -+void _gdm_session_authenticated (GdmSession *session, -+ const char *service_name); - void _gdm_session_authentication_failed (GdmSession *session, -+ const char *service_name, - const char *text); --void _gdm_session_authorized (GdmSession *session); -+void _gdm_session_authorized (GdmSession *session, -+ const char *service_name); - void _gdm_session_authorization_failed (GdmSession *session, -+ const char *service_name, - const char *text); --void _gdm_session_accredited (GdmSession *session); -+void _gdm_session_accredited (GdmSession *session, -+ const char *service_name); - void _gdm_session_accreditation_failed (GdmSession *session, -+ const char *service_name, - const char *text); --void _gdm_session_session_opened (GdmSession *session); -+void _gdm_session_session_opened (GdmSession *session, -+ const char *service_name); - void _gdm_session_session_open_failed (GdmSession *session, -+ const char *service_name, - const char *message); - void _gdm_session_session_started (GdmSession *session, -+ const char *service_name, - int pid); - void _gdm_session_session_start_failed (GdmSession *session, -+ const char *service_name, - const char *message); - void _gdm_session_session_exited (GdmSession *session, - int exit_code); -@@ -68,12 +82,16 @@ void _gdm_session_selected_user_changed (GdmSession *sessio - - /* call and response stuff */ - void _gdm_session_info_query (GdmSession *session, -+ const char *service_name, - const char *text); - void _gdm_session_secret_info_query (GdmSession *session, -+ const char *service_name, - const char *text); - void _gdm_session_info (GdmSession *session, -+ const char *service_name, - const char *text); - void _gdm_session_problem (GdmSession *session, -+ const char *service_name, - const char *text); - - G_END_DECLS -diff --git a/daemon/gdm-session-relay.c b/daemon/gdm-session-relay.c -index d559c71..50f1140 100644 ---- a/daemon/gdm-session-relay.c -+++ b/daemon/gdm-session-relay.c -@@ -212,31 +212,34 @@ gdm_session_relay_setup_for_user (GdmSession *session, - } - - static void --gdm_session_relay_authenticate (GdmSession *session) -+gdm_session_relay_authenticate (GdmSession *session, -+ const char *service_name) - { - GdmSessionRelay *impl = GDM_SESSION_RELAY (session); -- send_dbus_void_signal (impl, "Authenticate"); -+ send_dbus_string_signal (impl, "Authenticate", service_name); - } - - static void --gdm_session_relay_authorize (GdmSession *session) -+gdm_session_relay_authorize (GdmSession *session, -+ const char *service_name) - { - GdmSessionRelay *impl = GDM_SESSION_RELAY (session); -- send_dbus_void_signal (impl, "Authorize"); -+ send_dbus_string_signal (impl, "Authorize", service_name); - } - - static void - gdm_session_relay_accredit (GdmSession *session, -+ const char *service_name, - int cred_flag) - { - GdmSessionRelay *impl = GDM_SESSION_RELAY (session); - - switch (cred_flag) { - case GDM_SESSION_CRED_ESTABLISH: -- send_dbus_void_signal (impl, "EstablishCredentials"); -+ send_dbus_string_signal (impl, "EstablishCredentials", service_name); - break; - case GDM_SESSION_CRED_REFRESH: -- send_dbus_void_signal (impl, "RefreshCredentials"); -+ send_dbus_string_signal (impl, "RefreshCredentials", service_name); - break; - default: - g_assert_not_reached (); -@@ -244,18 +247,20 @@ gdm_session_relay_accredit (GdmSession *session, - } - - static void --gdm_session_relay_open_session (GdmSession *session) -+gdm_session_relay_open_session (GdmSession *session, -+ const char *service_name) - { - GdmSessionRelay *impl = GDM_SESSION_RELAY (session); -- send_dbus_void_signal (impl, "OpenSession"); -+ send_dbus_string_signal (impl, "OpenSession", service_name); - } - - static void - gdm_session_relay_answer_query (GdmSession *session, -+ const char *service_name, - const char *text) - { - GdmSessionRelay *impl = GDM_SESSION_RELAY (session); -- send_dbus_string_signal (impl, "AnswerQuery", text); -+ send_dbus_string_string_signal (impl, "AnswerQuery", service_name, text); - } - - static void -@@ -291,11 +296,12 @@ gdm_session_relay_cancel (GdmSession *session) - } - - static void --gdm_session_relay_start_session (GdmSession *session) -+gdm_session_relay_start_session (GdmSession *session, -+ const char *service_name) - { - GdmSessionRelay *impl = GDM_SESSION_RELAY (session); - -- send_dbus_void_signal (impl, "StartSession"); -+ send_dbus_string_signal (impl, "StartSession", service_name); - } - - /* Note: Use abstract sockets like dbus does by default on Linux. Abstract -@@ -333,10 +339,12 @@ handle_info_query (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -- const char *text; -+ char *service_name; -+ char *text; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) { - g_warning ("ERROR: %s", error.message); -@@ -348,7 +356,7 @@ handle_info_query (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_info_query (GDM_SESSION (session_relay), text); -+ _gdm_session_info_query (GDM_SESSION (session_relay), service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -360,12 +368,14 @@ handle_secret_info_query (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -- const char *text; -+ char *service_name; -+ char *text; - - text = NULL; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) { - g_warning ("ERROR: %s", error.message); -@@ -377,7 +387,7 @@ handle_secret_info_query (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_secret_info_query (GDM_SESSION (session_relay), text); -+ _gdm_session_secret_info_query (GDM_SESSION (session_relay), service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -389,12 +399,14 @@ handle_info (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -- const char *text; -+ char *service_name; -+ char *text; - - text = NULL; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) { - g_warning ("ERROR: %s", error.message); -@@ -406,7 +418,7 @@ handle_info (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_info (GDM_SESSION (session_relay), text); -+ _gdm_session_info (GDM_SESSION (session_relay), service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -418,12 +430,14 @@ handle_problem (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -- const char *text; -+ char *service_name; -+ char *text; - - text = NULL; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) { - g_warning ("ERROR: %s", error.message); -@@ -435,7 +449,7 @@ handle_problem (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_problem (GDM_SESSION (session_relay), text); -+ _gdm_session_problem (GDM_SESSION (session_relay), service_name, text); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -447,8 +461,15 @@ handle_setup_complete (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - - dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } -+ dbus_error_free (&error); - - g_debug ("GdmSessionRelay: SetupComplete"); - -@@ -456,7 +477,7 @@ handle_setup_complete (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_setup_complete (GDM_SESSION (session_relay)); -+ _gdm_session_setup_complete (GDM_SESSION (session_relay), service_name); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -468,8 +489,15 @@ handle_setup_failed (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - - dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } -+ dbus_error_free (&error); - - g_debug ("GdmSessionRelay: SetupFailed"); - -@@ -477,7 +505,7 @@ handle_setup_failed (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_setup_failed (GDM_SESSION (session_relay), NULL); -+ _gdm_session_setup_failed (GDM_SESSION (session_relay), service_name, NULL); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -490,8 +518,15 @@ handle_authenticated (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - - dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } -+ dbus_error_free (&error); - - g_debug ("GdmSessionRelay: Authenticated"); - -@@ -499,7 +534,7 @@ handle_authenticated (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_authenticated (GDM_SESSION (session_relay)); -+ _gdm_session_authenticated (GDM_SESSION (session_relay), service_name); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -511,8 +546,15 @@ handle_authentication_failed (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - - dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } -+ dbus_error_free (&error); - - g_debug ("GdmSessionRelay: AuthenticationFailed"); - -@@ -520,7 +562,7 @@ handle_authentication_failed (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_authentication_failed (GDM_SESSION (session_relay), NULL); -+ _gdm_session_authentication_failed (GDM_SESSION (session_relay), service_name, NULL); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -532,8 +574,15 @@ handle_authorized (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - - dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } -+ dbus_error_free (&error); - - g_debug ("GdmSessionRelay: Authorized"); - -@@ -541,7 +590,7 @@ handle_authorized (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_authorized (GDM_SESSION (session_relay)); -+ _gdm_session_authorized (GDM_SESSION (session_relay), service_name); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -553,8 +602,15 @@ handle_authorization_failed (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - - dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } -+ dbus_error_free (&error); - - g_debug ("GdmSessionRelay: AuthorizationFailed"); - -@@ -562,7 +618,7 @@ handle_authorization_failed (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_authorization_failed (GDM_SESSION (session_relay), NULL); -+ _gdm_session_authorization_failed (GDM_SESSION (session_relay), service_name, NULL); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -574,8 +630,15 @@ handle_accredited (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - - dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } -+ dbus_error_free (&error); - - g_debug ("GdmSessionRelay: Accredited"); - -@@ -583,7 +646,7 @@ handle_accredited (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_accredited (GDM_SESSION (session_relay)); -+ _gdm_session_accredited (GDM_SESSION (session_relay), service_name); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -595,8 +658,15 @@ handle_accreditation_failed (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - - dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } -+ dbus_error_free (&error); - - g_debug ("GdmSessionRelay: AccreditationFailed"); - -@@ -604,7 +674,7 @@ handle_accreditation_failed (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_accreditation_failed (GDM_SESSION (session_relay), NULL); -+ _gdm_session_accreditation_failed (GDM_SESSION (session_relay), service_name, NULL); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -615,9 +685,11 @@ handle_session_opened (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, - DBUS_TYPE_INVALID)) { - g_warning ("ERROR: %s", error.message); - } -@@ -629,7 +701,7 @@ handle_session_opened (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_session_opened (GDM_SESSION (session_relay)); -+ _gdm_session_session_opened (GDM_SESSION (session_relay), service_name); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -641,9 +713,11 @@ handle_session_open_failed (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, - DBUS_TYPE_INVALID)) { - g_warning ("ERROR: %s", error.message); - } -@@ -655,7 +729,7 @@ handle_session_open_failed (GdmSessionRelay *session_relay, - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - -- _gdm_session_session_open_failed (GDM_SESSION (session_relay), NULL); -+ _gdm_session_session_open_failed (GDM_SESSION (session_relay), service_name, NULL); - - return DBUS_HANDLER_RESULT_HANDLED; - } -@@ -667,6 +741,7 @@ handle_session_started (GdmSessionRelay *session_relay, - { - DBusMessage *reply; - DBusError error; -+ char *service_name; - int pid; - - dbus_error_init (&error); -@@ -674,6 +749,7 @@ handle_session_started (GdmSessionRelay *session_relay, - pid = 0; - if (! dbus_message_get_args (message, - &error, -+ DBUS_TYPE_STRING, &service_name, - DBUS_TYPE_INT32, &pid, - DBUS_TYPE_INVALID)) { - g_warning ("ERROR: %s", error.message); -@@ -686,6 +762,7 @@ handle_session_started (GdmSessionRelay *session_relay, - dbus_message_unref (reply); - - _gdm_session_session_started (GDM_SESSION (session_relay), -+ service_name, - pid); - - return DBUS_HANDLER_RESULT_HANDLED; -diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c -index 15ec0e9..19474d8 100644 ---- a/daemon/gdm-session-worker.c -+++ b/daemon/gdm-session-worker.c -@@ -2593,6 +2593,28 @@ worker_dbus_filter_function (DBusConnection *connection, - return DBUS_HANDLER_RESULT_HANDLED; - } - -+static void -+send_hello (GdmSessionWorker *worker) -+{ -+ DBusMessage *message, *reply; -+ DBusError error; -+ -+ message = dbus_message_new_method_call (NULL, -+ GDM_SESSION_DBUS_PATH, -+ GDM_SESSION_DBUS_INTERFACE, -+ "Hello"); -+ -+ dbus_error_init (&error); -+ reply = dbus_connection_send_with_reply_and_block (worker->priv->connection, -+ message, -1, &error); -+ dbus_message_unref (message); -+ dbus_error_free (&error); -+ -+ if (reply != NULL) { -+ dbus_message_unref (reply); -+ } -+} -+ - static GObject * - gdm_session_worker_constructor (GType type, - guint n_construct_properties, -@@ -2619,6 +2641,11 @@ gdm_session_worker_constructor (GType type, - exit (1); - } - -+ /* Send an initial Hello message so that the session can associate -+ * the conversation we manage with our pid. -+ */ -+ send_hello (worker); -+ - dbus_connection_setup_with_g_main (worker->priv->connection, NULL); - dbus_connection_set_exit_on_disconnect (worker->priv->connection, TRUE); - -diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c -index 6a87ddd..4c7f6bc 100644 ---- a/daemon/gdm-session.c -+++ b/daemon/gdm-session.c -@@ -24,11 +24,13 @@ - #include - #include - -+#include "gdm-marshal.h" - #include "gdm-session.h" - #include "gdm-session-private.h" - - enum { - CONVERSATION_STARTED = 0, -+ CONVERSATION_STOPPED, - SETUP_COMPLETE, - SETUP_FAILED, - RESET_COMPLETE, -@@ -88,6 +90,15 @@ gdm_session_start_conversation (GdmSession *session, - } - - void -+gdm_session_stop_conversation (GdmSession *session, -+ const char *service_name) -+{ -+ g_return_if_fail (GDM_IS_SESSION (session)); -+ -+ GDM_SESSION_GET_IFACE (session)->stop_conversation (session, service_name); -+} -+ -+void - gdm_session_close (GdmSession *session) - { - g_return_if_fail (GDM_IS_SESSION (session)); -@@ -115,37 +126,41 @@ gdm_session_setup_for_user (GdmSession *session, - } - - void --gdm_session_authenticate (GdmSession *session) -+gdm_session_authenticate (GdmSession *session, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_SESSION (session)); - -- GDM_SESSION_GET_IFACE (session)->authenticate (session); -+ GDM_SESSION_GET_IFACE (session)->authenticate (session, service_name); - } - - void --gdm_session_authorize (GdmSession *session) -+gdm_session_authorize (GdmSession *session, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_SESSION (session)); - -- GDM_SESSION_GET_IFACE (session)->authorize (session); -+ GDM_SESSION_GET_IFACE (session)->authorize (session, service_name); - } - - void - gdm_session_accredit (GdmSession *session, -+ const char *service_name, - int flag) - { - g_return_if_fail (GDM_IS_SESSION (session)); - -- GDM_SESSION_GET_IFACE (session)->accredit (session, flag); -+ GDM_SESSION_GET_IFACE (session)->accredit (session, service_name, flag); - } - - void - gdm_session_answer_query (GdmSession *session, -+ const char *service_name, - const char *text) - { - g_return_if_fail (GDM_IS_SESSION (session)); - -- GDM_SESSION_GET_IFACE (session)->answer_query (session, text); -+ GDM_SESSION_GET_IFACE (session)->answer_query (session, service_name, text); - } - - void -@@ -184,19 +199,21 @@ gdm_session_cancel (GdmSession *session) - } - - void --gdm_session_open_session (GdmSession *session) -+gdm_session_open_session (GdmSession *session, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_SESSION (session)); - -- GDM_SESSION_GET_IFACE (session)->open_session (session); -+ GDM_SESSION_GET_IFACE (session)->open_session (session, service_name); - } - - void --gdm_session_start_session (GdmSession *session) -+gdm_session_start_session (GdmSession *session, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_SESSION (session)); - -- GDM_SESSION_GET_IFACE (session)->start_session (session); -+ GDM_SESSION_GET_IFACE (session)->start_session (session, service_name); - } - - static void -@@ -213,7 +230,17 @@ gdm_session_class_init (gpointer g_iface) - NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, G_TYPE_STRING); -+ signals [CONVERSATION_STOPPED] = -+ g_signal_new ("conversation-stopped", -+ iface_type, -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmSessionIface, conversation_stopped), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__STRING, -+ G_TYPE_NONE, -+ 1, G_TYPE_STRING); - signals [SETUP_COMPLETE] = - g_signal_new ("setup-complete", - iface_type, -@@ -221,9 +248,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, setup_complete), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, -+ G_TYPE_STRING); - signals [SETUP_FAILED] = - g_signal_new ("setup-failed", - iface_type, -@@ -231,10 +259,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, setup_failed), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - signals [RESET_COMPLETE] = - g_signal_new ("reset-complete", - iface_type, -@@ -263,9 +291,9 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, authenticated), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, G_TYPE_STRING); - signals [AUTHENTICATION_FAILED] = - g_signal_new ("authentication-failed", - iface_type, -@@ -273,10 +301,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, authentication_failed), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - signals [AUTHORIZED] = - g_signal_new ("authorized", - iface_type, -@@ -284,9 +312,9 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, authorized), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, G_TYPE_STRING); - signals [AUTHORIZATION_FAILED] = - g_signal_new ("authorization-failed", - iface_type, -@@ -294,10 +322,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, authorization_failed), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - signals [ACCREDITED] = - g_signal_new ("accredited", - iface_type, -@@ -305,9 +333,9 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, accredited), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, G_TYPE_STRING); - signals [ACCREDITATION_FAILED] = - g_signal_new ("accreditation-failed", - iface_type, -@@ -315,10 +343,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, accreditation_failed), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - - signals [INFO_QUERY] = - g_signal_new ("info-query", -@@ -327,10 +355,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, info_query), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - signals [SECRET_INFO_QUERY] = - g_signal_new ("secret-info-query", - iface_type, -@@ -338,10 +366,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, secret_info_query), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - signals [INFO] = - g_signal_new ("info", - iface_type, -@@ -349,10 +377,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, info), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - signals [PROBLEM] = - g_signal_new ("problem", - iface_type, -@@ -360,10 +388,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, problem), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - signals [SESSION_OPENED] = - g_signal_new ("session-opened", - iface_type, -@@ -371,9 +399,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, session_opened), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, -+ G_TYPE_STRING); - signals [SESSION_OPEN_FAILED] = - g_signal_new ("session-open-failed", - iface_type, -@@ -381,10 +410,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, session_open_failed), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - signals [SESSION_STARTED] = - g_signal_new ("session-started", - iface_type, -@@ -392,10 +421,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, session_started), - NULL, - NULL, -- g_cclosure_marshal_VOID__INT, -+ gdm_marshal_VOID__STRING_INT, - G_TYPE_NONE, -- 1, -- G_TYPE_INT); -+ 2, -+ G_TYPE_STRING, G_TYPE_INT); - signals [SESSION_START_FAILED] = - g_signal_new ("session-start-failed", - iface_type, -@@ -403,10 +432,10 @@ gdm_session_class_init (gpointer g_iface) - G_STRUCT_OFFSET (GdmSessionIface, session_start_failed), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - signals [SESSION_EXITED] = - g_signal_new ("session-exited", - iface_type, -@@ -475,19 +504,21 @@ gdm_session_class_init (gpointer g_iface) - } - - void --_gdm_session_setup_complete (GdmSession *session) -+_gdm_session_setup_complete (GdmSession *session, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_SESSION (session)); - -- g_signal_emit (session, signals [SETUP_COMPLETE], 0); -+ g_signal_emit (session, signals [SETUP_COMPLETE], 0, service_name); - } - - void - _gdm_session_setup_failed (GdmSession *session, -+ const char *service_name, - const char *text) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [SETUP_FAILED], 0, text); -+ g_signal_emit (session, signals [SETUP_FAILED], 0, service_name, text); - } - - void -@@ -507,114 +538,128 @@ _gdm_session_reset_failed (GdmSession *session, - } - - void --_gdm_session_authenticated (GdmSession *session) -+_gdm_session_authenticated (GdmSession *session, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_SESSION (session)); - -- g_signal_emit (session, signals [AUTHENTICATED], 0); -+ g_signal_emit (session, signals [AUTHENTICATED], 0, service_name); - } - - void - _gdm_session_authentication_failed (GdmSession *session, -+ const char *service_name, - const char *text) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [AUTHENTICATION_FAILED], 0, text); -+ g_signal_emit (session, signals [AUTHENTICATION_FAILED], 0, service_name, text); - } - - void --_gdm_session_authorized (GdmSession *session) -+_gdm_session_authorized (GdmSession *session, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_SESSION (session)); - -- g_signal_emit (session, signals [AUTHORIZED], 0); -+ g_signal_emit (session, signals [AUTHORIZED], 0, service_name); - } - - void - _gdm_session_authorization_failed (GdmSession *session, -+ const char *service_name, - const char *text) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [AUTHORIZATION_FAILED], 0, text); -+ g_signal_emit (session, signals [AUTHORIZATION_FAILED], 0, service_name, text); - } - - void --_gdm_session_accredited (GdmSession *session) -+_gdm_session_accredited (GdmSession *session, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_SESSION (session)); - -- g_signal_emit (session, signals [ACCREDITED], 0); -+ g_signal_emit (session, signals [ACCREDITED], 0, service_name); - } - - void - _gdm_session_accreditation_failed (GdmSession *session, -+ const char *service_name, - const char *text) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [ACCREDITATION_FAILED], 0, text); -+ g_signal_emit (session, signals [ACCREDITATION_FAILED], 0, service_name, text); - } - - void - _gdm_session_info_query (GdmSession *session, -+ const char *service_name, - const char *text) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [INFO_QUERY], 0, text); -+ g_signal_emit (session, signals [INFO_QUERY], 0, service_name, text); - } - - void - _gdm_session_secret_info_query (GdmSession *session, -+ const char *service_name, - const char *text) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [SECRET_INFO_QUERY], 0, text); -+ g_signal_emit (session, signals [SECRET_INFO_QUERY], 0, service_name, text); - } - - void - _gdm_session_info (GdmSession *session, -+ const char *service_name, - const char *text) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [INFO], 0, text); -+ g_signal_emit (session, signals [INFO], 0, service_name, text); - } - - void - _gdm_session_problem (GdmSession *session, -+ const char *service_name, - const char *text) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [PROBLEM], 0, text); -+ g_signal_emit (session, signals [PROBLEM], 0, service_name, text); - } - - void --_gdm_session_session_opened (GdmSession *session) -+_gdm_session_session_opened (GdmSession *session, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [SESSION_OPENED], 0); -+ g_signal_emit (session, signals [SESSION_OPENED], 0, service_name); - } - - void - _gdm_session_session_open_failed (GdmSession *session, -+ const char *service_name, - const char *text) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [SESSION_OPEN_FAILED], 0, text); -+ g_signal_emit (session, signals [SESSION_OPEN_FAILED], 0, service_name, text); - } - - void - _gdm_session_session_started (GdmSession *session, -+ const char *service_name, - int pid) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [SESSION_STARTED], 0, pid); -+ g_signal_emit (session, signals [SESSION_STARTED], 0, service_name, pid); - } - - void - _gdm_session_session_start_failed (GdmSession *session, -+ const char *service_name, - const char *text) - { - g_return_if_fail (GDM_IS_SESSION (session)); -- g_signal_emit (session, signals [SESSION_START_FAILED], 0, text); -+ g_signal_emit (session, signals [SESSION_START_FAILED], 0, service_name, text); - } - - void -@@ -642,6 +687,14 @@ _gdm_session_conversation_started (GdmSession *session, - } - - void -+_gdm_session_conversation_stopped (GdmSession *session, -+ const char *service_name) -+{ -+ g_return_if_fail (GDM_IS_SESSION (session)); -+ g_signal_emit (session, signals [CONVERSATION_STOPPED], 0, service_name); -+} -+ -+void - _gdm_session_closed (GdmSession *session) - { - g_return_if_fail (GDM_IS_SESSION (session)); -diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h -index 202da36..9e72f89 100644 ---- a/daemon/gdm-session.h -+++ b/daemon/gdm-session.h -@@ -47,18 +47,25 @@ struct _GdmSessionIface - /* Methods */ - void (* start_conversation) (GdmSession *session, - const char *service_name); -+ void (* stop_conversation) (GdmSession *session, -+ const char *service_name); - void (* setup) (GdmSession *session, - const char *service_name); - void (* setup_for_user) (GdmSession *session, - const char *service_name, - const char *username); - void (* reset) (GdmSession *session); -- void (* authenticate) (GdmSession *session); -- void (* authorize) (GdmSession *session); -+ void (* authenticate) (GdmSession *session, -+ const char *service_name); -+ void (* authorize) (GdmSession *session, -+ const char *service_name); - void (* accredit) (GdmSession *session, -+ const char *service_name, - int cred_flag); -- void (* open_session) (GdmSession *session); -+ void (* open_session) (GdmSession *session, -+ const char *service_name); - void (* answer_query) (GdmSession *session, -+ const char *service_name, - const char *text); - void (* select_language) (GdmSession *session, - const char *text); -@@ -66,41 +73,58 @@ struct _GdmSessionIface - const char *text); - void (* select_user) (GdmSession *session, - const char *text); -- void (* start_session) (GdmSession *session); -+ void (* start_session) (GdmSession *session, -+ const char *service_name); - void (* close) (GdmSession *session); - void (* cancel) (GdmSession *session); - - /* Signals */ -- void (* setup_complete) (GdmSession *session); -+ void (* setup_complete) (GdmSession *session, -+ const char *service_name); - void (* setup_failed) (GdmSession *session, -+ const char *service_name, - const char *message); - void (* reset_complete) (GdmSession *session); - void (* reset_failed) (GdmSession *session, - const char *message); -- void (* authenticated) (GdmSession *session); -+ void (* authenticated) (GdmSession *session, -+ const char *service_name); - void (* authentication_failed) (GdmSession *session, -+ const char *service_name, - const char *message); -- void (* authorized) (GdmSession *session); -+ void (* authorized) (GdmSession *session, -+ const char *service_name); - void (* authorization_failed) (GdmSession *session, -+ const char *service_name, - const char *message); -- void (* accredited) (GdmSession *session); -+ void (* accredited) (GdmSession *session, -+ const char *service_name); - void (* accreditation_failed) (GdmSession *session, -+ const char *service_name, - const char *message); - - void (* info_query) (GdmSession *session, -+ const char *service_name, - const char *query_text); - void (* secret_info_query) (GdmSession *session, -+ const char *service_name, - const char *query_text); - void (* info) (GdmSession *session, -+ const char *service_name, - const char *info); - void (* problem) (GdmSession *session, -+ const char *service_name, - const char *problem); -- void (* session_opened) (GdmSession *session); -+ void (* session_opened) (GdmSession *session, -+ const char *service_name); - void (* session_open_failed) (GdmSession *session, -+ const char *service_name, - const char *message); - void (* session_started) (GdmSession *session, -+ const char *service_name, - int pid); - void (* session_start_failed) (GdmSession *session, -+ const char *service_name, - const char *message); - void (* session_exited) (GdmSession *session, - int exit_code); -@@ -108,6 +132,8 @@ struct _GdmSessionIface - int signal_number); - void (* conversation_started) (GdmSession *session, - const char *service_name); -+ void (* conversation_stopped) (GdmSession *session, -+ const char *service_name); - void (* closed) (GdmSession *session); - void (* selected_user_changed) (GdmSession *session, - const char *text); -@@ -122,21 +148,29 @@ GType gdm_session_get_type (void) G_GNUC_CONST; - - void gdm_session_start_conversation (GdmSession *session, - const char *service_name); -+void gdm_session_stop_conversation (GdmSession *session, -+ const char *service_name); - void gdm_session_setup (GdmSession *session, - const char *service_name); - void gdm_session_setup_for_user (GdmSession *session, - const char *service_name, - const char *username); - void gdm_session_reset (GdmSession *session); --void gdm_session_authenticate (GdmSession *session); --void gdm_session_authorize (GdmSession *session); -+void gdm_session_authenticate (GdmSession *session, -+ const char *service_name); -+void gdm_session_authorize (GdmSession *session, -+ const char *service_name); - void gdm_session_accredit (GdmSession *session, -+ const char *service_name, - int cred_flag); --void gdm_session_open_session (GdmSession *session); --void gdm_session_start_session (GdmSession *session); -+void gdm_session_open_session (GdmSession *session, -+ const char *service_name); -+void gdm_session_start_session (GdmSession *session, -+ const char *service_name); - void gdm_session_close (GdmSession *session); - - void gdm_session_answer_query (GdmSession *session, -+ const char *service_name, - const char *text); - void gdm_session_select_session (GdmSession *session, - const char *session_name); -diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c -index 155680c..4895bfe 100644 ---- a/daemon/gdm-simple-slave.c -+++ b/daemon/gdm-simple-slave.c -@@ -75,6 +75,8 @@ struct GdmSimpleSlavePrivate - guint greeter_reset_id; - guint start_session_id; - -+ char *start_session_service_name; -+ - int ping_interval; - - GPid server_pid; -@@ -109,6 +111,7 @@ static void start_greeter (GdmSimpleSlave *slave); - - static void - on_session_started (GdmSession *session, -+ const char *service_name, - int pid, - GdmSimpleSlave *slave) - { -@@ -300,23 +303,25 @@ queue_auth_failed_reset (GdmSimpleSlave *slave) - - static void - on_session_setup_complete (GdmSession *session, -+ const char *service_name, - GdmSimpleSlave *slave) - { -- gdm_session_authenticate (session); -+ gdm_session_authenticate (session, service_name); - } - - static void - on_session_setup_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmSimpleSlave *slave) - { - if (slave->priv->greeter_server != NULL) { - gdm_greeter_server_problem (slave->priv->greeter_server, -- message != NULL ? message: _("Unable to initialize login system")); -+ service_name, -+ message != NULL ? message: _("Unable to initialize login system")); - } - -- destroy_session (slave); -- queue_greeter_reset (slave); -+ gdm_session_stop_conversation (session, service_name); - } - - static void -@@ -336,29 +341,32 @@ on_session_reset_failed (GdmSession *session, - - static void - on_session_authenticated (GdmSession *session, -+ const char *service_name, - GdmSimpleSlave *slave) - { -- gdm_session_authorize (session); -+ gdm_session_authorize (session, service_name); - } - - static void - on_session_authentication_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmSimpleSlave *slave) - { - if (slave->priv->greeter_server != NULL) { - gdm_greeter_server_problem (slave->priv->greeter_server, -+ service_name, - message != NULL ? message : _("Unable to authenticate user")); - } - -- destroy_session (slave); -- - g_debug ("GdmSimpleSlave: Authentication failed - may retry"); -+ gdm_session_stop_conversation (session, service_name); - queue_auth_failed_reset (slave); - } - - static void --gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave) -+gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave, -+ const char *service_name) - { - if (slave->priv->start_session_when_ready) { - char *ssid; -@@ -379,7 +387,7 @@ gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave) - g_free (ssid); - g_free (username); - -- gdm_session_accredit (GDM_SESSION (slave->priv->session), cred_flag); -+ gdm_session_accredit (GDM_SESSION (slave->priv->session), service_name, cred_flag); - } else { - slave->priv->waiting_to_start_session = TRUE; - } -@@ -387,29 +395,31 @@ gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave) - - static void - on_session_authorized (GdmSession *session, -+ const char *service_name, - GdmSimpleSlave *slave) - { - if (slave->priv->greeter_server != NULL) { -- gdm_greeter_server_user_authorized (slave->priv->greeter_server); -- gdm_simple_slave_accredit_when_ready (slave); -+ gdm_greeter_server_user_authorized (slave->priv->greeter_server, service_name); -+ gdm_simple_slave_accredit_when_ready (slave, service_name); - } else { - slave->priv->start_session_when_ready = TRUE; -- gdm_simple_slave_accredit_when_ready (slave); -+ gdm_simple_slave_accredit_when_ready (slave, service_name); - } - } - - static void - on_session_authorization_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmSimpleSlave *slave) - { - if (slave->priv->greeter_server != NULL) { - gdm_greeter_server_problem (slave->priv->greeter_server, -- message != NULL ? message : _("Unable to authorize user")); -+ service_name, -+ message != NULL ? message : _("Unable to authorize user")); - } - -- destroy_session (slave); -- queue_greeter_reset (slave); -+ gdm_session_stop_conversation (session, service_name); - } - - static gboolean -@@ -492,31 +502,38 @@ start_session_timeout (GdmSimpleSlave *slave) - - g_free (auth_file); - -- gdm_session_start_session (GDM_SESSION (slave->priv->session)); -+ gdm_session_start_session (GDM_SESSION (slave->priv->session), -+ slave->priv->start_session_service_name); - out: - slave->priv->start_session_id = 0; -+ g_free (slave->priv->start_session_service_name); -+ slave->priv->start_session_service_name = NULL; - return FALSE; - } - - static void --queue_start_session (GdmSimpleSlave *slave) -+queue_start_session (GdmSimpleSlave *slave, -+ const char *service_name) - { - if (slave->priv->start_session_id > 0) { - return; - } - - slave->priv->start_session_id = g_idle_add ((GSourceFunc)start_session_timeout, slave); -+ slave->priv->start_session_service_name = g_strdup (service_name); - } - - static void - on_session_accredited (GdmSession *session, -+ const char *service_name, - GdmSimpleSlave *slave) - { -- gdm_session_open_session (session); -+ gdm_session_open_session (session, service_name); - } - - static void - on_session_accreditation_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmSimpleSlave *slave) - { -@@ -537,6 +554,7 @@ on_session_accreditation_failed (GdmSession *session, - problem = _("Unable to establish credentials"); - } - gdm_greeter_server_problem (slave->priv->greeter_server, -+ service_name, - problem); - } - } -@@ -545,73 +563,78 @@ on_session_accreditation_failed (GdmSession *session, - when Xorg exits it switches to the VT it was - started from. That interferes with fast - user switching. */ -- destroy_session (slave); - -- queue_greeter_reset (slave); -+ gdm_session_stop_conversation (session, service_name); - } - - static void - on_session_opened (GdmSession *session, -+ const char *service_name, - GdmSimpleSlave *slave) - { - #ifdef HAVE_LOGINDEVPERM - gdm_simple_slave_grant_console_permissions (slave); - #endif /* HAVE_LOGINDEVPERM */ - -- queue_start_session (slave); -+ queue_start_session (slave, service_name); - } - - static void - on_session_open_failed (GdmSession *session, -+ const char *service_name, - const char *message, - GdmSimpleSlave *slave) - { - if (slave->priv->greeter_server != NULL) { - gdm_greeter_server_problem (slave->priv->greeter_server, -+ service_name, - _("Unable to open session")); - } - -- destroy_session (slave); -- queue_greeter_reset (slave); -+ gdm_session_stop_conversation (session, service_name); - } - - static void - on_session_info (GdmSession *session, -+ const char *service_name, - const char *text, - GdmSimpleSlave *slave) - { - g_debug ("GdmSimpleSlave: Info: %s", text); - if (slave->priv->greeter_server != NULL) { -- gdm_greeter_server_info (slave->priv->greeter_server, text); -+ gdm_greeter_server_info (slave->priv->greeter_server, service_name, text); - } - } - - static void - on_session_problem (GdmSession *session, -+ const char *service_name, - const char *text, - GdmSimpleSlave *slave) - { - g_debug ("GdmSimpleSlave: Problem: %s", text); -- gdm_greeter_server_problem (slave->priv->greeter_server, text); -+ gdm_greeter_server_problem (slave->priv->greeter_server, service_name, text); - } - - static void - on_session_info_query (GdmSession *session, -+ const char *service_name, - const char *text, - GdmSimpleSlave *slave) - { - - g_debug ("GdmSimpleSlave: Info query: %s", text); -- gdm_greeter_server_info_query (slave->priv->greeter_server, text); -+ gdm_greeter_server_info_query (slave->priv->greeter_server, service_name, text); - } - - static void - on_session_secret_info_query (GdmSession *session, -+ const char *service_name, - const char *text, - GdmSimpleSlave *slave) - { - g_debug ("GdmSimpleSlave: Secret info query: %s", text); -- gdm_greeter_server_secret_info_query (slave->priv->greeter_server, text); -+ gdm_greeter_server_secret_info_query (slave->priv->greeter_server, service_name, text); - } - - static void -@@ -654,6 +677,23 @@ on_session_conversation_started (GdmSession *session, - } - - static void -+on_session_conversation_stopped (GdmSession *session, -+ const char *service_name, -+ GdmSimpleSlave *slave) -+{ -+ gboolean res; -+ g_debug ("GdmSimpleSlave: conversation stopped"); -+ -+ if (slave->priv->greeter != NULL) { -+ res = gdm_greeter_server_conversation_stopped (slave->priv->greeter_server, -+ service_name); -+ if (! res) { -+ g_warning ("Unable to send conversation stopped"); -+ } -+ } -+} -+ -+static void - on_session_selected_user_changed (GdmSession *session, - const char *text, - GdmSimpleSlave *slave) -@@ -745,6 +785,10 @@ create_new_session (GdmSimpleSlave *slave) - G_CALLBACK (on_session_conversation_started), - slave); - g_signal_connect (slave->priv->session, -+ "conversation-stopped", -+ G_CALLBACK (on_session_conversation_stopped), -+ slave); -+ g_signal_connect (slave->priv->session, - "setup-complete", - G_CALLBACK (on_session_setup_complete), - slave); -@@ -855,6 +899,9 @@ destroy_session (GdmSimpleSlave *slave) - G_CALLBACK (on_session_conversation_started), - slave); - g_signal_handlers_disconnect_by_func (slave->priv->session, -+ G_CALLBACK (on_session_conversation_stopped), -+ slave); -+ g_signal_handlers_disconnect_by_func (slave->priv->session, - G_CALLBACK (on_session_setup_complete), - slave); - g_signal_handlers_disconnect_by_func (slave->priv->session, -@@ -972,17 +1019,24 @@ on_greeter_start_conversation (GdmGreeterServer *greeter_server, - GdmSimpleSlave *slave) - { - g_debug ("GdmSimpleSlave: starting conversation with '%s' pam service'", service_name); -+ if (slave->priv->greeter_reset_id > 0) { -+ return; -+ } - gdm_session_start_conversation (GDM_SESSION (slave->priv->session), - service_name); - } - - static void - on_greeter_begin_verification (GdmGreeterServer *greeter_server, -+ const char *service_name, - GdmSimpleSlave *slave) - { - g_debug ("GdmSimpleSlave: begin verification"); -+ if (slave->priv->greeter_reset_id > 0) { -+ return; -+ } - gdm_session_setup (GDM_SESSION (slave->priv->session), -- "gdm"); -+ service_name); - } - - static void -@@ -1001,6 +1055,7 @@ on_greeter_begin_auto_login (GdmGreeterServer *greeter_server, - - static void - on_greeter_begin_verification_for_user (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *username, - GdmSimpleSlave *slave) - { -@@ -1009,19 +1064,20 @@ on_greeter_begin_verification_for_user (GdmGreeterServer *greeter_server, - return; - } - gdm_session_setup_for_user (GDM_SESSION (slave->priv->session), -- "gdm", -+ service_name, - username); - } - - static void - on_greeter_answer (GdmGreeterServer *greeter_server, -+ const char *service_name, - const char *text, - GdmSimpleSlave *slave) - { - if (slave->priv->greeter_reset_id > 0) { - return; - } -- gdm_session_answer_query (GDM_SESSION (slave->priv->session), text); -+ gdm_session_answer_query (GDM_SESSION (slave->priv->session), service_name, text); - } - - static void -@@ -1102,6 +1158,7 @@ on_greeter_disconnected (GdmGreeterServer *greeter_server, - - static void - on_start_session_when_ready (GdmGreeterServer *session, -+ const char *service_name, - GdmSimpleSlave *slave) - { - g_debug ("GdmSimpleSlave: Will start session when ready"); -@@ -1111,12 +1168,13 @@ on_start_session_when_ready (GdmGreeterServer *session, - slave->priv->start_session_when_ready = TRUE; - - if (slave->priv->waiting_to_start_session) { -- gdm_simple_slave_accredit_when_ready (slave); -+ gdm_simple_slave_accredit_when_ready (slave, service_name); - } - } - - static void - on_start_session_later (GdmGreeterServer *session, -+ const char *service_name, - GdmSimpleSlave *slave) - { - g_debug ("GdmSimpleSlave: Will start session when ready and told"); -diff --git a/daemon/test-session.c b/daemon/test-session.c -index 9bfda86..fe78230 100644 ---- a/daemon/test-session.c -+++ b/daemon/test-session.c -@@ -44,10 +44,11 @@ on_conversation_started (GdmSession *session, - - static void - on_session_setup_complete (GdmSession *session, -+ const char *service_name, - gpointer data) - { - g_debug ("Session setup complete"); -- gdm_session_authenticate (session); -+ gdm_session_authenticate (session, service_name); - } - - static void -@@ -79,10 +80,11 @@ on_session_reset_failed (GdmSession *session, - - static void - on_session_authenticated (GdmSession *session, -+ const char *service_name, - gpointer data) - { - g_debug ("Session authenticated"); -- gdm_session_authorize (session); -+ gdm_session_authorize (session, service_name); - } - - static void -@@ -97,14 +99,16 @@ on_session_authentication_failed (GdmSession *session, - - static void - on_session_authorized (GdmSession *session, -+ const char *service_name, - gpointer data) - { - g_debug ("Session authorized"); -- gdm_session_accredit (session, GDM_SESSION_CRED_ESTABLISH); -+ gdm_session_accredit (session, service_name, GDM_SESSION_CRED_ESTABLISH); - } - - static void - on_session_authorization_failed (GdmSession *session, -+ const char *service_name, - const char *message, - gpointer data) - { -@@ -115,6 +119,7 @@ on_session_authorization_failed (GdmSession *session, - - static void - on_session_accredited (GdmSession *session, -+ const char *service_name, - gpointer data) - { - char *username; -@@ -125,12 +130,13 @@ on_session_accredited (GdmSession *session, - username ? username : "", username ? " " : ""); - g_free (username); - -- gdm_session_start_session (session); -+ gdm_session_start_session (session, service_name); - - } - - static void - on_session_accreditation_failed (GdmSession *session, -+ const char *service_name, - const char *message, - gpointer data) - { -@@ -165,6 +171,7 @@ on_session_died (GdmSession *session, - - static void - on_info_query (GdmSession *session, -+ const char *service_name, - const char *query_text) - { - char answer[1024]; -@@ -184,12 +191,13 @@ on_info_query (GdmSession *session, - gdm_session_close (session); - g_main_loop_quit (loop); - } else { -- gdm_session_answer_query (session, answer); -+ gdm_session_answer_query (session, service_name, answer); - } - } - - static void - on_info (GdmSession *session, -+ const char *service_name, - const char *info) - { - g_print ("\n** NOTE: %s\n", info); -@@ -197,6 +205,7 @@ on_info (GdmSession *session, - - static void - on_problem (GdmSession *session, -+ const char *service_name, - const char *problem) - { - g_print ("\n** WARNING: %s\n", problem); -@@ -204,6 +213,7 @@ on_problem (GdmSession *session, - - static void - on_secret_info_query (GdmSession *session, -+ const char *service_name, - const char *query_text) - { - char answer[1024]; -@@ -233,7 +243,7 @@ on_secret_info_query (GdmSession *session, - - g_print ("\n"); - -- gdm_session_answer_query (session, answer); -+ gdm_session_answer_query (session, service_name, answer); - } - - static void -diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c -index ae61eb1..90bbb4d 100644 ---- a/gui/simple-greeter/gdm-greeter-client.c -+++ b/gui/simple-greeter/gdm-greeter-client.c -@@ -134,6 +134,37 @@ emit_string_and_int_signal_for_message (GdmGreeterClient *client, - } - - static void -+emit_string_and_string_signal_for_message (GdmGreeterClient *client, -+ const char *name, -+ DBusMessage *message, -+ int signal) -+{ -+ DBusError error; -+ char *text1; -+ char *text2; -+ dbus_bool_t res; -+ -+ dbus_error_init (&error); -+ res = dbus_message_get_args (message, -+ &error, -+ DBUS_TYPE_STRING, &text1, -+ DBUS_TYPE_STRING, &text2, -+ DBUS_TYPE_INVALID); -+ if (res) { -+ -+ g_debug ("GdmGreeterClient: Received %s (%s, %s)", name, text1, text2); -+ -+ g_signal_emit (client, -+ gdm_greeter_client_signals[signal], -+ 0, text1, text2); -+ } else { -+ g_warning ("Unable to get arguments: %s", error.message); -+ dbus_error_free (&error); -+ } -+ dbus_error_free (&error); -+} -+ -+static void - emit_string_signal_for_message (GdmGreeterClient *client, - const char *name, - DBusMessage *message, -@@ -193,37 +224,35 @@ static void - on_user_authorized (GdmGreeterClient *client, - DBusMessage *message) - { -- g_signal_emit (client, -- gdm_greeter_client_signals[USER_AUTHORIZED], -- 0); -+ emit_string_signal_for_message (client, "UserAuthorized", message, USER_AUTHORIZED); - } - - static void - on_info_query (GdmGreeterClient *client, - DBusMessage *message) - { -- emit_string_signal_for_message (client, "InfoQuery", message, INFO_QUERY); -+ emit_string_and_string_signal_for_message (client, "InfoQuery", message, INFO_QUERY); - } - - static void - on_secret_info_query (GdmGreeterClient *client, - DBusMessage *message) - { -- emit_string_signal_for_message (client, "SecretInfoQuery", message, SECRET_INFO_QUERY); -+ emit_string_and_string_signal_for_message (client, "SecretInfoQuery", message, SECRET_INFO_QUERY); - } - - static void - on_info (GdmGreeterClient *client, - DBusMessage *message) - { -- emit_string_signal_for_message (client, "Info", message, INFO); -+ emit_string_and_string_signal_for_message (client, "Info", message, INFO); - } - - static void - on_problem (GdmGreeterClient *client, - DBusMessage *message) - { -- emit_string_signal_for_message (client, "Problem", message, PROBLEM); -+ emit_string_and_string_signal_for_message (client, "Problem", message, PROBLEM); - } - - static void -@@ -311,14 +340,22 @@ send_dbus_string_method (DBusConnection *connection, - } - - static gboolean --send_dbus_bool_method (DBusConnection *connection, -- const char *method, -- gboolean payload) -+send_dbus_string_and_bool_method (DBusConnection *connection, -+ const char *method, -+ const char *string_payload, -+ gboolean bool_payload) - { - DBusError error; - DBusMessage *message; - DBusMessage *reply; - DBusMessageIter iter; -+ const char *str; -+ -+ if (string_payload != NULL) { -+ str = string_payload; -+ } else { -+ str = ""; -+ } - - g_debug ("GdmGreeterClient: Calling %s", method); - message = dbus_message_new_method_call (NULL, -@@ -332,8 +369,77 @@ send_dbus_bool_method (DBusConnection *connection, - - dbus_message_iter_init_append (message, &iter); - dbus_message_iter_append_basic (&iter, -+ DBUS_TYPE_STRING, -+ &str); -+ -+ dbus_message_iter_append_basic (&iter, - DBUS_TYPE_BOOLEAN, -- &payload); -+ &bool_payload); -+ -+ dbus_error_init (&error); -+ reply = dbus_connection_send_with_reply_and_block (connection, -+ message, -+ -1, -+ &error); -+ -+ dbus_message_unref (message); -+ -+ if (dbus_error_is_set (&error)) { -+ g_warning ("%s %s raised: %s\n", -+ method, -+ error.name, -+ error.message); -+ return FALSE; -+ } -+ if (reply != NULL) { -+ dbus_message_unref (reply); -+ } -+ dbus_connection_flush (connection); -+ -+ return TRUE; -+} -+ -+static gboolean -+send_dbus_string_and_string_method (DBusConnection *connection, -+ const char *method, -+ const char *payload1, -+ const char *payload2) -+{ -+ DBusError error; -+ DBusMessage *message; -+ DBusMessage *reply; -+ DBusMessageIter iter; -+ const char *str; -+ -+ g_debug ("GdmGreeterClient: Calling %s", method); -+ message = dbus_message_new_method_call (NULL, -+ GREETER_SERVER_DBUS_PATH, -+ GREETER_SERVER_DBUS_INTERFACE, -+ method); -+ if (message == NULL) { -+ g_warning ("Couldn't allocate the D-Bus message"); -+ return FALSE; -+ } -+ -+ dbus_message_iter_init_append (message, &iter); -+ -+ if (payload1 != NULL) { -+ str = payload1; -+ } else { -+ str = ""; -+ } -+ dbus_message_iter_append_basic (&iter, -+ DBUS_TYPE_STRING, -+ &str); -+ -+ if (payload2 != NULL) { -+ str = payload2; -+ } else { -+ str = ""; -+ } -+ dbus_message_iter_append_basic (&iter, -+ DBUS_TYPE_STRING, -+ &str); - - dbus_error_init (&error); - reply = dbus_connection_send_with_reply_and_block (connection, -@@ -416,37 +522,44 @@ gdm_greeter_client_call_begin_auto_login (GdmGreeterClient *client, - } - - void --gdm_greeter_client_call_begin_verification (GdmGreeterClient *client) -+gdm_greeter_client_call_begin_verification (GdmGreeterClient *client, -+ const char *service_name) - { -- send_dbus_void_method (client->priv->connection, -- "BeginVerification"); -+ send_dbus_string_method (client->priv->connection, -+ "BeginVerification", service_name); - } - - void - gdm_greeter_client_call_begin_verification_for_user (GdmGreeterClient *client, -+ const char *service_name, - const char *username) - { -- send_dbus_string_method (client->priv->connection, -- "BeginVerificationForUser", -- username); -+ send_dbus_string_and_string_method (client->priv->connection, -+ "BeginVerificationForUser", -+ service_name, -+ username); - } - - void - gdm_greeter_client_call_answer_query (GdmGreeterClient *client, -+ const char *service_name, - const char *text) - { -- send_dbus_string_method (client->priv->connection, -- "AnswerQuery", -- text); -+ send_dbus_string_and_string_method (client->priv->connection, -+ "AnswerQuery", -+ service_name, -+ text); - } - - void - gdm_greeter_client_call_start_session_when_ready (GdmGreeterClient *client, -+ const char *service_name, - gboolean should_start_session) - { -- send_dbus_bool_method (client->priv->connection, -- "StartSessionWhenReady", -- should_start_session); -+ send_dbus_string_and_bool_method (client->priv->connection, -+ "StartSessionWhenReady", -+ service_name, -+ should_start_session); - } - - void -@@ -831,10 +944,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass) - G_STRUCT_OFFSET (GdmGreeterClientClass, info_query), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - - gdm_greeter_client_signals[SECRET_INFO_QUERY] = - g_signal_new ("secret-info-query", -@@ -843,10 +956,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass) - G_STRUCT_OFFSET (GdmGreeterClientClass, secret_info_query), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - - gdm_greeter_client_signals[INFO] = - g_signal_new ("info", -@@ -855,10 +968,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass) - G_STRUCT_OFFSET (GdmGreeterClientClass, info), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - - gdm_greeter_client_signals[PROBLEM] = - g_signal_new ("problem", -@@ -867,10 +980,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass) - G_STRUCT_OFFSET (GdmGreeterClientClass, problem), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, -- G_TYPE_STRING); -+ 2, -+ G_TYPE_STRING, G_TYPE_STRING); - - gdm_greeter_client_signals[READY] = - g_signal_new ("ready", -@@ -952,8 +1065,9 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass) - G_STRUCT_OFFSET (GdmGreeterClientClass, user_authorized), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -- G_TYPE_NONE, 0); -+ g_cclosure_marshal_VOID__STRING, -+ G_TYPE_NONE, -+ 1, G_TYPE_STRING); - } - - static void -diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h -index 5f92abe..868b496 100644 ---- a/gui/simple-greeter/gdm-greeter-client.h -+++ b/gui/simple-greeter/gdm-greeter-client.h -@@ -45,17 +45,22 @@ typedef struct - GObjectClass parent_class; - - void (* info_query) (GdmGreeterClient *client, -+ const char *service_name, - const char *query_text); - - void (* secret_info_query) (GdmGreeterClient *client, -+ const char *service_name, - const char *query_text); - - void (* info) (GdmGreeterClient *client, -+ const char *service_name, - const char *info); - - void (* problem) (GdmGreeterClient *client, -+ const char *service_name, - const char *problem); -- void (* ready) (GdmGreeterClient *client); -+ void (* ready) (GdmGreeterClient *client, -+ const char *service_name); - void (* reset) (GdmGreeterClient *client); - void (* authentication_failed) (GdmGreeterClient *client); - void (* selected_user_changed) (GdmGreeterClient *client, -@@ -68,7 +73,8 @@ typedef struct - void (* timed_login_requested) (GdmGreeterClient *client, - const char *username, - int delay); -- void (* user_authorized) (GdmGreeterClient *client); -+ void (* user_authorized) (GdmGreeterClient *client, -+ const char *service_name); - } GdmGreeterClientClass; - - #define GDM_GREETER_CLIENT_ERROR (gdm_greeter_client_error_quark ()) -@@ -94,8 +100,10 @@ void gdm_greeter_client_call_start_conversation (GdmGreeter - const char *service_name); - void gdm_greeter_client_call_begin_auto_login (GdmGreeterClient *client, - const char *username); --void gdm_greeter_client_call_begin_verification (GdmGreeterClient *client); -+void gdm_greeter_client_call_begin_verification (GdmGreeterClient *client, -+ const char *service_name); - void gdm_greeter_client_call_begin_verification_for_user (GdmGreeterClient *client, -+ const char *service_name, - const char *username); - void gdm_greeter_client_call_cancel (GdmGreeterClient *client); - void gdm_greeter_client_call_disconnect (GdmGreeterClient *client); -@@ -108,9 +116,11 @@ void gdm_greeter_client_call_select_language (GdmGreeter - void gdm_greeter_client_call_select_session (GdmGreeterClient *client, - const char *text); - void gdm_greeter_client_call_answer_query (GdmGreeterClient *client, -+ const char *service_name, - const char *text); - - void gdm_greeter_client_call_start_session_when_ready (GdmGreeterClient *client, -+ const char *service_name, - gboolean should_start_session); - - -diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c -index ed20884..16f8db5 100644 ---- a/gui/simple-greeter/gdm-greeter-session.c -+++ b/gui/simple-greeter/gdm-greeter-session.c -@@ -69,6 +69,7 @@ static gpointer session_object = NULL; - - static void - on_info (GdmGreeterClient *client, -+ const char *service_name, - const char *text, - GdmGreeterSession *session) - { -@@ -79,6 +80,7 @@ on_info (GdmGreeterClient *client, - - static void - on_problem (GdmGreeterClient *client, -+ const char *service_name, - const char *text, - GdmGreeterSession *session) - { -@@ -187,6 +189,7 @@ on_user_authorized (GdmGreeterClient *client, - - static void - on_info_query (GdmGreeterClient *client, -+ const char *service_name, - const char *text, - GdmGreeterSession *session) - { -@@ -197,6 +200,7 @@ on_info_query (GdmGreeterClient *client, - - static void - on_secret_info_query (GdmGreeterClient *client, -+ const char *service_name, - const char *text, - GdmGreeterSession *session) - { -@@ -218,7 +222,8 @@ static void - on_begin_verification (GdmGreeterLoginWindow *login_window, - GdmGreeterSession *session) - { -- gdm_greeter_client_call_begin_verification (session->priv->client); -+ gdm_greeter_client_call_begin_verification (session->priv->client, -+ "gdm"); - } - - static void -@@ -227,6 +232,7 @@ on_begin_verification_for_user (GdmGreeterLoginWindow *login_window, - GdmGreeterSession *session) - { - gdm_greeter_client_call_begin_verification_for_user (session->priv->client, -+ "gdm", - username); - } - -@@ -236,6 +242,7 @@ on_query_answer (GdmGreeterLoginWindow *login_window, - GdmGreeterSession *session) - { - gdm_greeter_client_call_answer_query (session->priv->client, -+ "gdm", - text); - } - -@@ -284,7 +291,7 @@ static void - on_start_session (GdmGreeterLoginWindow *login_window, - GdmGreeterSession *session) - { -- gdm_greeter_client_call_start_session_when_ready (session->priv->client, TRUE); -+ gdm_greeter_client_call_start_session_when_ready (session->priv->client, "gdm", TRUE); - } - - static int --- -1.7.4.1 - - -From c0cf2003b56dd9593e889a6c20f64d89c031aff1 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 6 Nov 2009 13:35:26 -0500 -Subject: [PATCH 07/20] Don't delay login for passwd -d users - -Before we'd delay login if timed login was enabled, but -we should have been checking if it was the reason login -was happening. ---- - gui/simple-greeter/gdm-greeter-login-window.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c -index abd6707..f484ee6 100644 ---- a/gui/simple-greeter/gdm-greeter-login-window.c -+++ b/gui/simple-greeter/gdm-greeter-login-window.c -@@ -855,7 +855,7 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_ - * so they can pick language/session. Will need to refactor things - * a bit so we can share code with timed login. - */ -- if (!login_window->priv->timed_login_enabled) { -+ if (strcmp (service_name, "gdm-autologin") != 0) { - - g_debug ("GdmGreeterLoginWindow: Okay, we'll start the session anyway," - "because the user isn't ever going to get an opportunity to" --- -1.7.4.1 - - -From cd734d4517dc9f4e9f190de9e6aee2eaa947f715 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 28 Oct 2009 21:32:00 -0400 -Subject: [PATCH 08/20] Emit "service-unavailable" from session when pam service refuses to work - ---- - daemon/gdm-session-direct.c | 26 +++++++++++++++++++++++--- - daemon/gdm-session-private.h | 2 ++ - daemon/gdm-session-relay.c | 33 +++++++++++++++++++++++++++++++++ - daemon/gdm-session-worker.c | 29 ++++++++++++++++++++++------- - daemon/gdm-session.c | 21 +++++++++++++++++++++ - daemon/gdm-session.h | 2 ++ - 6 files changed, 103 insertions(+), 10 deletions(-) - -diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c -index 15a018f..23812d2 100644 ---- a/daemon/gdm-session-direct.c -+++ b/daemon/gdm-session-direct.c -@@ -281,9 +281,27 @@ on_session_exited (GdmSession *session, - } - - static DBusHandlerResult --gdm_session_direct_handle_setup_complete (GdmSessionDirect *session, -- GdmSessionConversation *conversation, -- DBusMessage *message) -+gdm_session_direct_handle_service_unavailable (GdmSessionDirect *session, -+ GdmSessionConversation *conversation, -+ DBusMessage *message) -+{ -+ DBusMessage *reply; -+ -+ g_debug ("GdmSessionDirect: Emitting 'service-unavailable' signal"); -+ -+ reply = dbus_message_new_method_return (message); -+ dbus_connection_send (conversation->worker_connection, reply, NULL); -+ dbus_message_unref (reply); -+ -+ _gdm_session_service_unavailable (GDM_SESSION (session), conversation->service_name); -+ -+ return DBUS_HANDLER_RESULT_HANDLED; -+} -+ -+static DBusHandlerResult -+gdm_session_direct_handle_setup_complete (GdmSessionDirect *session, -+ GdmSessionConversation *conversation, -+ DBusMessage *message) - { - DBusMessage *reply; - -@@ -1237,6 +1255,8 @@ session_worker_message (DBusConnection *connection, - return gdm_session_direct_handle_problem (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "CancelPendingQuery")) { - return gdm_session_direct_handle_cancel_pending_query (session, conversation, message); -+ } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "ServiceUnavailable")) { -+ return gdm_session_direct_handle_service_unavailable (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupComplete")) { - return gdm_session_direct_handle_setup_complete (session, conversation, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupFailed")) { -diff --git a/daemon/gdm-session-private.h b/daemon/gdm-session-private.h -index e15b7dd..fb1f972 100644 ---- a/daemon/gdm-session-private.h -+++ b/daemon/gdm-session-private.h -@@ -31,6 +31,8 @@ void _gdm_session_conversation_started (GdmSession *sessio - const char *service_name); - void _gdm_session_conversation_stopped (GdmSession *session, - const char *service_name); -+void _gdm_session_service_unavailable (GdmSession *session, -+ const char *service_name); - void _gdm_session_setup_complete (GdmSession *session, - const char *service_name); - void _gdm_session_setup_failed (GdmSession *session, -diff --git a/daemon/gdm-session-relay.c b/daemon/gdm-session-relay.c -index 50f1140..f76fa6f 100644 ---- a/daemon/gdm-session-relay.c -+++ b/daemon/gdm-session-relay.c -@@ -455,6 +455,34 @@ handle_problem (GdmSessionRelay *session_relay, - } - - static DBusHandlerResult -+handle_service_unavailable (GdmSessionRelay *session_relay, -+ DBusConnection *connection, -+ DBusMessage *message) -+{ -+ DBusMessage *reply; -+ DBusError error; -+ char *service_name; -+ -+ dbus_error_init (&error); -+ if (! dbus_message_get_args (message, &error, -+ DBUS_TYPE_STRING, &service_name, -+ DBUS_TYPE_INVALID)) { -+ g_warning ("ERROR: %s", error.message); -+ } -+ dbus_error_free (&error); -+ -+ g_debug ("GdmSessionRelay: ServiceUnavailable"); -+ -+ reply = dbus_message_new_method_return (message); -+ dbus_connection_send (connection, reply, NULL); -+ dbus_message_unref (reply); -+ -+ _gdm_session_service_unavailable (GDM_SESSION (session_relay), service_name); -+ -+ return DBUS_HANDLER_RESULT_HANDLED; -+} -+ -+static DBusHandlerResult - handle_setup_complete (GdmSessionRelay *session_relay, - DBusConnection *connection, - DBusMessage *message) -@@ -833,6 +861,8 @@ session_handle_child_message (DBusConnection *connection, - return handle_info (session_relay, connection, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "Problem")) { - return handle_problem (session_relay, connection, message); -+ } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "ServiceUnavailable")) { -+ return handle_service_unavailable (session_relay, connection, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SetupComplete")) { - return handle_setup_complete (session_relay, connection, message); - } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SetupFailed")) { -@@ -890,6 +920,9 @@ do_introspect (DBusConnection *connection, - " \n" - " \n" - " \n" -+ " \n" -+ " \n" -+ " \n" - " \n" - " \n" - " \n" -diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c -index 19474d8..0e18382 100644 ---- a/daemon/gdm-session-worker.c -+++ b/daemon/gdm-session-worker.c -@@ -1994,9 +1994,16 @@ do_setup (GdmSessionWorker *worker) - worker->priv->display_device, - &error); - if (! res) { -- send_dbus_string_method (worker->priv->connection, -- "SetupFailed", -- error->message); -+ if (g_error_matches (error, -+ GDM_SESSION_WORKER_ERROR, -+ GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE)) { -+ send_dbus_void_method (worker->priv->connection, -+ "ServiceUnavailable"); -+ } else { -+ send_dbus_string_method (worker->priv->connection, -+ "SetupFailed", -+ error->message); -+ } - g_error_free (error); - return; - } -@@ -2017,10 +2024,18 @@ do_authenticate (GdmSessionWorker *worker) - worker->priv->password_is_required, - &error); - if (! res) { -- g_debug ("GdmSessionWorker: Unable to verify user"); -- send_dbus_string_method (worker->priv->connection, -- "AuthenticationFailed", -- error->message); -+ if (g_error_matches (error, -+ GDM_SESSION_WORKER_ERROR, -+ GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE)) { -+ g_debug ("GdmSessionWorker: Unable to use authentication service"); -+ send_dbus_void_method (worker->priv->connection, -+ "ServiceUnavailable"); -+ } else { -+ g_debug ("GdmSessionWorker: Unable to verify user"); -+ send_dbus_string_method (worker->priv->connection, -+ "AuthenticationFailed", -+ error->message); -+ } - g_error_free (error); - return; - } -diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c -index 4c7f6bc..bf7c878 100644 ---- a/daemon/gdm-session.c -+++ b/daemon/gdm-session.c -@@ -31,6 +31,7 @@ - enum { - CONVERSATION_STARTED = 0, - CONVERSATION_STOPPED, -+ SERVICE_UNAVAILABLE, - SETUP_COMPLETE, - SETUP_FAILED, - RESET_COMPLETE, -@@ -241,6 +242,17 @@ gdm_session_class_init (gpointer g_iface) - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, - 1, G_TYPE_STRING); -+ signals [SERVICE_UNAVAILABLE] = -+ g_signal_new ("service-unavailable", -+ iface_type, -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmSessionIface, service_unavailable), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__STRING, -+ G_TYPE_NONE, -+ 1, -+ G_TYPE_STRING); - signals [SETUP_COMPLETE] = - g_signal_new ("setup-complete", - iface_type, -@@ -504,6 +516,15 @@ gdm_session_class_init (gpointer g_iface) - } - - void -+_gdm_session_service_unavailable (GdmSession *session, -+ const char *service_name) -+{ -+ g_return_if_fail (GDM_IS_SESSION (session)); -+ -+ g_signal_emit (session, signals [SERVICE_UNAVAILABLE], 0, service_name); -+} -+ -+void - _gdm_session_setup_complete (GdmSession *session, - const char *service_name) - { -diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h -index 9e72f89..ab16031 100644 ---- a/daemon/gdm-session.h -+++ b/daemon/gdm-session.h -@@ -49,6 +49,8 @@ struct _GdmSessionIface - const char *service_name); - void (* stop_conversation) (GdmSession *session, - const char *service_name); -+ void (* service_unavailable) (GdmSession *session, -+ const char *service_name); - void (* setup) (GdmSession *session, - const char *service_name); - void (* setup_for_user) (GdmSession *session, --- -1.7.4.1 - - -From 25977dd389a8f75b76d910ae5947988aae00b2b0 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 28 Oct 2009 21:38:52 -0400 -Subject: [PATCH 09/20] Bubble service-unavailable up to greeter - ---- - daemon/gdm-greeter-server.c | 13 +++++++++++-- - daemon/gdm-greeter-server.h | 5 ++++- - daemon/gdm-simple-slave.c | 36 ++++++++++++++---------------------- - 3 files changed, 29 insertions(+), 25 deletions(-) - -diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c -index d9ecb1f..6e300a0 100644 ---- a/daemon/gdm-greeter-server.c -+++ b/daemon/gdm-greeter-server.c -@@ -285,9 +285,18 @@ gdm_greeter_server_problem (GdmGreeterServer *greeter_server, - } - - gboolean --gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server) -+gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server, -+ const char *service_name) - { -- send_dbus_void_signal (greeter_server, "AuthenticationFailed"); -+ send_dbus_string_signal (greeter_server, "AuthenticationFailed", service_name); -+ return TRUE; -+} -+ -+gboolean -+gdm_greeter_server_service_unavailable (GdmGreeterServer *greeter_server, -+ const char *service_name) -+{ -+ send_dbus_string_signal (greeter_server, "ServiceUnavailable", service_name); - return TRUE; - } - -diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h -index 9015c26..52ce9fc 100644 ---- a/daemon/gdm-greeter-server.h -+++ b/daemon/gdm-greeter-server.h -@@ -91,7 +91,10 @@ gboolean gdm_greeter_server_info (GdmGreeterServer * - gboolean gdm_greeter_server_problem (GdmGreeterServer *greeter_server, - const char *service_name, - const char *text); --gboolean gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server); -+gboolean gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server, -+ const char *service_name); -+gboolean gdm_greeter_server_service_unavailable (GdmGreeterServer *greeter_server, -+ const char *service_name); - gboolean gdm_greeter_server_reset (GdmGreeterServer *greeter_server); - gboolean gdm_greeter_server_ready (GdmGreeterServer *greeter_server, - const char *service_name); -diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c -index 4895bfe..b6646aa 100644 ---- a/daemon/gdm-simple-slave.c -+++ b/daemon/gdm-simple-slave.c -@@ -264,22 +264,6 @@ greeter_reset_timeout (GdmSimpleSlave *slave) - return FALSE; - } - --static gboolean --auth_failed_reset_timeout (GdmSimpleSlave *slave) --{ -- g_debug ("GdmSimpleSlave: auth failed resetting slave"); -- -- if (slave->priv->greeter_server != NULL) { -- gdm_greeter_server_authentication_failed (slave->priv->greeter_server); -- reset_session (slave); -- } else { -- start_greeter (slave); -- create_new_session (slave); -- } -- slave->priv->greeter_reset_id = 0; -- return FALSE; --} -- - static void - queue_greeter_reset (GdmSimpleSlave *slave) - { -@@ -291,14 +275,16 @@ queue_greeter_reset (GdmSimpleSlave *slave) - } - - static void --queue_auth_failed_reset (GdmSimpleSlave *slave) -+on_session_service_unavailable (GdmSession *session, -+ const char *service_name, -+ GdmSimpleSlave *slave) - { -- /* use the greeter reset idle id so we don't do both at once */ -- if (slave->priv->greeter_reset_id > 0) { -- return; -+ if (slave->priv->greeter_server != NULL) { -+ gdm_greeter_server_service_unavailable (slave->priv->greeter_server, -+ service_name); - } - -- slave->priv->greeter_reset_id = g_idle_add ((GSourceFunc)auth_failed_reset_timeout, slave); -+ gdm_session_stop_conversation (session, service_name); - } - - static void -@@ -361,7 +347,6 @@ on_session_authentication_failed (GdmSession *session, - - g_debug ("GdmSimpleSlave: Authentication failed - may retry"); - gdm_session_stop_conversation (session, service_name); -- queue_auth_failed_reset (slave); - } - - static void -@@ -789,6 +774,10 @@ create_new_session (GdmSimpleSlave *slave) - G_CALLBACK (on_session_conversation_stopped), - slave); - g_signal_connect (slave->priv->session, -+ "service-unavailable", -+ G_CALLBACK (on_session_service_unavailable), -+ slave); -+ g_signal_connect (slave->priv->session, - "setup-complete", - G_CALLBACK (on_session_setup_complete), - slave); -@@ -902,6 +891,9 @@ destroy_session (GdmSimpleSlave *slave) - G_CALLBACK (on_session_conversation_stopped), - slave); - g_signal_handlers_disconnect_by_func (slave->priv->session, -+ G_CALLBACK (on_session_service_unavailable), -+ slave); -+ g_signal_handlers_disconnect_by_func (slave->priv->session, - G_CALLBACK (on_session_setup_complete), - slave); - g_signal_handlers_disconnect_by_func (slave->priv->session, --- -1.7.4.1 - - -From 5d43c9355b72bf0134063d058c595560d443a5df Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 28 Oct 2009 21:46:39 -0400 -Subject: [PATCH 10/20] Catch service-unavailable from server in client and propagate it - ---- - gui/simple-greeter/gdm-greeter-client.c | 20 ++++++++++++++++++++ - gui/simple-greeter/gdm-greeter-client.h | 2 ++ - 2 files changed, 22 insertions(+), 0 deletions(-) - -diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c -index 90bbb4d..7171741 100644 ---- a/gui/simple-greeter/gdm-greeter-client.c -+++ b/gui/simple-greeter/gdm-greeter-client.c -@@ -63,6 +63,7 @@ enum { - PROBLEM, - INFO_QUERY, - SECRET_INFO_QUERY, -+ SERVICE_UNAVAILABLE, - READY, - RESET, - AUTHENTICATION_FAILED, -@@ -256,6 +257,13 @@ on_problem (GdmGreeterClient *client, - } - - static void -+on_service_unavailable (GdmGreeterClient *client, -+ DBusMessage *message) -+{ -+ emit_string_signal_for_message (client, "ServiceUnavailable", message, SERVICE_UNAVAILABLE); -+} -+ -+static void - on_ready (GdmGreeterClient *client, - DBusMessage *message) - { -@@ -754,6 +762,8 @@ client_dbus_handle_message (DBusConnection *connection, - on_info (client, message); - } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Problem")) { - on_problem (client, message); -+ } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "ServiceUnavailable")) { -+ on_service_unavailable (client, message); - } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Ready")) { - on_ready (client, message); - } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Reset")) { -@@ -985,6 +995,16 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass) - 2, - G_TYPE_STRING, G_TYPE_STRING); - -+ gdm_greeter_client_signals[SERVICE_UNAVAILABLE] = -+ g_signal_new ("service-unavailable", -+ G_OBJECT_CLASS_TYPE (object_class), -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmGreeterClientClass, service_unavailable), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__STRING, -+ G_TYPE_NONE, 1, G_TYPE_STRING); -+ - gdm_greeter_client_signals[READY] = - g_signal_new ("ready", - G_OBJECT_CLASS_TYPE (object_class), -diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h -index 868b496..63bd4b5 100644 ---- a/gui/simple-greeter/gdm-greeter-client.h -+++ b/gui/simple-greeter/gdm-greeter-client.h -@@ -59,6 +59,8 @@ typedef struct - void (* problem) (GdmGreeterClient *client, - const char *service_name, - const char *problem); -+ void (* service_unavailable) (GdmGreeterClient *client, -+ const char *service_name); - void (* ready) (GdmGreeterClient *client, - const char *service_name); - void (* reset) (GdmGreeterClient *client); --- -1.7.4.1 - - -From c1964d63c574a8296062dc94213cd52cf0a233bf Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 30 Jan 2009 23:57:31 -0500 -Subject: [PATCH 11/20] Add a plugin based extension system to greeter - -This allows plugins to drive which PAM conversations -get run. This commit just adds one plugin "password" -which does the one PAM conversation we've traditionally -run. ---- - common/gdm-marshal.list | 1 + - configure.ac | 44 + - gui/simple-greeter/Makefile.am | 21 + - gui/simple-greeter/gdm-greeter-client.c | 21 + - gui/simple-greeter/gdm-greeter-client.h | 2 + - gui/simple-greeter/gdm-greeter-login-window.c | 1078 +++++++++++++++++--- - gui/simple-greeter/gdm-greeter-login-window.h | 33 +- - gui/simple-greeter/gdm-greeter-login-window.ui | 67 +- - gui/simple-greeter/gdm-greeter-plugin.c | 254 +++++ - gui/simple-greeter/gdm-greeter-plugin.h | 61 ++ - gui/simple-greeter/gdm-greeter-session.c | 160 +++- - gui/simple-greeter/gdm-plugin-manager.c | 478 +++++++++ - gui/simple-greeter/gdm-plugin-manager.h | 66 ++ - gui/simple-greeter/gdm-task-list.c | 390 +++++++ - gui/simple-greeter/gdm-task-list.h | 85 ++ - gui/simple-greeter/gdm-user-chooser-widget.c | 23 +- - gui/simple-greeter/libgdmsimplegreeter/Makefile.am | 48 + - .../libgdmsimplegreeter/gdm-conversation.c | 186 ++++ - .../libgdmsimplegreeter/gdm-conversation.h | 93 ++ - .../libgdmsimplegreeter/gdm-greeter-extension.c | 93 ++ - .../libgdmsimplegreeter/gdm-greeter-extension.h | 55 + - gui/simple-greeter/libgdmsimplegreeter/gdm-task.c | 129 +++ - gui/simple-greeter/libgdmsimplegreeter/gdm-task.h | 66 ++ - .../libgdmsimplegreeter/gdmsimplegreeter.pc.in | 11 + - gui/simple-greeter/plugins/Makefile.am | 1 + - gui/simple-greeter/plugins/password/Makefile.am | 52 + - .../plugins/password/gdm-password-extension.c | 337 ++++++ - .../plugins/password/gdm-password-extension.h | 56 + - .../plugins/password/gdm-password.pam | 19 + - gui/simple-greeter/plugins/password/page.ui | 57 + - gui/simple-greeter/plugins/password/plugin.c | 40 + - po/POTFILES.in | 1 + - 32 files changed, 3770 insertions(+), 258 deletions(-) - create mode 100644 gui/simple-greeter/gdm-greeter-plugin.c - create mode 100644 gui/simple-greeter/gdm-greeter-plugin.h - create mode 100644 gui/simple-greeter/gdm-plugin-manager.c - create mode 100644 gui/simple-greeter/gdm-plugin-manager.h - create mode 100644 gui/simple-greeter/gdm-task-list.c - create mode 100644 gui/simple-greeter/gdm-task-list.h - create mode 100644 gui/simple-greeter/libgdmsimplegreeter/Makefile.am - create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c - create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h - create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c - create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h - create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-task.c - create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-task.h - create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in - create mode 100644 gui/simple-greeter/plugins/Makefile.am - create mode 100644 gui/simple-greeter/plugins/password/Makefile.am - create mode 100644 gui/simple-greeter/plugins/password/gdm-password-extension.c - create mode 100644 gui/simple-greeter/plugins/password/gdm-password-extension.h - create mode 100644 gui/simple-greeter/plugins/password/gdm-password.pam - create mode 100644 gui/simple-greeter/plugins/password/page.ui - create mode 100644 gui/simple-greeter/plugins/password/plugin.c - -diff --git a/common/gdm-marshal.list b/common/gdm-marshal.list -index d5455e1..d8a9e72 100644 ---- a/common/gdm-marshal.list -+++ b/common/gdm-marshal.list -@@ -5,3 +5,4 @@ VOID:STRING,STRING - VOID:UINT,UINT - VOID:STRING,INT - VOID:DOUBLE -+BOOLEAN:STRING -diff --git a/configure.ac b/configure.ac -index 1755235..5258390 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -18,6 +18,22 @@ AC_PROG_CXX - AM_PROG_CC_C_O - AC_PROG_LIBTOOL() - -+## increment if the plugin interface has additions, changes, removals. -+LT_CURRENT=1 -+ -+## increment any time the source changes; set to -+## 0 if you increment CURRENT -+LT_REVISION=0 -+ -+## increment if any interfaces have been added; set to 0 -+## if any interfaces have been changed or removed. removal has -+## precedence over adding, so set to 0 if both happened. -+LT_AGE=0 -+ -+AC_SUBST(LT_CURRENT) -+AC_SUBST(LT_REVISION) -+AC_SUBST(LT_AGE) -+ - AC_HEADER_STDC - - AC_SUBST(VERSION) -@@ -193,6 +209,15 @@ AC_ARG_WITH(dmconfdir, - AC_SUBST(dmconfdir) - - dnl --------------------------------------------------------------------------- -+dnl - Configuration file stuff -+dnl --------------------------------------------------------------------------- -+AC_ARG_WITH(extensionsdatadir, -+ AS_HELP_STRING([--with-extensions-datadir], -+ [directory where extensions store data, default=DATADIR/gdm/simple-greeter/extensions]), -+ extensionsdatadir=${withval}, extensionsdatadir=${datadir}/gdm/simple-greeter/extensions) -+AC_SUBST(extensionsdatadir) -+ -+dnl --------------------------------------------------------------------------- - dnl - Configure arguments - dnl --------------------------------------------------------------------------- - -@@ -1269,6 +1294,21 @@ fi - - AC_SUBST(GDM_SCREENSHOT_DIR) - -+dnl --------------------------------------------------------------------------- -+dnl - Directory for simple greeter plugins -+dnl --------------------------------------------------------------------------- -+ -+AC_ARG_WITH(simple-greeter-plugins-dir, -+ AS_HELP_STRING([--with-simple-greeter-plugins-dir=], -+ [simple greeter plugins directory])) -+ -+if ! test -z "$with_simple_greeter_plugins_dir"; then -+ GDM_SIMPLE_GREETER_PLUGINS_DIR=$with_simple_greeter_plugins_dir -+else -+ GDM_SIMPLE_GREETER_PLUGINS_DIR=${libdir}/gdm/simple-greeter/plugins -+fi -+ -+AC_SUBST(GDM_SIMPLE_GREETER_PLUGINS_DIR) - - dnl --------------------------------------------------------------------------- - dnl - Finish -@@ -1396,6 +1436,10 @@ daemon/Makefile - docs/Makefile - gui/Makefile - gui/simple-greeter/Makefile -+gui/simple-greeter/libgdmsimplegreeter/Makefile -+gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc -+gui/simple-greeter/plugins/Makefile -+gui/simple-greeter/plugins/password/Makefile - gui/simple-chooser/Makefile - utils/Makefile - data/gdm.conf -diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am -index a842c7b..d5e68a2 100644 ---- a/gui/simple-greeter/Makefile.am -+++ b/gui/simple-greeter/Makefile.am -@@ -1,8 +1,13 @@ - NULL = -+SUBDIRS = \ -+ libgdmsimplegreeter \ -+ plugins \ -+ $(NULL) - - AM_CPPFLAGS = \ - -I$(top_srcdir)/common \ - -I$(top_builddir)/common \ -+ -I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter \ - -DDMCONFDIR=\""$(dmconfdir)"\" \ - -DGDMCONFDIR=\"$(gdmconfdir)\" \ - -DDATADIR=\""$(datadir)"\" \ -@@ -15,6 +20,7 @@ AM_CPPFLAGS = \ - -DGDM_CACHE_DIR=\""$(localstatedir)/cache/gdm"\" \ - -DAT_SPI_REGISTRYD_DIR="\"$(AT_SPI_REGISTRYD_DIR)\"" \ - $(UPOWER_CFLAGS) \ -+ -DGDM_SIMPLE_GREETER_PLUGINS_DIR="\"$(GDM_SIMPLE_GREETER_PLUGINS_DIR)\""\ - $(DISABLE_DEPRECATED_CFLAGS) \ - $(GTK_CFLAGS) \ - $(SIMPLE_GREETER_CFLAGS) \ -@@ -60,10 +66,17 @@ test_greeter_login_window_SOURCES = \ - gdm-user-chooser-widget.c \ - gdm-user-chooser-dialog.h \ - gdm-user-chooser-dialog.c \ -+ gdm-task-list.h \ -+ gdm-task-list.c \ -+ gdm-plugin-manager.h \ -+ gdm-plugin-manager.c \ -+ gdm-greeter-plugin.h \ -+ gdm-greeter-plugin.c \ - $(NULL) - - test_greeter_login_window_LDADD = \ - $(top_builddir)/common/libgdmcommon.la \ -+ $(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la \ - $(COMMON_LIBS) \ - $(SIMPLE_GREETER_LIBS) \ - $(RBAC_LIBS) \ -@@ -104,6 +117,7 @@ test_greeter_panel_SOURCES = \ - - test_greeter_panel_LDADD = \ - $(top_builddir)/common/libgdmcommon.la \ -+ $(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la \ - $(SIMPLE_GREETER_LIBS) \ - $(GTK_LIBS) \ - $(GCONF_LIBS) \ -@@ -245,16 +259,23 @@ gdm_simple_greeter_SOURCES = \ - gdm-language-chooser-dialog.c \ - gdm-language-option-widget.h \ - gdm-language-option-widget.c \ -+ gdm-plugin-manager.h \ -+ gdm-plugin-manager.c \ - gdm-sessions.h \ - gdm-sessions.c \ - gdm-session-option-widget.h \ - gdm-session-option-widget.c \ -+ gdm-greeter-plugin.h \ -+ gdm-greeter-plugin.c \ - gdm-user-chooser-widget.h \ - gdm-user-chooser-widget.c \ -+ gdm-task-list.h \ -+ gdm-task-list.c \ - $(NULL) - - gdm_simple_greeter_LDADD = \ - $(top_builddir)/common/libgdmcommon.la \ -+ $(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la \ - $(COMMON_LIBS) \ - $(EXTRA_GREETER_LIBS) \ - $(SIMPLE_GREETER_LIBS) \ -diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c -index 7171741..198b566 100644 ---- a/gui/simple-greeter/gdm-greeter-client.c -+++ b/gui/simple-greeter/gdm-greeter-client.c -@@ -65,6 +65,7 @@ enum { - SECRET_INFO_QUERY, - SERVICE_UNAVAILABLE, - READY, -+ CONVERSATION_STOPPED, - RESET, - AUTHENTICATION_FAILED, - SELECTED_USER_CHANGED, -@@ -271,6 +272,13 @@ on_ready (GdmGreeterClient *client, - } - - static void -+on_conversation_stopped (GdmGreeterClient *client, -+ DBusMessage *message) -+{ -+ emit_string_signal_for_message (client, "ConversationStopped", message, CONVERSATION_STOPPED); -+} -+ -+static void - on_reset (GdmGreeterClient *client, - DBusMessage *message) - { -@@ -766,6 +774,8 @@ client_dbus_handle_message (DBusConnection *connection, - on_service_unavailable (client, message); - } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Ready")) { - on_ready (client, message); -+ } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "ConversationStopped")) { -+ on_conversation_stopped (client, message); - } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Reset")) { - on_reset (client, message); - } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "AuthenticationFailed")) { -@@ -1016,6 +1026,17 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass) - G_TYPE_NONE, - 1, G_TYPE_STRING); - -+ gdm_greeter_client_signals[CONVERSATION_STOPPED] = -+ g_signal_new ("conversation-stopped", -+ G_OBJECT_CLASS_TYPE (object_class), -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmGreeterClientClass, conversation_stopped), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__STRING, -+ G_TYPE_NONE, -+ 1, G_TYPE_STRING); -+ - gdm_greeter_client_signals[RESET] = - g_signal_new ("reset", - G_OBJECT_CLASS_TYPE (object_class), -diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h -index 63bd4b5..8ff559c 100644 ---- a/gui/simple-greeter/gdm-greeter-client.h -+++ b/gui/simple-greeter/gdm-greeter-client.h -@@ -63,6 +63,8 @@ typedef struct - const char *service_name); - void (* ready) (GdmGreeterClient *client, - const char *service_name); -+ void (* conversation_stopped) (GdmGreeterClient *client, -+ const char *service_name); - void (* reset) (GdmGreeterClient *client); - void (* authentication_failed) (GdmGreeterClient *client); - void (* selected_user_changed) (GdmGreeterClient *client, -diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c -index f484ee6..56a790e 100644 ---- a/gui/simple-greeter/gdm-greeter-login-window.c -+++ b/gui/simple-greeter/gdm-greeter-login-window.c -@@ -1,7 +1,7 @@ - /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * Copyright (C) 2007 William Jon McCann -- * Copyright (C) 2008 Red Hat, Inc. -+ * Copyright (C) 2008, 2009 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -17,6 +17,9 @@ - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * -+ * Written by: William Jon McCann -+ * Ray Strode -+ * - */ - - #include "config.h" -@@ -50,13 +53,17 @@ - #include - #include - -+#include "gdm-marshal.h" -+ - #include "gdm-settings-client.h" - #include "gdm-settings-keys.h" - #include "gdm-profile.h" - -+#include "gdm-greeter-client.h" - #include "gdm-greeter-login-window.h" - #include "gdm-user-chooser-widget.h" - #include "gdm-session-option-widget.h" -+#include "gdm-task-list.h" - - #ifdef HAVE_PAM - #include -@@ -106,13 +113,15 @@ struct GdmGreeterLoginWindowPrivate - GtkBuilder *builder; - GtkWidget *session_option_widget; - GtkWidget *user_chooser; -+ GtkWidget *conversation_list; - GtkWidget *auth_banner_label; - GtkWidget *current_button; -- -+ GtkWidget *auth_page_box; - guint display_is_local : 1; - guint is_interactive : 1; - guint user_chooser_loaded : 1; - GConfClient *client; -+ GList *tasks_to_enable; - - gboolean banner_message_enabled; - guint gconf_cnxn; -@@ -140,6 +149,7 @@ enum { - }; - - enum { -+ START_CONVERSATION, - BEGIN_AUTO_LOGIN, - BEGIN_VERIFICATION, - BEGIN_VERIFICATION_FOR_USER, -@@ -164,6 +174,8 @@ static void on_user_unchosen (GdmUserChooserWidget *user_chooser, - static void switch_mode (GdmGreeterLoginWindow *login_window, - int number); - static void update_banner_message (GdmGreeterLoginWindow *login_window); -+static void gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window, -+ const char *service_name); - - G_DEFINE_TYPE (GdmGreeterLoginWindow, gdm_greeter_login_window, GTK_TYPE_WINDOW) - -@@ -189,9 +201,6 @@ set_sensitive (GdmGreeterLoginWindow *login_window, - { - GtkWidget *box; - -- box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-input-box")); -- gtk_widget_set_sensitive (box, sensitive); -- - box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "buttonbox")); - gtk_widget_set_sensitive (box, sensitive); - -@@ -201,27 +210,43 @@ set_sensitive (GdmGreeterLoginWindow *login_window, - static void - set_focus (GdmGreeterLoginWindow *login_window) - { -- GtkWidget *entry; -- -- entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry")); -+ GdmTask *task; - - gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME); - -- if (gtk_widget_get_realized (entry) && ! gtk_widget_has_focus (entry)) { -- gtk_widget_grab_focus (entry); -+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -+ -+ if (task != NULL && gdm_conversation_focus (GDM_CONVERSATION (task))) { -+ char *name; -+ name = gdm_task_get_name (task); -+ g_debug ("GdmGreeterLoginWindow: focusing task %s", name); -+ g_free (name); - } else if (gtk_widget_get_realized (login_window->priv->user_chooser) && ! gtk_widget_has_focus (login_window->priv->user_chooser)) { - gtk_widget_grab_focus (login_window->priv->user_chooser); - } -+ g_object_unref (task); -+} -+ -+static gboolean -+set_task_conversation_message (GdmTaskList *task_list, -+ GdmTask *task, -+ const char *message) -+{ -+ -+ gdm_conversation_set_message (GDM_CONVERSATION (task), message); -+ return FALSE; - } - - static void - set_message (GdmGreeterLoginWindow *login_window, - const char *text) - { -- GtkWidget *label; -+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window)); - -- label = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-message-label")); -- gtk_label_set_text (GTK_LABEL (label), text); -+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ (GdmTaskListForeachFunc) -+ set_task_conversation_message, -+ (gpointer) text); - } - - static void -@@ -343,20 +368,66 @@ show_widget (GdmGreeterLoginWindow *login_window, - } - - static void --on_login_button_clicked_answer_query (GtkButton *button, -- GdmGreeterLoginWindow *login_window) -+hide_task_actions (GdmTask *task) - { -- GtkWidget *entry; -- const char *text; -+ GtkActionGroup *actions; - -- set_busy (login_window); -- set_sensitive (login_window, FALSE); -+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task)); - -- entry = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-prompt-entry")); -- text = gtk_entry_get_text (GTK_ENTRY (entry)); -+ if (actions != NULL) { -+ gtk_action_group_set_visible (actions, FALSE); -+ gtk_action_group_set_sensitive (actions, FALSE); -+ g_object_unref (actions); -+ } -+} -+ -+static void -+grab_default_button_for_task (GdmTask *task) -+{ -+ GtkActionGroup *actions; -+ GtkAction *action; -+ GSList *proxies, *node; -+ -+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task)); -+ -+ if (actions == NULL) { -+ return; -+ } -+ -+ action = gtk_action_group_get_action (actions, GDM_CONVERSATION_DEFAULT_ACTION); -+ g_object_unref (actions); -+ -+ if (action == NULL) { -+ return; -+ } -+ -+ proxies = gtk_action_get_proxies (action); -+ for (node = proxies; node != NULL; node = node->next) { -+ GtkWidget *widget; -+ -+ widget = GTK_WIDGET (node->data); -+ -+ if (gtk_widget_get_can_default (widget) && -+ gtk_widget_get_visible (widget)) { -+ gtk_widget_grab_default (widget); -+ break; -+ } -+ } - -- _gdm_greeter_login_window_set_interactive (login_window, TRUE); -- g_signal_emit (login_window, signals[QUERY_ANSWER], 0, text); -+} -+ -+static void -+show_task_actions (GdmTask *task) -+{ -+ GtkActionGroup *actions; -+ -+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task)); -+ -+ if (actions != NULL) { -+ gtk_action_group_set_sensitive (actions, TRUE); -+ gtk_action_group_set_visible (actions, TRUE); -+ g_object_unref (actions); -+ } - } - - static void -@@ -378,6 +449,7 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window, - GtkWidget *unlock_button; - char *item; - gboolean in_use; -+ GdmTask *task; - - in_use = FALSE; - item = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser)); -@@ -417,13 +489,27 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window, - - login_window->priv->current_button = button; - -+ g_list_foreach (login_window->priv->tasks, (GFunc) hide_task_actions, NULL); -+ - switch (mode) { - case LOGIN_BUTTON_HIDDEN: -+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -+ if (task != NULL) { -+ hide_task_actions (task); -+ g_object_unref (task); -+ } -+ - gtk_widget_hide (button); - break; - case LOGIN_BUTTON_ANSWER_QUERY: -- login_window->priv->login_button_handler_id = g_signal_connect (button, "clicked", G_CALLBACK (on_login_button_clicked_answer_query), login_window); -- gtk_widget_show (button); -+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -+ if (task != NULL) { -+ show_task_actions (task); -+ grab_default_button_for_task (task); -+ g_object_unref (task); -+ } -+ -+ gtk_widget_hide (button); - break; - case LOGIN_BUTTON_TIMED_LOGIN: - login_window->priv->login_button_handler_id = g_signal_connect (button, "clicked", G_CALLBACK (on_login_button_clicked_timed_login), login_window); -@@ -487,6 +573,24 @@ maybe_show_cancel_button (GdmGreeterLoginWindow *login_window) - } - - static void -+update_conversation_list_visibility (GdmGreeterLoginWindow *login_window) -+{ -+ int number_of_tasks; -+ -+ if (login_window->priv->dialog_mode != MODE_AUTHENTICATION) { -+ gtk_widget_hide (login_window->priv->conversation_list); -+ return; -+ } -+ -+ number_of_tasks = gdm_task_list_get_number_of_visible_tasks (GDM_TASK_LIST (login_window->priv->conversation_list)); -+ if (number_of_tasks > 1) { -+ gtk_widget_show (login_window->priv->conversation_list); -+ } else { -+ gtk_widget_hide (login_window->priv->conversation_list); -+ } -+} -+ -+static void - switch_mode (GdmGreeterLoginWindow *login_window, - int number) - { -@@ -527,6 +631,7 @@ switch_mode (GdmGreeterLoginWindow *login_window, - } - - show_widget (login_window, "auth-input-box", FALSE); -+ update_conversation_list_visibility (login_window); - maybe_show_cancel_button (login_window); - - /* -@@ -557,58 +662,72 @@ switch_mode (GdmGreeterLoginWindow *login_window, - } - } - --static void --choose_user (GdmGreeterLoginWindow *login_window, -- const char *user_name) -+static gboolean -+task_has_service_name (GdmTaskList *task_list, -+ GdmTask *task, -+ const char *service_name) - { -- guint mode; -+ char *task_service_name; -+ gboolean has_service_name; - -- g_assert (user_name != NULL); -+ task_service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task)); - -- g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], -- 0, user_name); -+ has_service_name = strcmp (service_name, task_service_name) == 0; -+ g_free (task_service_name); - -- mode = MODE_AUTHENTICATION; -- if (strcmp (user_name, GDM_USER_CHOOSER_USER_OTHER) == 0) { -- g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0); -- } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_GUEST) == 0) { -- /* FIXME: handle guest account stuff */ -- } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_AUTO) == 0) { -- g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0, -- login_window->priv->timed_login_username); -+ return has_service_name; -+} - -- login_window->priv->timed_login_enabled = TRUE; -- restart_timed_login_timeout (login_window); -+static GdmTask * -+find_task_with_service_name (GdmGreeterLoginWindow *login_window, -+ const char *service_name) -+{ -+ GdmTask *task; - -- /* just wait for the user to select language and stuff */ -- mode = MODE_TIMED_LOGIN; -- set_message (login_window, _("Select language and click Log In")); -- } else { -- g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, user_name); -- } -+ task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ (GdmTaskListForeachFunc) -+ task_has_service_name, -+ (gpointer) service_name); - -- switch_mode (login_window, mode); -+ return task; - } - --static void --retry_login (GdmGreeterLoginWindow *login_window) -+static gboolean -+reset_task (GdmTaskList *task_list, -+ GdmTask *task, -+ GdmGreeterLoginWindow *login_window) - { -- GtkWidget *entry; -- char *user_name; -+ char *name; - -- user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser)); -- if (user_name == NULL) { -- return; -- } -+ name = gdm_task_get_name (task); -+ g_debug ("Resetting task '%s'", name); -+ g_free (name); -+ -+ login_window->priv->tasks_to_enable = g_list_remove (login_window->priv->tasks_to_enable, task); -+ -+ hide_task_actions (task); -+ gdm_conversation_reset (GDM_CONVERSATION (task)); -+ return FALSE; -+} - -- g_debug ("GdmGreeterLoginWindow: Retrying login for %s", user_name); -+static gboolean -+task_is_disabled (GdmTaskList *task_list, -+ GdmTask *task) -+{ -+ return !gdm_task_is_enabled (task); -+} - -- entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry")); -- gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1); -+static gboolean -+tasks_are_enabled (GdmGreeterLoginWindow *login_window) -+{ -+ GdmTask *task; - -- choose_user (login_window, user_name); -+ task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ (GdmTaskListForeachFunc) -+ task_is_disabled, -+ NULL); - -- g_free (user_name); -+ return task == NULL; - } - - static gboolean -@@ -618,6 +737,10 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window) - - if (!login_window->priv->user_chooser_loaded) { - res = FALSE; -+ } else if (!tasks_are_enabled (login_window)) { -+ res = FALSE; -+ } else if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) { -+ res = FALSE; - } else if (login_window->priv->user_list_disabled) { - res = (login_window->priv->timed_login_username == NULL); - } else { -@@ -627,13 +750,44 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window) - return res; - } - -+static gboolean -+begin_task_verification (GdmTaskList *task_list, -+ GdmTask *task, -+ GdmGreeterLoginWindow *login_window) -+{ -+ char *service_name; -+ -+ if (!gdm_task_is_visible (task)) { -+ return FALSE; -+ } -+ -+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task)); -+ if (service_name != NULL) { -+ g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name); -+ g_free (service_name); -+ } -+ -+ return FALSE; -+} -+ -+static void -+begin_verification (GdmGreeterLoginWindow *login_window) -+{ -+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ (GdmTaskListForeachFunc) -+ begin_task_verification, -+ login_window); -+ -+ switch_mode (login_window, MODE_AUTHENTICATION); -+ -+ update_conversation_list_visibility (login_window); -+} -+ -+ - static void - reset_dialog (GdmGreeterLoginWindow *login_window, - guint dialog_mode) - { -- GtkWidget *entry; -- GtkWidget *label; -- - g_debug ("GdmGreeterLoginWindow: Resetting dialog to mode %u", dialog_mode); - set_busy (login_window); - set_sensitive (login_window, FALSE); -@@ -663,28 +817,22 @@ reset_dialog (GdmGreeterLoginWindow *login_window, - set_message (login_window, ""); - } - -- entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry")); -- -- gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1); -- -- gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE); -- -- label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label")); -- gtk_label_set_text (GTK_LABEL (label), ""); -+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ (GdmTaskListForeachFunc) -+ reset_task, -+ login_window); - - if (can_jump_to_authenticate (login_window)) { - /* If we don't have a user list jump straight to authenticate */ - g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate"); -- switch_mode (login_window, MODE_AUTHENTICATION); -- -- g_debug ("Starting PAM conversation since no local users"); - g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], - 0, GDM_USER_CHOOSER_USER_OTHER); -- g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0); -+ begin_verification (login_window); - } else { - switch_mode (login_window, dialog_mode); - } - -+ gtk_widget_set_sensitive (login_window->priv->conversation_list, TRUE); - set_ready (login_window); - set_focus (GDM_GREETER_LOGIN_WINDOW (login_window)); - update_banner_message (login_window); -@@ -695,90 +843,179 @@ reset_dialog (GdmGreeterLoginWindow *login_window, - } - - static void --do_cancel (GdmGreeterLoginWindow *login_window) -+restart_conversations (GdmGreeterLoginWindow *login_window) - { -- /* need to wait for response from backend */ -- set_message (login_window, _("Cancelling…")); - set_busy (login_window); - set_sensitive (login_window, FALSE); - g_signal_emit (login_window, signals[CANCELLED], 0); - } - -+static void -+do_cancel (GdmGreeterLoginWindow *login_window) -+{ -+ /* need to wait for response from backend */ -+ set_message (login_window, _("Cancelling...")); -+ restart_conversations (login_window); -+} -+ - gboolean --gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window) -+gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window, -+ const char *service_name) - { -+ GdmTask *task; -+ - g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); - -+ task = find_task_with_service_name (login_window, service_name); -+ -+ if (task != NULL) { -+ if (gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) { -+ gdm_conversation_set_ready (GDM_CONVERSATION (task)); -+ } else { -+ login_window->priv->tasks_to_enable = g_list_prepend (login_window->priv->tasks_to_enable, task); -+ } -+ g_object_unref (task); -+ } -+ - set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE); - set_ready (GDM_GREETER_LOGIN_WINDOW (login_window)); - set_focus (GDM_GREETER_LOGIN_WINDOW (login_window)); - gdk_window_beep (gtk_widget_get_window (GTK_WIDGET (login_window))); - -- /* If we are retrying a previously selected user */ -- if (!login_window->priv->user_list_disabled && -- login_window->priv->dialog_mode == MODE_AUTHENTICATION) { -- retry_login (login_window); -- } else { -- /* If the user list is disabled, then start the PAM conversation */ -- if (can_jump_to_authenticate (login_window)) { -- g_debug ("Starting PAM conversation since user list disabled"); -- g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], -- 0, GDM_USER_CHOOSER_USER_OTHER); -- g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0); -- } -+ /* If the user list is disabled, then start the PAM conversation */ -+ if (can_jump_to_authenticate (login_window)) { -+ g_debug ("Starting PAM conversation since user list disabled or no local users"); -+ g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], -+ 0, GDM_USER_CHOOSER_USER_OTHER); -+ begin_verification (login_window); - } - - return TRUE; - } - - gboolean --gdm_greeter_login_window_authentication_failed (GdmGreeterLoginWindow *login_window) -+gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window, -+ const char *service_name) - { -+ GdmTask *task; -+ - g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); - -- g_debug ("GdmGreeterLoginWindow: got authentication failed"); -+ g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name); -+ -+ /* If the password conversation failed, then start over -+ * -+ * FIXME: we need to get this policy out of the source code -+ */ -+ if (strcmp (service_name, "gdm-password") == 0) { -+ g_debug ("GdmGreeterLoginWindow: main conversation failed, starting over"); -+ restart_conversations (login_window); -+ return TRUE; -+ } -+ -+ task = find_task_with_service_name (login_window, service_name); -+ -+ if (task != NULL) { -+ gdm_conversation_reset (GDM_CONVERSATION (task)); -+ g_object_unref (task); -+ } -+ -+ /* If every conversation has failed, then just start over. -+ */ -+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -+ -+ if (!gdm_task_is_enabled (task)) { -+ g_debug ("GdmGreeterLoginWindow: No conversations left, starting over"); -+ restart_conversations (login_window); -+ } -+ g_object_unref (task); - -- /* FIXME: shake? */ -- reset_dialog (login_window, MODE_AUTHENTICATION); -+ update_conversation_list_visibility (login_window); - - return TRUE; - } - -+static gboolean -+restart_task_conversation (GdmTaskList *task_list, -+ GdmTask *task, -+ GdmGreeterLoginWindow *login_window) -+{ -+ char *service_name; -+ -+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task)); -+ if (service_name != NULL) { -+ char *name; -+ -+ name = gdm_task_get_name (task); -+ g_debug ("GdmGreeterLoginWindow: restarting '%s' conversation", name); -+ g_free (name); -+ -+ g_signal_emit (login_window, signals[START_CONVERSATION], 0, service_name); -+ g_free (service_name); -+ } -+ -+ return FALSE; -+} -+ - gboolean - gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window) - { -+ g_debug ("GdmGreeterLoginWindow: window reset"); -+ - g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); -+ reset_dialog (GDM_GREETER_LOGIN_WINDOW (login_window), MODE_SELECTION); - -- g_debug ("GdmGreeterLoginWindow: got reset"); -- reset_dialog (login_window, MODE_SELECTION); -+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ (GdmTaskListForeachFunc) -+ restart_task_conversation, -+ login_window); - - return TRUE; - } - - gboolean - gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *text) - { -- g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); -+ GdmTask *task; - -+ g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); - g_debug ("GdmGreeterLoginWindow: info: %s", text); - -- set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text); - maybe_show_cancel_button (login_window); -+ task = find_task_with_service_name (login_window, service_name); -+ -+ if (task != NULL) { -+ gdm_conversation_set_message (GDM_CONVERSATION (task), -+ text); -+ show_task_actions (task); -+ g_object_unref (task); -+ } - - return TRUE; - } - - gboolean - gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *text) - { -- g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); -+ GdmTask *task; - -+ g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); - g_debug ("GdmGreeterLoginWindow: problem: %s", text); - maybe_show_cancel_button (login_window); - -- set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text); -+ task = find_task_with_service_name (login_window, service_name); -+ -+ if (task != NULL) { -+ gdm_conversation_set_message (GDM_CONVERSATION (task), -+ text); -+ show_task_actions (task); -+ g_object_unref (task); -+ } -+ - gdk_window_beep (gtk_widget_get_window (GTK_WIDGET (login_window))); - - return TRUE; -@@ -803,6 +1040,26 @@ request_timed_login (GdmGreeterLoginWindow *login_window) - login_window->priv->timed_login_already_enabled = TRUE; - } - -+gboolean -+gdm_greeter_login_window_service_unavailable (GdmGreeterLoginWindow *login_window, -+ const char *service_name) -+{ -+ GdmTask *task; -+ -+ g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); -+ g_debug ("GdmGreeterLoginWindow: service unavailable: %s", service_name); -+ -+ task = find_task_with_service_name (login_window, service_name); -+ -+ if (task != NULL) { -+ gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ task); -+ g_object_unref (task); -+ } -+ -+ return TRUE; -+} -+ - void - gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_window, - const char *username, -@@ -830,11 +1087,30 @@ gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_windo - } - - static void --gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window) -+on_ready_to_start_session (GdmGreeterLoginWindow *login_window, -+ GParamSpec *param_spec, -+ char *service_name) -+{ -+ if (!login_window->priv->is_interactive) { -+ return; -+ } -+ -+ gdm_greeter_login_window_start_session_when_ready (login_window, service_name); -+ g_free (service_name); -+ -+ if (login_window->priv->start_session_handler_id > 0) { -+ g_signal_handler_disconnect (login_window, login_window->priv->start_session_handler_id); -+ login_window->priv->start_session_handler_id = 0; -+ } -+} -+ -+static void -+gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window, -+ const char *service_name) - { - if (login_window->priv->is_interactive) { - g_debug ("GdmGreeterLoginWindow: starting session"); -- g_signal_emit (login_window, signals[START_SESSION], 0); -+ g_signal_emit (login_window, signals[START_SESSION], 0, service_name); - } else { - g_debug ("GdmGreeterLoginWindow: not starting session since " - "user hasn't had an opportunity to pick language " -@@ -844,8 +1120,8 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_ - */ - login_window->priv->start_session_handler_id = - g_signal_connect (login_window, "notify::is-interactive", -- G_CALLBACK (gdm_greeter_login_window_start_session_when_ready), -- NULL); -+ G_CALLBACK (on_ready_to_start_session), -+ g_strdup (service_name)); - - /* FIXME: If the user wasn't asked any questions by pam but - * pam still authorized them (passwd -d, or the questions got -@@ -868,10 +1144,10 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_ - - gboolean - gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *text) - { -- GtkWidget *entry; -- GtkWidget *label; -+ GdmTask *task; - - g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); - -@@ -880,16 +1156,15 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window, - - g_debug ("GdmGreeterLoginWindow: info query: %s", text); - -- entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry")); -- gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1); -- gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE); -- set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY); -+ task = find_task_with_service_name (login_window, service_name); - -- label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label")); -- gtk_label_set_text (GTK_LABEL (label), text); -- -- show_widget (login_window, "auth-input-box", TRUE); -+ if (task != NULL) { -+ gdm_conversation_ask_question (GDM_CONVERSATION (task), -+ text); -+ g_object_unref (task); -+ } - -+ set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY); - set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE); - set_ready (GDM_GREETER_LOGIN_WINDOW (login_window)); - set_focus (GDM_GREETER_LOGIN_WINDOW (login_window)); -@@ -901,26 +1176,26 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window, - - gboolean - gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *text) - { -- GtkWidget *entry; -- GtkWidget *label; -+ -+ GdmTask *task; - - g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); - - login_window->priv->num_queries++; - maybe_show_cancel_button (login_window); - -- entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry")); -- gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1); -- gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE); -- set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY); -+ task = find_task_with_service_name (login_window, service_name); - -- label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label")); -- gtk_label_set_text (GTK_LABEL (label), text); -+ if (task != NULL) { -+ gdm_conversation_ask_secret (GDM_CONVERSATION (task), -+ text); -+ g_object_unref (task); -+ } - -- show_widget (login_window, "auth-input-box", TRUE); -- gtk_widget_show (login_window->priv->session_option_widget); -+ set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY); - set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE); - set_ready (GDM_GREETER_LOGIN_WINDOW (login_window)); - set_focus (GDM_GREETER_LOGIN_WINDOW (login_window)); -@@ -931,13 +1206,16 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window, - } - - void --gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window) -+gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window, -+ const char *service_name) - { - g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window)); - -- g_debug ("GdmGreeterLoginWindow: user now authorized"); -+ g_debug ("GdmGreeterLoginWindow: user now authorized via service %s", -+ service_name); - -- gdm_greeter_login_window_start_session_when_ready (login_window); -+ gdm_greeter_login_window_start_session_when_ready (login_window, -+ service_name); - } - - static void -@@ -1008,6 +1286,49 @@ on_user_chooser_visibility_changed (GdmGreeterLoginWindow *login_window) - update_banner_message (login_window); - } - -+static gboolean -+begin_task_verification_for_selected_user (GdmTaskList *task_list, -+ GdmTask *task, -+ GdmGreeterLoginWindow *login_window) -+{ -+ char *user_name; -+ char *service_name; -+ -+ user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser)); -+ -+ if (user_name == NULL) { -+ return TRUE; -+ } -+ -+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task)); -+ if (service_name != NULL) { -+ g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, service_name, user_name); -+ g_free (service_name); -+ } -+ -+ g_free (user_name); -+ return FALSE; -+} -+ -+static void -+enable_waiting_tasks (GdmGreeterLoginWindow *login_window) -+{ -+ GList *node; -+ -+ node = login_window->priv->tasks_to_enable; -+ while (node != NULL) { -+ GdmTask *task; -+ -+ task = GDM_TASK (node->data); -+ -+ gdm_conversation_set_ready (GDM_CONVERSATION (task)); -+ -+ node = node->next; -+ } -+ -+ login_window->priv->tasks_to_enable = NULL; -+} -+ - static void - on_users_loaded (GdmUserChooserWidget *user_chooser, - GdmGreeterLoginWindow *login_window) -@@ -1021,37 +1342,153 @@ on_users_loaded (GdmUserChooserWidget *user_chooser, - gtk_widget_show (login_window->priv->user_chooser); - } - -+ enable_waiting_tasks (login_window); -+ - if (login_window->priv->timed_login_username != NULL - && !login_window->priv->timed_login_already_enabled) { - request_timed_login (login_window); - } else if (can_jump_to_authenticate (login_window)) { -+ - /* jump straight to authenticate */ - g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate"); -- -- switch_mode (login_window, MODE_AUTHENTICATION); -- -- g_debug ("Starting PAM conversation since no local users"); - g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], - 0, GDM_USER_CHOOSER_USER_OTHER); -- g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0); -+ begin_verification (login_window); - } - } - - static void --on_user_chosen (GdmUserChooserWidget *user_chooser, -- GdmGreeterLoginWindow *login_window) -+choose_user (GdmGreeterLoginWindow *login_window, -+ const char *user_name) -+{ -+ g_assert (user_name != NULL); -+ g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name); -+ -+ g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], -+ 0, user_name); -+ -+ -+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ (GdmTaskListForeachFunc) -+ begin_task_verification_for_selected_user, -+ login_window); -+ -+ switch_mode (login_window, MODE_AUTHENTICATION); -+ update_conversation_list_visibility (login_window); -+} -+ -+static void -+begin_auto_login (GdmGreeterLoginWindow *login_window) -+{ -+ g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0, -+ login_window->priv->timed_login_username); -+ -+ login_window->priv->timed_login_enabled = TRUE; -+ restart_timed_login_timeout (login_window); -+ -+ /* just wait for the user to select language and stuff */ -+ set_message (login_window, _("Select language and click Log In")); -+ -+ switch_mode (login_window, MODE_AUTHENTICATION); -+ -+ show_widget (login_window, "conversation-list", FALSE); -+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ (GdmTaskListForeachFunc) reset_task, -+ login_window); -+} -+ -+static gboolean -+reset_task_if_not_given (GdmTaskList *task_list, -+ GdmTask *task, -+ GdmTask *given_task) -+{ -+ if (task == given_task) { -+ return FALSE; -+ } -+ -+ gdm_conversation_reset (GDM_CONVERSATION (task)); -+ return FALSE; -+} -+ -+static void -+reset_every_task_but_given_task (GdmGreeterLoginWindow *login_window, -+ GdmTask *task) -+{ -+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ (GdmTaskListForeachFunc) -+ reset_task_if_not_given, -+ task); -+} -+ -+static void -+begin_single_service_verification (GdmGreeterLoginWindow *login_window, -+ const char *service_name) -+{ -+ GdmTask *task; -+ -+ task = find_task_with_service_name (login_window, service_name); -+ -+ if (task == NULL) { -+ g_debug ("GdmGreeterLoginWindow: %s has no task associated with it", service_name); -+ return; -+ } -+ -+ g_debug ("GdmGreeterLoginWindow: Beginning %s auth conversation", service_name); -+ -+ /* FIXME: we should probably give the plugin more say for -+ * what happens here. -+ */ -+ g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name); -+ -+ switch_mode (login_window, MODE_AUTHENTICATION); -+ gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task); -+ -+ reset_every_task_but_given_task (login_window, task); -+ g_object_unref (task); -+ -+ show_widget (login_window, "conversation-list", FALSE); -+} -+ -+static void -+on_user_chooser_activated (GdmUserChooserWidget *user_chooser, -+ GdmGreeterLoginWindow *login_window) - { - char *user_name; -+ char *item_id; - - user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser)); -- g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name); - -- if (user_name == NULL) { -+ if (user_name != NULL) { -+ g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name); -+ choose_user (login_window, user_name); -+ g_free (user_name); - return; - } - -- choose_user (login_window, user_name); -- g_free (user_name); -+ item_id = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (user_chooser)); -+ g_debug ("GdmGreeterLoginWindow: item chosen '%s'", item_id); -+ -+ g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], -+ 0, item_id); -+ -+ if (strcmp (item_id, GDM_USER_CHOOSER_USER_OTHER) == 0) { -+ g_debug ("GdmGreeterLoginWindow: Starting all auth conversations"); -+ g_free (item_id); -+ -+ begin_verification (login_window); -+ } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_GUEST) == 0) { -+ /* FIXME: handle guest account stuff */ -+ g_free (item_id); -+ } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_AUTO) == 0) { -+ g_debug ("GdmGreeterLoginWindow: Starting auto login"); -+ g_free (item_id); -+ -+ begin_auto_login (login_window); -+ } else { -+ g_debug ("GdmGreeterLoginWindow: Starting single auth conversation"); -+ begin_single_service_verification (login_window, item_id); -+ g_free (item_id); -+ } - } - - static void -@@ -1272,12 +1709,75 @@ create_computer_info (GdmGreeterLoginWindow *login_window) - #define INVISIBLE_CHAR_BULLET 0x2022 - #define INVISIBLE_CHAR_NONE 0 - -+static void -+on_task_activated (GdmGreeterLoginWindow *login_window, -+ GdmTask *task) -+{ -+ GtkWidget *container; -+ char *name; -+ -+ name = gdm_task_get_name (task); -+ g_debug ("GdmGreeterLoginWindow: task '%s' activated", name); -+ g_free (name); -+ -+ container = g_object_get_data (G_OBJECT (task), -+ "gdm-greeter-login-window-page-container"); -+ -+ if (container == NULL) { -+ GtkWidget *page; -+ -+ container = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); -+ gtk_container_add (GTK_CONTAINER (login_window->priv->auth_page_box), -+ container); -+ -+ page = gdm_conversation_get_page (GDM_CONVERSATION (task)); -+ if (page != NULL) { -+ gtk_container_add (GTK_CONTAINER (container), page); -+ gtk_widget_show (page); -+ } -+ g_object_set_data (G_OBJECT (task), -+ "gdm-greeter-login-window-page-container", -+ container); -+ } -+ -+ gtk_widget_show (container); -+ switch_mode (login_window, login_window->priv->dialog_mode); -+} -+ -+static void -+on_task_deactivated (GdmGreeterLoginWindow *login_window, -+ GdmTask *task) -+{ -+ GtkWidget *container; -+ char *name; -+ GtkActionGroup *actions; -+ -+ name = gdm_task_get_name (task); -+ g_debug ("GdmGreeterLoginWindow: task '%s' now in background", name); -+ g_free (name); -+ -+ container = g_object_get_data (G_OBJECT (task), -+ "gdm-greeter-login-window-page-container"); -+ -+ if (container != NULL) { -+ gtk_widget_hide (container); -+ } -+ -+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task)); -+ -+ if (actions != NULL) { -+ gtk_action_group_set_sensitive (actions, FALSE); -+ gtk_action_group_set_visible (actions, FALSE); -+ g_object_unref (actions); -+ } -+} - - static void - register_custom_types (GdmGreeterLoginWindow *login_window) - { - GType types[] = { GDM_TYPE_USER_CHOOSER_WIDGET, -- GDM_TYPE_SESSION_OPTION_WIDGET }; -+ GDM_TYPE_SESSION_OPTION_WIDGET, -+ GDM_TYPE_TASK_LIST }; - int i; - - for (i = 0; i < G_N_ELEMENTS (types); i++) { -@@ -1288,7 +1788,6 @@ register_custom_types (GdmGreeterLoginWindow *login_window) - static void - load_theme (GdmGreeterLoginWindow *login_window) - { -- GtkWidget *entry; - GtkWidget *button; - GtkWidget *box; - GtkWidget *image; -@@ -1341,7 +1840,7 @@ load_theme (GdmGreeterLoginWindow *login_window) - login_window); - g_signal_connect (login_window->priv->user_chooser, - "activated", -- G_CALLBACK (on_user_chosen), -+ G_CALLBACK (on_user_chooser_activated), - login_window); - g_signal_connect (login_window->priv->user_chooser, - "deactivated", -@@ -1360,30 +1859,30 @@ load_theme (GdmGreeterLoginWindow *login_window) - G_CALLBACK (on_session_activated), - login_window); - -+ login_window->priv->conversation_list = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "task-list")); -+ -+ g_signal_connect_swapped (GDM_TASK_LIST (login_window->priv->conversation_list), -+ "activated", -+ G_CALLBACK (on_task_activated), -+ login_window); -+ g_signal_connect_swapped (GDM_TASK_LIST (login_window->priv->conversation_list), -+ "deactivated", -+ G_CALLBACK (on_task_deactivated), -+ login_window); -+ - login_window->priv->auth_banner_label = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-banner-label")); - /*make_label_small_italic (login_window->priv->auth_banner_label);*/ -+ login_window->priv->auth_page_box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-page-box")); - - button = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "cancel-button")); - g_signal_connect (button, "clicked", G_CALLBACK (cancel_button_clicked), login_window); - -- entry = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-prompt-entry")); -- /* Only change the invisible character if it '*' otherwise assume it is OK */ -- if ('*' == gtk_entry_get_invisible_char (GTK_ENTRY (entry))) { -- gunichar invisible_char; -- invisible_char = INVISIBLE_CHAR_BLACK_CIRCLE; -- gtk_entry_set_invisible_char (GTK_ENTRY (entry), invisible_char); -- } -- - create_computer_info (login_window); - - box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "computer-info-event-box")); - g_signal_connect (box, "button-press-event", G_CALLBACK (on_computer_info_label_button_press), login_window); - -- if (login_window->priv->user_list_disabled) { -- switch_mode (login_window, MODE_AUTHENTICATION); -- } else { -- switch_mode (login_window, MODE_SELECTION); -- } -+ switch_mode (login_window, MODE_SELECTION); - - gdm_profile_end (NULL); - } -@@ -1580,6 +2079,15 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass) - - gtk_container_class_handle_border_width (container_class); - -+ signals [START_CONVERSATION] = -+ g_signal_new ("start-conversation", -+ G_TYPE_FROM_CLASS (object_class), -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, start_conversation), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__STRING, -+ G_TYPE_NONE, 1, G_TYPE_STRING); - signals [BEGIN_AUTO_LOGIN] = - g_signal_new ("begin-auto-login", - G_TYPE_FROM_CLASS (object_class), -@@ -1596,9 +2104,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass) - G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, begin_verification), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, G_TYPE_STRING); - signals [BEGIN_VERIFICATION_FOR_USER] = - g_signal_new ("begin-verification-for-user", - G_TYPE_FROM_CLASS (object_class), -@@ -1606,9 +2114,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass) - G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, begin_verification_for_user), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, G_TYPE_STRING); -+ 2, G_TYPE_STRING, G_TYPE_STRING); - signals [QUERY_ANSWER] = - g_signal_new ("query-answer", - G_TYPE_FROM_CLASS (object_class), -@@ -1616,9 +2124,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass) - G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, query_answer), - NULL, - NULL, -- g_cclosure_marshal_VOID__STRING, -+ gdm_marshal_VOID__STRING_STRING, - G_TYPE_NONE, -- 1, G_TYPE_STRING); -+ 2, G_TYPE_STRING, G_TYPE_STRING); - signals [USER_SELECTED] = - g_signal_new ("user-selected", - G_TYPE_FROM_CLASS (object_class), -@@ -1656,9 +2164,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass) - G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, start_session), - NULL, - NULL, -- g_cclosure_marshal_VOID__VOID, -+ g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, -- 0); -+ 1, G_TYPE_STRING); - - g_object_class_install_property (object_class, - PROP_DISPLAY_IS_LOCAL, -@@ -1711,6 +2219,246 @@ on_gconf_key_changed (GConfClient *client, - } - } - -+static void -+on_conversation_answer (GdmGreeterLoginWindow *login_window, -+ const char *text, -+ GdmConversation *conversation) -+{ -+ if (text != NULL) { -+ char *service_name; -+ -+ service_name = gdm_conversation_get_service_name (conversation); -+ if (service_name != NULL) { -+ g_signal_emit (login_window, signals[QUERY_ANSWER], 0, service_name, text); -+ g_free (service_name); -+ } -+ } -+ -+ set_sensitive (login_window, TRUE); -+ set_ready (login_window); -+} -+ -+static void -+on_conversation_cancel (GdmGreeterLoginWindow *login_window, -+ GdmConversation *conversation) -+{ -+ do_cancel (login_window); -+} -+ -+static gboolean -+on_conversation_chose_user (GdmGreeterLoginWindow *login_window, -+ const char *username, -+ GdmConversation *conversation) -+{ -+ if (!gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) { -+ char *name; -+ -+ name = gdm_task_get_name (GDM_TASK (conversation)); -+ g_warning ("Task %s is trying to choose user before list is loaded", name); -+ g_free (name); -+ return FALSE; -+ } -+ -+ /* If we're already authenticating then we can't pick a user -+ */ -+ if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) { -+ return FALSE; -+ } -+ -+ if (gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ GDM_TASK (conversation))) { -+ gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), -+ username); -+ } -+ -+ return TRUE; -+} -+ -+void -+gdm_greeter_login_window_remove_extension (GdmGreeterLoginWindow *login_window, -+ GdmGreeterExtension *extension) -+{ -+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window)); -+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension)); -+ -+ if (!GDM_IS_CONVERSATION (extension)) { -+ return; -+ } -+} -+ -+static void -+on_button_action_label_changed (GtkWidget *button) -+{ -+ GtkAction *action; -+ char *text; -+ -+ action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (button)); -+ -+ g_object_get (G_OBJECT (action), "label", &text, NULL); -+ -+ gtk_button_set_label (GTK_BUTTON (button), text); -+ g_free (text); -+} -+ -+static void -+on_button_action_icon_name_changed (GtkWidget *button) -+{ -+ GtkAction *action; -+ GtkWidget *image; -+ -+ action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (button)); -+ -+ if (gtk_action_get_is_important (action)) { -+ image = gtk_action_create_icon (GTK_ACTION (action), GTK_ICON_SIZE_BUTTON); -+ } else { -+ image = NULL; -+ } -+ -+ gtk_button_set_image (GTK_BUTTON (button), image); -+ -+} -+ -+static void -+on_button_action_tooltip_changed (GtkWidget *button) -+{ -+ GtkAction *action; -+ char *text; -+ -+ action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (button)); -+ -+ g_object_get (G_OBJECT (action), "tooltip", &text, NULL); -+ -+ gtk_widget_set_tooltip_text (button, text); -+ g_free (text); -+} -+ -+static GtkWidget * -+create_button_from_action (GtkAction *action) -+{ -+ GtkWidget *button; -+ -+ button = gtk_button_new (); -+ -+ gtk_activatable_set_related_action (GTK_ACTIVATABLE (button), action); -+ -+ g_signal_connect_swapped (action, -+ "notify::label", -+ G_CALLBACK (on_button_action_label_changed), -+ button); -+ g_signal_connect_swapped (action, -+ "notify::icon-name", -+ G_CALLBACK (on_button_action_icon_name_changed), -+ button); -+ g_signal_connect_swapped (action, -+ "notify::tooltip", -+ G_CALLBACK (on_button_action_tooltip_changed), -+ button); -+ -+ on_button_action_label_changed (button); -+ on_button_action_icon_name_changed (button); -+ on_button_action_tooltip_changed (button); -+ -+ if (strcmp (gtk_action_get_name (action), -+ GDM_CONVERSATION_DEFAULT_ACTION) == 0) { -+ gtk_widget_set_can_default (button, TRUE); -+ } -+ -+ return button; -+} -+ -+static void -+create_buttons_for_actions (GdmGreeterLoginWindow *login_window, -+ GtkActionGroup *actions) -+{ -+ GList *action_list; -+ GList *node; -+ GtkWidget *box; -+ -+ action_list = gtk_action_group_list_actions (actions); -+ -+ box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "buttonbox")); -+ for (node = action_list; node != NULL; node = node->next) { -+ GtkAction *action; -+ GtkWidget *button; -+ -+ action = node->data; -+ -+ button = create_button_from_action (action); -+ gtk_container_add (GTK_CONTAINER (box), button); -+ } -+ -+ g_list_free (action_list); -+} -+ -+void -+gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window, -+ GdmGreeterExtension *extension) -+{ -+ char *name; -+ char *description; -+ char *service_name; -+ GtkActionGroup *actions; -+ -+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window)); -+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension)); -+ -+ if (!GDM_IS_CONVERSATION (extension)) { -+ return; -+ } -+ -+ name = gdm_task_get_name (GDM_TASK (extension)); -+ description = gdm_task_get_description (GDM_TASK (extension)); -+ -+ if (!gdm_task_is_visible (GDM_TASK (extension))) { -+ g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' won't be added", -+ name, description); -+ g_free (name); -+ g_free (description); -+ return; -+ } -+ -+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (extension)); -+ -+ create_buttons_for_actions (login_window, actions); -+ hide_task_actions (GDM_TASK (extension)); -+ -+ g_object_unref (actions); -+ -+ g_signal_connect_swapped (GDM_CONVERSATION (extension), -+ "answer", -+ G_CALLBACK (on_conversation_answer), -+ login_window); -+ g_signal_connect_swapped (GDM_CONVERSATION (extension), -+ "cancel", -+ G_CALLBACK (on_conversation_cancel), -+ login_window); -+ g_signal_connect_swapped (GDM_CONVERSATION (extension), -+ "user-chosen", -+ G_CALLBACK (on_conversation_chose_user), -+ login_window); -+ -+ g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added", -+ name, description); -+ -+ gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ GDM_TASK (extension)); -+ -+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (extension)); -+ -+ if (gdm_task_is_choosable (GDM_TASK (extension))) { -+ gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser), -+ service_name, NULL, name, description, ~0, -+ FALSE, TRUE, NULL, NULL); -+ } -+ -+ g_free (name); -+ g_free (description); -+ -+ g_debug ("GdmGreeterLoginWindow: starting conversation with '%s'", service_name); -+ g_signal_emit (login_window, signals[START_CONVERSATION], 0, service_name); -+ g_free (service_name); -+} -+ - static gboolean - on_window_state_event (GtkWidget *widget, - GdkEventWindowState *event, -diff --git a/gui/simple-greeter/gdm-greeter-login-window.h b/gui/simple-greeter/gdm-greeter-login-window.h -index c8b1167..bcdfbd7 100644 ---- a/gui/simple-greeter/gdm-greeter-login-window.h -+++ b/gui/simple-greeter/gdm-greeter-login-window.h -@@ -23,6 +23,9 @@ - #define __GDM_GREETER_LOGIN_WINDOW_H - - #include -+#include "gdm-conversation.h" -+#include "gdm-task.h" -+#include "gdm-greeter-extension.h" - - G_BEGIN_DECLS - -@@ -33,6 +36,8 @@ G_BEGIN_DECLS - #define GDM_IS_GREETER_LOGIN_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_GREETER_LOGIN_WINDOW)) - #define GDM_GREETER_LOGIN_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_GREETER_LOGIN_WINDOW, GdmGreeterLoginWindowClass)) - -+#define GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION(e) (GDM_IS_CONVERSATION(e) && GDM_IS_TASK(e)) -+ - typedef struct GdmGreeterLoginWindowPrivate GdmGreeterLoginWindowPrivate; - - typedef struct -@@ -46,12 +51,17 @@ typedef struct - GtkWindowClass parent_class; - - /* signals */ -+ void (* start_conversation) (GdmGreeterLoginWindow *login_window, -+ const char *service_name); - void (* begin_auto_login) (GdmGreeterLoginWindow *login_window, - const char *username); -- void (* begin_verification) (GdmGreeterLoginWindow *login_window); -+ void (* begin_verification) (GdmGreeterLoginWindow *login_window, -+ const char *service_name); - void (* begin_verification_for_user) (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *username); - void (* query_answer) (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *text); - void (* user_selected) (GdmGreeterLoginWindow *login_window, - const char *text); -@@ -67,23 +77,38 @@ GtkWidget * gdm_greeter_login_window_new (gboolean displa - - - gboolean gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window); --gboolean gdm_greeter_login_window_authentication_failed (GdmGreeterLoginWindow *login_window); --gboolean gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window); -+gboolean gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window, -+ const char *service_name); -+gboolean gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window, -+ const char *service_name); - gboolean gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *text); - gboolean gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *text); - gboolean gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *text); - gboolean gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *text); - void gdm_greeter_login_window_set_default_session_name (GdmGreeterLoginWindow *login_window, - const char *text); - -+gboolean gdm_greeter_login_window_service_unavailable (GdmGreeterLoginWindow *login_window, -+ const char *service_name); -+ - void gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_window, - const char *username, - int delay); --void gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window); -+void gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window, -+ const char *service_name); -+ -+void gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window, -+ GdmGreeterExtension *extension); -+void gdm_greeter_login_window_remove_extension (GdmGreeterLoginWindow *login_window, -+ GdmGreeterExtension *extension); - - G_END_DECLS - -diff --git a/gui/simple-greeter/gdm-greeter-login-window.ui b/gui/simple-greeter/gdm-greeter-login-window.ui -index 4f6bed4..64ba0b7 100644 ---- a/gui/simple-greeter/gdm-greeter-login-window.ui -+++ b/gui/simple-greeter/gdm-greeter-login-window.ui -@@ -158,69 +158,40 @@ - - - True -- 10 -+ 2 - -- -- False -- -- -- True -- True -- 0 -- -- -- -- -+ - True -- 6 -+ 1.0 -+ 0.0 - -- -- True -- -- -- -- -+ -+ False - -- -- False -- False -- 0 -- -- -- -- -- True -- True -- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK -- True -- -- -- -- -- -- 1 -- -- -- -- - - - - False - False -+ 0 -+ -+ -+ -+ -+ False -+ -+ -+ True -+ True - 1 - - - -- -+ - True -+ 10 - -- -- True -- -- -- 0 -- -+ - - - -diff --git a/gui/simple-greeter/gdm-greeter-plugin.c b/gui/simple-greeter/gdm-greeter-plugin.c -new file mode 100644 -index 0000000..1919aae ---- /dev/null -+++ b/gui/simple-greeter/gdm-greeter-plugin.c -@@ -0,0 +1,254 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Written by: Ray Strode -+ */ -+ -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "gdm-greeter-extension.h" -+#include "gdm-greeter-plugin.h" -+ -+#define GDM_GREETER_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_GREETER_PLUGIN, GdmGreeterPluginPrivate)) -+ -+enum { -+ PROP_0, -+ PROP_FILENAME, -+}; -+ -+enum { -+ LOADED, -+ LOAD_FAILED, -+ UNLOADED, -+ LAST_SIGNAL -+}; -+ -+struct _GdmGreeterPluginPrivate { -+ GObject parent; -+ -+ GModule *module; -+ char *filename; -+ -+ GdmGreeterExtension *extension; -+}; -+ -+static void gdm_greeter_plugin_finalize (GObject *object); -+ -+static guint signals[LAST_SIGNAL] = { 0 }; -+ -+G_DEFINE_TYPE (GdmGreeterPlugin, gdm_greeter_plugin, G_TYPE_OBJECT) -+ -+static void -+gdm_greeter_plugin_set_property (GObject *object, -+ guint param_id, -+ const GValue *value, -+ GParamSpec *pspec) -+{ -+ GdmGreeterPlugin *plugin; -+ -+ plugin = GDM_GREETER_PLUGIN (object); -+ switch (param_id) { -+ case PROP_FILENAME: -+ plugin->priv->filename = g_strdup (g_value_get_string (value)); -+ break; -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); -+ break; -+ } -+} -+ -+static void -+gdm_greeter_plugin_get_property (GObject *object, -+ guint param_id, -+ GValue *value, -+ GParamSpec *pspec) -+{ -+ GdmGreeterPlugin *plugin; -+ -+ plugin = GDM_GREETER_PLUGIN (object); -+ -+ switch (param_id) { -+ case PROP_FILENAME: -+ g_value_set_string (value, plugin->priv->filename); -+ break; -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); -+ break; -+ } -+} -+ -+static void -+gdm_greeter_plugin_class_init (GdmGreeterPluginClass *class) -+{ -+ GObjectClass *gobject_class; -+ -+ gobject_class = G_OBJECT_CLASS (class); -+ -+ gobject_class->set_property = gdm_greeter_plugin_set_property; -+ gobject_class->get_property = gdm_greeter_plugin_get_property; -+ gobject_class->finalize = gdm_greeter_plugin_finalize; -+ -+ g_object_class_install_property (gobject_class, -+ PROP_FILENAME, -+ g_param_spec_string ("filename", -+ "Filename", -+ "The full path to the plugin.", -+ NULL, -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -+ -+ signals [LOADED] = -+ g_signal_new ("loaded", -+ G_TYPE_FROM_CLASS (class), -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (GdmGreeterPluginClass, loaded), -+ NULL, NULL, -+ g_cclosure_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); -+ signals [LOAD_FAILED] = -+ g_signal_new ("load-failed", -+ G_TYPE_FROM_CLASS (class), -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (GdmGreeterPluginClass, load_failed), -+ NULL, NULL, -+ g_cclosure_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); -+ signals [UNLOADED] = -+ g_signal_new ("unloaded", -+ G_TYPE_FROM_CLASS (class), -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (GdmGreeterPluginClass, unloaded), -+ NULL, NULL, -+ g_cclosure_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); -+ -+ g_type_class_add_private (class, sizeof (GdmGreeterPluginPrivate)); -+} -+ -+GdmGreeterPlugin * -+gdm_greeter_plugin_new (const char *filename) -+{ -+ GObject *object; -+ -+ object = g_object_new (GDM_TYPE_GREETER_PLUGIN, -+ "filename", filename, NULL); -+ -+ return GDM_GREETER_PLUGIN (object); -+} -+ -+void -+gdm_greeter_plugin_load (GdmGreeterPlugin *plugin) -+{ -+ GModule *module; -+ GdmGreeterExtension *extension; -+ union { -+ gpointer symbol; -+ GdmGreeterPluginGetExtensionFunc invoke; -+ } get_extension; -+ -+ -+ module = g_module_open (plugin->priv->filename, G_MODULE_BIND_LOCAL); -+ -+ if (module == NULL) { -+ g_warning ("plugin %s couldn't be opened: %s", -+ plugin->priv->filename, -+ g_module_error ()); -+ g_signal_emit (plugin, signals [LOAD_FAILED], 0); -+ return; -+ } -+ -+ if (!g_module_symbol (module, -+ "gdm_greeter_plugin_get_extension", -+ &get_extension.symbol) || -+ !get_extension.symbol) { -+ g_warning ("plugin %s lacks gdm_greeter_plugin_get_extension()", -+ plugin->priv->filename); -+ g_module_close (module); -+ g_signal_emit (plugin, signals [LOAD_FAILED], 0); -+ return; -+ } -+ -+ extension = get_extension.invoke (); -+ -+ if (!extension) { -+ g_warning ("plugin %s didn't return extension when asked", -+ plugin->priv->filename); -+ g_module_close (module); -+ g_signal_emit (plugin, signals [LOAD_FAILED], 0); -+ } -+ -+ if (!GDM_IS_GREETER_EXTENSION (extension)) { -+ g_warning ("plugin %s returned bogus extension when asked", -+ plugin->priv->filename); -+ g_module_close (module); -+ g_signal_emit (plugin, signals [LOAD_FAILED], 0); -+ } -+ -+ plugin->priv->module = module; -+ plugin->priv->extension = extension; -+ -+ g_signal_emit (plugin, signals [LOADED], 0); -+} -+ -+void -+gdm_greeter_plugin_unload (GdmGreeterPlugin *plugin) -+{ -+ if (plugin->priv->extension != NULL) { -+ g_object_unref (plugin->priv->extension); -+ plugin->priv->extension = NULL; -+ } -+ -+ if (plugin->priv->module != NULL) { -+ g_module_close (plugin->priv->module); -+ plugin->priv->module = NULL; -+ } -+} -+ -+const char * -+gdm_greeter_plugin_get_filename (GdmGreeterPlugin *plugin) -+{ -+ return plugin->priv->filename; -+} -+ -+GdmGreeterExtension * -+gdm_greeter_plugin_get_extension (GdmGreeterPlugin *plugin) -+{ -+ return g_object_ref (plugin->priv->extension); -+} -+ -+static void -+gdm_greeter_plugin_init (GdmGreeterPlugin *plugin) -+{ -+ plugin->priv = GDM_GREETER_PLUGIN_GET_PRIVATE (plugin); -+} -+ -+static void -+gdm_greeter_plugin_finalize (GObject *object) -+{ -+ GdmGreeterPlugin *plugin; -+ -+ plugin = GDM_GREETER_PLUGIN (object); -+ -+ gdm_greeter_plugin_unload (plugin); -+} -diff --git a/gui/simple-greeter/gdm-greeter-plugin.h b/gui/simple-greeter/gdm-greeter-plugin.h -new file mode 100644 -index 0000000..904c231 ---- /dev/null -+++ b/gui/simple-greeter/gdm-greeter-plugin.h -@@ -0,0 +1,61 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#ifndef __GDM_GREETER_PLUGIN -+#define __GDM_GREETER_PLUGIN -+ -+#include -+#include -+ -+#include "gdm-greeter-extension.h" -+ -+G_BEGIN_DECLS -+ -+#define GDM_TYPE_GREETER_PLUGIN (gdm_greeter_plugin_get_type ()) -+#define GDM_GREETER_PLUGIN(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDM_TYPE_GREETER_PLUGIN, GdmGreeterPlugin)) -+#define GDM_IS_GREETER_PLUGIN(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDM_TYPE_GREETER_PLUGIN)) -+ -+typedef struct _GdmGreeterPlugin GdmGreeterPlugin; -+typedef struct _GdmGreeterPluginPrivate GdmGreeterPluginPrivate; -+typedef struct _GdmGreeterPluginClass GdmGreeterPluginClass; -+ -+struct _GdmGreeterPlugin -+{ -+ GObject parent; -+ GdmGreeterPluginPrivate *priv; -+}; -+ -+struct _GdmGreeterPluginClass -+{ -+ GObjectClass parent_class; -+ -+ void (* loaded) (GdmGreeterPlugin *plugin); -+ void (* load_failed) (GdmGreeterPlugin *plugin); -+ void (* unloaded) (GdmGreeterPlugin *plugin); -+}; -+ -+GType gdm_greeter_plugin_get_type (void) G_GNUC_CONST; -+GdmGreeterPlugin *gdm_greeter_plugin_new (const char *filename); -+void gdm_greeter_plugin_load (GdmGreeterPlugin *plugin); -+void gdm_greeter_plugin_unload (GdmGreeterPlugin *plugin); -+const char *gdm_greeter_plugin_get_filename (GdmGreeterPlugin *plugin); -+GdmGreeterExtension *gdm_greeter_plugin_get_extension (GdmGreeterPlugin *plugin); -+ -+G_END_DECLS -+ -+#endif -diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c -index 16f8db5..a802770 100644 ---- a/gui/simple-greeter/gdm-greeter-session.c -+++ b/gui/simple-greeter/gdm-greeter-session.c -@@ -39,6 +39,8 @@ - #include "gdm-greeter-login-window.h" - #include "gdm-user-chooser-widget.h" - -+#include "gdm-plugin-manager.h" -+ - #include "gdm-profile.h" - - #define GDM_GREETER_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_GREETER_SESSION, GdmGreeterSessionPrivate)) -@@ -48,6 +50,7 @@ - struct GdmGreeterSessionPrivate - { - GdmGreeterClient *client; -+ GdmPluginManager *plugin_manager; - - GtkWidget *login_window; - GtkWidget *panel; -@@ -75,7 +78,7 @@ on_info (GdmGreeterClient *client, - { - g_debug ("GdmGreeterSession: Info: %s", text); - -- gdm_greeter_login_window_info (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text); -+ gdm_greeter_login_window_info (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text); - } - - static void -@@ -86,7 +89,17 @@ on_problem (GdmGreeterClient *client, - { - g_debug ("GdmGreeterSession: Problem: %s", text); - -- gdm_greeter_login_window_problem (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text); -+ gdm_greeter_login_window_problem (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text); -+} -+ -+static void -+on_service_unavailable (GdmGreeterClient *client, -+ const char *service_name, -+ GdmGreeterSession *session) -+{ -+ g_debug ("GdmGreeterSession: Service Unavailable: %s", service_name); -+ -+ gdm_greeter_login_window_service_unavailable (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name); - } - - static void -@@ -96,40 +109,30 @@ on_ready (GdmGreeterClient *client, - { - g_debug ("GdmGreeterSession: Ready"); - -- gdm_greeter_login_window_ready (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window)); -+ gdm_greeter_login_window_ready (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), -+ service_name); - } - - static void --on_reset (GdmGreeterClient *client, -- GdmGreeterSession *session) -+on_conversation_stopped (GdmGreeterClient *client, -+ const char *service_name, -+ GdmGreeterSession *session) - { -- g_debug ("GdmGreeterSession: Reset"); -+ g_debug ("GdmGreeterSession: Conversation '%s' stopped", service_name); - -- session->priv->num_tries = 0; -- -- gdm_greeter_login_window_reset (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window)); -+ gdm_greeter_login_window_conversation_stopped (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), -+ service_name); - } - - static void --on_authentication_failed (GdmGreeterClient *client, -- GdmGreeterSession *session) -+on_reset (GdmGreeterClient *client, -+ GdmGreeterSession *session) - { -- g_debug ("GdmGreeterSession: Authentication failed"); -- -- session->priv->num_tries++; -- -- if (session->priv->num_tries < MAX_LOGIN_TRIES) { -- g_debug ("GdmGreeterSession: Retrying login (%d)", -- session->priv->num_tries); -+ g_debug ("GdmGreeterSession: Reset"); - -- gdm_greeter_login_window_authentication_failed (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window)); -- } else { -- g_debug ("GdmGreeterSession: Maximum number of login tries exceeded (%d) - resetting", -- session->priv->num_tries - 1); -- session->priv->num_tries = 0; -+ session->priv->num_tries = 0; - -- gdm_greeter_login_window_reset (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window)); -- } -+ gdm_greeter_login_window_reset (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window)); - } - - static void -@@ -181,10 +184,11 @@ on_timed_login_requested (GdmGreeterClient *client, - - static void - on_user_authorized (GdmGreeterClient *client, -+ const char *service_name, - GdmGreeterSession *session) - { - g_debug ("GdmGreeterSession: user authorized"); -- gdm_greeter_login_window_user_authorized (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window)); -+ gdm_greeter_login_window_user_authorized (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name); - } - - static void -@@ -195,7 +199,7 @@ on_info_query (GdmGreeterClient *client, - { - g_debug ("GdmGreeterSession: Info query: %s", text); - -- gdm_greeter_login_window_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text); -+ gdm_greeter_login_window_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text); - } - - static void -@@ -206,10 +210,18 @@ on_secret_info_query (GdmGreeterClient *client, - { - g_debug ("GdmGreeterSession: Secret info query: %s", text); - -- gdm_greeter_login_window_secret_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text); -+ gdm_greeter_login_window_secret_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text); - } - - static void -+on_start_conversation (GdmGreeterLoginWindow *login_window, -+ const char *service_name, -+ GdmGreeterSession *session) -+{ -+ gdm_greeter_client_call_start_conversation (session->priv->client, -+ service_name); -+} -+static void - on_begin_auto_login (GdmGreeterLoginWindow *login_window, - const char *username, - GdmGreeterSession *session) -@@ -220,29 +232,32 @@ on_begin_auto_login (GdmGreeterLoginWindow *login_window, - - static void - on_begin_verification (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - GdmGreeterSession *session) - { - gdm_greeter_client_call_begin_verification (session->priv->client, -- "gdm"); -+ service_name); - } - - static void - on_begin_verification_for_user (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *username, - GdmGreeterSession *session) - { - gdm_greeter_client_call_begin_verification_for_user (session->priv->client, -- "gdm", -+ service_name, - username); - } - - static void - on_query_answer (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - const char *text, - GdmGreeterSession *session) - { - gdm_greeter_client_call_answer_query (session->priv->client, -- "gdm", -+ service_name, - text); - } - -@@ -278,7 +293,6 @@ on_cancelled (GdmGreeterLoginWindow *login_window, - GdmGreeterSession *session) - { - gdm_greeter_client_call_cancel (session->priv->client); -- gdm_greeter_client_call_start_conversation (session->priv->client, "gdm"); - } - - static void -@@ -289,9 +303,10 @@ on_disconnected (GdmGreeterSession *session) - - static void - on_start_session (GdmGreeterLoginWindow *login_window, -+ const char *service_name, - GdmGreeterSession *session) - { -- gdm_greeter_client_call_start_session_when_ready (session->priv->client, "gdm", TRUE); -+ gdm_greeter_client_call_start_session_when_ready (session->priv->client, service_name, TRUE); - } - - static int -@@ -376,7 +391,10 @@ toggle_login_window (GdmGreeterSession *session, - is_local = gdm_greeter_client_get_display_is_local (session->priv->client); - g_debug ("GdmGreeterSession: Starting a login window local:%d", is_local); - session->priv->login_window = gdm_greeter_login_window_new (is_local); -- -+ g_signal_connect (session->priv->login_window, -+ "start-conversation", -+ G_CALLBACK (on_start_conversation), -+ session); - g_signal_connect (session->priv->login_window, - "begin-auto-login", - G_CALLBACK (on_begin_auto_login), -@@ -432,8 +450,6 @@ gdm_greeter_session_start (GdmGreeterSession *session, - toggle_panel (session, TRUE); - toggle_login_window (session, TRUE); - -- gdm_greeter_client_call_start_conversation (session->priv->client, "gdm"); -- - gdm_profile_end (NULL); - - return res; -@@ -543,6 +559,64 @@ gdm_greeter_session_event_handler (GdkEvent *event, - } - - static void -+on_plugins_loaded (GdmGreeterSession *session) -+{ -+ g_debug ("GdmGreeterSession: done loading plugins"); -+} -+ -+static void -+on_plugin_removed (GdmGreeterSession *session, -+ GdmGreeterPlugin *plugin) -+{ -+ GdmGreeterExtension *extension; -+ -+ extension = gdm_greeter_plugin_get_extension (plugin); -+ -+ if (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension)) { -+ gdm_greeter_login_window_remove_extension (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), extension); -+ } -+ g_object_unref (extension); -+} -+ -+static void -+on_plugin_added (GdmGreeterSession *session, -+ GdmGreeterPlugin *plugin) -+{ -+ GdmGreeterExtension *extension; -+ -+ extension = gdm_greeter_plugin_get_extension (plugin); -+ -+ if (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension)) { -+ gdm_greeter_login_window_add_extension (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), extension); -+ } -+ g_object_unref (extension); -+} -+ -+static void -+load_plugins (GdmGreeterSession *session) -+{ -+ g_debug ("GdmGreeterSession: loading plugins"); -+ -+ session->priv->plugin_manager = gdm_plugin_manager_ref_default (); -+ -+ g_signal_connect_swapped (session->priv->plugin_manager, -+ "plugins-loaded", -+ G_CALLBACK (on_plugins_loaded), -+ session); -+ -+ g_signal_connect_swapped (session->priv->plugin_manager, -+ "plugin-added", -+ G_CALLBACK (on_plugin_added), -+ session); -+ -+ g_signal_connect_swapped (session->priv->plugin_manager, -+ "plugin-removed", -+ G_CALLBACK (on_plugin_removed), -+ session); -+ -+} -+ -+static void - gdm_greeter_session_init (GdmGreeterSession *session) - { - gdm_profile_start (NULL); -@@ -567,16 +641,20 @@ gdm_greeter_session_init (GdmGreeterSession *session) - G_CALLBACK (on_problem), - session); - g_signal_connect (session->priv->client, -+ "service-unavailable", -+ G_CALLBACK (on_service_unavailable), -+ session); -+ g_signal_connect (session->priv->client, - "ready", - G_CALLBACK (on_ready), - session); - g_signal_connect (session->priv->client, -- "reset", -- G_CALLBACK (on_reset), -+ "conversation-stopped", -+ G_CALLBACK (on_conversation_stopped), - session); - g_signal_connect (session->priv->client, -- "authentication-failed", -- G_CALLBACK (on_authentication_failed), -+ "reset", -+ G_CALLBACK (on_reset), - session); - g_signal_connect (session->priv->client, - "selected-user-changed", -@@ -605,6 +683,8 @@ gdm_greeter_session_init (GdmGreeterSession *session) - gdk_event_handler_set ((GdkEventFunc) gdm_greeter_session_event_handler, - session, NULL); - -+ -+ load_plugins (session); - gdm_profile_end (NULL); - } - -diff --git a/gui/simple-greeter/gdm-plugin-manager.c b/gui/simple-greeter/gdm-plugin-manager.c -new file mode 100644 -index 0000000..49e442c ---- /dev/null -+++ b/gui/simple-greeter/gdm-plugin-manager.c -@@ -0,0 +1,478 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ */ -+ -+#include "config.h" -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "gdm-plugin-manager.h" -+#include "gdm-greeter-extension.h" -+ -+#define GDM_PLUGIN_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManagerPrivate)) -+ -+typedef struct -+{ -+ GModule *module; -+ char *filename; -+ GdmGreeterExtension *extension; -+} GdmPluginManagerPlugin; -+ -+typedef struct -+{ -+ GdmPluginManager *manager; -+ GCancellable *cancellable; -+} GdmPluginManagerOperation; -+ -+struct GdmPluginManagerPrivate -+{ -+ GHashTable *plugins; -+ -+ GFileMonitor *plugin_dir_monitor; -+ GList *pending_operations; -+}; -+ -+enum { -+ PLUGINS_LOADED, -+ PLUGIN_ADDED, -+ PLUGIN_REMOVED, -+ LAST_SIGNAL -+}; -+ -+static guint signals [LAST_SIGNAL] = { 0, }; -+ -+static void gdm_plugin_manager_class_init (GdmPluginManagerClass *klass); -+static void gdm_plugin_manager_init (GdmPluginManager *plugin_manager); -+static void gdm_plugin_manager_finalize (GObject *object); -+ -+static GObject *plugin_manager_object = NULL; -+ -+G_DEFINE_TYPE (GdmPluginManager, gdm_plugin_manager, G_TYPE_OBJECT) -+ -+static GdmPluginManagerOperation * -+start_operation (GdmPluginManager *manager) -+{ -+ GdmPluginManagerOperation *operation; -+ -+ operation = g_new0 (GdmPluginManagerOperation, 1); -+ operation->cancellable = g_cancellable_new (); -+ operation->manager = manager; -+ -+ return operation; -+} -+ -+static void -+free_operation (GdmPluginManagerOperation *operation) -+{ -+ if (operation->cancellable != NULL) { -+ g_object_unref (operation->cancellable); -+ operation->cancellable = NULL; -+ } -+ g_free (operation); -+} -+ -+static void -+cancel_operation (GdmPluginManagerOperation *operation) -+{ -+ if (operation->cancellable != NULL && -+ !g_cancellable_is_cancelled (operation->cancellable)) { -+ g_cancellable_cancel (operation->cancellable); -+ } -+ -+ free_operation (operation); -+} -+ -+static void -+gdm_plugin_manager_track_operation (GdmPluginManager *manager, -+ GdmPluginManagerOperation *operation) -+{ -+ manager->priv->pending_operations = -+ g_list_prepend (manager->priv->pending_operations, operation); -+} -+ -+static void -+gdm_plugin_manager_untrack_operation (GdmPluginManager *manager, -+ GdmPluginManagerOperation *operation) -+{ -+ manager->priv->pending_operations = -+ g_list_remove (manager->priv->pending_operations, operation); -+} -+ -+static void -+gdm_plugin_manager_cancel_pending_operations (GdmPluginManager *manager) -+{ -+ GList *node; -+ -+ node = manager->priv->pending_operations; -+ while (node != NULL) { -+ GList *next_node; -+ GdmPluginManagerOperation *operation; -+ -+ operation = node->data; -+ next_node = node->next; -+ -+ cancel_operation (operation); -+ manager->priv->pending_operations = -+ g_list_delete_link (manager->priv->pending_operations, -+ node); -+ -+ node = next_node; -+ } -+} -+ -+static void -+gdm_plugin_manager_class_init (GdmPluginManagerClass *klass) -+{ -+ GObjectClass *object_class = G_OBJECT_CLASS (klass); -+ -+ object_class->finalize = gdm_plugin_manager_finalize; -+ -+ signals [PLUGINS_LOADED] = -+ g_signal_new ("plugins-loaded", -+ G_TYPE_FROM_CLASS (klass), -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (GdmPluginManagerClass, plugins_loaded), -+ NULL, NULL, -+ g_cclosure_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); -+ signals [PLUGIN_ADDED] = -+ g_signal_new ("plugin-added", -+ G_TYPE_FROM_CLASS (klass), -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (GdmPluginManagerClass, plugin_added), -+ NULL, NULL, -+ g_cclosure_marshal_VOID__OBJECT, -+ G_TYPE_NONE, 1, GDM_TYPE_GREETER_PLUGIN); -+ signals [PLUGIN_REMOVED] = -+ g_signal_new ("plugin-removed", -+ G_TYPE_FROM_CLASS (klass), -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (GdmPluginManagerClass, plugin_removed), -+ NULL, NULL, -+ g_cclosure_marshal_VOID__OBJECT, -+ G_TYPE_NONE, 1, GDM_TYPE_GREETER_PLUGIN); -+ -+ g_type_class_add_private (klass, sizeof (GdmPluginManagerPrivate)); -+} -+ -+static void -+on_plugin_loaded (GdmPluginManager *manager, -+ GdmGreeterPlugin *plugin) -+{ -+ g_debug ("GdmPluginManager: plugin '%s' loaded.", -+ gdm_greeter_plugin_get_filename (plugin)); -+ g_signal_emit (manager, signals [PLUGIN_ADDED], 0, plugin); -+} -+ -+static void -+on_plugin_load_failed (GdmPluginManager *manager, -+ GdmGreeterPlugin *plugin) -+{ -+ const char *filename; -+ -+ g_debug ("GdmPluginManager: plugin '%s' could not be loaded.", -+ gdm_greeter_plugin_get_filename (plugin)); -+ filename = gdm_greeter_plugin_get_filename (plugin); -+ g_hash_table_remove (manager->priv->plugins, filename); -+} -+ -+static void -+on_plugin_unloaded (GdmPluginManager *manager, -+ GdmGreeterPlugin *plugin) -+{ -+ const char *filename; -+ -+ filename = gdm_greeter_plugin_get_filename (plugin); -+ g_hash_table_remove (manager->priv->plugins, filename); -+} -+ -+static void -+load_plugin (GdmPluginManager *manager, -+ const char *filename) -+{ -+ GdmGreeterPlugin *plugin; -+ -+ g_debug ("GdmPluginManager: loading plugin '%s'", filename); -+ -+ plugin = gdm_greeter_plugin_new (filename); -+ -+ g_signal_connect_swapped (plugin, "loaded", -+ G_CALLBACK (on_plugin_loaded), -+ manager); -+ g_signal_connect_swapped (plugin, "load-failed", -+ G_CALLBACK (on_plugin_load_failed), -+ manager); -+ g_signal_connect_swapped (plugin, "unloaded", -+ G_CALLBACK (on_plugin_unloaded), -+ manager); -+ g_hash_table_insert (manager->priv->plugins, -+ g_strdup (filename), plugin); -+ -+ gdm_greeter_plugin_load (plugin); -+} -+ -+static void -+on_plugin_info_read (GFileEnumerator *enumerator, -+ GAsyncResult *result, -+ GdmPluginManagerOperation *operation) -+{ -+ GdmPluginManager *manager; -+ GFile *plugin_dir_file; -+ GList *file_list, *node; -+ GError *error; -+ -+ manager = operation->manager; -+ error = NULL; -+ file_list = g_file_enumerator_next_files_finish (enumerator, -+ result, &error); -+ plugin_dir_file = g_file_enumerator_get_container (enumerator); -+ if (error != NULL) { -+ char *plugin_dir; -+ -+ plugin_dir = g_file_get_parse_name (plugin_dir_file); -+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { -+ g_debug ("GdmPluginManager: Cancelled reading plugin directory %s", -+ plugin_dir); -+ } else { -+ g_warning ("GdmPluginManager: Unable to read plugin directory %s: %s", -+ plugin_dir, error->message); -+ } -+ g_free (plugin_dir); -+ g_error_free (error); -+ g_object_unref (plugin_dir_file); -+ gdm_plugin_manager_untrack_operation (manager, operation); -+ return; -+ } -+ -+#ifndef PLUGIN_ORDERING_FIGURED_OUT -+ node = file_list; -+ while (node != NULL) { -+ GFileInfo *info; -+ GFile *file; -+ char *path; -+ GList *next_node; -+ -+ next_node = node->next; -+ -+ info = (GFileInfo *) node->data; -+ -+ file = g_file_get_child (plugin_dir_file, -+ g_file_info_get_name (info)); -+ path = g_file_get_path (file); -+ -+ if (g_str_has_suffix (path, "password.so")) { -+ file_list = g_list_delete_link (file_list, node); -+ file_list = g_list_prepend (file_list, info); -+ next_node = NULL; -+ } -+ g_free (path); -+ g_object_unref (file); -+ -+ node = next_node; -+ } -+#endif -+ -+ node = file_list; -+ while (node != NULL) { -+ GFileInfo *info; -+ GFile *file; -+ char *path; -+ -+ info = (GFileInfo *) node->data; -+ -+ file = g_file_get_child (plugin_dir_file, -+ g_file_info_get_name (info)); -+ path = g_file_get_path (file); -+ -+ if (g_str_has_suffix (path, G_MODULE_SUFFIX)) { -+ load_plugin (manager, path); -+ } -+ g_free (path); -+ g_object_unref (file); -+ -+ node = node->next; -+ } -+ g_object_unref (plugin_dir_file); -+ -+ gdm_plugin_manager_untrack_operation (manager, operation); -+ g_signal_emit (manager, signals [PLUGINS_LOADED], 0); -+ -+ g_list_free (file_list); -+} -+ -+static void -+on_plugin_dir_opened (GFile *plugin_dir_file, -+ GAsyncResult *result, -+ GdmPluginManagerOperation *open_operation) -+{ -+ GdmPluginManager *manager; -+ GFileEnumerator *enumerator; -+ GError *error; -+ GdmPluginManagerOperation *operation; -+ -+ manager = open_operation->manager; -+ gdm_plugin_manager_untrack_operation (manager, open_operation); -+ -+ error = NULL; -+ enumerator = g_file_enumerate_children_finish (plugin_dir_file, -+ result, &error); -+ -+ if (enumerator == NULL) { -+ char *plugin_dir; -+ -+ plugin_dir = g_file_get_parse_name (plugin_dir_file); -+ -+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { -+ g_debug ("GdmPluginManager: Cancelled opening plugin directory %s", -+ plugin_dir); -+ } else { -+ g_warning ("GdmPluginManager: Unable to open plugin directory %s: %s", -+ plugin_dir, error->message); -+ } -+ g_free (plugin_dir); -+ g_error_free (error); -+ return; -+ } -+ -+ operation = start_operation (manager); -+ -+ g_file_enumerator_next_files_async (enumerator, G_MAXINT, -+ G_PRIORITY_DEFAULT, -+ operation->cancellable, -+ (GAsyncReadyCallback) -+ on_plugin_info_read, -+ operation); -+ -+ gdm_plugin_manager_track_operation (manager, operation); -+} -+ -+static void -+load_plugins_in_dir (GdmPluginManager *manager, -+ const char *plugin_dir) -+{ -+ GFile *plugin_dir_file; -+ GdmPluginManagerOperation *operation; -+ -+ g_debug ("GdmPluginManager: loading plugins in dir '%s'", plugin_dir); -+ -+ operation = start_operation (manager); -+ plugin_dir_file = g_file_new_for_path (plugin_dir); -+ g_file_enumerate_children_async (plugin_dir_file, "standard::*", -+ G_FILE_QUERY_INFO_NONE, -+ G_PRIORITY_DEFAULT, -+ operation->cancellable, -+ (GAsyncReadyCallback) -+ on_plugin_dir_opened, -+ operation); -+ g_object_unref (plugin_dir_file); -+ gdm_plugin_manager_track_operation (manager, operation); -+} -+ -+static void -+on_plugin_dir_changed (GFileMonitor *monitor, -+ GFile *file, -+ GFile *other_file, -+ GFileMonitorEvent event_type, -+ GdmPluginManagerOperation *operation) -+{ -+} -+ -+static void -+watch_plugin_dir (GdmPluginManager *manager, -+ const char *plugin_dir) -+{ -+ -+ GdmPluginManagerOperation *operation; -+ GFile *file; -+ GError *error; -+ -+ operation = start_operation (manager); -+ -+ file = g_file_new_for_path (plugin_dir); -+ manager->priv->plugin_dir_monitor = g_file_monitor_directory (file, -+ G_FILE_MONITOR_NONE, -+ operation->cancellable, -+ &error); -+ if (manager->priv->plugin_dir_monitor != NULL) { -+ g_signal_connect (manager->priv->plugin_dir_monitor, -+ "changed", -+ G_CALLBACK (on_plugin_dir_changed), -+ operation); -+ gdm_plugin_manager_track_operation (manager, operation); -+ } else { -+ g_warning ("Unable to monitor %s: %s", -+ plugin_dir, error->message); -+ g_error_free (error); -+ free_operation (operation); -+ } -+ g_object_unref (file); -+} -+ -+static void -+gdm_plugin_manager_init (GdmPluginManager *manager) -+{ -+ manager->priv = GDM_PLUGIN_MANAGER_GET_PRIVATE (manager); -+ -+ manager->priv->plugins = g_hash_table_new_full (g_str_hash, -+ g_str_equal, -+ g_free, -+ g_object_unref); -+ watch_plugin_dir (manager, GDM_SIMPLE_GREETER_PLUGINS_DIR); -+ load_plugins_in_dir (manager, GDM_SIMPLE_GREETER_PLUGINS_DIR); -+} -+ -+static void -+gdm_plugin_manager_finalize (GObject *object) -+{ -+ GdmPluginManager *manager; -+ -+ manager = GDM_PLUGIN_MANAGER (object); -+ -+ g_hash_table_destroy (manager->priv->plugins); -+ g_file_monitor_cancel (manager->priv->plugin_dir_monitor); -+ -+ gdm_plugin_manager_cancel_pending_operations (manager); -+ -+ G_OBJECT_CLASS (gdm_plugin_manager_parent_class)->finalize (object); -+} -+ -+GdmPluginManager * -+gdm_plugin_manager_ref_default (void) -+{ -+ if (plugin_manager_object != NULL) { -+ g_object_ref (plugin_manager_object); -+ } else { -+ plugin_manager_object = g_object_new (GDM_TYPE_PLUGIN_MANAGER, NULL); -+ g_object_add_weak_pointer (plugin_manager_object, -+ (gpointer *) &plugin_manager_object); -+ } -+ -+ return GDM_PLUGIN_MANAGER (plugin_manager_object); -+} -+ -+GdmGreeterPlugin * -+gdm_plugin_manager_get_plugin (GdmPluginManager *manager, -+ const char *name) -+{ -+ return g_hash_table_lookup (manager->priv->plugins, name); -+} -diff --git a/gui/simple-greeter/gdm-plugin-manager.h b/gui/simple-greeter/gdm-plugin-manager.h -new file mode 100644 -index 0000000..f181140 ---- /dev/null -+++ b/gui/simple-greeter/gdm-plugin-manager.h -@@ -0,0 +1,66 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written by: Ray Strode -+ * -+ */ -+ -+#ifndef __GDM_PLUGIN_MANAGER_H -+#define __GDM_PLUGIN_MANAGER_H -+ -+#include -+ -+#include "gdm-greeter-plugin.h" -+ -+G_BEGIN_DECLS -+ -+#define GDM_TYPE_PLUGIN_MANAGER (gdm_plugin_manager_get_type ()) -+#define GDM_PLUGIN_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManager)) -+#define GDM_PLUGIN_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManagerClass)) -+#define GDM_IS_PLUGIN_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_PLUGIN_MANAGER)) -+#define GDM_IS_PLUGIN_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_PLUGIN_MANAGER)) -+#define GDM_PLUGIN_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManagerClass)) -+ -+typedef struct GdmPluginManagerPrivate GdmPluginManagerPrivate; -+ -+typedef struct -+{ -+ GObject parent; -+ GdmPluginManagerPrivate *priv; -+} GdmPluginManager; -+ -+typedef struct -+{ -+ GObjectClass parent_class; -+ -+ void (* plugins_loaded) (GdmPluginManager *plugin_manager); -+ void (* plugin_added) (GdmPluginManager *plugin_manager, -+ GdmGreeterPlugin *plugin); -+ void (* plugin_removed) (GdmPluginManager *plugin_manager, -+ GdmGreeterPlugin *plugin); -+} GdmPluginManagerClass; -+ -+GType gdm_plugin_manager_get_type (void); -+ -+GdmPluginManager *gdm_plugin_manager_ref_default (void); -+ -+GdmGreeterPlugin *gdm_plugin_manager_get_plugin (GdmPluginManager *plugin, -+ const char *name); -+ -+G_END_DECLS -+ -+#endif /* __GDM_PLUGIN_MANAGER_H */ -diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c -new file mode 100644 -index 0000000..3e49fb7 ---- /dev/null -+++ b/gui/simple-greeter/gdm-task-list.c -@@ -0,0 +1,390 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written by: Ray Strode -+ */ -+ -+#include "config.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "gdm-task-list.h" -+ -+#define GDM_TASK_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_TASK_LIST, GdmTaskListPrivate)) -+ -+struct GdmTaskListPrivate -+{ -+ GtkWidget *box; -+ GList *tasks; -+}; -+ -+enum { -+ ACTIVATED = 0, -+ DEACTIVATED, -+ NUMBER_OF_SIGNALS -+}; -+ -+static guint signals[NUMBER_OF_SIGNALS]; -+ -+static void gdm_task_list_class_init (GdmTaskListClass *klass); -+static void gdm_task_list_init (GdmTaskList *task_list); -+static void gdm_task_list_finalize (GObject *object); -+ -+G_DEFINE_TYPE (GdmTaskList, gdm_task_list, GTK_TYPE_ALIGNMENT); -+ -+static void -+on_task_toggled (GdmTaskList *widget, -+ GtkRadioButton *button) -+{ -+ GdmTask *task; -+ -+ task = g_object_get_data (G_OBJECT (button), "gdm-task"); -+ -+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) { -+ -+ GList *task_node; -+ /* Sort the list such that the tasks the user clicks last end -+ * up first. This doesn't change the order in which the tasks -+ * appear in the UI, but will affect which tasks we implicitly -+ * activate if the currently active task gets disabled. -+ */ -+ task_node = g_list_find (widget->priv->tasks, task); -+ if (task_node != NULL) { -+ widget->priv->tasks = g_list_delete_link (widget->priv->tasks, task_node); -+ widget->priv->tasks = g_list_prepend (widget->priv->tasks, -+ task); -+ } -+ -+ g_signal_emit (widget, signals[ACTIVATED], 0, task); -+ } else { -+ g_signal_emit (widget, signals[DEACTIVATED], 0, task); -+ } -+} -+ -+GdmTask * -+gdm_task_list_foreach_task (GdmTaskList *task_list, -+ GdmTaskListForeachFunc search_func, -+ gpointer data) -+{ -+ GList *node; -+ -+ for (node = task_list->priv->tasks; node != NULL; node = node->next) { -+ GdmTask *task; -+ -+ task = node->data; -+ -+ if (search_func (task_list, task, data)) { -+ return g_object_ref (task); -+ } -+ } -+ -+ return NULL; -+} -+ -+static void -+on_task_enabled (GdmTaskList *task_list, -+ GdmTask *task) -+{ -+ GtkWidget *button; -+ -+ button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button"); -+ -+ gtk_widget_set_sensitive (button, TRUE); -+} -+ -+static void -+activate_first_available_task (GdmTaskList *task_list) -+{ -+ GList *node; -+ -+ node = task_list->priv->tasks; -+ while (node != NULL) { -+ GdmTask *task; -+ -+ task = GDM_TASK (node->data); -+ -+ if (gdm_task_list_set_active_task (task_list, task)) { -+ break; -+ } -+ -+ node = node->next; -+ } -+} -+ -+static void -+on_task_disabled (GdmTaskList *task_list, -+ GdmTask *task) -+{ -+ GtkWidget *button; -+ gboolean was_active; -+ -+ button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button"); -+ was_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); -+ -+ gtk_widget_set_sensitive (button, FALSE); -+ -+ if (was_active) { -+ activate_first_available_task (task_list); -+ } -+} -+ -+void -+gdm_task_list_add_task (GdmTaskList *task_list, -+ GdmTask *task) -+{ -+ GtkWidget *image; -+ GtkWidget *button; -+ GIcon *icon; -+ char *description; -+ -+ if (task_list->priv->tasks == NULL) { -+ button = gtk_radio_button_new (NULL); -+ } else { -+ GdmTask *previous_task; -+ GtkRadioButton *previous_button; -+ -+ previous_task = GDM_TASK (task_list->priv->tasks->data); -+ previous_button = GTK_RADIO_BUTTON (g_object_get_data (G_OBJECT (previous_task), "gdm-task-list-button")); -+ button = gtk_radio_button_new_from_widget (previous_button); -+ } -+ g_object_set_data (G_OBJECT (task), "gdm-task-list-button", button); -+ -+ g_object_set (G_OBJECT (button), "draw-indicator", FALSE, NULL); -+ g_object_set_data (G_OBJECT (button), "gdm-task", task); -+ g_signal_connect_swapped (button, "toggled", -+ G_CALLBACK (on_task_toggled), -+ task_list); -+ -+ gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE); -+ gtk_widget_set_sensitive (button, gdm_task_is_enabled (task)); -+ -+ g_signal_connect_swapped (G_OBJECT (task), "enabled", -+ G_CALLBACK (on_task_enabled), -+ task_list); -+ -+ g_signal_connect_swapped (G_OBJECT (task), "disabled", -+ G_CALLBACK (on_task_disabled), -+ task_list); -+ -+ icon = gdm_task_get_icon (task); -+ image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_SMALL_TOOLBAR); -+ g_object_unref (icon); -+ -+ gtk_widget_show (image); -+ gtk_container_add (GTK_CONTAINER (button), image); -+ description = gdm_task_get_description (task); -+ gtk_widget_set_tooltip_text (button, description); -+ g_free (description); -+ gtk_widget_show (button); -+ -+ gtk_container_add (GTK_CONTAINER (task_list->priv->box), button); -+ task_list->priv->tasks = g_list_append (task_list->priv->tasks, -+ g_object_ref (task)); -+ -+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) { -+ g_signal_emit (task_list, signals[ACTIVATED], 0, task); -+ } -+} -+ -+void -+gdm_task_list_remove_task (GdmTaskList *task_list, -+ GdmTask *task) -+{ -+ GtkWidget *button; -+ GList *node; -+ -+ node = g_list_find (task_list->priv->tasks, task); -+ -+ if (node == NULL) { -+ return; -+ } -+ -+ task_list->priv->tasks = g_list_delete_link (task_list->priv->tasks, node); -+ -+ button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button"); -+ -+ if (button != NULL) { -+ g_signal_handlers_disconnect_by_func (G_OBJECT (task), -+ G_CALLBACK (on_task_enabled), -+ task_list); -+ g_signal_handlers_disconnect_by_func (G_OBJECT (task), -+ G_CALLBACK (on_task_disabled), -+ task_list); -+ gtk_widget_destroy (button); -+ g_object_set_data (G_OBJECT (task), "gdm-task-list-button", NULL); -+ } -+ -+ g_object_unref (task); -+ -+ activate_first_available_task (task_list); -+} -+ -+static void -+gdm_task_list_class_init (GdmTaskListClass *klass) -+{ -+ GObjectClass *object_class = G_OBJECT_CLASS (klass); -+ -+ object_class->finalize = gdm_task_list_finalize; -+ -+ signals [ACTIVATED] = g_signal_new ("activated", -+ G_TYPE_FROM_CLASS (object_class), -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmTaskListClass, activated), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__OBJECT, -+ G_TYPE_NONE, -+ 1, G_TYPE_OBJECT); -+ -+ signals [DEACTIVATED] = g_signal_new ("deactivated", -+ G_TYPE_FROM_CLASS (object_class), -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmTaskListClass, deactivated), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__OBJECT, -+ G_TYPE_NONE, -+ 1, G_TYPE_OBJECT); -+ -+ g_type_class_add_private (klass, sizeof (GdmTaskListPrivate)); -+} -+ -+static void -+gdm_task_list_init (GdmTaskList *widget) -+{ -+ widget->priv = GDM_TASK_LIST_GET_PRIVATE (widget); -+ -+ gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 0, 0); -+ gtk_alignment_set (GTK_ALIGNMENT (widget), 0.0, 0.0, 0, 0); -+ -+ widget->priv->box = gtk_hbox_new (TRUE, 2); -+ gtk_widget_show (widget->priv->box); -+ gtk_container_add (GTK_CONTAINER (widget), -+ widget->priv->box); -+} -+ -+static void -+gdm_task_list_finalize (GObject *object) -+{ -+ GdmTaskList *widget; -+ -+ g_return_if_fail (object != NULL); -+ g_return_if_fail (GDM_IS_TASK_LIST (object)); -+ -+ widget = GDM_TASK_LIST (object); -+ -+ g_list_foreach (widget->priv->tasks, (GFunc) g_object_unref, NULL); -+ g_list_free (widget->priv->tasks); -+ -+ G_OBJECT_CLASS (gdm_task_list_parent_class)->finalize (object); -+} -+ -+GtkWidget * -+gdm_task_list_new (void) -+{ -+ GObject *object; -+ -+ object = g_object_new (GDM_TYPE_TASK_LIST, NULL); -+ -+ return GTK_WIDGET (object); -+} -+ -+gboolean -+gdm_task_list_task_is_active (GdmTaskList *task_list, -+ GdmTask *task) -+{ -+ GtkWidget *button; -+ -+ button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button"); -+ -+ return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); -+} -+ -+GdmTask * -+gdm_task_list_get_active_task (GdmTaskList *widget) -+{ -+ return gdm_task_list_foreach_task (widget, -+ (GdmTaskListForeachFunc) -+ gdm_task_list_task_is_active, -+ NULL); -+} -+ -+gboolean -+gdm_task_list_set_active_task (GdmTaskList *widget, -+ GdmTask *task) -+{ -+ GtkWidget *button; -+ gboolean was_sensitive; -+ gboolean was_activated; -+ -+ if (!gdm_task_is_visible (task)) { -+ return FALSE; -+ } -+ -+ was_sensitive = gtk_widget_get_sensitive (GTK_WIDGET (widget)); -+ gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE); -+ -+ button = GTK_WIDGET (g_object_get_data (G_OBJECT (task), -+ "gdm-task-list-button")); -+ -+ was_activated = FALSE; -+ if (gtk_widget_is_sensitive (button)) { -+ if (gtk_widget_activate (button)) { -+ was_activated = TRUE; -+ } -+ } -+ -+ gtk_widget_set_sensitive (GTK_WIDGET (widget), was_sensitive); -+ return was_activated; -+} -+ -+int -+gdm_task_list_get_number_of_tasks (GdmTaskList *widget) -+{ -+ return g_list_length (widget->priv->tasks); -+} -+ -+int -+gdm_task_list_get_number_of_visible_tasks (GdmTaskList *widget) -+{ -+ GList *node; -+ int number_of_visible_tasks; -+ -+ number_of_visible_tasks = 0; -+ for (node = widget->priv->tasks; node != NULL; node = node->next) { -+ GdmTask *task; -+ -+ task = node->data; -+ -+ if (gdm_task_is_enabled (task) && gdm_task_is_visible (task)) { -+ number_of_visible_tasks++; -+ } -+ } -+ -+ return number_of_visible_tasks; -+} -diff --git a/gui/simple-greeter/gdm-task-list.h b/gui/simple-greeter/gdm-task-list.h -new file mode 100644 -index 0000000..cc377bd ---- /dev/null -+++ b/gui/simple-greeter/gdm-task-list.h -@@ -0,0 +1,85 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written by: Ray Strode -+ */ -+ -+#ifndef __GDM_TASK_LIST_H -+#define __GDM_TASK_LIST_H -+ -+#include -+#include -+#include -+ -+#include "gdm-task.h" -+ -+G_BEGIN_DECLS -+ -+#define GDM_TYPE_TASK_LIST (gdm_task_list_get_type ()) -+#define GDM_TASK_LIST(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_TASK_LIST, GdmTaskList)) -+#define GDM_TASK_LIST_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_TASK_LIST, GdmTaskListClass)) -+#define GDM_IS_TASK_LIST(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_TASK_LIST)) -+#define GDM_IS_TASK_LIST_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_TASK_LIST)) -+#define GDM_TASK_LIST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_TASK_LIST, GdmTaskListClass)) -+ -+typedef struct GdmTaskListPrivate GdmTaskListPrivate; -+typedef struct _GdmTaskList GdmTaskList; -+ -+typedef gboolean (* GdmTaskListForeachFunc) (GdmTaskList *task_list, -+ GdmTask *task, -+ gpointer data); -+ -+struct _GdmTaskList -+{ -+ GtkAlignment parent; -+ GdmTaskListPrivate *priv; -+}; -+ -+typedef struct -+{ -+ GtkAlignmentClass parent_class; -+ -+ void (* deactivated) (GdmTaskList *widget, -+ GdmTask *task); -+ void (* activated) (GdmTaskList *widget, -+ GdmTask *task); -+} GdmTaskListClass; -+ -+GType gdm_task_list_get_type (void); -+GtkWidget * gdm_task_list_new (void); -+ -+ -+gboolean gdm_task_list_task_is_active (GdmTaskList *task_list, -+ GdmTask *task); -+GdmTask * gdm_task_list_get_active_task (GdmTaskList *widget); -+gboolean gdm_task_list_set_active_task (GdmTaskList *widget, -+ GdmTask *task); -+GdmTask * gdm_task_list_foreach_task (GdmTaskList *widget, -+ GdmTaskListForeachFunc foreach_func, -+ gpointer data); -+void gdm_task_list_add_task (GdmTaskList *widget, -+ GdmTask *task); -+ -+void gdm_task_list_remove_task (GdmTaskList *widget, -+ GdmTask *task); -+ -+int gdm_task_list_get_number_of_tasks (GdmTaskList *widget); -+ -+int gdm_task_list_get_number_of_visible_tasks (GdmTaskList *widget); -+G_END_DECLS -+ -+#endif /* __GDM_TASK_LIST_H */ -diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c -index 84c9586..ba75d72 100644 ---- a/gui/simple-greeter/gdm-user-chooser-widget.c -+++ b/gui/simple-greeter/gdm-user-chooser-widget.c -@@ -654,9 +654,30 @@ gdm_user_chooser_widget_set_show_user_auto (GdmUserChooserWidget *widget, - char * - gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget) - { -+ char *active_item_id; -+ gboolean isnt_user; -+ - g_return_val_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget), NULL); - -- return gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget)); -+ active_item_id = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget)); -+ if (active_item_id == NULL) { -+ g_debug ("GdmUserChooserWidget: no active item in list"); -+ return NULL; -+ } -+ -+ gdm_chooser_widget_lookup_item (GDM_CHOOSER_WIDGET (widget), active_item_id, -+ NULL, NULL, NULL, NULL, NULL, -+ &isnt_user); -+ -+ if (isnt_user) { -+ g_debug ("GdmUserChooserWidget: active item '%s' isn't a user", active_item_id); -+ g_free (active_item_id); -+ return NULL; -+ } -+ -+ g_debug ("GdmUserChooserWidget: active item '%s' is a user", active_item_id); -+ -+ return active_item_id; - } - - void -diff --git a/gui/simple-greeter/libgdmsimplegreeter/Makefile.am b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am -new file mode 100644 -index 0000000..0d7a0bd ---- /dev/null -+++ b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am -@@ -0,0 +1,48 @@ -+NULL = -+ -+AM_CPPFLAGS = \ -+ -I. \ -+ -I.. \ -+ -I$(top_srcdir)/common \ -+ -DBINDIR=\"$(bindir)\" \ -+ -DDATADIR=\"$(datadir)\" \ -+ -DLIBDIR=\"$(libdir)\" \ -+ -DLIBEXECDIR=\"$(libexecdir)\" \ -+ -DLOGDIR=\"$(logdir)\" \ -+ -DPIXMAPDIR=\"$(pixmapdir)\" \ -+ -DSBINDIR=\"$(sbindir)\" \ -+ $(GTK_CFLAGS) \ -+ $(NULL) -+ -+lib_LTLIBRARIES = \ -+ libgdmsimplegreeter.la \ -+ $(NULL) -+ -+libgdmsimplegreeter_la_SOURCES = \ -+ gdm-task.h \ -+ gdm-task.c \ -+ gdm-conversation.h \ -+ gdm-conversation.c \ -+ gdm-greeter-extension.h \ -+ gdm-greeter-extension.c \ -+ $(NULL) -+ -+libgdmsimplegreeter_la_LIBADD = \ -+ $(GTK_LIBS) \ -+ $(top_builddir)/common/libgdmcommon.la \ -+ $(NULL) -+ -+libgdmsimplegreeter_la_LDFLAGS = \ -+ -export-symbols-regex '^[^_].*' \ -+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ -+ -no-undefined \ -+ $(NULL) -+ -+headersdir = $(includedir)/gdm/simple-greeter -+headers_HEADERS = gdm-greeter-extension.h -+ -+pkgconfigdir = $(libdir)/pkgconfig -+pkgconfig_DATA = gdmsimplegreeter.pc -+ -+EXTRA_DIST = gdmsimplegreeter.pc -+MAINTAINERCLEANFILES = Makefile.in -diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c -new file mode 100644 -index 0000000..ee763ef ---- /dev/null -+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c -@@ -0,0 +1,186 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ * -+ */ -+ -+#include -+#include -+ -+#include -+ -+#include "gdm-conversation.h" -+#include "gdm-marshal.h" -+#include "gdm-task.h" -+ -+enum { -+ ANSWER, -+ USER_CHOSEN, -+ CANCEL, -+ LAST_SIGNAL -+}; -+ -+static guint signals [LAST_SIGNAL] = { 0, }; -+ -+static void gdm_conversation_class_init (gpointer g_iface); -+ -+GType -+gdm_conversation_get_type (void) -+{ -+ static GType type = 0; -+ -+ if (!type) { -+ type = g_type_register_static_simple (G_TYPE_INTERFACE, -+ "GdmConversation", -+ sizeof (GdmConversationIface), -+ (GClassInitFunc) gdm_conversation_class_init, -+ 0, NULL, 0); -+ -+ g_type_interface_add_prerequisite (type, G_TYPE_OBJECT); -+ g_type_interface_add_prerequisite (type, GDM_TYPE_TASK); -+ } -+ -+ return type; -+} -+ -+static void -+gdm_conversation_class_init (gpointer g_iface) -+{ -+ GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); -+ -+ signals [ANSWER] = -+ g_signal_new ("answer", -+ iface_type, -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmConversationIface, answer), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__STRING, -+ G_TYPE_NONE, -+ 1, G_TYPE_STRING); -+ signals [USER_CHOSEN] = -+ g_signal_new ("user-chosen", -+ iface_type, -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (GdmConversationIface, user_chosen), -+ NULL, -+ NULL, -+ gdm_marshal_BOOLEAN__STRING, -+ G_TYPE_BOOLEAN, -+ 1, G_TYPE_STRING); -+ signals [CANCEL] = -+ g_signal_new ("cancel", -+ iface_type, -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmConversationIface, cancel), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); -+} -+ -+void -+gdm_conversation_set_message (GdmConversation *conversation, -+ const char *message) -+{ -+ GDM_CONVERSATION_GET_IFACE (conversation)->set_message (conversation, message); -+} -+ -+void -+gdm_conversation_ask_question (GdmConversation *conversation, -+ const char *message) -+{ -+ GDM_CONVERSATION_GET_IFACE (conversation)->ask_question (conversation, message); -+} -+ -+void -+gdm_conversation_ask_secret (GdmConversation *conversation, -+ const char *message) -+{ -+ GDM_CONVERSATION_GET_IFACE (conversation)->ask_secret (conversation, message); -+} -+ -+void -+gdm_conversation_reset (GdmConversation *conversation) -+{ -+ return GDM_CONVERSATION_GET_IFACE (conversation)->reset (conversation); -+} -+ -+void -+gdm_conversation_set_ready (GdmConversation *conversation) -+{ -+ return GDM_CONVERSATION_GET_IFACE (conversation)->set_ready (conversation); -+} -+ -+char * -+gdm_conversation_get_service_name (GdmConversation *conversation) -+{ -+ return GDM_CONVERSATION_GET_IFACE (conversation)->get_service_name (conversation); -+} -+ -+GtkWidget * -+gdm_conversation_get_page (GdmConversation *conversation) -+{ -+ return GDM_CONVERSATION_GET_IFACE (conversation)->get_page (conversation); -+} -+ -+GtkActionGroup * -+gdm_conversation_get_actions (GdmConversation *conversation) -+{ -+ return GDM_CONVERSATION_GET_IFACE (conversation)->get_actions (conversation); -+} -+ -+gboolean -+gdm_conversation_focus (GdmConversation *conversation) -+{ -+ return GDM_CONVERSATION_GET_IFACE (conversation)->focus (conversation); -+} -+ -+void -+gdm_conversation_request_answer (GdmConversation *conversation) -+{ -+ return GDM_CONVERSATION_GET_IFACE (conversation)->request_answer (conversation); -+} -+ -+/* protected -+ */ -+void -+gdm_conversation_answer (GdmConversation *conversation, -+ const char *answer) -+{ -+ g_signal_emit (conversation, signals [ANSWER], 0, answer); -+} -+ -+void -+gdm_conversation_cancel (GdmConversation *conversation) -+{ -+ g_signal_emit (conversation, signals [CANCEL], 0); -+} -+ -+gboolean -+gdm_conversation_choose_user (GdmConversation *conversation, -+ const char *username) -+{ -+ gboolean was_chosen; -+ -+ was_chosen = FALSE; -+ -+ g_signal_emit (conversation, signals [USER_CHOSEN], 0, username, &was_chosen); -+ -+ return was_chosen; -+} -diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h -new file mode 100644 -index 0000000..b37b21e ---- /dev/null -+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h -@@ -0,0 +1,93 @@ -+/* -+ * Copyright (C) Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written by: Ray Strode -+ */ -+ -+ -+#ifndef __GDM_CONVERSATION_H -+#define __GDM_CONVERSATION_H -+ -+#include -+#include -+ -+G_BEGIN_DECLS -+ -+#define GDM_TYPE_CONVERSATION (gdm_conversation_get_type ()) -+#define GDM_CONVERSATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CONVERSATION, GdmConversation)) -+#define GDM_CONVERSATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CONVERSATION, GdmConversationIface)) -+#define GDM_IS_CONVERSATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CONVERSATION)) -+#define GDM_CONVERSATION_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDM_TYPE_CONVERSATION, GdmConversationIface)) -+ -+#define GDM_CONVERSATION_DEFAULT_ACTION "default-action" -+#define GDM_CONVERSATION_OTHER_USER "__other" -+ -+typedef struct _GdmConversation GdmConversation; -+typedef struct _GdmConversationIface GdmConversationIface; -+ -+struct _GdmConversationIface -+{ -+ GTypeInterface base_iface; -+ -+ /* methods */ -+ void (* set_message) (GdmConversation *conversation, -+ const char *message); -+ void (* ask_question) (GdmConversation *conversation, -+ const char *message); -+ void (* ask_secret) (GdmConversation *conversation, -+ const char *message); -+ void (* reset) (GdmConversation *conversation); -+ void (* set_ready) (GdmConversation *conversation); -+ char * (* get_service_name) (GdmConversation *conversation); -+ GtkWidget * (* get_page) (GdmConversation *conversation); -+ GtkActionGroup * (* get_actions) (GdmConversation *conversation); -+ void (* request_answer) (GdmConversation *conversation); -+ gboolean (* focus) (GdmConversation *conversation); -+ -+ /* signals */ -+ char * (* answer) (GdmConversation *conversation); -+ void (* cancel) (GdmConversation *conversation); -+ gboolean (* user_chosen) (GdmConversation *conversation); -+}; -+ -+GType gdm_conversation_get_type (void) G_GNUC_CONST; -+ -+void gdm_conversation_set_message (GdmConversation *conversation, -+ const char *message); -+void gdm_conversation_ask_question (GdmConversation *conversation, -+ const char *message); -+void gdm_conversation_ask_secret (GdmConversation *conversation, -+ const char *message); -+void gdm_conversation_reset (GdmConversation *converastion); -+void gdm_conversation_set_ready (GdmConversation *converastion); -+char *gdm_conversation_get_service_name (GdmConversation *conversation); -+GtkWidget *gdm_conversation_get_page (GdmConversation *conversation); -+GtkActionGroup *gdm_conversation_get_actions (GdmConversation *conversation); -+void gdm_conversation_request_answer (GdmConversation *conversation); -+gboolean gdm_conversation_focus (GdmConversation *conversation); -+ -+/* protected -+ */ -+void gdm_conversation_answer (GdmConversation *conversation, -+ const char *answer); -+void gdm_conversation_cancel (GdmConversation *conversation); -+gboolean gdm_conversation_choose_user (GdmConversation *conversation, -+ const char *username); -+ -+G_END_DECLS -+ -+#endif /* __GDM_CONVERSATION_H */ -diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c -new file mode 100644 -index 0000000..a71d3f7 ---- /dev/null -+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c -@@ -0,0 +1,93 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ * -+ */ -+ -+#include -+#include -+ -+#include "gdm-greeter-extension.h" -+ -+enum { -+ LOADED, -+ LOAD_FAILED, -+ LAST_SIGNAL -+}; -+ -+static guint signals [LAST_SIGNAL] = { 0, }; -+ -+static void gdm_greeter_extension_class_init (gpointer g_iface); -+ -+GType -+gdm_greeter_extension_get_type (void) -+{ -+ static GType greeter_extension_type = 0; -+ -+ if (!greeter_extension_type) { -+ greeter_extension_type = g_type_register_static_simple (G_TYPE_INTERFACE, -+ "GdmGreeterExtension", -+ sizeof (GdmGreeterExtensionIface), -+ (GClassInitFunc) gdm_greeter_extension_class_init, -+ 0, NULL, 0); -+ -+ g_type_interface_add_prerequisite (greeter_extension_type, G_TYPE_OBJECT); -+ } -+ -+ return greeter_extension_type; -+} -+ -+static void -+gdm_greeter_extension_class_init (gpointer g_iface) -+{ -+ GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); -+ -+ signals [LOADED] = -+ g_signal_new ("loaded", -+ iface_type, -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmGreeterExtensionIface, loaded), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); -+ -+ signals [LOADED] = -+ g_signal_new ("load_failed", -+ iface_type, -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmGreeterExtensionIface, load_failed), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__POINTER, -+ G_TYPE_NONE, -+ 1, G_TYPE_POINTER); -+} -+ -+void -+gdm_greeter_extension_loaded (GdmGreeterExtension *extension) -+{ -+ g_signal_emit (extension, signals [LOADED], 0); -+} -+ -+void -+gdm_greeter_extension_load_failed (GdmGreeterExtension *extension, -+ GError *error) -+{ -+ g_signal_emit (extension, signals [LOAD_FAILED], 0, error); -+} -diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h -new file mode 100644 -index 0000000..283ba0e ---- /dev/null -+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h -@@ -0,0 +1,55 @@ -+/* -+ * Copyright 2009 Red Hat, Inc. * -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written by: Ray Strode -+ */ -+ -+#ifndef __GDM_GREETER_EXTENSION_H -+#define __GDM_GREETER_EXTENSION_H -+ -+#include -+ -+G_BEGIN_DECLS -+ -+#define GDM_TYPE_GREETER_EXTENSION (gdm_greeter_extension_get_type ()) -+#define GDM_GREETER_EXTENSION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_GREETER_EXTENSION, GdmGreeterExtension)) -+#define GDM_GREETER_EXTENSION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_GREETER_EXTENSION, GdmGreeterExtensionClass)) -+#define GDM_IS_GREETER_EXTENSION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_GREETER_EXTENSION)) -+#define GDM_GREETER_EXTENSION_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDM_TYPE_GREETER_EXTENSION, GdmGreeterExtensionIface)) -+ -+typedef struct _GdmGreeterExtension GdmGreeterExtension; -+typedef struct _GdmGreeterExtensionIface GdmGreeterExtensionIface; -+ -+struct _GdmGreeterExtensionIface -+{ -+ GTypeInterface base_iface; -+ -+ void (* loaded) (GdmGreeterExtension *extension); -+ void (* load_failed) (GdmGreeterExtension *extension, -+ GError *error); -+}; -+ -+GType gdm_greeter_extension_get_type (void) G_GNUC_CONST; -+ -+void gdm_greeter_extension_loaded (GdmGreeterExtension *extension); -+void gdm_greeter_extension_load_failed (GdmGreeterExtension *extension, -+ GError *error); -+ -+typedef GdmGreeterExtension * (* GdmGreeterPluginGetExtensionFunc) (void); -+ -+G_END_DECLS -+#endif /* __GDM_GREETER_EXTENSION_H */ -diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c -new file mode 100644 -index 0000000..858b1ef ---- /dev/null -+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c -@@ -0,0 +1,129 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ * -+ */ -+ -+#include -+#include -+ -+#include "gdm-task.h" -+ -+enum { -+ ENABLED, -+ DISABLED, -+ LAST_SIGNAL -+}; -+ -+static guint signals [LAST_SIGNAL] = { 0, }; -+static void gdm_task_class_init (gpointer g_iface); -+ -+GType -+gdm_task_get_type (void) -+{ -+ static GType task_type = 0; -+ -+ if (!task_type) { -+ task_type = g_type_register_static_simple (G_TYPE_INTERFACE, -+ "GdmTask", -+ sizeof (GdmTaskIface), -+ (GClassInitFunc) gdm_task_class_init, -+ 0, NULL, 0); -+ -+ g_type_interface_add_prerequisite (task_type, G_TYPE_OBJECT); -+ } -+ -+ return task_type; -+} -+ -+GIcon * -+gdm_task_get_icon (GdmTask *task) -+{ -+ return GDM_TASK_GET_IFACE (task)->get_icon (task); -+} -+ -+char * -+gdm_task_get_description (GdmTask *task) -+{ -+ return GDM_TASK_GET_IFACE (task)->get_description (task); -+} -+ -+char * -+gdm_task_get_name (GdmTask *task) -+{ -+ return GDM_TASK_GET_IFACE (task)->get_name (task); -+} -+ -+void -+gdm_task_set_enabled (GdmTask *task, -+ gboolean should_enable) -+{ -+ g_object_set_data (G_OBJECT (task), "gdm-task-is-disabled", GINT_TO_POINTER (!should_enable)); -+ -+ if (should_enable) { -+ g_signal_emit (G_OBJECT (task), signals [ENABLED], 0); -+ } else { -+ g_signal_emit (G_OBJECT (task), signals [DISABLED], 0); -+ } -+} -+ -+gboolean -+gdm_task_is_enabled (GdmTask *task) -+{ -+ return !g_object_get_data (G_OBJECT (task), "gdm-task-is-disabled"); -+} -+ -+gboolean -+gdm_task_is_choosable (GdmTask *task) -+{ -+ return GDM_TASK_GET_IFACE (task)->is_choosable (task); -+} -+ -+gboolean -+gdm_task_is_visible (GdmTask *task) -+{ -+ return GDM_TASK_GET_IFACE (task)->is_visible (task); -+} -+ -+static void -+gdm_task_class_init (gpointer g_iface) -+{ -+ GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); -+ -+ signals [ENABLED] = -+ g_signal_new ("enabled", -+ iface_type, -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmTaskIface, enabled), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__VOID, -+ G_TYPE_NONE, -+ 0); -+ -+ signals [DISABLED] = -+ g_signal_new ("disabled", -+ iface_type, -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmTaskIface, disabled), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__VOID, -+ G_TYPE_NONE, -+ 0); -+} -diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h -new file mode 100644 -index 0000000..51e2b0a ---- /dev/null -+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h -@@ -0,0 +1,66 @@ -+/* -+ * Copyright (C) Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written by: Ray Strode -+ */ -+ -+ -+#ifndef __GDM_TASK_H -+#define __GDM_TASK_H -+ -+#include -+#include -+ -+G_BEGIN_DECLS -+ -+#define GDM_TYPE_TASK (gdm_task_get_type ()) -+#define GDM_TASK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_TASK, GdmTask)) -+#define GDM_TASK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_TASK, GdmTaskIface)) -+#define GDM_IS_TASK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_TASK)) -+#define GDM_TASK_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDM_TYPE_TASK, GdmTaskIface)) -+ -+typedef struct _GdmTask GdmTask; -+typedef struct _GdmTaskIface GdmTaskIface; -+ -+struct _GdmTaskIface -+{ -+ GTypeInterface base_iface; -+ -+ /* methods */ -+ GIcon * (* get_icon) (GdmTask *task); -+ char * (* get_description) (GdmTask *task); -+ char * (* get_name) (GdmTask *task); -+ gboolean (* is_choosable) (GdmTask *task); -+ gboolean (* is_visible) (GdmTask *task); -+ /* signals */ -+ void (* enabled) (GdmTask *task); -+ void (* disabled) (GdmTask *task); -+}; -+ -+GType gdm_task_get_type (void) G_GNUC_CONST; -+ -+GIcon *gdm_task_get_icon (GdmTask *task); -+char *gdm_task_get_description (GdmTask *task); -+char *gdm_task_get_name (GdmTask *task); -+void gdm_task_set_enabled (GdmTask *task, -+ gboolean should_enable); -+gboolean gdm_task_is_enabled (GdmTask *task); -+gboolean gdm_task_is_choosable (GdmTask *task); -+gboolean gdm_task_is_visible (GdmTask *task); -+G_END_DECLS -+ -+#endif /* __GDM_TASK_H */ -diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in b/gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in -new file mode 100644 -index 0000000..a429d99 ---- /dev/null -+++ b/gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in -@@ -0,0 +1,11 @@ -+prefix=@prefix@ -+exec_prefix=@exec_prefix@ -+libdir=@libdir@ -+includedir=@includedir@ -+pluginsdir=@GDM_SIMPLE_GREETER_PLUGINS_DIR@ -+ -+Name: GDM Simple Greeter -+Description: Library for GDM Simple Greeter Plugins -+Version: @VERSION@ -+Libs: -L${libdir} -lgdmsimplegreeter -+Cflags: -I${includedir}/gdm/simple-greeter -diff --git a/gui/simple-greeter/plugins/Makefile.am b/gui/simple-greeter/plugins/Makefile.am -new file mode 100644 -index 0000000..c0390db ---- /dev/null -+++ b/gui/simple-greeter/plugins/Makefile.am -@@ -0,0 +1 @@ -+SUBDIRS = password -diff --git a/gui/simple-greeter/plugins/password/Makefile.am b/gui/simple-greeter/plugins/password/Makefile.am -new file mode 100644 -index 0000000..5a81499 ---- /dev/null -+++ b/gui/simple-greeter/plugins/password/Makefile.am -@@ -0,0 +1,52 @@ -+NULL = -+PAM_SERVICE_NAME = gdm-password -+ -+extensiondir = $(extensionsdatadir)/password -+extension_DATA = page.ui -+ -+AM_CPPFLAGS = \ -+ -I$(top_srcdir)/common \ -+ -I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter \ -+ -DDMCONFDIR=\""$(dmconfdir)"\" \ -+ -DGDMCONFDIR=\"$(gdmconfdir)\" \ -+ -DPLUGINDATADIR=\""$(extensiondir)"\" \ -+ -DPAMSERVICENAME=\""$(PAM_SERVICE_NAME)"\" \ -+ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -+ -DLIBLOCALEDIR=\""$(prefix)/lib/locale"\" \ -+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ -+ -DLIBEXECDIR=\""$(libexecdir)"\" \ -+ -DSBINDIR=\""$(sbindir)"\" \ -+ $(DISABLE_DEPRECATED_CFLAGS) \ -+ $(GTK_CFLAGS) \ -+ $(SIMPLE_GREETER_CFLAGS) \ -+ $(POLKIT_GNOME_CFLAGS) \ -+ $(NULL) -+ -+plugindir = $(GDM_SIMPLE_GREETER_PLUGINS_DIR) -+plugin_LTLIBRARIES = password.la -+ -+password_la_CFLAGS = \ -+ $(SIMPLE_GREETER_CFLAGS) \ -+ $(NULL) -+ -+password_la_LDFLAGS = -module -avoid-version -export-dynamic -+password_la_LIBADD = ../../../../common/libgdmcommon.la \ -+ ../../libgdmsimplegreeter/libgdmsimplegreeter.la -+password_la_SOURCES = \ -+ gdm-password-extension.h \ -+ gdm-password-extension.c \ -+ plugin.c -+ -+$(PAM_SERVICE_NAME): $(PAM_SERVICE_NAME).pam -+ cp $(PAM_SERVICE_NAME).pam $(PAM_SERVICE_NAME) -+ -+pamdir = $(PAM_PREFIX)/pam.d -+pam_DATA = $(PAM_SERVICE_NAME) -+ -+EXTRA_DIST = $(extension_DATA) $(PAM_SERVICE_NAME).pam -+CLEANFILES = $(PAM_SERVICE_NAME) -+ -+MAINTAINERCLEANFILES = \ -+ *~ \ -+ $(PAM_SERVICE_NAME) \ -+ Makefile.in -diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.c b/gui/simple-greeter/plugins/password/gdm-password-extension.c -new file mode 100644 -index 0000000..11a171c ---- /dev/null -+++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c -@@ -0,0 +1,337 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ * -+ */ -+ -+#include -+#include "gdm-password-extension.h" -+#include "gdm-conversation.h" -+#include "gdm-task.h" -+ -+#include -+#include -+#include -+ -+struct _GdmPasswordExtensionPrivate -+{ -+ GIcon *icon; -+ GtkWidget *page; -+ GtkActionGroup *actions; -+ GtkAction *login_action; -+ -+ GtkWidget *message_label; -+ GtkWidget *prompt_label; -+ GtkWidget *prompt_entry; -+ -+ guint answer_pending : 1; -+}; -+ -+static void gdm_password_extension_finalize (GObject *object); -+ -+static void gdm_task_iface_init (GdmTaskIface *iface); -+static void gdm_conversation_iface_init (GdmConversationIface *iface); -+static void gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface); -+ -+G_DEFINE_TYPE_WITH_CODE (GdmPasswordExtension, -+ gdm_password_extension, -+ G_TYPE_OBJECT, -+ G_IMPLEMENT_INTERFACE (GDM_TYPE_GREETER_EXTENSION, -+ gdm_greeter_extension_iface_init) -+ G_IMPLEMENT_INTERFACE (GDM_TYPE_TASK, -+ gdm_task_iface_init) -+ G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION, -+ gdm_conversation_iface_init)); -+ -+static void -+gdm_password_extension_set_message (GdmConversation *conversation, -+ const char *message) -+{ -+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation); -+ gtk_widget_show (extension->priv->message_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message); -+} -+ -+static void -+gdm_password_extension_ask_question (GdmConversation *conversation, -+ const char *message) -+{ -+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation); -+ gtk_widget_show (extension->priv->prompt_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE); -+ gtk_widget_show (extension->priv->prompt_entry); -+ gtk_widget_grab_focus (extension->priv->prompt_entry); -+ extension->priv->answer_pending = TRUE; -+ -+ gtk_action_set_sensitive (extension->priv->login_action, TRUE); -+} -+ -+static void -+gdm_password_extension_ask_secret (GdmConversation *conversation, -+ const char *message) -+{ -+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation); -+ gtk_widget_show (extension->priv->prompt_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message); -+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), FALSE); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+ gtk_widget_show (extension->priv->prompt_entry); -+ gtk_widget_grab_focus (extension->priv->prompt_entry); -+ extension->priv->answer_pending = TRUE; -+ -+ gtk_action_set_sensitive (extension->priv->login_action, TRUE); -+} -+ -+static void -+gdm_password_extension_reset (GdmConversation *conversation) -+{ -+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation); -+ gtk_widget_hide (extension->priv->prompt_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), ""); -+ -+ gtk_widget_hide (extension->priv->prompt_entry); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE); -+ extension->priv->answer_pending = FALSE; -+ -+ gdm_task_set_enabled (GDM_TASK (conversation), FALSE); -+} -+ -+static void -+gdm_password_extension_set_ready (GdmConversation *conversation) -+{ -+ gdm_task_set_enabled (GDM_TASK (conversation), TRUE); -+} -+ -+char * -+gdm_password_extension_get_service_name (GdmConversation *conversation) -+{ -+ return g_strdup (PAMSERVICENAME); -+} -+ -+GtkWidget * -+gdm_password_extension_get_page (GdmConversation *conversation) -+{ -+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation); -+ return extension->priv->page; -+} -+ -+GtkActionGroup * -+gdm_password_extension_get_actions (GdmConversation *conversation) -+{ -+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation); -+ return g_object_ref (extension->priv->actions); -+} -+ -+void -+gdm_password_extension_request_answer (GdmConversation *conversation) -+{ -+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation); -+ const char *text; -+ -+ if (!extension->priv->answer_pending) { -+ gdm_conversation_answer (conversation, NULL); -+ return; -+ } -+ -+ extension->priv->answer_pending = FALSE; -+ text = gtk_entry_get_text (GTK_ENTRY (extension->priv->prompt_entry)); -+ gdm_conversation_answer (conversation, text); -+ -+ gtk_widget_hide (extension->priv->prompt_entry); -+ gtk_widget_hide (extension->priv->prompt_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), ""); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+} -+ -+gboolean -+gdm_password_extension_focus (GdmConversation *conversation) -+{ -+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation); -+ if (!extension->priv->answer_pending) { -+ gdm_conversation_answer (conversation, NULL); -+ return FALSE; -+ } -+ -+ gtk_widget_grab_focus (extension->priv->prompt_entry); -+ return TRUE; -+} -+ -+GIcon * -+gdm_password_extension_get_icon (GdmTask *task) -+{ -+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (task); -+ return g_object_ref (extension->priv->icon); -+} -+ -+char * -+gdm_password_extension_get_name (GdmTask *task) -+{ -+ return g_strdup (_("Password Authentication")); -+} -+ -+char * -+gdm_password_extension_get_description (GdmTask *task) -+{ -+ return g_strdup (_("Log into session with username and password")); -+} -+ -+gboolean -+gdm_password_extension_is_choosable (GdmTask *task) -+{ -+ return FALSE; -+} -+ -+gboolean -+gdm_password_extension_is_visible (GdmTask *task) -+{ -+ return TRUE; -+} -+ -+static void -+gdm_task_iface_init (GdmTaskIface *iface) -+{ -+ iface->get_icon = gdm_password_extension_get_icon; -+ iface->get_description = gdm_password_extension_get_description; -+ iface->get_name = gdm_password_extension_get_name; -+ iface->is_choosable = gdm_password_extension_is_choosable; -+ iface->is_visible = gdm_password_extension_is_visible; -+} -+ -+static void -+gdm_conversation_iface_init (GdmConversationIface *iface) -+{ -+ iface->set_message = gdm_password_extension_set_message; -+ iface->ask_question = gdm_password_extension_ask_question; -+ iface->ask_secret = gdm_password_extension_ask_secret; -+ iface->reset = gdm_password_extension_reset; -+ iface->set_ready = gdm_password_extension_set_ready; -+ iface->get_service_name = gdm_password_extension_get_service_name; -+ iface->get_page = gdm_password_extension_get_page; -+ iface->get_actions = gdm_password_extension_get_actions; -+ iface->request_answer = gdm_password_extension_request_answer; -+ iface->focus = gdm_password_extension_focus; -+} -+ -+static void -+gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface) -+{ -+} -+ -+static void -+gdm_password_extension_class_init (GdmPasswordExtensionClass *extension_class) -+{ -+ GObjectClass *object_class; -+ -+ object_class = G_OBJECT_CLASS (extension_class); -+ -+ object_class->finalize = gdm_password_extension_finalize; -+ -+ g_type_class_add_private (extension_class, -+ sizeof (GdmPasswordExtensionPrivate)); -+} -+ -+static void -+gdm_password_extension_finalize (GObject *object) -+{ -+} -+ -+static void -+on_activate_log_in (GdmPasswordExtension *extension, -+ GtkAction *action) -+{ -+ gdm_password_extension_request_answer (GDM_CONVERSATION (extension)); -+ gtk_action_set_sensitive (action, FALSE); -+} -+ -+static void -+create_page (GdmPasswordExtension *extension) -+{ -+ GtkBuilder *builder; -+ GObject *object; -+ GError *error; -+ -+ builder = gtk_builder_new (); -+ -+ error = NULL; -+ gtk_builder_add_from_file (builder, -+ PLUGINDATADIR "/page.ui", -+ &error); -+ -+ if (error != NULL) { -+ g_warning ("Could not load UI file: %s", error->message); -+ g_error_free (error); -+ return; -+ } -+ -+ object = gtk_builder_get_object (builder, "page"); -+ g_object_ref (object); -+ -+ extension->priv->page = GTK_WIDGET (object); -+ -+ object = gtk_builder_get_object (builder, "auth-prompt-label"); -+ g_object_ref (object); -+ extension->priv->prompt_label = GTK_WIDGET (object); -+ gtk_widget_hide (extension->priv->prompt_label); -+ -+ object = gtk_builder_get_object (builder, "auth-prompt-entry"); -+ g_object_ref (object); -+ extension->priv->prompt_entry = GTK_WIDGET (object); -+ gtk_widget_hide (extension->priv->prompt_entry); -+ -+ object = gtk_builder_get_object (builder, "auth-message-label"); -+ g_object_ref (object); -+ extension->priv->message_label = GTK_WIDGET (object); -+ gtk_widget_show (extension->priv->message_label); -+ -+ g_object_unref (builder); -+} -+ -+static void -+create_actions (GdmPasswordExtension *extension) -+{ -+ GtkAction *action; -+ -+ extension->priv->actions = gtk_action_group_new ("gdm-password-extension"); -+ -+ action = gtk_action_new (GDM_CONVERSATION_DEFAULT_ACTION, -+ _("Log In"), NULL, NULL); -+ g_signal_connect_swapped (action, "activate", -+ G_CALLBACK (on_activate_log_in), extension); -+ g_object_set (G_OBJECT (action), "icon-name", "go-home", NULL); -+ gtk_action_group_add_action (extension->priv->actions, -+ action); -+ -+ extension->priv->login_action = action; -+} -+ -+static void -+gdm_password_extension_init (GdmPasswordExtension *extension) -+{ -+ extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (extension, -+ GDM_TYPE_PASSWORD_EXTENSION, -+ GdmPasswordExtensionPrivate); -+ -+ extension->priv->icon = g_themed_icon_new ("dialog-password"); -+ create_page (extension); -+ create_actions (extension); -+ -+ gdm_password_extension_reset (GDM_CONVERSATION (extension)); -+} -diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.h b/gui/simple-greeter/plugins/password/gdm-password-extension.h -new file mode 100644 -index 0000000..99fe17b ---- /dev/null -+++ b/gui/simple-greeter/plugins/password/gdm-password-extension.h -@@ -0,0 +1,56 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -+ * 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ */ -+ -+#ifndef __GDM_PASSWORD_EXTENSION_H -+#define __GDM_PASSWORD_EXTENSION_H -+ -+#include -+#include "gdm-greeter-extension.h" -+ -+G_BEGIN_DECLS -+ -+#define GDM_TYPE_PASSWORD_EXTENSION (gdm_password_extension_get_type ()) -+#define GDM_PASSWORD_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_PASSWORD_EXTENSION, GdmPasswordExtension)) -+#define GDM_PASSWORD_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_PASSWORD_EXTENSION, GdmPasswordExtensionClass)) -+#define GDM_IS_PASSWORD_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_PASSWORD_EXTENSION)) -+#define GDM_IS_PASSWORD_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_PASSWORD_EXTENSION)) -+#define GDM_PASSWORD_EXTENSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_PASSWORD_EXTENSION, GdmPasswordExtensionClass)) -+ -+typedef struct _GdmPasswordExtensionPrivate GdmPasswordExtensionPrivate; -+ -+typedef struct -+{ -+ GObject parent; -+ GdmPasswordExtensionPrivate *priv; -+} GdmPasswordExtension; -+ -+typedef struct -+{ -+ GObjectClass parent_class; -+} GdmPasswordExtensionClass; -+ -+GType gdm_password_extension_get_type (void); -+ -+GdmPasswordExtension *gdm_password_extension_new (void); -+ -+G_END_DECLS -+ -+#endif /* GDM_PASSWORD_EXTENSION_H */ -diff --git a/gui/simple-greeter/plugins/password/gdm-password.pam b/gui/simple-greeter/plugins/password/gdm-password.pam -new file mode 100644 -index 0000000..bac431d ---- /dev/null -+++ b/gui/simple-greeter/plugins/password/gdm-password.pam -@@ -0,0 +1,19 @@ -+# Sample PAM file for doing password authentication. -+# Distros should replace this with what makes sense for them. -+auth required pam_env.so -+auth sufficient pam_unix.so nullok try_first_pass -+auth requisite pam_succeed_if.so uid >= 500 quiet -+auth required pam_deny.so -+ -+account required pam_unix.so -+account sufficient pam_localuser.so -+account sufficient pam_succeed_if.so uid < 500 quiet -+account required pam_permit.so -+ -+password requisite pam_cracklib.so try_first_pass retry=3 type= -+password sufficient pam_unix.so nullok try_first_pass use_authtok -+password required pam_deny.so -+ -+session optional pam_keyinit.so revoke -+session required pam_limits.so -+session required pam_unix.so -diff --git a/gui/simple-greeter/plugins/password/page.ui b/gui/simple-greeter/plugins/password/page.ui -new file mode 100644 -index 0000000..8fa5c7b ---- /dev/null -+++ b/gui/simple-greeter/plugins/password/page.ui -@@ -0,0 +1,57 @@ -+ -+ -+ -+ -+ True -+ vertical -+ -+ -+ True -+ 6 -+ -+ -+ True -+ -+ -+ False -+ False -+ 0 -+ -+ -+ -+ -+ True -+ True -+ True -+ -+ -+ 1 -+ -+ -+ -+ -+ True -+ True -+ 0 -+ -+ -+ -+ -+ True -+ -+ -+ True -+ -+ -+ 0 -+ -+ -+ -+ -+ True -+ True -+ 1 -+ -+ -+ -+ -diff --git a/gui/simple-greeter/plugins/password/plugin.c b/gui/simple-greeter/plugins/password/plugin.c -new file mode 100644 -index 0000000..9b87c67 ---- /dev/null -+++ b/gui/simple-greeter/plugins/password/plugin.c -@@ -0,0 +1,40 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ * -+ */ -+ -+#include "gdm-password-extension.h" -+ -+#include -+#include -+ -+GdmGreeterExtension * -+gdm_greeter_plugin_get_extension (void) -+{ -+ static GObject *extension; -+ -+ if (extension != NULL) { -+ g_object_ref (extension); -+ } else { -+ extension = g_object_new (GDM_TYPE_PASSWORD_EXTENSION, NULL); -+ g_object_add_weak_pointer (extension, (gpointer *) &extension); -+ } -+ -+ return GDM_GREETER_EXTENSION (extension); -+} -diff --git a/po/POTFILES.in b/po/POTFILES.in -index d2f59a7..d4d5a51 100644 ---- a/po/POTFILES.in -+++ b/po/POTFILES.in -@@ -81,6 +81,7 @@ gui/simple-greeter/gdm-simple-greeter.schemas.in - gui/simple-greeter/gdm-timer.c - gui/simple-greeter/gdm-user-chooser-widget.c - gui/simple-greeter/greeter-main.c -+gui/simple-greeter/plugins/password/gdm-password-extension.c - utils/gdmflexiserver.c - utils/gdm-screenshot.c - --- -1.7.4.1 - - -From 3019c4b8631c2823119b737736d81688f1e793b3 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 6 Feb 2009 16:25:47 -0500 -Subject: [PATCH 12/20] Add fingerprint plugin - -This commit adds a plugin to initiate a conversation for -fingerprint scans. ---- - configure.ac | 4 + - gui/simple-greeter/plugins/Makefile.am | 2 +- - gui/simple-greeter/plugins/fingerprint/Makefile.am | 55 +++ - .../fingerprint/gdm-fingerprint-extension.c | 347 ++++++++++++++++++++ - .../fingerprint/gdm-fingerprint-extension.h | 56 ++++ - .../plugins/fingerprint/gdm-fingerprint.pam | 17 + - .../plugins/fingerprint/icons/16x16/Makefile.am | 5 + - .../fingerprint/icons/16x16/gdm-fingerprint.png | Bin 0 -> 461 bytes - .../plugins/fingerprint/icons/48x48/Makefile.am | 5 + - .../fingerprint/icons/48x48/gdm-fingerprint.png | Bin 0 -> 1638 bytes - .../plugins/fingerprint/icons/Makefile.am | 1 + - gui/simple-greeter/plugins/fingerprint/page.ui | 57 ++++ - gui/simple-greeter/plugins/fingerprint/plugin.c | 40 +++ - po/POTFILES.in | 1 + - 14 files changed, 589 insertions(+), 1 deletions(-) - create mode 100644 gui/simple-greeter/plugins/fingerprint/Makefile.am - create mode 100644 gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c - create mode 100644 gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.h - create mode 100644 gui/simple-greeter/plugins/fingerprint/gdm-fingerprint.pam - create mode 100644 gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile.am - create mode 100644 gui/simple-greeter/plugins/fingerprint/icons/16x16/gdm-fingerprint.png - create mode 100644 gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile.am - create mode 100644 gui/simple-greeter/plugins/fingerprint/icons/48x48/gdm-fingerprint.png - create mode 100644 gui/simple-greeter/plugins/fingerprint/icons/Makefile.am - create mode 100644 gui/simple-greeter/plugins/fingerprint/page.ui - create mode 100644 gui/simple-greeter/plugins/fingerprint/plugin.c - -diff --git a/configure.ac b/configure.ac -index 5258390..7e825cb 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1440,6 +1440,10 @@ gui/simple-greeter/libgdmsimplegreeter/Makefile - gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc - gui/simple-greeter/plugins/Makefile - gui/simple-greeter/plugins/password/Makefile -+gui/simple-greeter/plugins/fingerprint/Makefile -+gui/simple-greeter/plugins/fingerprint/icons/Makefile -+gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile -+gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile - gui/simple-chooser/Makefile - utils/Makefile - data/gdm.conf -diff --git a/gui/simple-greeter/plugins/Makefile.am b/gui/simple-greeter/plugins/Makefile.am -index c0390db..9811a68 100644 ---- a/gui/simple-greeter/plugins/Makefile.am -+++ b/gui/simple-greeter/plugins/Makefile.am -@@ -1 +1 @@ --SUBDIRS = password -+SUBDIRS = password fingerprint -diff --git a/gui/simple-greeter/plugins/fingerprint/Makefile.am b/gui/simple-greeter/plugins/fingerprint/Makefile.am -new file mode 100644 -index 0000000..ec8b326 ---- /dev/null -+++ b/gui/simple-greeter/plugins/fingerprint/Makefile.am -@@ -0,0 +1,55 @@ -+SUBDIRS = icons -+ -+NULL = -+PAM_SERVICE_NAME = gdm-fingerprint -+ -+extensiondir = $(extensionsdatadir)/fingerprint -+extension_DATA = page.ui -+ -+AM_CPPFLAGS = \ -+ -I$(top_srcdir)/common \ -+ -I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter \ -+ -DDMCONFDIR=\""$(dmconfdir)"\" \ -+ -DGDMCONFDIR=\"$(gdmconfdir)\" \ -+ -DPLUGINDATADIR=\""$(extensiondir)"\" \ -+ -DPAMSERVICENAME=\""$(PAM_SERVICE_NAME)"\" \ -+ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -+ -DLIBLOCALEDIR=\""$(prefix)/lib/locale"\" \ -+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ -+ -DLIBEXECDIR=\""$(libexecdir)"\" \ -+ -DSBINDIR=\""$(sbindir)"\" \ -+ $(DISABLE_DEPRECATED_CFLAGS) \ -+ $(GTK_CFLAGS) \ -+ $(SIMPLE_GREETER_CFLAGS) \ -+ $(POLKIT_GNOME_CFLAGS) \ -+ $(NULL) -+ -+ -+plugindir = $(GDM_SIMPLE_GREETER_PLUGINS_DIR) -+plugin_LTLIBRARIES = fingerprint.la -+ -+fingerprint_la_CFLAGS = \ -+ $(SIMPLE_GREETER_CFLAGS) \ -+ $(NULL) -+ -+fingerprint_la_LDFLAGS = -module -avoid-version -export-dynamic -+fingerprint_la_LIBADD = ../../../../common/libgdmcommon.la \ -+ ../../libgdmsimplegreeter/libgdmsimplegreeter.la -+fingerprint_la_SOURCES = \ -+ gdm-fingerprint-extension.h \ -+ gdm-fingerprint-extension.c \ -+ plugin.c -+ -+$(PAM_SERVICE_NAME): $(PAM_SERVICE_NAME).pam -+ cp $(PAM_SERVICE_NAME).pam $(PAM_SERVICE_NAME) -+ -+pamdir = $(PAM_PREFIX)/pam.d -+pam_DATA = $(PAM_SERVICE_NAME) -+ -+EXTRA_DIST = $(extension_DATA) $(PAM_SERVICE_NAME).pam -+CLEANFILES = $(PAM_SERVICE_NAME) -+ -+MAINTAINERCLEANFILES = \ -+ *~ \ -+ $(PAM_SERVICE_NAME) \ -+ Makefile.in -diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c -new file mode 100644 -index 0000000..55f5d32 ---- /dev/null -+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c -@@ -0,0 +1,347 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ * -+ */ -+ -+#include -+#include -+ -+#include "gdm-fingerprint-extension.h" -+#include "gdm-conversation.h" -+#include "gdm-task.h" -+ -+#include -+#include -+#include -+ -+struct _GdmFingerprintExtensionPrivate -+{ -+ GIcon *icon; -+ GtkWidget *page; -+ GtkActionGroup *actions; -+ -+ GtkWidget *message_label; -+ GtkWidget *prompt_label; -+ GtkWidget *prompt_entry; -+ -+ guint answer_pending : 1; -+}; -+ -+static void gdm_fingerprint_extension_finalize (GObject *object); -+ -+static void gdm_task_iface_init (GdmTaskIface *iface); -+static void gdm_conversation_iface_init (GdmConversationIface *iface); -+static void gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface); -+ -+G_DEFINE_TYPE_WITH_CODE (GdmFingerprintExtension, -+ gdm_fingerprint_extension, -+ G_TYPE_OBJECT, -+ G_IMPLEMENT_INTERFACE (GDM_TYPE_GREETER_EXTENSION, -+ gdm_greeter_extension_iface_init) -+ G_IMPLEMENT_INTERFACE (GDM_TYPE_TASK, -+ gdm_task_iface_init) -+ G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION, -+ gdm_conversation_iface_init)); -+ -+static void -+gdm_fingerprint_extension_set_message (GdmConversation *conversation, -+ const char *message) -+{ -+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation); -+ gtk_widget_show (extension->priv->message_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message); -+} -+ -+static void -+gdm_fingerprint_extension_ask_question (GdmConversation *conversation, -+ const char *message) -+{ -+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation); -+ gtk_widget_show (extension->priv->prompt_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE); -+ gtk_widget_show (extension->priv->prompt_entry); -+ gtk_widget_grab_focus (extension->priv->prompt_entry); -+ extension->priv->answer_pending = TRUE; -+} -+ -+static void -+gdm_fingerprint_extension_ask_secret (GdmConversation *conversation, -+ const char *message) -+{ -+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation); -+ gtk_widget_show (extension->priv->prompt_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message); -+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), FALSE); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+ gtk_widget_show (extension->priv->prompt_entry); -+ gtk_widget_grab_focus (extension->priv->prompt_entry); -+ extension->priv->answer_pending = TRUE; -+} -+ -+static void -+gdm_fingerprint_extension_reset (GdmConversation *conversation) -+{ -+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation); -+ gtk_widget_hide (extension->priv->prompt_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), ""); -+ -+ gtk_widget_hide (extension->priv->prompt_entry); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE); -+ extension->priv->answer_pending = FALSE; -+ -+ gdm_task_set_enabled (GDM_TASK (conversation), FALSE); -+} -+ -+static void -+gdm_fingerprint_extension_set_ready (GdmConversation *conversation) -+{ -+ gdm_task_set_enabled (GDM_TASK (conversation), TRUE); -+} -+ -+char * -+gdm_fingerprint_extension_get_service_name (GdmConversation *conversation) -+{ -+ return g_strdup (PAMSERVICENAME); -+} -+ -+GtkWidget * -+gdm_fingerprint_extension_get_page (GdmConversation *conversation) -+{ -+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation); -+ return extension->priv->page; -+} -+ -+GtkActionGroup * -+gdm_fingerprint_extension_get_actions (GdmConversation *conversation) -+{ -+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation); -+ -+ return g_object_ref (extension->priv->actions); -+} -+ -+void -+gdm_fingerprint_extension_request_answer (GdmConversation *conversation) -+{ -+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation); -+ const char *text; -+ -+ if (!extension->priv->answer_pending) { -+ gdm_conversation_answer (conversation, NULL); -+ return; -+ } -+ -+ extension->priv->answer_pending = FALSE; -+ text = gtk_entry_get_text (GTK_ENTRY (extension->priv->prompt_entry)); -+ gdm_conversation_answer (conversation, text); -+ -+ gtk_widget_hide (extension->priv->prompt_entry); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), ""); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+} -+ -+gboolean -+gdm_fingerprint_extension_focus (GdmConversation *conversation) -+{ -+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation); -+ -+ if (!extension->priv->answer_pending) { -+ return FALSE; -+ } -+ -+ gtk_widget_grab_focus (extension->priv->prompt_entry); -+ return TRUE; -+} -+ -+GIcon * -+gdm_fingerprint_extension_get_icon (GdmTask *task) -+{ -+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (task); -+ return g_object_ref (extension->priv->icon); -+} -+ -+char * -+gdm_fingerprint_extension_get_name (GdmTask *task) -+{ -+ return g_strdup (_("Fingerprint Authentication")); -+} -+ -+char * -+gdm_fingerprint_extension_get_description (GdmTask *task) -+{ -+ return g_strdup (_("Log into session with fingerprint")); -+} -+ -+gboolean -+gdm_fingerprint_extension_is_choosable (GdmTask *task) -+{ -+ return FALSE; -+} -+ -+gboolean -+gdm_fingerprint_extension_is_visible (GdmTask *task) -+{ -+ char *contents, **lines; -+ gboolean ret; -+ guint i; -+ -+ /* Stolen from gnome-about-me. -+ * -+ * FIXME: We should fix pam_fprintd to return authinfo_unavail instead of -+ * doing this distro specific hack. -+ */ -+ -+ if (g_file_get_contents ("/etc/sysconfig/authconfig", -+ &contents, NULL, NULL) == FALSE) { -+ return FALSE; -+ } -+ -+ lines = g_strsplit (contents, "\n", -1); -+ g_free (contents); -+ -+ ret = FALSE; -+ -+ for (i = 0; lines[i] ; i++) { -+ if (g_str_has_prefix (lines[i], "USEFPRINTD=") != FALSE) { -+ char *value; -+ -+ value = lines[i] + strlen ("USEFPRINTD="); -+ if (rpmatch (value)) { -+ ret = TRUE; -+ break; -+ } -+ } -+ } -+ -+ g_strfreev (lines); -+ -+ return ret; -+} -+ -+static void -+gdm_task_iface_init (GdmTaskIface *iface) -+{ -+ iface->get_icon = gdm_fingerprint_extension_get_icon; -+ iface->get_description = gdm_fingerprint_extension_get_description; -+ iface->get_name = gdm_fingerprint_extension_get_name; -+ iface->is_choosable = gdm_fingerprint_extension_is_choosable; -+ iface->is_visible = gdm_fingerprint_extension_is_visible; -+} -+ -+static void -+gdm_conversation_iface_init (GdmConversationIface *iface) -+{ -+ iface->set_message = gdm_fingerprint_extension_set_message; -+ iface->ask_question = gdm_fingerprint_extension_ask_question; -+ iface->ask_secret = gdm_fingerprint_extension_ask_secret; -+ iface->reset = gdm_fingerprint_extension_reset; -+ iface->set_ready = gdm_fingerprint_extension_set_ready; -+ iface->get_service_name = gdm_fingerprint_extension_get_service_name; -+ iface->get_page = gdm_fingerprint_extension_get_page; -+ iface->get_actions = gdm_fingerprint_extension_get_actions; -+ iface->request_answer = gdm_fingerprint_extension_request_answer; -+ iface->focus = gdm_fingerprint_extension_focus; -+} -+ -+static void -+gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface) -+{ -+} -+ -+static void -+gdm_fingerprint_extension_class_init (GdmFingerprintExtensionClass *extension_class) -+{ -+ GObjectClass *object_class; -+ -+ object_class = G_OBJECT_CLASS (extension_class); -+ -+ object_class->finalize = gdm_fingerprint_extension_finalize; -+ -+ g_type_class_add_private (extension_class, -+ sizeof (GdmFingerprintExtensionPrivate)); -+} -+ -+static void -+gdm_fingerprint_extension_finalize (GObject *object) -+{ -+} -+ -+static void -+create_page (GdmFingerprintExtension *extension) -+{ -+ GtkBuilder *builder; -+ GObject *object; -+ GError *error; -+ -+ builder = gtk_builder_new (); -+ -+ error = NULL; -+ gtk_builder_add_from_file (builder, -+ PLUGINDATADIR "/page.ui", -+ &error); -+ -+ if (error != NULL) { -+ g_warning ("Could not load UI file: %s", error->message); -+ g_error_free (error); -+ return; -+ } -+ -+ object = gtk_builder_get_object (builder, "page"); -+ g_object_ref (object); -+ -+ extension->priv->page = GTK_WIDGET (object); -+ -+ object = gtk_builder_get_object (builder, "auth-prompt-label"); -+ g_object_ref (object); -+ extension->priv->prompt_label = GTK_WIDGET (object); -+ gtk_widget_hide (extension->priv->prompt_label); -+ -+ object = gtk_builder_get_object (builder, "auth-prompt-entry"); -+ g_object_ref (object); -+ extension->priv->prompt_entry = GTK_WIDGET (object); -+ gtk_widget_hide (extension->priv->prompt_entry); -+ -+ object = gtk_builder_get_object (builder, "auth-message-label"); -+ g_object_ref (object); -+ extension->priv->message_label = GTK_WIDGET (object); -+ gtk_widget_show (extension->priv->message_label); -+ -+ g_object_unref (builder); -+} -+ -+static void -+create_actions (GdmFingerprintExtension *extension) -+{ -+ extension->priv->actions = gtk_action_group_new ("gdm-fingerprint-extension"); -+} -+ -+static void -+gdm_fingerprint_extension_init (GdmFingerprintExtension *extension) -+{ -+ extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (extension, -+ GDM_TYPE_FINGERPRINT_EXTENSION, -+ GdmFingerprintExtensionPrivate); -+ -+ extension->priv->icon = g_themed_icon_new ("gdm-fingerprint"); -+ create_page (extension); -+ create_actions (extension); -+ gdm_fingerprint_extension_reset (GDM_CONVERSATION (extension)); -+} -diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.h b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.h -new file mode 100644 -index 0000000..5d34b21 ---- /dev/null -+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.h -@@ -0,0 +1,56 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -+ * 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ */ -+ -+#ifndef __GDM_FINGERPRINT_EXTENSION_H -+#define __GDM_FINGERPRINT_EXTENSION_H -+ -+#include -+#include "gdm-greeter-extension.h" -+ -+G_BEGIN_DECLS -+ -+#define GDM_TYPE_FINGERPRINT_EXTENSION (gdm_fingerprint_extension_get_type ()) -+#define GDM_FINGERPRINT_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_FINGERPRINT_EXTENSION, GdmFingerprintExtension)) -+#define GDM_FINGERPRINT_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_FINGERPRINT_EXTENSION, GdmFingerprintExtensionClass)) -+#define GDM_IS_FINGERPRINT_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_FINGERPRINT_EXTENSION)) -+#define GDM_IS_FINGERPRINT_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_FINGERPRINT_EXTENSION)) -+#define GDM_FINGERPRINT_EXTENSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_FINGERPRINT_EXTENSION, GdmFingerprintExtensionClass)) -+ -+typedef struct _GdmFingerprintExtensionPrivate GdmFingerprintExtensionPrivate; -+ -+typedef struct -+{ -+ GObject parent; -+ GdmFingerprintExtensionPrivate *priv; -+} GdmFingerprintExtension; -+ -+typedef struct -+{ -+ GObjectClass parent_class; -+} GdmFingerprintExtensionClass; -+ -+GType gdm_fingerprint_extension_get_type (void); -+ -+GdmFingerprintExtension *gdm_fingerprint_extension_new (void); -+ -+G_END_DECLS -+ -+#endif /* GDM_FINGERPRINT_EXTENSION_H */ -diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint.pam b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint.pam -new file mode 100644 -index 0000000..1a1c777 ---- /dev/null -+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint.pam -@@ -0,0 +1,17 @@ -+# Sample PAM file for doing fingerprint authentication. -+# Distros should replace this with what makes sense for them. -+auth required pam_env.so -+auth required pam_fprintd.so -+auth sufficient pam_succeed_if.so uid >= 500 quiet -+auth required pam_deny.so -+ -+account required pam_unix.so -+account sufficient pam_localuser.so -+account sufficient pam_succeed_if.so uid < 500 quiet -+account required pam_permit.so -+ -+password required pam_deny.so -+ -+session optional pam_keyinit.so revoke -+session required pam_limits.so -+session required pam_unix.so -diff --git a/gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile.am b/gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile.am -new file mode 100644 -index 0000000..f42e317 ---- /dev/null -+++ b/gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile.am -@@ -0,0 +1,5 @@ -+iconsdir = $(datadir)/icons/hicolor/16x16/apps -+ -+icons_DATA = gdm-fingerprint.png -+ -+EXTRA_DIST = $(icons_DATA) -diff --git a/gui/simple-greeter/plugins/fingerprint/icons/16x16/gdm-fingerprint.png b/gui/simple-greeter/plugins/fingerprint/icons/16x16/gdm-fingerprint.png -new file mode 100644 -index 0000000000000000000000000000000000000000..4438cee2895638422dd470b05214dfae07751c3c -GIT binary patch -literal 461 -zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6U4S$Y -z{B+)352QE?JR*x382FBWFymBhK53vJdx@v7EBj3rUJ*vkeVx{~fu{I+x;TbdoNm3m -z(R*5;$nlToe`n0t7U_A+O~xmQ|0`3{N*Pgg&ebxsLQ0N@R| -ASO5S3 - -literal 0 -HcmV?d00001 - -diff --git a/gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile.am b/gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile.am -new file mode 100644 -index 0000000..f4ab2a0 ---- /dev/null -+++ b/gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile.am -@@ -0,0 +1,5 @@ -+iconsdir = $(datadir)/icons/hicolor/48x48/apps -+ -+icons_DATA = gdm-fingerprint.png -+ -+EXTRA_DIST = $(icons_DATA) -diff --git a/gui/simple-greeter/plugins/fingerprint/icons/48x48/gdm-fingerprint.png b/gui/simple-greeter/plugins/fingerprint/icons/48x48/gdm-fingerprint.png -new file mode 100644 -index 0000000000000000000000000000000000000000..fd6f546c387db5dbce1a88cb4bb46c3bdaa7f4a5 -GIT binary patch -literal 1638 -zcmV-s2ATPZP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01m_e01m_fl`9S#00007bV*G`2iXJ- -z6EzRg;agMy00rhrL_t(&-sPBGY!p=#$N%TDp+=0hNP*1SPbzi -z_#h8rz!1>~h>0&gm>3fi(P#*P#E(e);7KL17{vI2V$cRcYAxICZVOdtv6z0hl(w|p -zkIu~T!6|O1Q__!_#l-Wnv*+A%@A=(x?%aEaumF+2LW#)s>?en#7^-%IICZFQoAOI~ -zo8sbPcOVeh$;|PrtgJ7?;qU}36z6;$H~iq<(J^;e)KCp6W -zuuwE-q2*XBI_kP`{*8Kg`vO?zFL7t*`gd1+4}Vovm6M2;rMa#uD=YJ*_a#ZvK~2*d -zHBGy`e*Jpcc7RYdmbkqB)jkmb_x|gysT#UY_rfn0VNw3_)k$`2zj^bf*I1^xxw(0h -z&y|&x9sqmwzu69l<7wLg$bk}9jxXOuE>Lo+duOBvE^@)+&J*Mi6=wdaR4Qlkd2DQK -zBLMH@e`a23JAekL%&amP-u#>?ww^1!&?Yo6YtR@eP1CZcEjoweRtX6q?lsPj?En)h -zT9Ttf0||};0iI%0k_!4-`!P0tJtb7_41gSyE*7QD_*#Q)&~|`}Phm8f7;PR>ZXoH4 -zPqTMj?8Wdv$M2$3J*6m$e_94LEszFKW-#B#$XiI67~j|a*M%!X?(5TReHXiv6UouH -z!h116MBZrw3URBfh{%`$#n?U=3_c-A(u)-p6@JSAVvnOEInuZ5Qs+-CMq47LbT>Sb -z`a=IZt%R7_1puX`r7i&X7|dga;2$NTuK~Q9NF)wg1^@u{k4@COy0345gQwIHk2v!u -z7o!luV*=m?0H4oSVjQ2Dr)*?I^itZwF0m8<0BZIi0hO*A)IM33SLn}yX|G`-2LPz5 -zT4G}By|v$jLdyU=lm<6yIe;$BMun=X<@%sLllHlKu%#y1=}PNkXZlfxh#G7GVCEJR -z^?mxFi%r^30<1By^`!;;tRXwKwg3nr`b`2^r~l^7R6?4jtuwmC?@ot!$1YP1o -zLqq56%D{k$dW{}z&WuMAA|pUwYiny#pOoE(wl(eT?Fm}|h{$a7DZQOfd3kvWfF%ZX -z8vs;QRXLg2c&MwfbR#n?ShMZFK$4^clp)?F9e^2M4zTC@@UY&$GUf1%tu6 -z0entGGJtDD^g&}|<0k-khCWg==uga`f0>9>6Mdr|>@x=aKxt`dBoc|tE(1b{twgjH -zKpuemnfW70lFrDo9I*2y$jsfcEEfXUZkYX($B!RZXI(QvPD(ZGqNn_z$Otw -zyrw8hH2{yHL_eL=VJ;etUIuX31WZ;GMYu&znRxv+M;bgYC$)3cML!XF|g1+yk2k5oy@>O*FdVawl;pp004|G -k&_6!!?EgnH@c)&+0Y61Y+XKhC^Z)<=07*qoM6N<$f~|xG1poj5 - -literal 0 -HcmV?d00001 - -diff --git a/gui/simple-greeter/plugins/fingerprint/icons/Makefile.am b/gui/simple-greeter/plugins/fingerprint/icons/Makefile.am -new file mode 100644 -index 0000000..c20f10d ---- /dev/null -+++ b/gui/simple-greeter/plugins/fingerprint/icons/Makefile.am -@@ -0,0 +1 @@ -+SUBDIRS = 16x16 48x48 -diff --git a/gui/simple-greeter/plugins/fingerprint/page.ui b/gui/simple-greeter/plugins/fingerprint/page.ui -new file mode 100644 -index 0000000..8fa5c7b ---- /dev/null -+++ b/gui/simple-greeter/plugins/fingerprint/page.ui -@@ -0,0 +1,57 @@ -+ -+ -+ -+ -+ True -+ vertical -+ -+ -+ True -+ 6 -+ -+ -+ True -+ -+ -+ False -+ False -+ 0 -+ -+ -+ -+ -+ True -+ True -+ True -+ -+ -+ 1 -+ -+ -+ -+ -+ True -+ True -+ 0 -+ -+ -+ -+ -+ True -+ -+ -+ True -+ -+ -+ 0 -+ -+ -+ -+ -+ True -+ True -+ 1 -+ -+ -+ -+ -diff --git a/gui/simple-greeter/plugins/fingerprint/plugin.c b/gui/simple-greeter/plugins/fingerprint/plugin.c -new file mode 100644 -index 0000000..5ea9925 ---- /dev/null -+++ b/gui/simple-greeter/plugins/fingerprint/plugin.c -@@ -0,0 +1,40 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ * -+ */ -+ -+#include "gdm-fingerprint-extension.h" -+ -+#include -+#include -+ -+GdmGreeterExtension * -+gdm_greeter_plugin_get_extension (void) -+{ -+ static GObject *extension; -+ -+ if (extension != NULL) { -+ g_object_ref (extension); -+ } else { -+ extension = g_object_new (GDM_TYPE_FINGERPRINT_EXTENSION, NULL); -+ g_object_add_weak_pointer (extension, (gpointer *) &extension); -+ } -+ -+ return GDM_GREETER_EXTENSION (extension); -+} -diff --git a/po/POTFILES.in b/po/POTFILES.in -index d4d5a51..77fe17d 100644 ---- a/po/POTFILES.in -+++ b/po/POTFILES.in -@@ -82,6 +82,7 @@ gui/simple-greeter/gdm-timer.c - gui/simple-greeter/gdm-user-chooser-widget.c - gui/simple-greeter/greeter-main.c - gui/simple-greeter/plugins/password/gdm-password-extension.c -+gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c - utils/gdmflexiserver.c - utils/gdm-screenshot.c - --- -1.7.4.1 - - -From 286a7a3e5391bc860fb0f562f74c86169bbc6899 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 6 Feb 2009 16:25:47 -0500 -Subject: [PATCH 13/20] Add smartcard plugin - -This commit adds a plugin to initiate a conversation when -smartcards are inserted. ---- - configure.ac | 11 + - gui/simple-greeter/plugins/Makefile.am | 2 +- - gui/simple-greeter/plugins/smartcard/Makefile.am | 76 + - .../plugins/smartcard/gdm-smartcard-extension.c | 513 +++++++ - .../plugins/smartcard/gdm-smartcard-extension.h | 56 + - .../plugins/smartcard/gdm-smartcard-manager.c | 1521 ++++++++++++++++++++ - .../plugins/smartcard/gdm-smartcard-manager.h | 86 ++ - .../plugins/smartcard/gdm-smartcard-worker.c | 186 +++ - .../plugins/smartcard/gdm-smartcard.c | 554 +++++++ - .../plugins/smartcard/gdm-smartcard.h | 94 ++ - .../plugins/smartcard/gdm-smartcard.pam | 18 + - .../plugins/smartcard/icons/16x16/Makefile.am | 5 + - .../smartcard/icons/16x16/gdm-smartcard.png | Bin 0 -> 871 bytes - .../plugins/smartcard/icons/48x48/Makefile.am | 5 + - .../smartcard/icons/48x48/gdm-smartcard.png | Bin 0 -> 4202 bytes - .../plugins/smartcard/icons/Makefile.am | 1 + - gui/simple-greeter/plugins/smartcard/page.ui | 57 + - gui/simple-greeter/plugins/smartcard/plugin.c | 40 + - po/POTFILES.in | 3 + - 19 files changed, 3227 insertions(+), 1 deletions(-) - create mode 100644 gui/simple-greeter/plugins/smartcard/Makefile.am - create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c - create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.h - create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c - create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.h - create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c - create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard.c - create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard.h - create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam - create mode 100644 gui/simple-greeter/plugins/smartcard/icons/16x16/Makefile.am - create mode 100644 gui/simple-greeter/plugins/smartcard/icons/16x16/gdm-smartcard.png - create mode 100644 gui/simple-greeter/plugins/smartcard/icons/48x48/Makefile.am - create mode 100644 gui/simple-greeter/plugins/smartcard/icons/48x48/gdm-smartcard.png - create mode 100644 gui/simple-greeter/plugins/smartcard/icons/Makefile.am - create mode 100644 gui/simple-greeter/plugins/smartcard/page.ui - create mode 100644 gui/simple-greeter/plugins/smartcard/plugin.c - -diff --git a/configure.ac b/configure.ac -index 7e825cb..b8b6ecf 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -68,6 +68,7 @@ LIBCANBERRA_GTK_REQUIRED_VERSION=0.4 - FONTCONFIG_REQUIRED_VERSION=2.5.0 - UPOWER_REQUIRED_VERSION=0.9.0 - ACCOUNTS_SERVICE_REQUIRED_VERSION=0.6.5 -+NSS_REQUIRED_VERSION=3.11.1 - - EXTRA_COMPILE_WARNINGS(yes) - -@@ -92,6 +93,12 @@ PKG_CHECK_MODULES(DAEMON, - AC_SUBST(DAEMON_CFLAGS) - AC_SUBST(DAEMON_LIBS) - -+PKG_CHECK_MODULES(NSS, -+ nss >= $NSS_REQUIRED_VERSION -+) -+AC_SUBST(NSS_CFLAGS) -+AC_SUBST(NSS_LIBS) -+ - PKG_CHECK_MODULES(XLIB, x11 xau xrandr, , - [AC_PATH_XTRA - if test "x$no_x" = xyes; then -@@ -1444,6 +1451,10 @@ gui/simple-greeter/plugins/fingerprint/Makefile - gui/simple-greeter/plugins/fingerprint/icons/Makefile - gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile - gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile -+gui/simple-greeter/plugins/smartcard/Makefile -+gui/simple-greeter/plugins/smartcard/icons/Makefile -+gui/simple-greeter/plugins/smartcard/icons/16x16/Makefile -+gui/simple-greeter/plugins/smartcard/icons/48x48/Makefile - gui/simple-chooser/Makefile - utils/Makefile - data/gdm.conf -diff --git a/gui/simple-greeter/plugins/Makefile.am b/gui/simple-greeter/plugins/Makefile.am -index 9811a68..3dd336f 100644 ---- a/gui/simple-greeter/plugins/Makefile.am -+++ b/gui/simple-greeter/plugins/Makefile.am -@@ -1 +1 @@ --SUBDIRS = password fingerprint -+SUBDIRS = password fingerprint smartcard -diff --git a/gui/simple-greeter/plugins/smartcard/Makefile.am b/gui/simple-greeter/plugins/smartcard/Makefile.am -new file mode 100644 -index 0000000..e43e424 ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/Makefile.am -@@ -0,0 +1,76 @@ -+SUBDIRS = icons -+ -+NULL = -+PAM_SERVICE_NAME = gdm-smartcard -+ -+extensiondir = $(extensionsdatadir)/smartcard -+extension_DATA = page.ui -+ -+AM_CPPFLAGS = \ -+ -I$(top_srcdir)/common \ -+ -I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter \ -+ -DDMCONFDIR=\""$(dmconfdir)"\" \ -+ -DGDMCONFDIR=\"$(gdmconfdir)\" \ -+ -DPLUGINDATADIR=\""$(extensiondir)"\" \ -+ -DPAMSERVICENAME=\""$(pam_DATA)"\" \ -+ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -+ -DLIBLOCALEDIR=\""$(prefix)/lib/locale"\" \ -+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \ -+ -DLIBEXECDIR=\""$(libexecdir)"\" \ -+ -DLIBDIR=\""$(libdir)"\" \ -+ -DSBINDIR=\""$(sbindir)"\" \ -+ $(DISABLE_DEPRECATED_CFLAGS) \ -+ $(GTK_CFLAGS) \ -+ $(SIMPLE_GREETER_CFLAGS) \ -+ $(POLKIT_GNOME_CFLAGS) \ -+ $(NULL) -+ -+plugindir = $(GDM_SIMPLE_GREETER_PLUGINS_DIR) -+plugin_LTLIBRARIES = smartcard.la -+ -+smartcard_la_CFLAGS = \ -+ $(SIMPLE_GREETER_CFLAGS) \ -+ $(NULL) -+ -+libexec_PROGRAMS = \ -+ gdm-smartcard-worker \ -+ $(NULL) -+ -+ -+smartcard_la_LDFLAGS = -module -avoid-version -export-dynamic -+smartcard_la_LIBADD = ../../../../common/libgdmcommon.la \ -+ ../../libgdmsimplegreeter/libgdmsimplegreeter.la -+smartcard_la_SOURCES = \ -+ gdm-smartcard-extension.h \ -+ gdm-smartcard-extension.c \ -+ plugin.c -+ -+gdm_smartcard_worker_LDADD = ../../../../common/libgdmcommon.la \ -+ $(DAEMON_LIBS) \ -+ $(GTHREAD_LIBS) \ -+ $(NSS_LIBS) \ -+ $(NULL) -+gdm_smartcard_worker_CFLAGS = $(DAEMON_CFLAGS) \ -+ $(NSS_CFLAGS) \ -+ $(NULL) -+gdm_smartcard_worker_SOURCES = \ -+ gdm-smartcard.h \ -+ gdm-smartcard.c \ -+ gdm-smartcard-manager.h \ -+ gdm-smartcard-manager.c \ -+ gdm-smartcard-worker.c \ -+ $(NULL) -+ -+$(PAM_SERVICE_NAME): $(PAM_SERVICE_NAME).pam -+ cp $(PAM_SERVICE_NAME).pam $(PAM_SERVICE_NAME) -+ -+pamdir = $(PAM_PREFIX)/pam.d -+pam_DATA = $(PAM_SERVICE_NAME) -+ -+EXTRA_DIST = $(extension_DATA) $(PAM_SERVICE_NAME).pam -+CLEANFILES = $(PAM_SERVICE_NAME) -+ -+MAINTAINERCLEANFILES = \ -+ *~ \ -+ $(PAM_SERVICE_NAME) \ -+ Makefile.in -diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c -new file mode 100644 -index 0000000..b40a21c ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c -@@ -0,0 +1,513 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ * -+ */ -+ -+#include -+#include "gdm-smartcard-extension.h" -+#include "gdm-conversation.h" -+#include "gdm-task.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#ifndef GDM_SMARTCARD_WORKER_COMMAND -+#define GDM_SMARTCARD_WORKER_COMMAND LIBEXECDIR "/gdm-smartcard-worker" -+#endif -+ -+struct _GdmSmartcardExtensionPrivate -+{ -+ GIcon *icon; -+ GtkWidget *page; -+ GtkActionGroup *actions; -+ GtkAction *login_action; -+ -+ GtkWidget *message_label; -+ GtkWidget *prompt_label; -+ GtkWidget *prompt_entry; -+ -+ GPid worker_pid; -+ int number_of_tokens; -+ -+ guint answer_pending : 1; -+ guint select_when_ready : 1; -+}; -+ -+static void gdm_smartcard_extension_finalize (GObject *object); -+ -+static void gdm_task_iface_init (GdmTaskIface *iface); -+static void gdm_conversation_iface_init (GdmConversationIface *iface); -+static void gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface); -+ -+G_DEFINE_TYPE_WITH_CODE (GdmSmartcardExtension, -+ gdm_smartcard_extension, -+ G_TYPE_OBJECT, -+ G_IMPLEMENT_INTERFACE (GDM_TYPE_GREETER_EXTENSION, -+ gdm_greeter_extension_iface_init) -+ G_IMPLEMENT_INTERFACE (GDM_TYPE_TASK, -+ gdm_task_iface_init) -+ G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION, -+ gdm_conversation_iface_init)); -+ -+static gboolean -+on_smartcard_event (GIOChannel *io_channel, -+ GIOCondition condition, -+ gpointer data) -+{ -+ GdmSmartcardExtension *extension; -+ -+ extension = GDM_SMARTCARD_EXTENSION (data); -+ -+ if (condition & G_IO_IN) { -+ char buffer[1024]; -+ ssize_t num_bytes; -+ -+ num_bytes = read (g_io_channel_unix_get_fd (io_channel), -+ buffer, sizeof (buffer)); -+ -+ if (num_bytes < 0 && errno != EINTR) -+ return FALSE; -+ -+ if (num_bytes != 1) { -+ g_debug ("buffer: %s\n", buffer); -+ return TRUE; -+ } -+ -+ if (buffer[0] == 'I') { -+ extension->priv->number_of_tokens++; -+ } else { -+ extension->priv->number_of_tokens--; -+ } -+ -+ if (extension->priv->number_of_tokens == 1) { -+ if (!gdm_conversation_choose_user (GDM_CONVERSATION (extension), -+ PAMSERVICENAME)) { -+ g_debug ("could not choose smart card user, cancelling..."); -+ gdm_conversation_cancel (GDM_CONVERSATION (extension)); -+ extension->priv->select_when_ready = TRUE; -+ } else { -+ g_debug ("chose smart card user!"); -+ } -+ } else if (extension->priv->number_of_tokens == 0) { -+ gdm_conversation_cancel (GDM_CONVERSATION (extension)); -+ } -+ -+ return TRUE; -+ } -+ -+ if (condition & G_IO_HUP) { -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static void -+watch_for_smartcards (GdmSmartcardExtension *extension) -+{ -+ GError *error; -+ GIOChannel *io_channel; -+ char *args[] = { GDM_SMARTCARD_WORKER_COMMAND, NULL }; -+ GPid pid; -+ int stdout_fd; -+ -+ error = NULL; -+ -+ if (!g_spawn_async_with_pipes (NULL, args, NULL, 0, -+ NULL, NULL, &pid, NULL, -+ &stdout_fd, NULL, &error)) { -+ g_debug ("could not start smart card manager: %s", error->message); -+ g_error_free (error); -+ return; -+ } -+ fcntl (stdout_fd, F_SETFD, FD_CLOEXEC); -+ -+ io_channel = g_io_channel_unix_new (stdout_fd); -+ g_io_channel_set_flags (io_channel, G_IO_FLAG_NONBLOCK, NULL); -+ g_io_channel_set_encoding (io_channel, NULL, NULL); -+ g_io_channel_set_buffered (io_channel, FALSE); -+ g_io_add_watch (io_channel, G_IO_IN, on_smartcard_event, extension); -+ g_io_channel_set_close_on_unref (io_channel, TRUE); -+ g_io_channel_unref (io_channel); -+ -+ extension->priv->worker_pid = pid; -+} -+ -+static void -+stop_watching_for_smartcards (GdmSmartcardExtension *extension) -+{ -+ kill (extension->priv->worker_pid, SIGTERM); -+} -+ -+static void -+gdm_smartcard_extension_set_message (GdmConversation *conversation, -+ const char *message) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation); -+ gtk_widget_show (extension->priv->message_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message); -+} -+ -+static void -+gdm_smartcard_extension_ask_question (GdmConversation *conversation, -+ const char *message) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation); -+ gtk_widget_show (extension->priv->prompt_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE); -+ gtk_widget_show (extension->priv->prompt_entry); -+ gtk_action_set_visible (extension->priv->login_action, TRUE); -+ gtk_action_set_sensitive (extension->priv->login_action, TRUE); -+ gtk_widget_grab_focus (extension->priv->prompt_entry); -+ extension->priv->answer_pending = TRUE; -+} -+ -+static void -+gdm_smartcard_extension_ask_secret (GdmConversation *conversation, -+ const char *message) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation); -+ gtk_widget_show (extension->priv->prompt_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message); -+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), FALSE); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+ gtk_widget_show (extension->priv->prompt_entry); -+ gtk_widget_grab_focus (extension->priv->prompt_entry); -+ gtk_action_set_visible (extension->priv->login_action, TRUE); -+ gtk_action_set_sensitive (extension->priv->login_action, TRUE); -+ extension->priv->answer_pending = TRUE; -+} -+ -+static void -+gdm_smartcard_extension_reset (GdmConversation *conversation) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation); -+ gtk_widget_hide (extension->priv->prompt_label); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), ""); -+ -+ gtk_widget_hide (extension->priv->prompt_entry); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE); -+ gtk_action_set_visible (extension->priv->login_action, FALSE); -+ extension->priv->answer_pending = FALSE; -+ -+ gdm_task_set_enabled (GDM_TASK (conversation), FALSE); -+} -+ -+static void -+gdm_smartcard_extension_set_ready (GdmConversation *conversation) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation); -+ gdm_task_set_enabled (GDM_TASK (conversation), TRUE); -+ -+ if (extension->priv->worker_pid <= 0) { -+ watch_for_smartcards (extension); -+ } -+ -+ if (extension->priv->select_when_ready) { -+ if (gdm_conversation_choose_user (GDM_CONVERSATION (extension), -+ PAMSERVICENAME)) { -+ extension->priv->select_when_ready = FALSE; -+ } -+ } -+} -+ -+char * -+gdm_smartcard_extension_get_service_name (GdmConversation *conversation) -+{ -+ return g_strdup (PAMSERVICENAME); -+} -+ -+GtkWidget * -+gdm_smartcard_extension_get_page (GdmConversation *conversation) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation); -+ return extension->priv->page; -+} -+ -+GtkActionGroup * -+gdm_smartcard_extension_get_actions (GdmConversation *conversation) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation); -+ -+ return g_object_ref (extension->priv->actions); -+} -+ -+void -+gdm_smartcard_extension_request_answer (GdmConversation *conversation) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation); -+ const char *text; -+ -+ if (!extension->priv->answer_pending) { -+ gdm_conversation_answer (conversation, NULL); -+ return; -+ } -+ -+ extension->priv->answer_pending = FALSE; -+ text = gtk_entry_get_text (GTK_ENTRY (extension->priv->prompt_entry)); -+ gdm_conversation_answer (conversation, text); -+ -+ gtk_widget_hide (extension->priv->prompt_entry); -+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), ""); -+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), ""); -+ gtk_action_set_visible (extension->priv->login_action, FALSE); -+} -+ -+gboolean -+gdm_smartcard_extension_focus (GdmConversation *conversation) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation); -+ -+ if (!extension->priv->answer_pending) { -+ return FALSE; -+ } -+ -+ gtk_widget_grab_focus (extension->priv->prompt_entry); -+ return TRUE; -+} -+ -+GIcon * -+gdm_smartcard_extension_get_icon (GdmTask *task) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (task); -+ return g_object_ref (extension->priv->icon); -+} -+ -+char * -+gdm_smartcard_extension_get_name (GdmTask *task) -+{ -+ return g_strdup (_("Smartcard Authentication")); -+} -+ -+char * -+gdm_smartcard_extension_get_description (GdmTask *task) -+{ -+ return g_strdup (_("Log into session with smartcard")); -+} -+ -+gboolean -+gdm_smartcard_extension_is_choosable (GdmTask *task) -+{ -+ return TRUE; -+} -+ -+gboolean -+gdm_smartcard_extension_is_visible (GdmTask *task) -+{ -+ char *contents, **lines, *pid_dir; -+ gboolean ret; -+ guint i; -+ pid_t pid; -+ -+ /* -+ * FIXME: We shouldn't use a distro specific hack here -+ */ -+ -+ if (g_file_get_contents ("/var/run/pcscd.pid", -+ &contents, NULL, NULL) == FALSE) { -+ return FALSE; -+ } -+ -+ pid = (pid_t) atoi (contents); -+ g_free (contents); -+ -+ if (pid == 0) { -+ return FALSE; -+ } -+ -+ pid_dir = g_strdup_printf ("/proc/%d", (int) pid); -+ if (!g_file_test (pid_dir, G_FILE_TEST_EXISTS)) { -+ g_free (pid_dir); -+ return FALSE; -+ } -+ g_free (pid_dir); -+ -+ if (g_file_get_contents ("/etc/sysconfig/authconfig", -+ &contents, NULL, NULL) == FALSE) { -+ return FALSE; -+ } -+ -+ lines = g_strsplit (contents, "\n", -1); -+ g_free (contents); -+ -+ ret = FALSE; -+ -+ for (i = 0; lines[i] ; i++) { -+ if (g_str_has_prefix (lines[i], "USESMARTCARD=") != FALSE) { -+ char *value; -+ -+ value = lines[i] + strlen ("USESMARTCARD="); -+ if (rpmatch (value)) { -+ ret = TRUE; -+ break; -+ } -+ } -+ } -+ -+ g_strfreev (lines); -+ -+ return TRUE; -+} -+ -+static void -+gdm_task_iface_init (GdmTaskIface *iface) -+{ -+ iface->get_icon = gdm_smartcard_extension_get_icon; -+ iface->get_description = gdm_smartcard_extension_get_description; -+ iface->get_name = gdm_smartcard_extension_get_name; -+ iface->is_choosable = gdm_smartcard_extension_is_choosable; -+ iface->is_visible = gdm_smartcard_extension_is_visible; -+} -+ -+static void -+gdm_conversation_iface_init (GdmConversationIface *iface) -+{ -+ iface->set_message = gdm_smartcard_extension_set_message; -+ iface->ask_question = gdm_smartcard_extension_ask_question; -+ iface->ask_secret = gdm_smartcard_extension_ask_secret; -+ iface->reset = gdm_smartcard_extension_reset; -+ iface->set_ready = gdm_smartcard_extension_set_ready; -+ iface->get_service_name = gdm_smartcard_extension_get_service_name; -+ iface->get_page = gdm_smartcard_extension_get_page; -+ iface->get_actions = gdm_smartcard_extension_get_actions; -+ iface->request_answer = gdm_smartcard_extension_request_answer; -+ iface->focus = gdm_smartcard_extension_focus; -+} -+ -+static void -+gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface) -+{ -+} -+ -+static void -+gdm_smartcard_extension_class_init (GdmSmartcardExtensionClass *extension_class) -+{ -+ GObjectClass *object_class; -+ -+ object_class = G_OBJECT_CLASS (extension_class); -+ -+ object_class->finalize = gdm_smartcard_extension_finalize; -+ -+ g_type_class_add_private (extension_class, -+ sizeof (GdmSmartcardExtensionPrivate)); -+} -+ -+static void -+gdm_smartcard_extension_finalize (GObject *object) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (object); -+ -+ if (extension->priv->worker_pid > 0) { -+ stop_watching_for_smartcards (extension); -+ } -+} -+ -+static void -+create_page (GdmSmartcardExtension *extension) -+{ -+ GtkBuilder *builder; -+ GObject *object; -+ GError *error; -+ -+ builder = gtk_builder_new (); -+ -+ error = NULL; -+ gtk_builder_add_from_file (builder, -+ PLUGINDATADIR "/page.ui", -+ &error); -+ -+ if (error != NULL) { -+ g_warning ("Could not load UI file: %s", error->message); -+ g_error_free (error); -+ return; -+ } -+ -+ object = gtk_builder_get_object (builder, "page"); -+ g_object_ref (object); -+ -+ extension->priv->page = GTK_WIDGET (object); -+ -+ object = gtk_builder_get_object (builder, "auth-prompt-label"); -+ g_object_ref (object); -+ extension->priv->prompt_label = GTK_WIDGET (object); -+ gtk_widget_hide (extension->priv->prompt_label); -+ -+ object = gtk_builder_get_object (builder, "auth-prompt-entry"); -+ g_object_ref (object); -+ extension->priv->prompt_entry = GTK_WIDGET (object); -+ gtk_widget_hide (extension->priv->prompt_entry); -+ -+ object = gtk_builder_get_object (builder, "auth-message-label"); -+ g_object_ref (object); -+ extension->priv->message_label = GTK_WIDGET (object); -+ gtk_widget_show (extension->priv->message_label); -+ -+ g_object_unref (builder); -+} -+ -+static void -+on_activate_log_in (GdmSmartcardExtension *extension) -+{ -+ gdm_smartcard_extension_request_answer (GDM_CONVERSATION (extension)); -+ gtk_action_set_sensitive (extension->priv->login_action, FALSE); -+} -+ -+static void -+create_actions (GdmSmartcardExtension *extension) -+{ -+ GtkAction *action; -+ -+ extension->priv->actions = gtk_action_group_new ("gdm-smartcard-extension"); -+ -+ action = gtk_action_new (GDM_CONVERSATION_DEFAULT_ACTION, -+ _("Log In"), NULL, NULL); -+ g_signal_connect_swapped (action, "activate", -+ G_CALLBACK (on_activate_log_in), extension); -+ g_object_set (G_OBJECT (action), "icon-name", "go-home", NULL); -+ gtk_action_group_add_action (extension->priv->actions, -+ action); -+ -+ gtk_action_set_visible (action, FALSE); -+ extension->priv->login_action = action; -+} -+ -+static void -+gdm_smartcard_extension_init (GdmSmartcardExtension *extension) -+{ -+ extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (extension, -+ GDM_TYPE_SMARTCARD_EXTENSION, -+ GdmSmartcardExtensionPrivate); -+ -+ extension->priv->icon = g_themed_icon_new ("gdm-smartcard"); -+ create_page (extension); -+ create_actions (extension); -+ gdm_smartcard_extension_reset (GDM_CONVERSATION (extension)); -+} -diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.h b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.h -new file mode 100644 -index 0000000..285b51a ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.h -@@ -0,0 +1,56 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -+ * 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ */ -+ -+#ifndef __GDM_SMARTCARD_EXTENSION_H -+#define __GDM_SMARTCARD_EXTENSION_H -+ -+#include -+#include "gdm-greeter-extension.h" -+ -+G_BEGIN_DECLS -+ -+#define GDM_TYPE_SMARTCARD_EXTENSION (gdm_smartcard_extension_get_type ()) -+#define GDM_SMARTCARD_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_SMARTCARD_EXTENSION, GdmSmartcardExtension)) -+#define GDM_SMARTCARD_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_SMARTCARD_EXTENSION, GdmSmartcardExtensionClass)) -+#define GDM_IS_SMARTCARD_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_SMARTCARD_EXTENSION)) -+#define GDM_IS_SMARTCARD_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_SMARTCARD_EXTENSION)) -+#define GDM_SMARTCARD_EXTENSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_SMARTCARD_EXTENSION, GdmSmartcardExtensionClass)) -+ -+typedef struct _GdmSmartcardExtensionPrivate GdmSmartcardExtensionPrivate; -+ -+typedef struct -+{ -+ GObject parent; -+ GdmSmartcardExtensionPrivate *priv; -+} GdmSmartcardExtension; -+ -+typedef struct -+{ -+ GObjectClass parent_class; -+} GdmSmartcardExtensionClass; -+ -+GType gdm_smartcard_extension_get_type (void); -+ -+GdmSmartcardExtension *gdm_smartcard_extension_new (void); -+ -+G_END_DECLS -+ -+#endif /* GDM_SMARTCARD_EXTENSION_H */ -diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c -new file mode 100644 -index 0000000..5af0da9 ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c -@@ -0,0 +1,1521 @@ -+/* gdm-smartcard-manager.c - object for monitoring smartcard insertion and -+ * removal events -+ * -+ * Copyright (C) 2006, 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -+ * 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ */ -+#define _GNU_SOURCE -+#include "gdm-smartcard-manager.h" -+ -+#define GDM_SMARTCARD_ENABLE_INTERNAL_API -+#include "gdm-smartcard.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifndef GDM_SMARTCARD_MANAGER_DRIVER -+#define GDM_SMARTCARD_MANAGER_DRIVER LIBDIR"/pkcs11/libcoolkeypk11.so" -+#endif -+ -+#ifndef GDM_SMARTCARD_MANAGER_NSS_DB -+#define GDM_SMARTCARD_MANAGER_NSS_DB SYSCONFDIR"/pki/nssdb" -+#endif -+ -+#ifndef GDM_MAX_OPEN_FILE_DESCRIPTORS -+#define GDM_MAX_OPEN_FILE_DESCRIPTORS 1024 -+#endif -+ -+#ifndef GDM_OPEN_FILE_DESCRIPTORS_DIR -+#define GDM_OPEN_FILE_DESCRIPTORS_DIR "/proc/self/fd" -+#endif -+ -+typedef enum _GdmSmartcardManagerState GdmSmartcardManagerState; -+typedef struct _GdmSmartcardManagerWorker GdmSmartcardManagerWorker; -+ -+enum _GdmSmartcardManagerState { -+ GDM_SMARTCARD_MANAGER_STATE_STOPPED = 0, -+ GDM_SMARTCARD_MANAGER_STATE_STARTING, -+ GDM_SMARTCARD_MANAGER_STATE_STARTED, -+ GDM_SMARTCARD_MANAGER_STATE_STOPPING, -+}; -+ -+struct _GdmSmartcardManagerPrivate { -+ GdmSmartcardManagerState state; -+ GList *modules; -+ char *module_path; -+ -+ GList *workers; -+ -+ GPid smartcard_event_watcher_pid; -+ GHashTable *smartcards; -+ -+ guint poll_timeout_id; -+ -+ guint32 is_unstoppable : 1; -+ guint32 nss_is_loaded : 1; -+}; -+ -+struct _GdmSmartcardManagerWorker { -+ GdmSmartcardManager *manager; -+ gint manager_fd; -+ -+ GThread *thread; -+ SECMODModule *module; -+ GHashTable *smartcards; -+ gint fd; -+ GSource *event_source; -+ -+ guint32 nss_is_loaded : 1; -+}; -+ -+static void gdm_smartcard_manager_finalize (GObject *object); -+static void gdm_smartcard_manager_class_install_signals (GdmSmartcardManagerClass *service_class); -+static void gdm_smartcard_manager_class_install_properties (GdmSmartcardManagerClass *service_class); -+static void gdm_smartcard_manager_set_property (GObject *object, -+ guint prop_id, -+ const GValue *value, -+ GParamSpec *pspec); -+static void gdm_smartcard_manager_get_property (GObject *object, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec); -+static void gdm_smartcard_manager_set_module_path (GdmSmartcardManager *manager, -+ const char *module_path); -+static void gdm_smartcard_manager_card_removed_handler (GdmSmartcardManager *manager, -+ GdmSmartcard *card); -+static void gdm_smartcard_manager_card_inserted_handler (GdmSmartcardManager *manager_class, -+ GdmSmartcard *card); -+static gboolean gdm_smartcard_manager_stop_now (GdmSmartcardManager *manager); -+static void gdm_smartcard_manager_queue_stop (GdmSmartcardManager *manager); -+ -+static GdmSmartcardManagerWorker *gdm_smartcard_manager_create_worker (GdmSmartcardManager *manager, -+ SECMODModule *module); -+ -+static GdmSmartcardManagerWorker * gdm_smartcard_manager_worker_new (GdmSmartcardManager *manager, -+ int worker_fd, -+ int manager_fd, -+ SECMODModule *module); -+static void gdm_smartcard_manager_worker_free (GdmSmartcardManagerWorker *worker); -+static gboolean gdm_open_pipe (gint *write_fd, gint *read_fd); -+static gboolean sc_read_bytes (gint fd, gpointer bytes, gsize num_bytes); -+static gboolean sc_write_bytes (gint fd, gconstpointer bytes, gsize num_bytes); -+static GdmSmartcard *sc_read_smartcard (gint fd, SECMODModule *module); -+static gboolean sc_write_smartcard (gint fd, GdmSmartcard *card); -+ -+enum { -+ PROP_0 = 0, -+ PROP_MODULE_PATH, -+ NUMBER_OF_PROPERTIES -+}; -+ -+enum { -+ SMARTCARD_INSERTED = 0, -+ SMARTCARD_REMOVED, -+ ERROR, -+ NUMBER_OF_SIGNALS -+}; -+ -+static guint gdm_smartcard_manager_signals[NUMBER_OF_SIGNALS]; -+ -+G_DEFINE_TYPE (GdmSmartcardManager, -+ gdm_smartcard_manager, -+ G_TYPE_OBJECT); -+ -+static void -+gdm_smartcard_manager_class_init (GdmSmartcardManagerClass *manager_class) -+{ -+ GObjectClass *gobject_class; -+ -+ gobject_class = G_OBJECT_CLASS (manager_class); -+ -+ gobject_class->finalize = gdm_smartcard_manager_finalize; -+ -+ gdm_smartcard_manager_class_install_signals (manager_class); -+ gdm_smartcard_manager_class_install_properties (manager_class); -+ -+ g_type_class_add_private (manager_class, -+ sizeof (GdmSmartcardManagerPrivate)); -+} -+ -+static void -+gdm_smartcard_manager_class_install_properties (GdmSmartcardManagerClass *card_class) -+{ -+ GObjectClass *object_class; -+ GParamSpec *param_spec; -+ -+ object_class = G_OBJECT_CLASS (card_class); -+ object_class->set_property = gdm_smartcard_manager_set_property; -+ object_class->get_property = gdm_smartcard_manager_get_property; -+ -+ param_spec = g_param_spec_string ("module-path", _("Module Path"), -+ _("path to smartcard PKCS #11 driver"), -+ NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); -+ g_object_class_install_property (object_class, PROP_MODULE_PATH, param_spec); -+} -+ -+static void -+gdm_smartcard_manager_set_property (GObject *object, -+ guint prop_id, -+ const GValue *value, -+ GParamSpec *pspec) -+{ -+ GdmSmartcardManager *manager = GDM_SMARTCARD_MANAGER (object); -+ -+ switch (prop_id) { -+ case PROP_MODULE_PATH: -+ gdm_smartcard_manager_set_module_path (manager, -+ g_value_get_string (value)); -+ break; -+ -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+ break; -+ } -+} -+ -+static void -+gdm_smartcard_manager_get_property (GObject *object, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec) -+{ -+ GdmSmartcardManager *manager = GDM_SMARTCARD_MANAGER (object); -+ char *module_path; -+ -+ switch (prop_id) { -+ case PROP_MODULE_PATH: -+ module_path = gdm_smartcard_manager_get_module_path (manager); -+ g_value_set_string (value, module_path); -+ g_free (module_path); -+ break; -+ -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+ break; -+ } -+} -+ -+char * -+gdm_smartcard_manager_get_module_path (GdmSmartcardManager *manager) -+{ -+ return manager->priv->module_path; -+} -+ -+static void -+gdm_smartcard_manager_set_module_path (GdmSmartcardManager *manager, -+ const char *module_path) -+{ -+ if ((manager->priv->module_path == NULL) && (module_path == NULL)) { -+ return; -+ } -+ -+ if (((manager->priv->module_path == NULL) || -+ (module_path == NULL) || -+ (strcmp (manager->priv->module_path, module_path) != 0))) { -+ g_free (manager->priv->module_path); -+ manager->priv->module_path = g_strdup (module_path); -+ g_object_notify (G_OBJECT (manager), "module-path"); -+ } -+} -+ -+static void -+gdm_smartcard_manager_card_removed_handler (GdmSmartcardManager *manager, -+ GdmSmartcard *card) -+{ -+ g_debug ("informing smartcard of its removal"); -+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_REMOVED); -+ g_debug ("done"); -+} -+ -+static void -+gdm_smartcard_manager_card_inserted_handler (GdmSmartcardManager *manager, -+ GdmSmartcard *card) -+{ -+ g_debug ("informing smartcard of its insertion"); -+ -+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_INSERTED); -+ g_debug ("done"); -+ -+} -+ -+static void -+gdm_smartcard_manager_class_install_signals (GdmSmartcardManagerClass *manager_class) -+{ -+ GObjectClass *object_class; -+ -+ object_class = G_OBJECT_CLASS (manager_class); -+ -+ gdm_smartcard_manager_signals[SMARTCARD_INSERTED] = -+ g_signal_new ("smartcard-inserted", -+ G_OBJECT_CLASS_TYPE (object_class), -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmSmartcardManagerClass, -+ smartcard_inserted), -+ NULL, NULL, g_cclosure_marshal_VOID__POINTER, -+ G_TYPE_NONE, 1, G_TYPE_POINTER); -+ manager_class->smartcard_inserted = gdm_smartcard_manager_card_inserted_handler; -+ -+ gdm_smartcard_manager_signals[SMARTCARD_REMOVED] = -+ g_signal_new ("smartcard-removed", -+ G_OBJECT_CLASS_TYPE (object_class), -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmSmartcardManagerClass, -+ smartcard_removed), -+ NULL, NULL, g_cclosure_marshal_VOID__POINTER, -+ G_TYPE_NONE, 1, G_TYPE_POINTER); -+ manager_class->smartcard_removed = gdm_smartcard_manager_card_removed_handler; -+ -+ gdm_smartcard_manager_signals[ERROR] = -+ g_signal_new ("error", -+ G_OBJECT_CLASS_TYPE (object_class), -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (GdmSmartcardManagerClass, error), -+ NULL, NULL, g_cclosure_marshal_VOID__POINTER, -+ G_TYPE_NONE, 1, G_TYPE_POINTER); -+ manager_class->error = NULL; -+} -+ -+static gboolean -+sc_slot_id_equal (CK_SLOT_ID *slot_id_1, -+ CK_SLOT_ID *slot_id_2) -+{ -+ g_assert (slot_id_1 != NULL); -+ g_assert (slot_id_2 != NULL); -+ -+ return *slot_id_1 == *slot_id_2; -+} -+ -+static gboolean -+sc_slot_id_hash (CK_SLOT_ID *slot_id) -+{ -+ guint32 upper_bits, lower_bits; -+ gint temp; -+ -+ if (sizeof (CK_SLOT_ID) == sizeof (gint)) { -+ return g_int_hash (slot_id); -+ } -+ -+ upper_bits = ((*slot_id) >> 31) - 1; -+ lower_bits = (*slot_id) & 0xffffffff; -+ -+ /* The upper bits are almost certainly always zero, -+ * so let's degenerate to g_int_hash for the -+ * (very) common case -+ */ -+ temp = lower_bits + upper_bits; -+ return upper_bits + g_int_hash (&temp); -+} -+ -+static void -+gdm_smartcard_manager_init (GdmSmartcardManager *manager) -+{ -+ g_debug ("initializing smartcard manager"); -+ -+ manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, -+ GDM_TYPE_SMARTCARD_MANAGER, -+ GdmSmartcardManagerPrivate); -+ manager->priv->poll_timeout_id = 0; -+ manager->priv->is_unstoppable = FALSE; -+ -+ manager->priv->smartcards = -+ g_hash_table_new_full (g_str_hash, -+ g_str_equal, -+ (GDestroyNotify) g_free, -+ (GDestroyNotify) g_object_unref); -+ -+ if (!g_thread_supported()) { -+ g_thread_init (NULL); -+ } -+ -+} -+ -+static void -+gdm_smartcard_manager_finalize (GObject *object) -+{ -+ GdmSmartcardManager *manager; -+ GObjectClass *gobject_class; -+ -+ manager = GDM_SMARTCARD_MANAGER (object); -+ gobject_class = -+ G_OBJECT_CLASS (gdm_smartcard_manager_parent_class); -+ -+ gdm_smartcard_manager_stop_now (manager); -+ -+ g_hash_table_destroy (manager->priv->smartcards); -+ manager->priv->smartcards = NULL; -+ -+ gobject_class->finalize (object); -+} -+ -+GQuark -+gdm_smartcard_manager_error_quark (void) -+{ -+ static GQuark error_quark = 0; -+ -+ if (error_quark == 0) { -+ error_quark = g_quark_from_static_string ("gdm-smartcard-manager-error-quark"); -+ } -+ -+ return error_quark; -+} -+ -+GdmSmartcardManager * -+gdm_smartcard_manager_new (const char *module_path) -+{ -+ GdmSmartcardManager *instance; -+ -+ instance = GDM_SMARTCARD_MANAGER (g_object_new (GDM_TYPE_SMARTCARD_MANAGER, -+ "module-path", module_path, -+ NULL)); -+ -+ return instance; -+} -+ -+static void -+gdm_smartcard_manager_emit_error (GdmSmartcardManager *manager, -+ GError *error) -+{ -+ manager->priv->is_unstoppable = TRUE; -+ g_signal_emit (manager, gdm_smartcard_manager_signals[ERROR], 0, -+ error); -+ manager->priv->is_unstoppable = FALSE; -+} -+ -+static void -+gdm_smartcard_manager_emit_smartcard_inserted (GdmSmartcardManager *manager, -+ GdmSmartcard *card) -+{ -+ manager->priv->is_unstoppable = TRUE; -+ g_signal_emit (manager, gdm_smartcard_manager_signals[SMARTCARD_INSERTED], 0, -+ card); -+ manager->priv->is_unstoppable = FALSE; -+} -+ -+static void -+gdm_smartcard_manager_emit_smartcard_removed (GdmSmartcardManager *manager, -+ GdmSmartcard *card) -+{ -+ GdmSmartcardManagerState old_state; -+ -+ old_state = manager->priv->state; -+ manager->priv->is_unstoppable = TRUE; -+ g_signal_emit (manager, gdm_smartcard_manager_signals[SMARTCARD_REMOVED], 0, -+ card); -+ manager->priv->is_unstoppable = FALSE; -+} -+ -+static gboolean -+gdm_smartcard_manager_check_for_and_process_events (GIOChannel *io_channel, -+ GIOCondition condition, -+ GdmSmartcardManagerWorker *worker) -+{ -+ GdmSmartcard *card; -+ GdmSmartcardManager *manager; -+ gboolean should_stop; -+ guchar event_type; -+ char *card_name; -+ gint fd; -+ -+ manager = worker->manager; -+ -+ g_debug ("event!"); -+ card = NULL; -+ should_stop = (condition & G_IO_HUP) || (condition & G_IO_ERR); -+ -+ if (should_stop) { -+ g_debug ("received %s on event socket, stopping " -+ "manager...", -+ (condition & G_IO_HUP) && (condition & G_IO_ERR)? -+ "error and hangup" : -+ (condition & G_IO_HUP)? -+ "hangup" : "error"); -+ } -+ -+ if (!(condition & G_IO_IN)) { -+ g_debug ("nevermind outta here!"); -+ goto out; -+ } -+ -+ fd = g_io_channel_unix_get_fd (io_channel); -+ -+ event_type = '\0'; -+ if (!sc_read_bytes (fd, &event_type, 1)) { -+ g_debug ("could not read event type, stopping"); -+ should_stop = TRUE; -+ goto out; -+ } -+ -+ card = sc_read_smartcard (fd, worker->module); -+ -+ if (card == NULL) { -+ g_debug ("could not read card, stopping"); -+ should_stop = TRUE; -+ goto out; -+ } -+ -+ card_name = gdm_smartcard_get_name (card); -+ g_debug ("card '%s' had event %c", card_name, event_type); -+ -+ switch (event_type) { -+ case 'I': -+ g_hash_table_replace (manager->priv->smartcards, -+ card_name, card); -+ card_name = NULL; -+ -+ gdm_smartcard_manager_emit_smartcard_inserted (manager, card); -+ card = NULL; -+ break; -+ -+ case 'R': -+ gdm_smartcard_manager_emit_smartcard_removed (manager, card); -+ if (!g_hash_table_remove (manager->priv->smartcards, card_name)) { -+ g_debug ("got removal event of unknown card!"); -+ } -+ g_free (card_name); -+ card_name = NULL; -+ card = NULL; -+ break; -+ -+ default: -+ g_free (card_name); -+ card_name = NULL; -+ g_object_unref (card); -+ -+ should_stop = TRUE; -+ break; -+ } -+ -+out: -+ if (should_stop) { -+ GError *error; -+ -+ error = g_error_new (GDM_SMARTCARD_MANAGER_ERROR, -+ GDM_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, -+ "%s", (condition & G_IO_IN) ? g_strerror (errno) : _("received error or hang up from event source")); -+ -+ gdm_smartcard_manager_emit_error (manager, error); -+ g_error_free (error); -+ gdm_smartcard_manager_stop_now (manager); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static void -+stop_manager (GdmSmartcardManager *manager) -+{ -+ manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STOPPED; -+ -+ if (manager->priv->nss_is_loaded) { -+ NSS_Shutdown (); -+ manager->priv->nss_is_loaded = FALSE; -+ } -+ g_debug ("smartcard manager stopped"); -+} -+ -+static void -+stop_worker (GdmSmartcardManagerWorker *worker) -+{ -+ GdmSmartcardManager *manager; -+ -+ manager = worker->manager; -+ -+ if (worker->event_source != NULL) { -+ g_source_destroy (worker->event_source); -+ worker->event_source = NULL; -+ } -+ -+ if (worker->thread != NULL) { -+ SECMOD_CancelWait (worker->module); -+ worker->thread = NULL; -+ } -+ -+ SECMOD_DestroyModule (worker->module); -+ manager->priv->workers = g_list_remove (manager->priv->workers, worker); -+ -+ if (manager->priv->workers == NULL && manager->priv->state != GDM_SMARTCARD_MANAGER_STATE_STOPPED) { -+ stop_manager (manager); -+ } -+} -+ -+static void -+gdm_smartcard_manager_event_processing_stopped_handler (GdmSmartcardManagerWorker *worker) -+{ -+ worker->event_source = NULL; -+ -+ stop_worker (worker); -+} -+ -+static gboolean -+gdm_open_pipe (gint *write_fd, -+ gint *read_fd) -+{ -+ gint pipe_fds[2] = { -1, -1 }; -+ -+ g_assert (write_fd != NULL); -+ g_assert (read_fd != NULL); -+ -+ if (pipe (pipe_fds) < 0) { -+ return FALSE; -+ } -+ -+ if (fcntl (pipe_fds[0], F_SETFD, FD_CLOEXEC) < 0) { -+ close (pipe_fds[0]); -+ close (pipe_fds[1]); -+ return FALSE; -+ } -+ -+ if (fcntl (pipe_fds[1], F_SETFD, FD_CLOEXEC) < 0) { -+ close (pipe_fds[0]); -+ close (pipe_fds[1]); -+ return FALSE; -+ } -+ -+ *read_fd = pipe_fds[0]; -+ *write_fd = pipe_fds[1]; -+ -+ return TRUE; -+} -+ -+static void -+gdm_smartcard_manager_stop_watching_for_events (GdmSmartcardManager *manager) -+{ -+ GList *node; -+ -+ node = manager->priv->workers; -+ while (node != NULL) { -+ GdmSmartcardManagerWorker *worker; -+ GList *next_node; -+ -+ worker = (GdmSmartcardManagerWorker *) node->data; -+ next_node = node->next; -+ -+ stop_worker (worker); -+ -+ node = next_node; -+ } -+} -+ -+static gboolean -+sc_load_nss (GError **error) -+{ -+ SECStatus status = SECSuccess; -+ static const guint32 flags = -+ NSS_INIT_READONLY | -+ NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | -+ NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD; -+ -+ g_debug ("attempting to load NSS database '%s'", -+ GDM_SMARTCARD_MANAGER_NSS_DB); -+ -+ PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); -+ -+ status = NSS_Initialize (GDM_SMARTCARD_MANAGER_NSS_DB, -+ "", "", SECMOD_DB, flags); -+ -+ if (status != SECSuccess) { -+ gsize error_message_size; -+ char *error_message; -+ -+ error_message_size = PR_GetErrorTextLength (); -+ -+ if (error_message_size == 0) { -+ g_debug ("NSS security system could not be initialized"); -+ g_set_error (error, -+ GDM_SMARTCARD_MANAGER_ERROR, -+ GDM_SMARTCARD_MANAGER_ERROR_WITH_NSS, -+ _("NSS security system could not be initialized")); -+ goto out; -+ } -+ -+ error_message = g_slice_alloc0 (error_message_size); -+ PR_GetErrorText (error_message); -+ -+ g_set_error (error, -+ GDM_SMARTCARD_MANAGER_ERROR, -+ GDM_SMARTCARD_MANAGER_ERROR_WITH_NSS, -+ "%s", error_message); -+ g_debug ("NSS security system could not be initialized - %s", -+ error_message); -+ -+ g_slice_free1 (error_message_size, error_message); -+ -+ goto out; -+ } -+ -+ g_debug ("NSS database sucessfully loaded"); -+ return TRUE; -+ -+out: -+ g_debug ("NSS database couldn't be sucessfully loaded"); -+ return FALSE; -+} -+ -+static GList * -+get_available_modules (GdmSmartcardManager *manager) -+{ -+ SECMODModuleList *module_list, *tmp; -+ GList *modules; -+ -+ g_debug ("Getting list of suitable modules"); -+ -+ module_list = SECMOD_GetDefaultModuleList (); -+ modules = NULL; -+ for (tmp = module_list; tmp != NULL; tmp = tmp->next) { -+ if (!SECMOD_HasRemovableSlots (tmp->module) || -+ !tmp->module->loaded) -+ continue; -+ -+ g_debug ("Using module '%s'", tmp->module->commonName); -+ -+ modules = g_list_prepend (modules, -+ SECMOD_ReferenceModule (tmp->module)); -+ } -+ -+ return modules; -+} -+ -+static gboolean -+load_driver (GdmSmartcardManager *manager, -+ char *module_path, -+ GError **error) -+{ -+ GList *modules; -+ char *module_spec; -+ gboolean module_explicitly_specified; -+ -+ g_debug ("attempting to load driver..."); -+ -+ modules = NULL; -+ module_explicitly_specified = module_path != NULL; -+ if (module_explicitly_specified) { -+ SECMODModule *module; -+ -+ module_spec = g_strdup_printf ("library=\"%s\"", module_path); -+ g_debug ("loading smartcard driver using spec '%s'", -+ module_spec); -+ -+ module = SECMOD_LoadUserModule (module_spec, -+ NULL /* parent */, -+ FALSE /* recurse */); -+ g_free (module_spec); -+ module_spec = NULL; -+ -+ if (!SECMOD_HasRemovableSlots (module) || -+ !module->loaded) { -+ modules = g_list_prepend (modules, module); -+ } else { -+ g_debug ("fallback module found but not %s", -+ SECMOD_HasRemovableSlots (module)? -+ "removable" : "loaded"); -+ SECMOD_DestroyModule (module); -+ } -+ -+ } else { -+ SECMODListLock *lock; -+ -+ lock = SECMOD_GetDefaultModuleListLock (); -+ -+ if (lock != NULL) { -+ SECMOD_GetReadLock (lock); -+ modules = get_available_modules (manager); -+ SECMOD_ReleaseReadLock (lock); -+ } -+ -+ /* fallback to compiled in driver path -+ */ -+ if (modules == NULL) { -+ SECMODModule *module; -+ module_path = GDM_SMARTCARD_MANAGER_DRIVER; -+ module_spec = g_strdup_printf ("library=\"%s\"", module_path); -+ g_debug ("loading smartcard driver using spec '%s'", -+ module_spec); -+ -+ module = SECMOD_LoadUserModule (module_spec, -+ NULL /* parent */, -+ FALSE /* recurse */); -+ g_free (module_spec); -+ module_spec = NULL; -+ -+ if (!SECMOD_HasRemovableSlots (module) || -+ !module->loaded) { -+ modules = g_list_prepend (modules, module); -+ } else { -+ g_debug ("fallback module found but not loaded"); -+ SECMOD_DestroyModule (module); -+ } -+ } -+ -+ } -+ -+ if (!module_explicitly_specified && modules == NULL) { -+ g_set_error (error, -+ GDM_SMARTCARD_MANAGER_ERROR, -+ GDM_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, -+ _("no suitable smartcard driver could be found")); -+ } else if (modules == NULL) { -+ -+ gsize error_message_size; -+ char *error_message; -+ -+ error_message_size = PR_GetErrorTextLength (); -+ -+ if (error_message_size == 0) { -+ g_debug ("smartcard driver '%s' could not be loaded", -+ module_path); -+ g_set_error (error, -+ GDM_SMARTCARD_MANAGER_ERROR, -+ GDM_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, -+ _("smartcard driver '%s' could not be " -+ "loaded"), module_path); -+ goto out; -+ } -+ -+ error_message = g_slice_alloc0 (error_message_size); -+ PR_GetErrorText (error_message); -+ -+ g_set_error (error, -+ GDM_SMARTCARD_MANAGER_ERROR, -+ GDM_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, -+ "%s", error_message); -+ -+ g_debug ("smartcard driver '%s' could not be loaded - %s", -+ module_path, error_message); -+ g_slice_free1 (error_message_size, error_message); -+ } -+ -+ manager->priv->modules = modules; -+out: -+ return manager->priv->modules != NULL; -+} -+ -+static void -+gdm_smartcard_manager_get_all_cards (GdmSmartcardManager *manager) -+{ -+ GList *node; -+ int i; -+ -+ node = manager->priv->workers; -+ while (node != NULL) { -+ -+ GdmSmartcardManagerWorker *worker; -+ -+ worker = (GdmSmartcardManagerWorker *) node->data; -+ -+ for (i = 0; i < worker->module->slotCount; i++) { -+ GdmSmartcard *card; -+ CK_SLOT_ID slot_id; -+ gint slot_series; -+ char *card_name; -+ -+ slot_id = PK11_GetSlotID (worker->module->slots[i]); -+ slot_series = PK11_GetSlotSeries (worker->module->slots[i]); -+ -+ card = _gdm_smartcard_new (worker->module, -+ slot_id, slot_series); -+ -+ card_name = gdm_smartcard_get_name (card); -+ -+ g_hash_table_replace (manager->priv->smartcards, -+ card_name, card); -+ } -+ node = node->next; -+ } -+} -+ -+static GdmSmartcardManagerWorker * -+start_worker (GdmSmartcardManager *manager, -+ SECMODModule *module, -+ GError **error) -+{ -+ GIOChannel *io_channel; -+ GSource *source; -+ GIOFlags channel_flags; -+ GdmSmartcardManagerWorker *worker; -+ -+ worker = gdm_smartcard_manager_create_worker (manager, module); -+ -+ if (worker == NULL) { -+ g_set_error (error, -+ GDM_SMARTCARD_MANAGER_ERROR, -+ GDM_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, -+ _("could not watch for incoming card events - %s"), -+ g_strerror (errno)); -+ -+ goto out; -+ } -+ -+ io_channel = g_io_channel_unix_new (worker->manager_fd); -+ -+ channel_flags = g_io_channel_get_flags (io_channel); -+ -+ source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP); -+ g_io_channel_unref (io_channel); -+ io_channel = NULL; -+ -+ worker->event_source = source; -+ -+ g_source_set_callback (worker->event_source, -+ (GSourceFunc) (GIOFunc) -+ gdm_smartcard_manager_check_for_and_process_events, -+ worker, -+ (GDestroyNotify) -+ gdm_smartcard_manager_event_processing_stopped_handler); -+ g_source_attach (worker->event_source, NULL); -+ g_source_unref (worker->event_source); -+out: -+ return worker; -+} -+ -+static void -+start_workers (GdmSmartcardManager *manager) -+{ -+ GList *node; -+ -+ node = manager->priv->modules; -+ while (node != NULL) { -+ SECMODModule *module; -+ GdmSmartcardManagerWorker *worker; -+ GError *error; -+ -+ module = (SECMODModule *) node->data; -+ -+ error = NULL; -+ worker = start_worker (manager, module, &error); -+ if (worker == NULL) { -+ g_warning ("%s", error->message); -+ g_error_free (error); -+ } else { -+ manager->priv->workers = g_list_prepend (manager->priv->workers, -+ worker); -+ } -+ node = node->next; -+ } -+} -+ -+gboolean -+gdm_smartcard_manager_start (GdmSmartcardManager *manager, -+ GError **error) -+{ -+ GError *nss_error; -+ -+ if (manager->priv->state == GDM_SMARTCARD_MANAGER_STATE_STARTED) { -+ g_debug ("smartcard manager already started"); -+ return TRUE; -+ } -+ -+ manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STARTING; -+ -+ nss_error = NULL; -+ if (!manager->priv->nss_is_loaded && !sc_load_nss (&nss_error)) { -+ g_propagate_error (error, nss_error); -+ goto out; -+ } -+ manager->priv->nss_is_loaded = TRUE; -+ -+ if (manager->priv->modules == NULL) { -+ if (!load_driver (manager, manager->priv->module_path, &nss_error)) { -+ g_propagate_error (error, nss_error); -+ goto out; -+ } -+ } -+ -+ start_workers (manager); -+ -+ /* populate the hash with cards that are already inserted -+ */ -+ gdm_smartcard_manager_get_all_cards (manager); -+ -+ manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STARTED; -+ -+out: -+ /* don't leave it in a half started state -+ */ -+ if (manager->priv->state != GDM_SMARTCARD_MANAGER_STATE_STARTED) { -+ g_debug ("smartcard manager could not be completely started"); -+ gdm_smartcard_manager_stop (manager); -+ } else { -+ g_debug ("smartcard manager started"); -+ } -+ -+ return manager->priv->state == GDM_SMARTCARD_MANAGER_STATE_STARTED; -+} -+ -+static gboolean -+gdm_smartcard_manager_stop_now (GdmSmartcardManager *manager) -+{ -+ if (manager->priv->state == GDM_SMARTCARD_MANAGER_STATE_STOPPED) { -+ return FALSE; -+ } -+ -+ gdm_smartcard_manager_stop_watching_for_events (manager); -+ -+ return FALSE; -+} -+ -+static void -+gdm_smartcard_manager_queue_stop (GdmSmartcardManager *manager) -+{ -+ -+ manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STOPPING; -+ -+ g_idle_add ((GSourceFunc) gdm_smartcard_manager_stop_now, manager); -+} -+ -+void -+gdm_smartcard_manager_stop (GdmSmartcardManager *manager) -+{ -+ if (manager->priv->state == GDM_SMARTCARD_MANAGER_STATE_STOPPED) { -+ return; -+ } -+ -+ if (manager->priv->is_unstoppable) { -+ gdm_smartcard_manager_queue_stop (manager); -+ return; -+ } -+ -+ gdm_smartcard_manager_stop_now (manager); -+} -+ -+static void -+gdm_smartcard_manager_check_for_login_card (CK_SLOT_ID slot_id, -+ GdmSmartcard *card, -+ gboolean *is_inserted) -+{ -+ g_assert (is_inserted != NULL); -+ -+ if (gdm_smartcard_is_login_card (card)) { -+ *is_inserted = TRUE; -+ } -+ -+} -+ -+gboolean -+gdm_smartcard_manager_login_card_is_inserted (GdmSmartcardManager *manager) -+ -+{ -+ gboolean is_inserted; -+ -+ is_inserted = FALSE; -+ g_hash_table_foreach (manager->priv->smartcards, -+ (GHFunc) -+ gdm_smartcard_manager_check_for_login_card, -+ &is_inserted); -+ return is_inserted; -+} -+ -+static GdmSmartcardManagerWorker * -+gdm_smartcard_manager_worker_new (GdmSmartcardManager *manager, -+ gint worker_fd, -+ gint manager_fd, -+ SECMODModule *module) -+{ -+ GdmSmartcardManagerWorker *worker; -+ -+ worker = g_slice_new0 (GdmSmartcardManagerWorker); -+ worker->manager = manager; -+ worker->fd = worker_fd; -+ worker->manager_fd = manager_fd; -+ worker->module = module; -+ -+ worker->smartcards = -+ g_hash_table_new_full ((GHashFunc) sc_slot_id_hash, -+ (GEqualFunc) sc_slot_id_equal, -+ (GDestroyNotify) g_free, -+ (GDestroyNotify) g_object_unref); -+ -+ return worker; -+} -+ -+static void -+gdm_smartcard_manager_worker_free (GdmSmartcardManagerWorker *worker) -+{ -+ if (worker->smartcards != NULL) { -+ g_hash_table_destroy (worker->smartcards); -+ worker->smartcards = NULL; -+ } -+ -+ g_slice_free (GdmSmartcardManagerWorker, worker); -+} -+ -+static gboolean -+sc_read_bytes (gint fd, gpointer bytes, gsize num_bytes) -+{ -+ size_t bytes_left; -+ size_t total_bytes_read; -+ ssize_t bytes_read; -+ -+ bytes_left = (size_t) num_bytes; -+ total_bytes_read = 0; -+ -+ do { -+ bytes_read = read (fd, (gchar *) bytes + total_bytes_read, bytes_left); -+ g_assert (bytes_read <= (ssize_t) bytes_left); -+ -+ if (bytes_read <= 0) { -+ if ((bytes_read < 0) && (errno == EINTR || errno == EAGAIN)) { -+ continue; -+ } -+ -+ bytes_left = 0; -+ } else { -+ bytes_left -= bytes_read; -+ total_bytes_read += bytes_read; -+ } -+ } while (bytes_left > 0); -+ -+ if (total_bytes_read < (size_t) num_bytes) { -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static gboolean -+sc_write_bytes (gint fd, gconstpointer bytes, gsize num_bytes) -+{ -+ size_t bytes_left; -+ size_t total_bytes_written; -+ ssize_t bytes_written; -+ -+ bytes_left = (size_t) num_bytes; -+ total_bytes_written = 0; -+ -+ do { -+ bytes_written = write (fd, (gchar *) bytes + total_bytes_written, bytes_left); -+ g_assert (bytes_written <= (ssize_t) bytes_left); -+ -+ if (bytes_written <= 0) { -+ if ((bytes_written < 0) && (errno == EINTR || errno == EAGAIN)) { -+ continue; -+ } -+ -+ bytes_left = 0; -+ } else { -+ bytes_left -= bytes_written; -+ total_bytes_written += bytes_written; -+ } -+ } while (bytes_left > 0); -+ -+ if (total_bytes_written < (size_t) num_bytes) { -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static GdmSmartcard * -+sc_read_smartcard (gint fd, -+ SECMODModule *module) -+{ -+ GdmSmartcard *card; -+ char *card_name; -+ gsize card_name_size; -+ -+ card_name_size = 0; -+ if (!sc_read_bytes (fd, &card_name_size, sizeof (card_name_size))) { -+ return NULL; -+ } -+ -+ card_name = g_slice_alloc0 (card_name_size); -+ if (!sc_read_bytes (fd, card_name, card_name_size)) { -+ g_slice_free1 (card_name_size, card_name); -+ return NULL; -+ } -+ card = _gdm_smartcard_new_from_name (module, card_name); -+ g_slice_free1 (card_name_size, card_name); -+ -+ return card; -+} -+ -+static gboolean -+sc_write_smartcard (gint fd, -+ GdmSmartcard *card) -+{ -+ gsize card_name_size; -+ char *card_name; -+ -+ card_name = gdm_smartcard_get_name (card); -+ card_name_size = strlen (card_name) + 1; -+ -+ if (!sc_write_bytes (fd, &card_name_size, sizeof (card_name_size))) { -+ g_free (card_name); -+ return FALSE; -+ } -+ -+ if (!sc_write_bytes (fd, card_name, card_name_size)) { -+ g_free (card_name); -+ return FALSE; -+ } -+ g_free (card_name); -+ -+ return TRUE; -+} -+ -+static gboolean -+gdm_smartcard_manager_worker_emit_smartcard_removed (GdmSmartcardManagerWorker *worker, -+ GdmSmartcard *card, -+ GError **error) -+{ -+ g_debug ("card '%s' removed!", gdm_smartcard_get_name (card)); -+ -+ if (!sc_write_bytes (worker->fd, "R", 1)) { -+ goto error_out; -+ } -+ -+ if (!sc_write_smartcard (worker->fd, card)) { -+ goto error_out; -+ } -+ -+ return TRUE; -+ -+error_out: -+ g_set_error (error, GDM_SMARTCARD_MANAGER_ERROR, -+ GDM_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, -+ "%s", g_strerror (errno)); -+ return FALSE; -+} -+ -+static gboolean -+gdm_smartcard_manager_worker_emit_smartcard_inserted (GdmSmartcardManagerWorker *worker, -+ GdmSmartcard *card, -+ GError **error) -+{ -+ GError *write_error; -+ -+ write_error = NULL; -+ g_debug ("card '%s' inserted!", gdm_smartcard_get_name (card)); -+ if (!sc_write_bytes (worker->fd, "I", 1)) { -+ goto error_out; -+ } -+ -+ if (!sc_write_smartcard (worker->fd, card)) { -+ goto error_out; -+ } -+ -+ return TRUE; -+ -+error_out: -+ g_set_error (error, GDM_SMARTCARD_MANAGER_ERROR, -+ GDM_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, -+ "%s", g_strerror (errno)); -+ return FALSE; -+} -+ -+static gboolean -+gdm_smartcard_manager_worker_watch_for_and_process_event (GdmSmartcardManagerWorker *worker, -+ GError **error) -+{ -+ PK11SlotInfo *slot; -+ CK_SLOT_ID slot_id, *key; -+ gint slot_series, card_slot_series; -+ GdmSmartcard *card; -+ GError *processing_error; -+ -+ g_debug ("waiting for card event"); -+ -+ /* FIXME: we return FALSE quite a bit in this function without cleaning up -+ * resources. By returning FALSE we're going to ultimately exit anyway, but -+ * we should still be tidier about things. -+ */ -+ -+ slot = SECMOD_WaitForAnyTokenEvent (worker->module, 0, PR_SecondsToInterval (1)); -+ -+ processing_error = NULL; -+ -+ if (slot == NULL) { -+ int error_code; -+ -+ error_code = PORT_GetError (); -+ if ((error_code == 0) || (error_code == SEC_ERROR_NO_EVENT)) { -+ g_debug ("spurrious event occurred"); -+ return TRUE; -+ } -+ -+ /* FIXME: is there a function to convert from a PORT error -+ * code to a translated string? -+ */ -+ g_set_error (error, GDM_SMARTCARD_MANAGER_ERROR, -+ GDM_SMARTCARD_MANAGER_ERROR_WITH_NSS, -+ _("encountered unexpected error while " -+ "waiting for smartcard events")); -+ return FALSE; -+ } -+ -+ /* the slot id and series together uniquely identify a card. -+ * You can never have two cards with the same slot id at the -+ * same time, however (I think), so we can key off of it. -+ */ -+ slot_id = PK11_GetSlotID (slot); -+ slot_series = PK11_GetSlotSeries (slot); -+ -+ /* First check to see if there is a card that we're currently -+ * tracking in the slot. -+ */ -+ key = g_new (CK_SLOT_ID, 1); -+ *key = slot_id; -+ card = g_hash_table_lookup (worker->smartcards, key); -+ -+ if (card != NULL) { -+ card_slot_series = gdm_smartcard_get_slot_series (card); -+ } else { -+ card_slot_series = -1; -+ } -+ -+ if (PK11_IsPresent (slot)) { -+ /* Now, check to see if their is a new card in the slot. -+ * If there was a different card in the slot now than -+ * there was before, then we need to emit a removed signal -+ * for the old card (we don't want unpaired insertion events). -+ */ -+ if ((card != NULL) && -+ card_slot_series != slot_series) { -+ if (!gdm_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { -+ g_propagate_error (error, processing_error); -+ return FALSE; -+ } -+ } -+ -+ card = _gdm_smartcard_new (worker->module, -+ slot_id, slot_series); -+ -+ g_hash_table_replace (worker->smartcards, -+ key, card); -+ key = NULL; -+ -+ if (!gdm_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) { -+ g_propagate_error (error, processing_error); -+ return FALSE; -+ } -+ } else { -+ /* if we aren't tracking the card, just discard the event. -+ * We don't want unpaired remove events. Note on startup -+ * NSS will generate an "insertion" event if a card is -+ * already inserted in the slot. -+ */ -+ if ((card != NULL)) { -+ /* FIXME: i'm not sure about this code. Maybe we -+ * shouldn't do this at all, or maybe we should do it -+ * n times (where n = slot_series - card_slot_series + 1) -+ * -+ * Right now, i'm just doing it once. -+ */ -+ if ((slot_series - card_slot_series) > 1) { -+ -+ if (!gdm_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { -+ g_propagate_error (error, processing_error); -+ return FALSE; -+ } -+ g_hash_table_remove (worker->smartcards, key); -+ -+ card = _gdm_smartcard_new (worker->module, -+ slot_id, slot_series); -+ g_hash_table_replace (worker->smartcards, -+ key, card); -+ key = NULL; -+ if (!gdm_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) { -+ g_propagate_error (error, processing_error); -+ return FALSE; -+ } -+ } -+ -+ if (!gdm_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { -+ g_propagate_error (error, processing_error); -+ return FALSE; -+ } -+ -+ g_hash_table_remove (worker->smartcards, key); -+ card = NULL; -+ } else { -+ g_debug ("got spurious remove event"); -+ } -+ } -+ -+ g_free (key); -+ PK11_FreeSlot (slot); -+ -+ return TRUE; -+} -+ -+static void -+gdm_smartcard_manager_worker_run (GdmSmartcardManagerWorker *worker) -+{ -+ GError *error; -+ gboolean should_continue; -+ -+ do -+ { -+ error = NULL; -+ should_continue = gdm_smartcard_manager_worker_watch_for_and_process_event (worker, &error); -+ } -+ while (should_continue); -+ -+ if (error != NULL) { -+ g_debug ("could not process card event - %s", error->message); -+ g_error_free (error); -+ } -+ -+out: -+ gdm_smartcard_manager_worker_free (worker); -+} -+ -+static GdmSmartcardManagerWorker * -+gdm_smartcard_manager_create_worker (GdmSmartcardManager *manager, -+ SECMODModule *module) -+{ -+ GdmSmartcardManagerWorker *worker; -+ gint write_fd, read_fd; -+ -+ write_fd = -1; -+ read_fd = -1; -+ if (!gdm_open_pipe (&write_fd, &read_fd)) { -+ return FALSE; -+ } -+ -+ worker = gdm_smartcard_manager_worker_new (manager, -+ write_fd, -+ read_fd, -+ module); -+ -+ worker->thread = g_thread_create ((GThreadFunc) -+ gdm_smartcard_manager_worker_run, -+ worker, FALSE, NULL); -+ -+ if (worker->thread == NULL) { -+ gdm_smartcard_manager_worker_free (worker); -+ return NULL; -+ } -+ -+ return worker; -+} -+ -+#ifdef GDM_SMARTCARD_MANAGER_ENABLE_TEST -+#include -+ -+static GMainLoop *event_loop; -+static gboolean should_exit_on_next_remove = FALSE; -+ -+static gboolean -+on_timeout (GdmSmartcardManager *manager) -+{ -+ GError *error; -+ g_print ("Re-enabling manager.\n"); -+ -+ if (!gdm_smartcard_manager_start (manager, &error)) { -+ g_warning ("could not start smartcard manager - %s", -+ error->message); -+ g_error_free (error); -+ return 1; -+ } -+ g_print ("Please re-insert smartcard\n"); -+ -+ should_exit_on_next_remove = TRUE; -+ -+ return FALSE; -+} -+ -+static void -+on_device_inserted (GdmSmartcardManager *manager, -+ GdmSmartcard *card) -+{ -+ g_print ("smartcard inserted!\n"); -+ g_print ("Please remove it.\n"); -+} -+ -+static void -+on_device_removed (GdmSmartcardManager *manager, -+ GdmSmartcard *card) -+{ -+ g_print ("smartcard removed!\n"); -+ -+ if (should_exit_on_next_remove) { -+ g_main_loop_quit (event_loop); -+ } else { -+ g_print ("disabling manager for 2 seconds\n"); -+ gdm_smartcard_manager_stop (manager); -+ g_timeout_add (2000, (GSourceFunc) on_timeout, manager); -+ } -+} -+ -+int -+main (int argc, -+ char *argv[]) -+{ -+ GdmSmartcardManager *manager; -+ GError *error; -+ -+ g_log_set_always_fatal (G_LOG_LEVEL_ERROR -+ | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); -+ -+ g_type_init (); -+ -+ g_message ("creating instance of 'smartcard manager' object..."); -+ manager = gdm_smartcard_manager_new (NULL); -+ g_message ("'smartcard manager' object created successfully"); -+ -+ g_signal_connect (manager, "smartcard-inserted", -+ G_CALLBACK (on_device_inserted), NULL); -+ -+ g_signal_connect (manager, "smartcard-removed", -+ G_CALLBACK (on_device_removed), NULL); -+ -+ g_message ("starting listener..."); -+ -+ error = NULL; -+ if (!gdm_smartcard_manager_start (manager, &error)) { -+ g_warning ("could not start smartcard manager - %s", -+ error->message); -+ g_error_free (error); -+ return 1; -+ } -+ -+ event_loop = g_main_loop_new (NULL, FALSE); -+ g_main_loop_run (event_loop); -+ g_main_loop_unref (event_loop); -+ event_loop = NULL; -+ -+ g_message ("destroying previously created 'smartcard manager' object..."); -+ g_object_unref (manager); -+ manager = NULL; -+ g_message ("'smartcard manager' object destroyed successfully"); -+ -+ return 0; -+} -+#endif -diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.h b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.h -new file mode 100644 -index 0000000..932a703 ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.h -@@ -0,0 +1,86 @@ -+/* gdm-smartcard-manager.h - object for monitoring smartcard insertion and -+ * removal events -+ * -+ * Copyright (C) 2006, 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -+ * 02111-1307, USA. -+ * -+ * Written by: Ray Strode -+ */ -+#ifndef GDM_SMARTCARD_MANAGER_H -+#define GDM_SMARTCARD_MANAGER_H -+ -+#define GDM_SMARTCARD_ENABLE_INTERNAL_API -+#include "gdm-smartcard.h" -+ -+#include -+#include -+ -+G_BEGIN_DECLS -+#define GDM_TYPE_SMARTCARD_MANAGER (gdm_smartcard_manager_get_type ()) -+#define GDM_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_SMARTCARD_MANAGER, GdmSmartcardManager)) -+#define GDM_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_SMARTCARD_MANAGER, GdmSmartcardManagerClass)) -+#define GDM_IS_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_SMARTCARD_MANAGER)) -+#define GDM_IS_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_SMARTCARD_MANAGER)) -+#define GDM_SMARTCARD_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_SMARTCARD_MANAGER, GdmSmartcardManagerClass)) -+#define GDM_SMARTCARD_MANAGER_ERROR (gdm_smartcard_manager_error_quark ()) -+typedef struct _GdmSmartcardManager GdmSmartcardManager; -+typedef struct _GdmSmartcardManagerClass GdmSmartcardManagerClass; -+typedef struct _GdmSmartcardManagerPrivate GdmSmartcardManagerPrivate; -+typedef enum _GdmSmartcardManagerError GdmSmartcardManagerError; -+ -+struct _GdmSmartcardManager { -+ GObject parent; -+ -+ /*< private > */ -+ GdmSmartcardManagerPrivate *priv; -+}; -+ -+struct _GdmSmartcardManagerClass { -+ GObjectClass parent_class; -+ -+ /* Signals */ -+ void (*smartcard_inserted) (GdmSmartcardManager *manager, -+ GdmSmartcard *token); -+ void (*smartcard_removed) (GdmSmartcardManager *manager, -+ GdmSmartcard *token); -+ void (*error) (GdmSmartcardManager *manager, -+ GError *error); -+}; -+ -+enum _GdmSmartcardManagerError { -+ GDM_SMARTCARD_MANAGER_ERROR_GENERIC = 0, -+ GDM_SMARTCARD_MANAGER_ERROR_WITH_NSS, -+ GDM_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, -+ GDM_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, -+ GDM_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS -+}; -+ -+GType gdm_smartcard_manager_get_type (void) G_GNUC_CONST; -+GQuark gdm_smartcard_manager_error_quark (void) G_GNUC_CONST; -+ -+GdmSmartcardManager *gdm_smartcard_manager_new (const char *module); -+ -+gboolean gdm_smartcard_manager_start (GdmSmartcardManager *manager, -+ GError **error); -+ -+void gdm_smartcard_manager_stop (GdmSmartcardManager *manager); -+ -+char *gdm_smartcard_manager_get_module_path (GdmSmartcardManager *manager); -+gboolean gdm_smartcard_manager_login_token_is_inserted (GdmSmartcardManager *manager); -+ -+G_END_DECLS -+#endif /* GDM_SMARTCARD_MANAGER_H */ -diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c -new file mode 100644 -index 0000000..9af1346 ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c -@@ -0,0 +1,186 @@ -+#include "config.h" -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "gdm-smartcard-manager.h" -+#include "gdm-smartcard.h" -+ -+#ifndef GDM_SMARTCARDS_CONF -+#define GDM_SMARTCARDS_CONF GDMCONFDIR "/smartcards.conf" -+#endif -+ -+#ifndef GDM_SMARTCARDS_GROUP -+#define GDM_SMARTCARDS_GROUP "Smartcards" -+#endif -+ -+#ifndef GDM_SMARTCARDS_KEY_ENABLED -+#define GDM_SMARTCARDS_KEY_ENABLED "Enabled" -+#endif -+ -+#ifndef GDM_SMARTCARDS_KEY_DRIVER -+#define GDM_SMARTCARDS_KEY_DRIVER "Driver" -+#endif -+ -+static GMainLoop *event_loop; -+static GdmSmartcardManager *manager; -+static int signal_pipe_fds[2] = { -1, -1 }; -+ -+static void -+on_smartcard_event (const char *event_string) -+{ -+ g_debug ("smartcard event '%s' happened", event_string); -+ g_print ("%s", event_string); -+ fflush (stdout); -+} -+ -+static void -+watch_for_smartcards (void) -+{ -+ GError *error; -+ char *driver; -+ GKeyFile *cfg; -+ -+ cfg = g_key_file_new (); -+ -+ error = NULL; -+ driver = NULL; -+ if (g_key_file_load_from_file (cfg, GDM_SMARTCARDS_CONF, G_KEY_FILE_NONE, &error)) { -+ if (!g_key_file_get_boolean (cfg, GDM_SMARTCARDS_GROUP, GDM_SMARTCARDS_KEY_ENABLED, &error)) { -+ g_debug ("smartcard support is not enabled"); -+ goto out; -+ } -+ -+ driver = g_key_file_get_string (cfg, GDM_SMARTCARDS_GROUP, GDM_SMARTCARDS_KEY_DRIVER, NULL); -+ g_debug ("smartcards driver is set to '%s'", -+ driver == NULL || driver[0] == '\0'? "" : driver); -+ } -+ -+ g_debug ("watching for smartcard insertion and removal events"); -+ manager = gdm_smartcard_manager_new (driver); -+ g_free (driver); -+ -+ g_signal_connect_swapped (manager, -+ "smartcard-inserted", -+ G_CALLBACK (on_smartcard_event), -+ "I"); -+ -+ g_signal_connect_swapped (manager, -+ "smartcard-removed", -+ G_CALLBACK (on_smartcard_event), -+ "R"); -+ -+ error = NULL; -+ if (!gdm_smartcard_manager_start (manager, &error)) { -+ g_object_unref (manager); -+ manager = NULL; -+ -+ if (error != NULL) { -+ g_debug ("%s", error->message); -+ g_error_free (error); -+ } else { -+ g_debug ("could not start smartcard manager"); -+ -+ } -+ goto out; -+ } -+out: -+ g_key_file_free (cfg); -+} -+ -+static void -+stop_watching_for_smartcards (void) -+{ -+ if (manager != NULL) { -+ gdm_smartcard_manager_stop (manager); -+ g_object_unref (manager); -+ manager = NULL; -+ } -+} -+ -+static void -+on_alrm_signal (int signal_number) -+{ -+ raise (SIGKILL); -+} -+ -+static void -+on_term_signal (int signal_number) -+{ -+ close (signal_pipe_fds[1]); -+ signal_pipe_fds[1] = -1; -+ -+ /* Give us 10 seconds to clean up orderly. -+ * If that fails, then the smartcard stack -+ * is hung up and we need to die hard -+ */ -+ alarm (10); -+ signal (SIGALRM, on_alrm_signal); -+} -+ -+static gboolean -+after_term_signal (GIOChannel *io_channel, -+ GIOCondition condition, -+ gpointer data) -+{ -+ g_main_loop_quit (event_loop); -+ return FALSE; -+} -+ -+static void -+on_debug_message (const char *log_domain, -+ GLogLevelFlags log_level, -+ const char *message, -+ gpointer user_data) -+{ -+ g_printerr ("*** DEBUG: %s\n", message); -+} -+ -+int -+main (int argc, -+ char **argv) -+{ -+ GIOChannel *io_channel; -+ -+ setlocale (LC_ALL, ""); -+ -+ g_type_init (); -+ -+ g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG, on_debug_message, NULL); -+ -+ event_loop = g_main_loop_new (NULL, FALSE); -+ -+ watch_for_smartcards (); -+ -+ if (pipe (signal_pipe_fds) != 0) { -+ return 1; -+ } -+ fcntl (signal_pipe_fds[0], F_SETFD, FD_CLOEXEC); -+ fcntl (signal_pipe_fds[1], F_SETFD, FD_CLOEXEC); -+ -+ io_channel = g_io_channel_unix_new (signal_pipe_fds[0]); -+ g_io_channel_set_flags (io_channel, G_IO_FLAG_NONBLOCK, NULL); -+ g_io_channel_set_encoding (io_channel, NULL, NULL); -+ g_io_channel_set_buffered (io_channel, FALSE); -+ g_io_add_watch (io_channel, G_IO_HUP, after_term_signal, NULL); -+ g_io_channel_set_close_on_unref (io_channel, TRUE); -+ g_io_channel_unref (io_channel); -+ -+ signal (SIGTERM, on_term_signal); -+ signal (SIGPIPE, on_term_signal); -+ -+#ifdef HAVE_SYS_PRCTL_H -+ prctl (PR_SET_PDEATHSIG, SIGTERM); -+#endif -+ -+ g_main_loop_run (event_loop); -+ -+ stop_watching_for_smartcards (); -+ -+ return 0; -+} -diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.c -new file mode 100644 -index 0000000..1af3638 ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.c -@@ -0,0 +1,554 @@ -+/* gdm-smartcard.c - smartcard object -+ * -+ * Copyright (C) 2006 Ray Strode -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -+ * 02111-1307, USA. -+ */ -+#define GDM_SMARTCARD_ENABLE_INTERNAL_API -+#include "gdm-smartcard.h" -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct _GdmSmartcardPrivate { -+ SECMODModule *module; -+ GdmSmartcardState state; -+ -+ CK_SLOT_ID slot_id; -+ int slot_series; -+ -+ PK11SlotInfo *slot; -+ char *name; -+ -+ CERTCertificate *signing_certificate; -+ CERTCertificate *encryption_certificate; -+}; -+ -+static void gdm_smartcard_finalize (GObject *object); -+static void gdm_smartcard_class_install_signals (GdmSmartcardClass *card_class); -+static void gdm_smartcard_class_install_properties (GdmSmartcardClass *card_class); -+static void gdm_smartcard_set_property (GObject *object, -+ guint prop_id, -+ const GValue *value, -+ GParamSpec *pspec); -+static void gdm_smartcard_get_property (GObject *object, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec); -+static void gdm_smartcard_set_name (GdmSmartcard *card, const char *name); -+static void gdm_smartcard_set_slot_id (GdmSmartcard *card, -+ int slot_id); -+static void gdm_smartcard_set_slot_series (GdmSmartcard *card, -+ int slot_series); -+static void gdm_smartcard_set_module (GdmSmartcard *card, -+ SECMODModule *module); -+ -+static PK11SlotInfo *gdm_smartcard_find_slot_from_id (GdmSmartcard *card, -+ int slot_id); -+ -+static PK11SlotInfo *gdm_smartcard_find_slot_from_card_name (GdmSmartcard *card, -+ const char *card_name); -+static gboolean gdm_smartcard_fetch_certificates (GdmSmartcard *card); -+ -+#ifndef GDM_SMARTCARD_DEFAULT_SLOT_ID -+#define GDM_SMARTCARD_DEFAULT_SLOT_ID ((gulong) -1) -+#endif -+ -+#ifndef GDM_SMARTCARD_DEFAULT_SLOT_SERIES -+#define GDM_SMARTCARD_DEFAULT_SLOT_SERIES -1 -+#endif -+ -+enum { -+ PROP_0 = 0, -+ PROP_NAME, -+ PROP_SLOT_ID, -+ PROP_SLOT_SERIES, -+ PROP_MODULE, -+ NUMBER_OF_PROPERTIES -+}; -+ -+enum { -+ INSERTED, -+ REMOVED, -+ NUMBER_OF_SIGNALS -+}; -+ -+static guint gdm_smartcard_signals[NUMBER_OF_SIGNALS]; -+ -+G_DEFINE_TYPE (GdmSmartcard, gdm_smartcard, G_TYPE_OBJECT); -+ -+static void -+gdm_smartcard_class_init (GdmSmartcardClass *card_class) -+{ -+ GObjectClass *gobject_class; -+ -+ gobject_class = G_OBJECT_CLASS (card_class); -+ -+ gobject_class->finalize = gdm_smartcard_finalize; -+ -+ gdm_smartcard_class_install_signals (card_class); -+ gdm_smartcard_class_install_properties (card_class); -+ -+ g_type_class_add_private (card_class, -+ sizeof (GdmSmartcardPrivate)); -+} -+ -+static void -+gdm_smartcard_class_install_signals (GdmSmartcardClass *card_class) -+{ -+ GObjectClass *object_class; -+ -+ object_class = G_OBJECT_CLASS (card_class); -+ -+ gdm_smartcard_signals[INSERTED] = -+ g_signal_new ("inserted", -+ G_OBJECT_CLASS_TYPE (object_class), -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (GdmSmartcardClass, -+ inserted), -+ NULL, NULL, g_cclosure_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); -+ -+ gdm_smartcard_signals[REMOVED] = -+ g_signal_new ("removed", -+ G_OBJECT_CLASS_TYPE (object_class), -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (GdmSmartcardClass, -+ removed), -+ NULL, NULL, g_cclosure_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); -+} -+ -+static void -+gdm_smartcard_class_install_properties (GdmSmartcardClass *card_class) -+{ -+ GObjectClass *object_class; -+ GParamSpec *param_spec; -+ -+ object_class = G_OBJECT_CLASS (card_class); -+ object_class->set_property = gdm_smartcard_set_property; -+ object_class->get_property = gdm_smartcard_get_property; -+ -+ param_spec = g_param_spec_ulong ("slot-id", _("Slot ID"), -+ _("The slot the card is in"), -+ 1, G_MAXULONG, -+ GDM_SMARTCARD_DEFAULT_SLOT_ID, -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); -+ g_object_class_install_property (object_class, PROP_SLOT_ID, param_spec); -+ -+ param_spec = g_param_spec_int ("slot-series", _("Slot Series"), -+ _("per-slot card identifier"), -+ -1, G_MAXINT, -+ GDM_SMARTCARD_DEFAULT_SLOT_SERIES, -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); -+ g_object_class_install_property (object_class, PROP_SLOT_SERIES, param_spec); -+ -+ param_spec = g_param_spec_string ("name", _("name"), -+ _("name"), NULL, -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); -+ g_object_class_install_property (object_class, PROP_NAME, param_spec); -+ -+ param_spec = g_param_spec_pointer ("module", _("Module"), -+ _("smartcard driver"), -+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); -+ g_object_class_install_property (object_class, PROP_MODULE, param_spec); -+} -+ -+static void -+gdm_smartcard_set_property (GObject *object, -+ guint prop_id, -+ const GValue *value, -+ GParamSpec *pspec) -+{ -+ GdmSmartcard *card = GDM_SMARTCARD (object); -+ -+ switch (prop_id) { -+ case PROP_NAME: -+ gdm_smartcard_set_name (card, g_value_get_string (value)); -+ break; -+ -+ case PROP_SLOT_ID: -+ gdm_smartcard_set_slot_id (card, -+ g_value_get_ulong (value)); -+ break; -+ -+ case PROP_SLOT_SERIES: -+ gdm_smartcard_set_slot_series (card, -+ g_value_get_int (value)); -+ break; -+ -+ case PROP_MODULE: -+ gdm_smartcard_set_module (card, -+ (SECMODModule *) -+ g_value_get_pointer (value)); -+ break; -+ -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+ } -+} -+ -+CK_SLOT_ID -+gdm_smartcard_get_slot_id (GdmSmartcard *card) -+{ -+ return card->priv->slot_id; -+} -+ -+GdmSmartcardState -+gdm_smartcard_get_state (GdmSmartcard *card) -+{ -+ return card->priv->state; -+} -+ -+char * -+gdm_smartcard_get_name (GdmSmartcard *card) -+{ -+ return g_strdup (card->priv->name); -+} -+ -+gboolean -+gdm_smartcard_is_login_card (GdmSmartcard *card) -+{ -+ const char *login_card_name; -+ login_card_name = g_getenv ("PKCS11_LOGIN_TOKEN_NAME"); -+ -+ if ((login_card_name == NULL) || (card->priv->name == NULL)) { -+ return FALSE; -+ } -+ -+ if (strcmp (card->priv->name, login_card_name) == 0) { -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+static void -+gdm_smartcard_get_property (GObject *object, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec) -+{ -+ GdmSmartcard *card = GDM_SMARTCARD (object); -+ -+ switch (prop_id) { -+ case PROP_NAME: -+ g_value_take_string (value, -+ gdm_smartcard_get_name (card)); -+ break; -+ -+ case PROP_SLOT_ID: -+ g_value_set_ulong (value, -+ (gulong) gdm_smartcard_get_slot_id (card)); -+ break; -+ -+ case PROP_SLOT_SERIES: -+ g_value_set_int (value, -+ gdm_smartcard_get_slot_series (card)); -+ break; -+ -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+ } -+} -+ -+static void -+gdm_smartcard_set_name (GdmSmartcard *card, -+ const char *name) -+{ -+ if (name == NULL) { -+ return; -+ } -+ -+ if ((card->priv->name == NULL) || -+ (strcmp (card->priv->name, name) != 0)) { -+ g_free (card->priv->name); -+ card->priv->name = g_strdup (name); -+ -+ if (card->priv->slot == NULL) { -+ card->priv->slot = gdm_smartcard_find_slot_from_card_name (card, -+ card->priv->name); -+ -+ if (card->priv->slot != NULL) { -+ int slot_id, slot_series; -+ -+ slot_id = PK11_GetSlotID (card->priv->slot); -+ if (slot_id != card->priv->slot_id) { -+ gdm_smartcard_set_slot_id (card, slot_id); -+ } -+ -+ slot_series = PK11_GetSlotSeries (card->priv->slot); -+ if (slot_series != card->priv->slot_series) { -+ gdm_smartcard_set_slot_series (card, slot_series); -+ } -+ -+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_INSERTED); -+ } else { -+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_REMOVED); -+ } -+ } -+ -+ g_object_notify (G_OBJECT (card), "name"); -+ } -+} -+ -+static void -+gdm_smartcard_set_slot_id (GdmSmartcard *card, -+ int slot_id) -+{ -+ if (card->priv->slot_id != slot_id) { -+ card->priv->slot_id = slot_id; -+ -+ if (card->priv->slot == NULL) { -+ card->priv->slot = gdm_smartcard_find_slot_from_id (card, -+ card->priv->slot_id); -+ -+ if (card->priv->slot != NULL) { -+ const char *card_name; -+ -+ card_name = PK11_GetTokenName (card->priv->slot); -+ if ((card->priv->name == NULL) || -+ ((card_name != NULL) && -+ (strcmp (card_name, card->priv->name) != 0))) { -+ gdm_smartcard_set_name (card, card_name); -+ } -+ -+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_INSERTED); -+ } else { -+ _gdm_smartcard_set_state (card, GDM_SMARTCARD_STATE_REMOVED); -+ } -+ } -+ -+ g_object_notify (G_OBJECT (card), "slot-id"); -+ } -+} -+ -+static void -+gdm_smartcard_set_slot_series (GdmSmartcard *card, -+ int slot_series) -+{ -+ if (card->priv->slot_series != slot_series) { -+ card->priv->slot_series = slot_series; -+ g_object_notify (G_OBJECT (card), "slot-series"); -+ } -+} -+ -+static void -+gdm_smartcard_set_module (GdmSmartcard *card, -+ SECMODModule *module) -+{ -+ gboolean should_notify; -+ -+ if (card->priv->module != module) { -+ should_notify = TRUE; -+ } else { -+ should_notify = FALSE; -+ } -+ -+ if (card->priv->module != NULL) { -+ SECMOD_DestroyModule (card->priv->module); -+ card->priv->module = NULL; -+ } -+ -+ if (module != NULL) { -+ card->priv->module = SECMOD_ReferenceModule (module); -+ } -+ -+ if (should_notify) { -+ g_object_notify (G_OBJECT (card), "module"); -+ } -+} -+ -+int -+gdm_smartcard_get_slot_series (GdmSmartcard *card) -+{ -+ return card->priv->slot_series; -+} -+ -+static void -+gdm_smartcard_init (GdmSmartcard *card) -+{ -+ -+ g_debug ("initializing smartcard "); -+ -+ card->priv = G_TYPE_INSTANCE_GET_PRIVATE (card, -+ GDM_TYPE_SMARTCARD, -+ GdmSmartcardPrivate); -+} -+ -+static void gdm_smartcard_finalize (GObject *object) -+{ -+ GdmSmartcard *card; -+ GObjectClass *gobject_class; -+ -+ card = GDM_SMARTCARD (object); -+ -+ g_free (card->priv->name); -+ -+ gdm_smartcard_set_module (card, NULL); -+ -+ gobject_class = G_OBJECT_CLASS (gdm_smartcard_parent_class); -+ -+ gobject_class->finalize (object); -+} -+ -+GQuark gdm_smartcard_error_quark (void) -+{ -+ static GQuark error_quark = 0; -+ -+ if (error_quark == 0) { -+ error_quark = g_quark_from_static_string ("gdm-smartcard-error-quark"); -+ } -+ -+ return error_quark; -+} -+ -+GdmSmartcard * -+_gdm_smartcard_new (SECMODModule *module, -+ CK_SLOT_ID slot_id, -+ int slot_series) -+{ -+ GdmSmartcard *card; -+ -+ g_return_val_if_fail (module != NULL, NULL); -+ g_return_val_if_fail (slot_id >= 1, NULL); -+ g_return_val_if_fail (slot_series > 0, NULL); -+ g_return_val_if_fail (sizeof (gulong) == sizeof (slot_id), NULL); -+ -+ card = GDM_SMARTCARD (g_object_new (GDM_TYPE_SMARTCARD, -+ "module", module, -+ "slot-id", (gulong) slot_id, -+ "slot-series", slot_series, -+ NULL)); -+ return card; -+} -+ -+GdmSmartcard * -+_gdm_smartcard_new_from_name (SECMODModule *module, -+ const char *name) -+{ -+ GdmSmartcard *card; -+ -+ g_return_val_if_fail (module != NULL, NULL); -+ g_return_val_if_fail (name != NULL, NULL); -+ -+ card = GDM_SMARTCARD (g_object_new (GDM_TYPE_SMARTCARD, -+ "module", module, -+ "name", name, -+ NULL)); -+ return card; -+} -+ -+void -+_gdm_smartcard_set_state (GdmSmartcard *card, -+ GdmSmartcardState state) -+{ -+ /* gdm_smartcard_fetch_certificates (card); */ -+ if (card->priv->state != state) { -+ card->priv->state = state; -+ -+ if (state == GDM_SMARTCARD_STATE_INSERTED) { -+ g_signal_emit (card, gdm_smartcard_signals[INSERTED], 0); -+ } else if (state == GDM_SMARTCARD_STATE_REMOVED) { -+ g_signal_emit (card, gdm_smartcard_signals[REMOVED], 0); -+ } else { -+ g_assert_not_reached (); -+ } -+ } -+} -+ -+/* So we could conceivably make the closure data a pointer to the card -+ * or something similiar and then emit signals when we want passwords, -+ * but it's probably easier to just get the password up front and use -+ * it. So we just take the passed in g_malloc'd (well probably, who knows) -+ * and strdup it using NSPR's memory allocation routines. -+ */ -+static char * -+gdm_smartcard_password_handler (PK11SlotInfo *slot, -+ PRBool is_retrying, -+ const char *password) -+{ -+ if (is_retrying) { -+ return NULL; -+ } -+ -+ return password != NULL? PL_strdup (password): NULL; -+} -+ -+gboolean -+gdm_smartcard_unlock (GdmSmartcard *card, -+ const char *password) -+{ -+ SECStatus status; -+ -+ PK11_SetPasswordFunc ((PK11PasswordFunc) gdm_smartcard_password_handler); -+ -+ /* we pass PR_TRUE to load certificates -+ */ -+ status = PK11_Authenticate (card->priv->slot, PR_TRUE, (gpointer) password); -+ -+ if (status != SECSuccess) { -+ g_debug ("could not unlock card - %d", status); -+ return FALSE; -+ } -+ return TRUE; -+} -+ -+static PK11SlotInfo * -+gdm_smartcard_find_slot_from_card_name (GdmSmartcard *card, -+ const char *card_name) -+{ -+ int i; -+ -+ for (i = 0; i < card->priv->module->slotCount; i++) { -+ const char *slot_card_name; -+ -+ slot_card_name = PK11_GetTokenName (card->priv->module->slots[i]); -+ -+ if ((slot_card_name != NULL) && -+ (strcmp (slot_card_name, card_name) == 0)) { -+ return card->priv->module->slots[i]; -+ } -+ } -+ -+ return NULL; -+} -+ -+static PK11SlotInfo * -+gdm_smartcard_find_slot_from_id (GdmSmartcard *card, -+ int slot_id) -+{ -+ int i; -+ -+ for (i = 0; i < card->priv->module->slotCount; i++) { -+ if (PK11_GetSlotID (card->priv->module->slots[i]) == slot_id) { -+ return card->priv->module->slots[i]; -+ } -+ } -+ -+ return NULL; -+} -diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard.h b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.h -new file mode 100644 -index 0000000..20303bd ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.h -@@ -0,0 +1,94 @@ -+/* securitycard.h - api for reading and writing data to a security card -+ * -+ * Copyright (C) 2006 Ray Strode -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -+ * 02111-1307, USA. -+ */ -+#ifndef GDM_SMARTCARD_H -+#define GDM_SMARTCARD_H -+ -+#include -+#include -+ -+#include -+ -+G_BEGIN_DECLS -+#define GDM_TYPE_SMARTCARD (gdm_smartcard_get_type ()) -+#define GDM_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_SMARTCARD, GdmSmartcard)) -+#define GDM_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_SMARTCARD, GdmSmartcardClass)) -+#define GDM_IS_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_SMARTCARD)) -+#define GDM_IS_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_SMARTCARD)) -+#define GDM_SMARTCARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_SMARTCARD, GdmSmartcardClass)) -+#define GDM_SMARTCARD_ERROR (gdm_smartcard_error_quark ()) -+typedef struct _GdmSmartcardClass GdmSmartcardClass; -+typedef struct _GdmSmartcard GdmSmartcard; -+typedef struct _GdmSmartcardPrivate GdmSmartcardPrivate; -+typedef enum _GdmSmartcardError GdmSmartcardError; -+typedef enum _GdmSmartcardState GdmSmartcardState; -+ -+typedef struct _GdmSmartcardRequest GdmSmartcardRequest; -+ -+struct _GdmSmartcard { -+ GObject parent; -+ -+ /*< private > */ -+ GdmSmartcardPrivate *priv; -+}; -+ -+struct _GdmSmartcardClass { -+ GObjectClass parent_class; -+ -+ void (* inserted) (GdmSmartcard *card); -+ void (* removed) (GdmSmartcard *card); -+}; -+ -+enum _GdmSmartcardError { -+ GDM_SMARTCARD_ERROR_GENERIC = 0, -+}; -+ -+enum _GdmSmartcardState { -+ GDM_SMARTCARD_STATE_INSERTED = 0, -+ GDM_SMARTCARD_STATE_REMOVED, -+}; -+ -+GType gdm_smartcard_get_type (void) G_GNUC_CONST; -+GQuark gdm_smartcard_error_quark (void) G_GNUC_CONST; -+ -+CK_SLOT_ID gdm_smartcard_get_slot_id (GdmSmartcard *card); -+gint gdm_smartcard_get_slot_series (GdmSmartcard *card); -+GdmSmartcardState gdm_smartcard_get_state (GdmSmartcard *card); -+ -+char *gdm_smartcard_get_name (GdmSmartcard *card); -+gboolean gdm_smartcard_is_login_card (GdmSmartcard *card); -+ -+gboolean gdm_smartcard_unlock (GdmSmartcard *card, -+ const char *password); -+ -+/* don't under any circumstances call these functions */ -+#ifdef GDM_SMARTCARD_ENABLE_INTERNAL_API -+ -+GdmSmartcard *_gdm_smartcard_new (SECMODModule *module, -+ CK_SLOT_ID slot_id, -+ gint slot_series); -+GdmSmartcard *_gdm_smartcard_new_from_name (SECMODModule *module, -+ const char *name); -+ -+void _gdm_smartcard_set_state (GdmSmartcard *card, -+ GdmSmartcardState state); -+#endif -+ -+G_END_DECLS -+#endif /* GDM_SMARTCARD_H */ -diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam -new file mode 100644 -index 0000000..d5ac1fa ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam -@@ -0,0 +1,18 @@ -+# Sample PAM file for doing smartcard authentication. -+# Distros should replace this with what makes sense for them. -+auth required pam_env.so -+auth [success=done ignore=ignore default=die] pam_pkcs11.so wait_for_card card_only -+auth requisite pam_succeed_if.so uid >= 500 quiet -+auth required pam_deny.so -+ -+account required pam_unix.so -+account sufficient pam_localuser.so -+account sufficient pam_succeed_if.so uid < 500 quiet -+account required pam_permit.so -+ -+password optional pam_pkcs11.so -+password requisite pam_cracklib.so try_first_pass retry=3 type= -+ -+session optional pam_keyinit.so revoke -+session required pam_limits.so -+session required pam_unix.so -diff --git a/gui/simple-greeter/plugins/smartcard/icons/16x16/Makefile.am b/gui/simple-greeter/plugins/smartcard/icons/16x16/Makefile.am -new file mode 100644 -index 0000000..661d687 ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/icons/16x16/Makefile.am -@@ -0,0 +1,5 @@ -+iconsdir = $(datadir)/icons/hicolor/16x16/apps -+ -+icons_DATA = gdm-smartcard.png -+ -+EXTRA_DIST = $(icons_DATA) -diff --git a/gui/simple-greeter/plugins/smartcard/icons/16x16/gdm-smartcard.png b/gui/simple-greeter/plugins/smartcard/icons/16x16/gdm-smartcard.png -new file mode 100644 -index 0000000000000000000000000000000000000000..0112af1b8d891ad312f9fcc3bf6074df3e003359 -GIT binary patch -literal 871 -zcmV-t1DO1YP)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXJ- -z6cQQvze?o*000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0008QNkl25h)mRS()F5IML|LeofZ5$Phq#SvEXn3)x9QHz&V1jD*OHUa=lnh|yoWc& -zo1+2m0}628RN4)kP9zfJhGEoz$TZEX{|)Htgf`%?ZQIABl!txa-_X&~;rI9Vo88^r -z1;L|^!4>6dV71>-}NC2_0X(TUE+qIrDYmT)AaSb -zqQSwzu&1X-?Cbi7rG`eaTxYT75y*%ZE6&r0<4pW|3Ey2K2m+~;x&Y(=rCFBMd{LP< -ze!f%2@g%ktXZzbJvY9kitjV=&V+;=uGc+_rtyZH_sW3S?$@KK}cfeU)DJ6Ufjwku* -z#Jf~p{6)1o%ag||*tX5+=qR~dj#8<_+}s>O2(sBM#bWVH7>3^p-}m(}(unH3ls_kY}+QE&oeeQMlzYCTCI{!r;|XJ05A-lFao6%Gcz-k%VnBP$+`1i -z^JL;6j^og}#l)>&;?s|J5k(Q5do}@lp##MA7)pgK{$tR(^AIgbgR>VO(YA9dDYL-` -zsh`;Y%6?x&ziM4udm5K2(B3uPvQ%dL5Nt5QX;$Nu&Y|(&dU|=Ac -znwoM8g@R?8=8}~1uJ8MIfoDQ+^ZMlj@4UAwMAl}h&MMZb@Tk<}`x}kRnq^tHG);3I -x$GHPM0G_Y=$2Q;_pbrQE4|oMk0zdM9c?}H%H!P_~w{rjh002ovPDHLkV1ieHj1>R? - -literal 0 -HcmV?d00001 - -diff --git a/gui/simple-greeter/plugins/smartcard/icons/48x48/Makefile.am b/gui/simple-greeter/plugins/smartcard/icons/48x48/Makefile.am -new file mode 100644 -index 0000000..e79d85b ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/icons/48x48/Makefile.am -@@ -0,0 +1,5 @@ -+iconsdir = $(datadir)/icons/hicolor/48x48/apps -+ -+icons_DATA = gdm-smartcard.png -+ -+EXTRA_DIST = $(icons_DATA) -diff --git a/gui/simple-greeter/plugins/smartcard/icons/48x48/gdm-smartcard.png b/gui/simple-greeter/plugins/smartcard/icons/48x48/gdm-smartcard.png -new file mode 100644 -index 0000000000000000000000000000000000000000..35d5578d9ec83ae6b17aa7230c1b4df34e13e2cc -GIT binary patch -literal 4202 -zcmV-w5S8zVP)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iXJ- -z6calzC#000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000lgNkl2aFf(X>ozT5 -zC$5aZk)aA|*R=Bt;5o9kwWGLxmKt<-N{vG7>41KQobz$)Btw?d%RxnyB)`A*IJ8UFsQn_yUTz( -zIywx~G;av_`rnpip|uYDs!S+YWQjXH9?w0l>%LQKZTS6uy>sVI(cRrmPfriG+;WTI -z@p#@6@Iu;UXgp0zq>6^HuiPI91TYLkD5ZWW0{DTQz#hx8?o~?Nrj#^8Cli339gNwym|C9-PB*HI@kv?`fqW>?@BILKy#D -z4S0a;tuC6Y+ySqg!7UTBYZx?>Q|Av62(oD=`2?xClT$$(W&^%g! -zTIQ6mo}a-m1X^pf7EI3NXk4{4pHeFHiwMvG>@`jEE+8hQ^c#kuJ3Bk+>FE)%Sd1Mz -zc8Fjw_@?GCIhSXAHcNDspBGO};7E<_NQ5YWEH$6Uz?B-Qba9Tt=f>65#Ugb-f=#OBSLRV)@WcJJQJ&Ye3&I2?Xcz^>Gsxim*Q?-KBt3|v`2Duq&D7y_j< -z0x%8GT2LLZXlt%!eN&J%4OM6j-+g(6iP&p8JBMy -zy3F*%&q)02ENiPXEG{l``t)fA1_rW9sr5kOEj1ve^tZRS)6mec0`UBz&A;|tBkxE8 -zJ`-DNTvuTTQMPBVWuO4R$D}nHpshK?+Qt9@f2Dh6vsn^}1XEK}BoYa1+on2P$8&%6 -zXIvfZ$23jq>+2Chkjv#zN>u?Pz<%H{Erluyw#>N;L8e(*Gv`DLkM=6Eh@8_O-?!oKzic_afJqug{j#UWY -zI1WMx{9Y4}DUeEFnSyt9HPNv?jFgh;>FJ6cc3rnJpQx!J5{ZgwtW?Zo48;_*12 -z``qW)zI{6nKKLN5t*wlWjnUuVPdc4OO3Cu*tCS+0PNS5ftE-FQ;bCK9V&ZR$v@chf -zkjFCFxTc!(L-W*!{dBgi;_~Io^!N9#0K96|Dx%RSjg5^&qfr8ZKzY%*xj8OgyvW4F -z1XEK}>x86!T9_QS-bIi`plFQ}rcswhZN^6ajlEuYEVzC(e_wU~V -z+zY(8LIVqFhs)QJ0IY2cAcP>F&!d#0zP_GlG)g2Ap|P=%QWSPwm+9$g;_-OdoE*og -z01*m>XliQW%9Sf@-MW=syLK@>JxwZ=VrXcH^XJdAdi838!626|T_TxG(%9I@=FOYS -zb7V3ZJRT2`NQ6Wp@!QJRH14t>!X0sePaDb|+Dtta4 -zufP5}>(;HKy}g}yJWeK)K}yM*HET#D5_gq-z%nx;u(VMPRx)Uz}P+MC|E|(*h%P~DYjo0fXolcX@W|^3n;K?VS -z=PjT#i5aQW?mE5b2T$nTAnL5%hH+mw(UYawHN7CMG7BoSbBK -zcDC#XmSxf2-d=ux&mFsn4_)CepZOr~-DB`-zg6b=QkMFm4`zAa9rIv#i`l6cfsfvw -z_z8tV<+xB{xngSqhOH8x3L#k27{o9{kzJNdD3i&Q!A?v}Fh4)Pf>N8BnrLorrmd~5 -zBC`MZ%vp~A^A0vdhpDPHkW!Sv=ks~A)_B7YQoHF6K%;R$=YcHQS6;()T|6F7S%CJ< -zbqo!K7#mys4zSHC0Te=DI}%+K&@JZcGcz+BJb17yxe$W-`uZ~9Xf#@3GS_Qtdshpd -zwL$D_<2Z{M=10zx+0coUlJW6zgb*Yyo<{4fMa?VFE?|@Y=}Y|0muHAXA{a&?n~etY -z9P4|4p56OfCnvLCu!Imf*L4eElX(zJ0YnHvFc_q*t*y-E(P;FBEOY(uGv_CfN@Iyd -zG=jRG)y$q8NID7Ow6H`@eTVF+6OPB|KYcpCU3TtbPMgo#YKK*`%esqSRvqNln -zpqi@2ChmQx6*WK2XMblkk3SRtJqyT}R35DhAP@)vj$3fzKp?=LJ$v31aC~^4{x=eA -zXj#R{fia%>`ybP`HcWiDU}lTM)ujQ{++^d8y6n0%1+77R?~CGDRgIki0dHM>MW1&~E51#8(B?Z)b2G@9BjiR-q4GA` -z1ub=fK}=Ct*j6}6g`JexNsUf|*Y6{37kt7}N;%nV79j+wjLp=14y`qgT5{rlI`BH5 -z{mKvd{1e@L^!^UAIhUc)1+HFO;Fhh8oWDGcl$uX|^j7xn*+4^G6}2^f9{+F`vDn{L -z20p7A?c0LsjY3r&qTw=za|xYyakFs#oWrS~*yucTzr#yQorzb0vK2C~srG4v)|3pQ -zM5AR5h>{xR(mC-vFAnngC%W-i2J7yu1oZVkzl;0s*uX+6PhHsmU!P$`9z1I?gdc^x -zt`9mkTYUR_S^n|gGW_BFK_3555VOj_sxol18q=#;KFm@|=@P?K`7AcIgt;&@%krwE -zWg5KNKgNqM4*{_6W4G~}_ipC-e}A2u*41JfVg>lwWR9!jDW>ML#nMs{q)Z@$4sA?5`wY$vF6CHez{E%@3`>BkDOHUut+h_2QsozaHc|NQ$fdzg?~8Hx=udg_ -z(OcQlR#*Q2Q;*%gl=Cmz42>tbG(5-E@f1>O6q; -zX-_O5v;07EtbcS_^-VG|xmachDJ7OAFfh5jGlJ`CydHyHoz3{XW -z{(dz$IAT2ho_d-#6|#4&hB1V1g$WsgB6x$QI*YsCwN&|#S%sTbNE@USNTtgHIC@#} -zG8FJ)ngXp0H6j3yX`s=3WJoXpKFL!MA(BVttUA6Kx!+>2od~AOws2nU#N~T`3Nv9y~ -zm^h|M`!<7cBlMoN0Zv;$_WFsm)?B!7f!^L;`uh5GZ*Q+kCX;57$_9&od$ratYprK~ -z&O-86fXE$>&V1^7U-zHPRK--Qpu^f!9}X+|e<~ -z6MvoI@K5qN;7er_x_I#-M~@z*udk0IM~=vunHdwn -+ -+ -+ -+ True -+ vertical -+ -+ -+ True -+ 6 -+ -+ -+ True -+ -+ -+ False -+ False -+ 0 -+ -+ -+ -+ -+ True -+ True -+ True -+ -+ -+ 1 -+ -+ -+ -+ -+ True -+ True -+ 0 -+ -+ -+ -+ -+ True -+ -+ -+ True -+ -+ -+ 0 -+ -+ -+ -+ -+ True -+ True -+ 1 -+ -+ -+ -+ -diff --git a/gui/simple-greeter/plugins/smartcard/plugin.c b/gui/simple-greeter/plugins/smartcard/plugin.c -new file mode 100644 -index 0000000..fffbd50 ---- /dev/null -+++ b/gui/simple-greeter/plugins/smartcard/plugin.c -@@ -0,0 +1,40 @@ -+/* -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Written By: Ray Strode -+ * -+ */ -+ -+#include "gdm-smartcard-extension.h" -+ -+#include -+#include -+ -+GdmGreeterExtension * -+gdm_greeter_plugin_get_extension (void) -+{ -+ static GObject *extension; -+ -+ if (extension != NULL) { -+ g_object_ref (extension); -+ } else { -+ extension = g_object_new (GDM_TYPE_SMARTCARD_EXTENSION, NULL); -+ g_object_add_weak_pointer (extension, (gpointer *) &extension); -+ } -+ -+ return GDM_GREETER_EXTENSION (extension); -+} -diff --git a/po/POTFILES.in b/po/POTFILES.in -index 77fe17d..11f8725 100644 ---- a/po/POTFILES.in -+++ b/po/POTFILES.in -@@ -83,6 +83,9 @@ gui/simple-greeter/gdm-user-chooser-widget.c - gui/simple-greeter/greeter-main.c - gui/simple-greeter/plugins/password/gdm-password-extension.c - gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c -+gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c -+gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c -+gui/simple-greeter/plugins/smartcard/gdm-smartcard.c - utils/gdmflexiserver.c - utils/gdm-screenshot.c - --- -1.7.4.1 - - -From 5944a6d2870817e66253349b63f4808fefa0a99a Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 24 Jul 2009 14:41:48 -0400 -Subject: [PATCH 14/20] KILL stuck processes if they don't die on TERM - -Some PAM modules are really slow to shut down. -We need to handle them being slow to shut down better, -(by not blocking login on them shutting down etc), but -in the mean time force them to die immediately. - -This is a temporary hack. ---- - common/gdm-common.c | 48 ++++++++++++++++++++++++++++++++++++-- - common/gdm-common.h | 2 + - daemon/gdm-session-worker-job.c | 2 +- - 3 files changed, 48 insertions(+), 4 deletions(-) - -diff --git a/common/gdm-common.c b/common/gdm-common.c -index de80700..7a4e26d 100644 ---- a/common/gdm-common.c -+++ b/common/gdm-common.c -@@ -93,13 +93,25 @@ gdm_get_pwent_for_name (const char *name, - } - - int --gdm_wait_on_pid (int pid) -+gdm_wait_on_and_kill_pid (int pid, -+ int timeout) - { - int status; -- -+ int ret; -+ int num_tries; -+ int flags; -+ -+ if (timeout > 0) { -+ flags = WNOHANG; -+ num_tries = 10 * timeout; -+ } else { -+ flags = 0; -+ num_tries = 0; -+ } - wait_again: - errno = 0; -- if (waitpid (pid, &status, 0) < 0) { -+ ret = waitpid (pid, &status, flags); -+ if (ret < 0) { - if (errno == EINTR) { - goto wait_again; - } else if (errno == ECHILD) { -@@ -107,6 +119,30 @@ gdm_wait_on_pid (int pid) - } else { - g_debug ("GdmCommon: waitpid () should not fail"); - } -+ } else if (ret == 0) { -+ num_tries--; -+ -+ if (num_tries > 0) { -+ g_usleep (G_USEC_PER_SEC / 10); -+ } else { -+ char *path; -+ char *command; -+ -+ path = g_strdup_printf ("/proc/%ld/cmdline", (long) pid); -+ if (g_file_get_contents (path, &command, NULL, NULL)) {; -+ g_debug ("GdmCommon: process (pid:%d, command '%s') isn't dying, now killing it.", -+ (int) pid, command); -+ g_free (command); -+ } else { -+ g_debug ("GdmCommon: process (pid:%d) isn't dying, now killing it.", -+ (int) pid); -+ } -+ g_free (path); -+ -+ kill (pid, SIGKILL); -+ flags = 0; -+ } -+ goto wait_again; - } - - g_debug ("GdmCommon: process (pid:%d) done (%s:%d)", -@@ -122,6 +158,12 @@ gdm_wait_on_pid (int pid) - } - - int -+gdm_wait_on_pid (int pid) -+{ -+ return gdm_wait_on_and_kill_pid (pid, 0); -+} -+ -+int - gdm_signal_pid (int pid, - int signal) - { -diff --git a/common/gdm-common.h b/common/gdm-common.h -index 8faeda5..06300c8 100644 ---- a/common/gdm-common.h -+++ b/common/gdm-common.h -@@ -34,6 +34,8 @@ gboolean gdm_is_version_unstable (void); - void gdm_set_fatal_warnings_if_unstable (void); - - int gdm_wait_on_pid (int pid); -+int gdm_wait_on_and_kill_pid (int pid, -+ int timeout); - int gdm_signal_pid (int pid, - int signal); - gboolean gdm_get_pwent_for_name (const char *name, -diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c -index be85f30..8b93663 100644 ---- a/daemon/gdm-session-worker-job.c -+++ b/daemon/gdm-session-worker-job.c -@@ -296,7 +296,7 @@ session_worker_job_died (GdmSessionWorkerJob *session_worker_job) - int exit_status; - - g_debug ("GdmSessionWorkerJob: Waiting on process %d", session_worker_job->priv->pid); -- exit_status = gdm_wait_on_pid (session_worker_job->priv->pid); -+ exit_status = gdm_wait_on_and_kill_pid (session_worker_job->priv->pid, 3); - - if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) { - g_debug ("GdmSessionWorkerJob: Wait on child process failed"); --- -1.7.4.1 - - -From f745d04390e1bcc0de885efe99f5d436b3c7f54b Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 13 Jul 2010 22:37:35 -0400 -Subject: [PATCH 15/20] switch to proper mode when going to timed login - ---- - gui/simple-greeter/gdm-greeter-login-window.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c -index 56a790e..9b07ffe 100644 ---- a/gui/simple-greeter/gdm-greeter-login-window.c -+++ b/gui/simple-greeter/gdm-greeter-login-window.c -@@ -1389,7 +1389,7 @@ begin_auto_login (GdmGreeterLoginWindow *login_window) - /* just wait for the user to select language and stuff */ - set_message (login_window, _("Select language and click Log In")); - -- switch_mode (login_window, MODE_AUTHENTICATION); -+ switch_mode (login_window, MODE_TIMED_LOGIN); - - show_widget (login_window, "conversation-list", FALSE); - gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), --- -1.7.4.1 - - -From 989a304e776877a51aba2e8236f667529214dbb6 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Tue, 3 Aug 2010 15:21:26 -0400 -Subject: [PATCH 16/20] Drop "Cancelling" message for plugin initiated cancels - -The plugin may be cancelling the mesage for a number of -reasons. We could potentially let it specify the message, -but for now just drop the message. ---- - gui/simple-greeter/gdm-greeter-login-window.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c -index 9b07ffe..907f34b 100644 ---- a/gui/simple-greeter/gdm-greeter-login-window.c -+++ b/gui/simple-greeter/gdm-greeter-login-window.c -@@ -2242,7 +2242,7 @@ static void - on_conversation_cancel (GdmGreeterLoginWindow *login_window, - GdmConversation *conversation) - { -- do_cancel (login_window); -+ restart_conversations (login_window); - } - - static gboolean --- -1.7.4.1 - - -From 59a49f2d5840d2797856e5135735a813c6b08d48 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 4 Aug 2010 18:03:52 -0400 -Subject: [PATCH 17/20] Add delay when showing messages (needs split) - -Previously, there were times when the user would be unable -to read messages, because they would blink by so fast. - -This jumble of assorted changes (which needs to be split up) -adds some queueing and timeouts to make sure the messages stay on -screen for a sufficient amount of time. ---- - gui/simple-greeter/gdm-greeter-login-window.c | 119 ++++++++++++++++++-- - .../libgdmsimplegreeter/gdm-conversation.c | 17 +++ - .../libgdmsimplegreeter/gdm-conversation.h | 2 + - .../fingerprint/gdm-fingerprint-extension.c | 20 ++++ - .../plugins/password/gdm-password-extension.c | 20 ++++ - .../plugins/smartcard/gdm-smartcard-extension.c | 19 +++ - 6 files changed, 187 insertions(+), 10 deletions(-) - -diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c -index 907f34b..d4e177d 100644 ---- a/gui/simple-greeter/gdm-greeter-login-window.c -+++ b/gui/simple-greeter/gdm-greeter-login-window.c -@@ -140,6 +140,9 @@ struct GdmGreeterLoginWindowPrivate - - guint login_button_handler_id; - guint start_session_handler_id; -+ -+ char *service_name_of_session_ready_to_start; -+ - }; - - enum { -@@ -176,6 +179,8 @@ static void switch_mode (GdmGreeterLoginWindow *login_window - static void update_banner_message (GdmGreeterLoginWindow *login_window); - static void gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window, - const char *service_name); -+static void handle_stopped_conversation (GdmGreeterLoginWindow *login_window, -+ const char *service_name); - - G_DEFINE_TYPE (GdmGreeterLoginWindow, gdm_greeter_login_window, GTK_TYPE_WINDOW) - -@@ -234,6 +239,7 @@ set_task_conversation_message (GdmTaskList *task_list, - { - - gdm_conversation_set_message (GDM_CONVERSATION (task), message); -+ g_object_set_data (G_OBJECT (task), "message-pending", GINT_TO_POINTER (TRUE)); - return FALSE; - } - -@@ -893,16 +899,12 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window, - return TRUE; - } - --gboolean --gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window, -- const char *service_name) -+static void -+handle_stopped_conversation (GdmGreeterLoginWindow *login_window, -+ const char *service_name) - { - GdmTask *task; - -- g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); -- -- g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name); -- - /* If the password conversation failed, then start over - * - * FIXME: we need to get this policy out of the source code -@@ -910,13 +912,15 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind - if (strcmp (service_name, "gdm-password") == 0) { - g_debug ("GdmGreeterLoginWindow: main conversation failed, starting over"); - restart_conversations (login_window); -- return TRUE; -+ return; - } - - task = find_task_with_service_name (login_window, service_name); - - if (task != NULL) { - gdm_conversation_reset (GDM_CONVERSATION (task)); -+ -+ g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (FALSE)); - g_object_unref (task); - } - -@@ -931,6 +935,34 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind - g_object_unref (task); - - update_conversation_list_visibility (login_window); -+} -+ -+gboolean -+gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window, -+ const char *service_name) -+{ -+ GdmTask *task; -+ gboolean messages_pending; -+ -+ g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); -+ -+ g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name); -+ -+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -+ if (task != NULL && task_has_service_name (GDM_TASK_LIST (login_window->priv->conversation_list), task, service_name)) { -+ -+ messages_pending = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "message-pending")); -+ } else { -+ messages_pending = FALSE; -+ } -+ -+ if (!messages_pending) { -+ handle_stopped_conversation (login_window, service_name); -+ } else { -+ g_assert (task != NULL); -+ -+ g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (TRUE)); -+ } - - return TRUE; - } -@@ -942,6 +974,7 @@ restart_task_conversation (GdmTaskList *task_list, - { - char *service_name; - -+ g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (FALSE)); - service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task)); - if (service_name != NULL) { - char *name; -@@ -970,6 +1003,9 @@ gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window) - restart_task_conversation, - login_window); - -+ g_free (login_window->priv->service_name_of_session_ready_to_start); -+ login_window->priv->service_name_of_session_ready_to_start = NULL; -+ - return TRUE; - } - -@@ -987,6 +1023,7 @@ gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window, - task = find_task_with_service_name (login_window, service_name); - - if (task != NULL) { -+ g_object_set_data (G_OBJECT (task), "message-pending", GINT_TO_POINTER (TRUE)); - gdm_conversation_set_message (GDM_CONVERSATION (task), - text); - show_task_actions (task); -@@ -1010,6 +1047,7 @@ gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window, - task = find_task_with_service_name (login_window, service_name); - - if (task != NULL) { -+ g_object_set_data (G_OBJECT (task), "message-pending", GINT_TO_POINTER (TRUE)); - gdm_conversation_set_message (GDM_CONVERSATION (task), - text); - show_task_actions (task); -@@ -1105,12 +1143,40 @@ on_ready_to_start_session (GdmGreeterLoginWindow *login_window, - } - - static void -+gdm_greeter_login_window_start_session (GdmGreeterLoginWindow *login_window) -+{ -+ g_debug ("GdmGreeterLoginWindow: starting session"); -+ g_signal_emit (login_window, -+ signals[START_SESSION], -+ 0, -+ login_window->priv->service_name_of_session_ready_to_start); -+ g_free (login_window->priv->service_name_of_session_ready_to_start); -+ login_window->priv->service_name_of_session_ready_to_start = NULL; -+} -+ -+static void - gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window, - const char *service_name) - { - if (login_window->priv->is_interactive) { -- g_debug ("GdmGreeterLoginWindow: starting session"); -- g_signal_emit (login_window, signals[START_SESSION], 0, service_name); -+ gboolean messages_pending; -+ GdmTask *task; -+ -+ set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), FALSE); -+ -+ task = find_task_with_service_name (login_window, service_name); -+ -+ if (task != NULL) { -+ messages_pending = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "message-pending")); -+ -+ } else { -+ messages_pending = FALSE; -+ } -+ -+ login_window->priv->service_name_of_session_ready_to_start = g_strdup (service_name); -+ if (!messages_pending) { -+ gdm_greeter_login_window_start_session (login_window); -+ } - } else { - g_debug ("GdmGreeterLoginWindow: not starting session since " - "user hasn't had an opportunity to pick language " -@@ -2274,6 +2340,35 @@ on_conversation_chose_user (GdmGreeterLoginWindow *login_window, - return TRUE; - } - -+static void -+on_conversation_message_set (GdmGreeterLoginWindow *login_window, -+ GdmConversation *conversation) -+{ -+ gboolean needs_to_be_stopped; -+ -+ g_object_set_data (G_OBJECT (conversation), "message-pending", GINT_TO_POINTER (FALSE)); -+ -+ needs_to_be_stopped = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (conversation), "needs-to-be-stopped")); -+ -+ if (needs_to_be_stopped) { -+ char *service_name; -+ -+ service_name = gdm_conversation_get_service_name (conversation); -+ handle_stopped_conversation (login_window, service_name); -+ g_free (service_name); -+ } -+ -+ if (login_window->priv->service_name_of_session_ready_to_start != NULL ) { -+ GdmTask *task; -+ -+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -+ -+ if (task == GDM_TASK (conversation)) { -+ gdm_greeter_login_window_start_session (login_window); -+ } -+ } -+} -+ - void - gdm_greeter_login_window_remove_extension (GdmGreeterLoginWindow *login_window, - GdmGreeterExtension *extension) -@@ -2436,6 +2531,10 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window, - "user-chosen", - G_CALLBACK (on_conversation_chose_user), - login_window); -+ g_signal_connect_swapped (GDM_CONVERSATION (extension), -+ "message-set", -+ G_CALLBACK (on_conversation_message_set), -+ login_window); - - g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added", - name, description); -diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c -index ee763ef..a3514e8 100644 ---- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c -+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c -@@ -32,6 +32,7 @@ enum { - ANSWER, - USER_CHOSEN, - CANCEL, -+ MESSAGE_SET, - LAST_SIGNAL - }; - -@@ -92,6 +93,16 @@ gdm_conversation_class_init (gpointer g_iface) - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -+ -+ signals [MESSAGE_SET] = -+ g_signal_new ("message-set", -+ iface_type, -+ G_SIGNAL_RUN_FIRST, -+ G_STRUCT_OFFSET (GdmConversationIface, message_set), -+ NULL, -+ NULL, -+ g_cclosure_marshal_VOID__VOID, -+ G_TYPE_NONE, 0); - } - - void -@@ -184,3 +195,9 @@ gdm_conversation_choose_user (GdmConversation *conversation, - - return was_chosen; - } -+ -+void -+gdm_conversation_message_set (GdmConversation *conversation) -+{ -+ g_signal_emit (conversation, signals [MESSAGE_SET], 0); -+} -diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h -index b37b21e..f76b18c 100644 ---- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h -+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h -@@ -62,6 +62,7 @@ struct _GdmConversationIface - char * (* answer) (GdmConversation *conversation); - void (* cancel) (GdmConversation *conversation); - gboolean (* user_chosen) (GdmConversation *conversation); -+ void (* message_set) (GdmConversation *conversation); - }; - - GType gdm_conversation_get_type (void) G_GNUC_CONST; -@@ -87,6 +88,7 @@ void gdm_conversation_answer (GdmConversation *conversation, - void gdm_conversation_cancel (GdmConversation *conversation); - gboolean gdm_conversation_choose_user (GdmConversation *conversation, - const char *username); -+void gdm_conversation_message_set (GdmConversation *conversation); - - G_END_DECLS - -diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c -index 55f5d32..2f7e968 100644 ---- a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c -+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c -@@ -41,6 +41,8 @@ struct _GdmFingerprintExtensionPrivate - GtkWidget *prompt_entry; - - guint answer_pending : 1; -+ -+ guint message_timeout_id; - }; - - static void gdm_fingerprint_extension_finalize (GObject *object); -@@ -59,6 +61,17 @@ G_DEFINE_TYPE_WITH_CODE (GdmFingerprintExtension, - G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION, - gdm_conversation_iface_init)); - -+static gboolean -+on_message_expired (GdmConversation *conversation) -+{ -+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation); -+ extension->priv->message_timeout_id = 0; -+ -+ gdm_conversation_message_set (conversation); -+ -+ return FALSE; -+} -+ - static void - gdm_fingerprint_extension_set_message (GdmConversation *conversation, - const char *message) -@@ -66,6 +79,11 @@ gdm_fingerprint_extension_set_message (GdmConversation *conversation, - GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation); - gtk_widget_show (extension->priv->message_label); - gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message); -+ -+ if (extension->priv->message_timeout_id != 0) { -+ g_source_remove (extension->priv->message_timeout_id); -+ } -+ extension->priv->message_timeout_id = g_timeout_add_seconds (2, (GSourceFunc) on_message_expired, conversation); - } - - static void -@@ -282,6 +300,8 @@ gdm_fingerprint_extension_class_init (GdmFingerprintExtensionClass *extension_cl - static void - gdm_fingerprint_extension_finalize (GObject *object) - { -+ GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (object); -+ g_source_remove (extension->priv->message_timeout_id); - } - - static void -diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.c b/gui/simple-greeter/plugins/password/gdm-password-extension.c -index 11a171c..5157ea2 100644 ---- a/gui/simple-greeter/plugins/password/gdm-password-extension.c -+++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c -@@ -40,6 +40,8 @@ struct _GdmPasswordExtensionPrivate - GtkWidget *prompt_entry; - - guint answer_pending : 1; -+ -+ guint message_timeout_id; - }; - - static void gdm_password_extension_finalize (GObject *object); -@@ -58,6 +60,16 @@ G_DEFINE_TYPE_WITH_CODE (GdmPasswordExtension, - G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION, - gdm_conversation_iface_init)); - -+static gboolean -+on_message_expired (GdmConversation *conversation) -+{ -+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation); -+ extension->priv->message_timeout_id = 0; -+ -+ gdm_conversation_message_set (conversation); -+ return FALSE; -+} -+ - static void - gdm_password_extension_set_message (GdmConversation *conversation, - const char *message) -@@ -65,6 +77,11 @@ gdm_password_extension_set_message (GdmConversation *conversation, - GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation); - gtk_widget_show (extension->priv->message_label); - gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message); -+ -+ if (extension->priv->message_timeout_id != 0) { -+ g_source_remove (extension->priv->message_timeout_id); -+ } -+ extension->priv->message_timeout_id = g_timeout_add_seconds (2, (GSourceFunc) on_message_expired, conversation); - } - - static void -@@ -251,6 +268,9 @@ gdm_password_extension_class_init (GdmPasswordExtensionClass *extension_class) - static void - gdm_password_extension_finalize (GObject *object) - { -+ -+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (object); -+ g_source_remove (extension->priv->message_timeout_id); - } - - static void -diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c -index b40a21c..5e234b9 100644 ---- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c -+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c -@@ -56,6 +56,8 @@ struct _GdmSmartcardExtensionPrivate - - guint answer_pending : 1; - guint select_when_ready : 1; -+ -+ guint message_timeout_id; - }; - - static void gdm_smartcard_extension_finalize (GObject *object); -@@ -164,6 +166,16 @@ stop_watching_for_smartcards (GdmSmartcardExtension *extension) - kill (extension->priv->worker_pid, SIGTERM); - } - -+static gboolean -+on_message_expired (GdmConversation *conversation) -+{ -+ GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation); -+ extension->priv->message_timeout_id = 0; -+ -+ gdm_conversation_message_set (conversation); -+ return FALSE; -+} -+ - static void - gdm_smartcard_extension_set_message (GdmConversation *conversation, - const char *message) -@@ -171,6 +183,11 @@ gdm_smartcard_extension_set_message (GdmConversation *conversation, - GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation); - gtk_widget_show (extension->priv->message_label); - gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message); -+ -+ if (extension->priv->message_timeout_id != 0) { -+ g_source_remove (extension->priv->message_timeout_id); -+ } -+ extension->priv->message_timeout_id = g_timeout_add_seconds (2, (GSourceFunc) on_message_expired, conversation); - } - - static void -@@ -428,6 +445,8 @@ gdm_smartcard_extension_finalize (GObject *object) - if (extension->priv->worker_pid > 0) { - stop_watching_for_smartcards (extension); - } -+ -+ g_source_remove (extension->priv->message_timeout_id); - } - - static void --- -1.7.4.1 - - -From 7c18fc7396b247538008e79ff4c0a0962ceaa4a2 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Wed, 4 Aug 2010 19:27:14 -0400 -Subject: [PATCH 18/20] Drop cancelling message - -We cancel very quickly in most cases now, so the message isn't useful ---- - gui/simple-greeter/gdm-greeter-login-window.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c -index d4e177d..ca03073 100644 ---- a/gui/simple-greeter/gdm-greeter-login-window.c -+++ b/gui/simple-greeter/gdm-greeter-login-window.c -@@ -860,7 +860,7 @@ static void - do_cancel (GdmGreeterLoginWindow *login_window) - { - /* need to wait for response from backend */ -- set_message (login_window, _("Cancelling...")); -+ //set_message (login_window, _("Cancelling...")); - restart_conversations (login_window); - } - --- -1.7.4.1 - - -From 7b800188fb140b52dbee9136cee9428ee97158b7 Mon Sep 17 00:00:00 2001 -From: Ray Strode -Date: Fri, 6 Aug 2010 11:14:23 -0400 -Subject: [PATCH 19/20] manage tasks outside of task list - -The task list isn't very good for tracking tasks as -they come and go, since it relies on the groaty details -of toggle buttons and widget activation and such. - -We now use it soley for display purposes when necessary -and otherwise, keep track of the tasks in a separate list. - -Also, differentiate single authentication modes from -multiple authentication modes, so we don't show the task list -when we don't need to. ---- - gui/simple-greeter/gdm-greeter-login-window.c | 396 +++++++++++++------------ - 1 files changed, 206 insertions(+), 190 deletions(-) - -diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c -index ca03073..93ae192 100644 ---- a/gui/simple-greeter/gdm-greeter-login-window.c -+++ b/gui/simple-greeter/gdm-greeter-login-window.c -@@ -100,6 +100,7 @@ enum { - MODE_TIMED_LOGIN, - MODE_SELECTION, - MODE_AUTHENTICATION, -+ MODE_MULTIPLE_AUTHENTICATION, - }; - - enum { -@@ -121,6 +122,8 @@ struct GdmGreeterLoginWindowPrivate - guint is_interactive : 1; - guint user_chooser_loaded : 1; - GConfClient *client; -+ GList *tasks; -+ GdmTask *active_task; - GList *tasks_to_enable; - - gboolean banner_message_enabled; -@@ -182,6 +185,9 @@ static void gdm_greeter_login_window_start_session_when_ready (GdmGreeterLog - static void handle_stopped_conversation (GdmGreeterLoginWindow *login_window, - const char *service_name); - -+static void begin_single_service_verification (GdmGreeterLoginWindow *login_window, -+ const char *service_name); -+ - G_DEFINE_TYPE (GdmGreeterLoginWindow, gdm_greeter_login_window, GTK_TYPE_WINDOW) - - static void -@@ -215,26 +221,22 @@ set_sensitive (GdmGreeterLoginWindow *login_window, - static void - set_focus (GdmGreeterLoginWindow *login_window) - { -- GdmTask *task; -- - gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME); - -- task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -- -- if (task != NULL && gdm_conversation_focus (GDM_CONVERSATION (task))) { -+ if (login_window->priv->active_task != NULL && -+ gdm_conversation_focus (GDM_CONVERSATION (login_window->priv->active_task))) { - char *name; -- name = gdm_task_get_name (task); -+ name = gdm_task_get_name (login_window->priv->active_task); - g_debug ("GdmGreeterLoginWindow: focusing task %s", name); - g_free (name); - } else if (gtk_widget_get_realized (login_window->priv->user_chooser) && ! gtk_widget_has_focus (login_window->priv->user_chooser)) { - gtk_widget_grab_focus (login_window->priv->user_chooser); - } -- g_object_unref (task); -+ - } - - static gboolean --set_task_conversation_message (GdmTaskList *task_list, -- GdmTask *task, -+set_task_conversation_message (GdmTask *task, - const char *message) - { - -@@ -249,10 +251,9 @@ set_message (GdmGreeterLoginWindow *login_window, - { - g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window)); - -- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- (GdmTaskListForeachFunc) -- set_task_conversation_message, -- (gpointer) text); -+ g_list_foreach (login_window->priv->tasks, -+ (GFunc) set_task_conversation_message, -+ (gpointer) text); - } - - static void -@@ -455,7 +456,6 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window, - GtkWidget *unlock_button; - char *item; - gboolean in_use; -- GdmTask *task; - - in_use = FALSE; - item = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser)); -@@ -499,20 +499,16 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window, - - switch (mode) { - case LOGIN_BUTTON_HIDDEN: -- task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -- if (task != NULL) { -- hide_task_actions (task); -- g_object_unref (task); -+ if (login_window->priv->active_task != NULL) { -+ hide_task_actions (login_window->priv->active_task); - } - - gtk_widget_hide (button); - break; - case LOGIN_BUTTON_ANSWER_QUERY: -- task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -- if (task != NULL) { -- show_task_actions (task); -- grab_default_button_for_task (task); -- g_object_unref (task); -+ if (login_window->priv->active_task != NULL) { -+ show_task_actions (login_window->priv->active_task); -+ grab_default_button_for_task (login_window->priv->active_task); - } - - gtk_widget_hide (button); -@@ -559,6 +555,7 @@ maybe_show_cancel_button (GdmGreeterLoginWindow *login_window) - show = TRUE; - break; - case MODE_AUTHENTICATION: -+ case MODE_MULTIPLE_AUTHENTICATION: - if (login_window->priv->num_queries > 1) { - /* if we are inside a pam conversation past - the first step */ -@@ -583,7 +580,7 @@ update_conversation_list_visibility (GdmGreeterLoginWindow *login_window) - { - int number_of_tasks; - -- if (login_window->priv->dialog_mode != MODE_AUTHENTICATION) { -+ if (login_window->priv->dialog_mode != MODE_MULTIPLE_AUTHENTICATION) { - gtk_widget_hide (login_window->priv->conversation_list); - return; - } -@@ -628,6 +625,7 @@ switch_mode (GdmGreeterLoginWindow *login_window, - gtk_widget_show (login_window->priv->session_option_widget); - break; - case MODE_AUTHENTICATION: -+ case MODE_MULTIPLE_AUTHENTICATION: - set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY); - set_sensitive (login_window, FALSE); - gtk_widget_show (login_window->priv->session_option_widget); -@@ -668,39 +666,36 @@ switch_mode (GdmGreeterLoginWindow *login_window, - } - } - --static gboolean --task_has_service_name (GdmTaskList *task_list, -- GdmTask *task, -- const char *service_name) -+static GdmTask * -+find_task_with_service_name (GdmGreeterLoginWindow *login_window, -+ const char *service_name) - { -- char *task_service_name; -- gboolean has_service_name; -+ GList *node; - -- task_service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task)); -+ node = login_window->priv->tasks; -+ while (node != NULL) { -+ GdmTask *task; -+ char *task_service_name; -+ gboolean has_service_name; - -- has_service_name = strcmp (service_name, task_service_name) == 0; -- g_free (task_service_name); -+ task = GDM_TASK (node->data); - -- return has_service_name; --} -+ task_service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task)); -+ has_service_name = strcmp (service_name, task_service_name) == 0; -+ g_free (task_service_name); - --static GdmTask * --find_task_with_service_name (GdmGreeterLoginWindow *login_window, -- const char *service_name) --{ -- GdmTask *task; -+ if (has_service_name) { -+ return task; -+ } - -- task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- (GdmTaskListForeachFunc) -- task_has_service_name, -- (gpointer) service_name); -+ node = node->next; -+ } - -- return task; -+ return NULL; - } - - static gboolean --reset_task (GdmTaskList *task_list, -- GdmTask *task, -+reset_task (GdmTask *task, - GdmGreeterLoginWindow *login_window) - { - char *name; -@@ -712,28 +707,31 @@ reset_task (GdmTaskList *task_list, - login_window->priv->tasks_to_enable = g_list_remove (login_window->priv->tasks_to_enable, task); - - hide_task_actions (task); -+ gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list), task); - gdm_conversation_reset (GDM_CONVERSATION (task)); - return FALSE; - } - - static gboolean --task_is_disabled (GdmTaskList *task_list, -- GdmTask *task) --{ -- return !gdm_task_is_enabled (task); --} -- --static gboolean - tasks_are_enabled (GdmGreeterLoginWindow *login_window) - { -- GdmTask *task; - -- task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- (GdmTaskListForeachFunc) -- task_is_disabled, -- NULL); -+ GList *node; -+ -+ node = login_window->priv->tasks; -+ while (node != NULL) { -+ GdmTask *task; -+ -+ task = GDM_TASK (node->data); -+ -+ if (!gdm_task_is_enabled (task)) { -+ return FALSE; -+ } -+ -+ node = node->next; -+ } - -- return task == NULL; -+ return TRUE; - } - - static gboolean -@@ -747,6 +745,8 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window) - res = FALSE; - } else if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) { - res = FALSE; -+ } else if (login_window->priv->dialog_mode == MODE_MULTIPLE_AUTHENTICATION) { -+ res = FALSE; - } else if (login_window->priv->user_list_disabled) { - res = (login_window->priv->timed_login_username == NULL); - } else { -@@ -756,39 +756,81 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window) - return res; - } - --static gboolean --begin_task_verification (GdmTaskList *task_list, -- GdmTask *task, -- GdmGreeterLoginWindow *login_window) -+static void -+begin_other_verification (GdmGreeterLoginWindow *login_window) - { -- char *service_name; -+ /* FIXME: we should drop this code and do all OTHER handling -+ * entirely from within the password plugin -+ * (ala how smart card manages its "Smartcard Authentication" item) -+ */ -+ begin_single_service_verification (login_window, "gdm-password"); -+} - -- if (!gdm_task_is_visible (task)) { -- return FALSE; -- } -+static void -+set_task_active (GdmGreeterLoginWindow *login_window, -+ GdmTask *task) -+{ -+ GtkWidget *container; -+ char *name; - -- service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task)); -- if (service_name != NULL) { -- g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name); -- g_free (service_name); -+ name = gdm_task_get_name (task); -+ g_debug ("GdmGreeterLoginWindow: task '%s' activated", name); -+ g_free (name); -+ -+ container = g_object_get_data (G_OBJECT (task), -+ "gdm-greeter-login-window-page-container"); -+ -+ if (container == NULL) { -+ GtkWidget *page; -+ -+ container = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); -+ gtk_container_add (GTK_CONTAINER (login_window->priv->auth_page_box), -+ container); -+ -+ page = gdm_conversation_get_page (GDM_CONVERSATION (task)); -+ if (page != NULL) { -+ gtk_container_add (GTK_CONTAINER (container), page); -+ gtk_widget_show (page); -+ } -+ g_object_set_data (G_OBJECT (task), -+ "gdm-greeter-login-window-page-container", -+ container); - } - -- return FALSE; -+ gtk_widget_show (container); -+ -+ login_window->priv->active_task = task; -+ switch_mode (login_window, login_window->priv->dialog_mode); - } - - static void --begin_verification (GdmGreeterLoginWindow *login_window) -+clear_active_task (GdmGreeterLoginWindow *login_window) - { -- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- (GdmTaskListForeachFunc) -- begin_task_verification, -- login_window); - -- switch_mode (login_window, MODE_AUTHENTICATION); -+ GtkWidget *container; -+ GtkActionGroup *actions; - -- update_conversation_list_visibility (login_window); --} -+ if (login_window->priv->active_task == NULL) { -+ return; -+ } -+ -+ container = g_object_get_data (G_OBJECT (login_window->priv->active_task), -+ "gdm-greeter-login-window-page-container"); -+ -+ if (container != NULL) { -+ gtk_widget_hide (container); -+ } -+ -+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (login_window->priv->active_task)); -+ -+ if (actions != NULL) { -+ gtk_action_group_set_sensitive (actions, FALSE); -+ gtk_action_group_set_visible (actions, FALSE); -+ g_object_unref (actions); -+ } - -+ login_window->priv->active_task = NULL; -+} - - static void - reset_dialog (GdmGreeterLoginWindow *login_window, -@@ -823,18 +865,16 @@ reset_dialog (GdmGreeterLoginWindow *login_window, - set_message (login_window, ""); - } - -- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- (GdmTaskListForeachFunc) -- reset_task, -- login_window); -+ g_list_foreach (login_window->priv->tasks, (GFunc) reset_task, login_window); - - if (can_jump_to_authenticate (login_window)) { - /* If we don't have a user list jump straight to authenticate */ - g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate"); - g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], - 0, GDM_USER_CHOOSER_USER_OTHER); -- begin_verification (login_window); -+ begin_other_verification (login_window); - } else { -+ clear_active_task (login_window); - switch_mode (login_window, dialog_mode); - } - -@@ -878,9 +918,9 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window, - if (gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) { - gdm_conversation_set_ready (GDM_CONVERSATION (task)); - } else { -- login_window->priv->tasks_to_enable = g_list_prepend (login_window->priv->tasks_to_enable, task); -+ login_window->priv->tasks_to_enable = g_list_prepend (login_window->priv->tasks_to_enable, -+ g_object_ref (task)); - } -- g_object_unref (task); - } - - set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE); -@@ -893,7 +933,7 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window, - g_debug ("Starting PAM conversation since user list disabled or no local users"); - g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], - 0, GDM_USER_CHOOSER_USER_OTHER); -- begin_verification (login_window); -+ begin_other_verification (login_window); - } - - return TRUE; -@@ -915,24 +955,37 @@ handle_stopped_conversation (GdmGreeterLoginWindow *login_window, - return; - } - -+ if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) { -+ g_debug ("GdmGreeterLoginWindow: conversation failed, starting over"); -+ restart_conversations (login_window); -+ return; -+ } else if (login_window->priv->dialog_mode != MODE_MULTIPLE_AUTHENTICATION) { -+ g_warning ("conversation %s stopped when it shouldn't have been running (mode %d)", -+ service_name, login_window->priv->dialog_mode); -+ restart_conversations (login_window); -+ return; -+ } -+ - task = find_task_with_service_name (login_window, service_name); - - if (task != NULL) { - gdm_conversation_reset (GDM_CONVERSATION (task)); - - g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (FALSE)); -- g_object_unref (task); - } - - /* If every conversation has failed, then just start over. - */ - task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); - -- if (!gdm_task_is_enabled (task)) { -+ if (task == NULL || !gdm_task_is_enabled (task)) { - g_debug ("GdmGreeterLoginWindow: No conversations left, starting over"); - restart_conversations (login_window); - } -- g_object_unref (task); -+ -+ if (task != NULL) { -+ g_object_unref (task); -+ } - - update_conversation_list_visibility (login_window); - } -@@ -948,8 +1001,8 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind - - g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name); - -- task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -- if (task != NULL && task_has_service_name (GDM_TASK_LIST (login_window->priv->conversation_list), task, service_name)) { -+ task = find_task_with_service_name (login_window, service_name); -+ if (task != NULL && gdm_task_is_enabled (task)) { - - messages_pending = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "message-pending")); - } else { -@@ -968,8 +1021,7 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind - } - - static gboolean --restart_task_conversation (GdmTaskList *task_list, -- GdmTask *task, -+restart_task_conversation (GdmTask *task, - GdmGreeterLoginWindow *login_window) - { - char *service_name; -@@ -998,10 +1050,7 @@ gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window) - g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE); - reset_dialog (GDM_GREETER_LOGIN_WINDOW (login_window), MODE_SELECTION); - -- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- (GdmTaskListForeachFunc) -- restart_task_conversation, -- login_window); -+ g_list_foreach (login_window->priv->tasks, (GFunc) restart_task_conversation, login_window); - - g_free (login_window->priv->service_name_of_session_ready_to_start); - login_window->priv->service_name_of_session_ready_to_start = NULL; -@@ -1027,7 +1076,6 @@ gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window, - gdm_conversation_set_message (GDM_CONVERSATION (task), - text); - show_task_actions (task); -- g_object_unref (task); - } - - return TRUE; -@@ -1051,7 +1099,6 @@ gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window, - gdm_conversation_set_message (GDM_CONVERSATION (task), - text); - show_task_actions (task); -- g_object_unref (task); - } - - gdk_window_beep (gtk_widget_get_window (GTK_WIDGET (login_window))); -@@ -1090,9 +1137,19 @@ gdm_greeter_login_window_service_unavailable (GdmGreeterLoginWindow *login_windo - task = find_task_with_service_name (login_window, service_name); - - if (task != NULL) { -- gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- task); -- g_object_unref (task); -+ GdmTask *active_task; -+ -+ gdm_task_set_enabled (task, FALSE); -+ -+ active_task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -+ -+ if (active_task == task) { -+ restart_conversations (login_window); -+ } -+ -+ if (active_task != NULL) { -+ g_object_unref (active_task); -+ } - } - - return TRUE; -@@ -1227,7 +1284,6 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window, - if (task != NULL) { - gdm_conversation_ask_question (GDM_CONVERSATION (task), - text); -- g_object_unref (task); - } - - set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY); -@@ -1258,7 +1314,6 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window, - if (task != NULL) { - gdm_conversation_ask_secret (GDM_CONVERSATION (task), - text); -- g_object_unref (task); - } - - set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY); -@@ -1353,8 +1408,7 @@ on_user_chooser_visibility_changed (GdmGreeterLoginWindow *login_window) - } - - static gboolean --begin_task_verification_for_selected_user (GdmTaskList *task_list, -- GdmTask *task, -+begin_task_verification_for_selected_user (GdmTask *task, - GdmGreeterLoginWindow *login_window) - { - char *user_name; -@@ -1372,6 +1426,9 @@ begin_task_verification_for_selected_user (GdmTaskList *task_list, - g_free (service_name); - } - -+ gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list), -+ task); -+ - g_free (user_name); - return FALSE; - } -@@ -1419,7 +1476,7 @@ on_users_loaded (GdmUserChooserWidget *user_chooser, - g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate"); - g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], - 0, GDM_USER_CHOOSER_USER_OTHER); -- begin_verification (login_window); -+ begin_other_verification (login_window); - } - } - -@@ -1427,19 +1484,23 @@ static void - choose_user (GdmGreeterLoginWindow *login_window, - const char *user_name) - { -+ GdmTask *task; -+ - g_assert (user_name != NULL); - g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name); - - g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED], - 0, user_name); - -+ g_list_foreach (login_window->priv->tasks, -+ (GFunc) begin_task_verification_for_selected_user, -+ login_window); - -- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- (GdmTaskListForeachFunc) -- begin_task_verification_for_selected_user, -- login_window); -+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -+ set_task_active (login_window, task); -+ g_object_unref (task); - -- switch_mode (login_window, MODE_AUTHENTICATION); -+ switch_mode (login_window, MODE_MULTIPLE_AUTHENTICATION); - update_conversation_list_visibility (login_window); - } - -@@ -1455,35 +1516,34 @@ begin_auto_login (GdmGreeterLoginWindow *login_window) - /* just wait for the user to select language and stuff */ - set_message (login_window, _("Select language and click Log In")); - -+ clear_active_task (login_window); - switch_mode (login_window, MODE_TIMED_LOGIN); - - show_widget (login_window, "conversation-list", FALSE); -- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- (GdmTaskListForeachFunc) reset_task, -- login_window); -+ g_list_foreach (login_window->priv->tasks, -+ (GFunc) reset_task, -+ login_window); - } - --static gboolean --reset_task_if_not_given (GdmTaskList *task_list, -- GdmTask *task, -+static void -+reset_task_if_not_given (GdmTask *task, - GdmTask *given_task) - { - if (task == given_task) { -- return FALSE; -+ return; - } - - gdm_conversation_reset (GDM_CONVERSATION (task)); -- return FALSE; - } - - static void - reset_every_task_but_given_task (GdmGreeterLoginWindow *login_window, - GdmTask *task) - { -- gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- (GdmTaskListForeachFunc) -- reset_task_if_not_given, -- task); -+ g_list_foreach (login_window->priv->tasks, -+ (GFunc) reset_task_if_not_given, -+ task); -+ - } - - static void -@@ -1506,11 +1566,10 @@ begin_single_service_verification (GdmGreeterLoginWindow *login_window, - */ - g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name); - -- switch_mode (login_window, MODE_AUTHENTICATION); -- gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task); -- - reset_every_task_but_given_task (login_window, task); -- g_object_unref (task); -+ -+ set_task_active (login_window, task); -+ switch_mode (login_window, MODE_AUTHENTICATION); - - show_widget (login_window, "conversation-list", FALSE); - } -@@ -1541,7 +1600,7 @@ on_user_chooser_activated (GdmUserChooserWidget *user_chooser, - g_debug ("GdmGreeterLoginWindow: Starting all auth conversations"); - g_free (item_id); - -- begin_verification (login_window); -+ begin_other_verification (login_window); - } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_GUEST) == 0) { - /* FIXME: handle guest account stuff */ - g_free (item_id); -@@ -1779,63 +1838,28 @@ static void - on_task_activated (GdmGreeterLoginWindow *login_window, - GdmTask *task) - { -- GtkWidget *container; -- char *name; -- -- name = gdm_task_get_name (task); -- g_debug ("GdmGreeterLoginWindow: task '%s' activated", name); -- g_free (name); -- -- container = g_object_get_data (G_OBJECT (task), -- "gdm-greeter-login-window-page-container"); -- -- if (container == NULL) { -- GtkWidget *page; -- -- container = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); -- gtk_container_add (GTK_CONTAINER (login_window->priv->auth_page_box), -- container); -- -- page = gdm_conversation_get_page (GDM_CONVERSATION (task)); -- if (page != NULL) { -- gtk_container_add (GTK_CONTAINER (container), page); -- gtk_widget_show (page); -- } -- g_object_set_data (G_OBJECT (task), -- "gdm-greeter-login-window-page-container", -- container); -- } -- -- gtk_widget_show (container); -- switch_mode (login_window, login_window->priv->dialog_mode); -+ set_task_active (login_window, task); - } - - static void - on_task_deactivated (GdmGreeterLoginWindow *login_window, - GdmTask *task) - { -- GtkWidget *container; - char *name; -- GtkActionGroup *actions; -+ -+ if (login_window->priv->active_task != task) { -+ g_warning ("inactive task has been deactivated"); -+ return; -+ } - - name = gdm_task_get_name (task); - g_debug ("GdmGreeterLoginWindow: task '%s' now in background", name); - g_free (name); - -- container = g_object_get_data (G_OBJECT (task), -- "gdm-greeter-login-window-page-container"); -+ clear_active_task (login_window); - -- if (container != NULL) { -- gtk_widget_hide (container); -- } -- -- actions = gdm_conversation_get_actions (GDM_CONVERSATION (task)); -- -- if (actions != NULL) { -- gtk_action_group_set_sensitive (actions, FALSE); -- gtk_action_group_set_visible (actions, FALSE); -- g_object_unref (actions); -- } -+ login_window->priv->active_task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -+ g_object_unref (login_window->priv->active_task); - } - - static void -@@ -1948,6 +1972,7 @@ load_theme (GdmGreeterLoginWindow *login_window) - box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "computer-info-event-box")); - g_signal_connect (box, "button-press-event", G_CALLBACK (on_computer_info_label_button_press), login_window); - -+ clear_active_task (login_window); - switch_mode (login_window, MODE_SELECTION); - - gdm_profile_end (NULL); -@@ -2327,15 +2352,12 @@ on_conversation_chose_user (GdmGreeterLoginWindow *login_window, - - /* If we're already authenticating then we can't pick a user - */ -- if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) { -+ if (login_window->priv->dialog_mode == MODE_AUTHENTICATION || login_window->priv->dialog_mode == MODE_MULTIPLE_AUTHENTICATION) { - return FALSE; - } - -- if (gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- GDM_TASK (conversation))) { -- gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), -- username); -- } -+ gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), -+ username); - - return TRUE; - } -@@ -2359,11 +2381,7 @@ on_conversation_message_set (GdmGreeterLoginWindow *login_window, - } - - if (login_window->priv->service_name_of_session_ready_to_start != NULL ) { -- GdmTask *task; -- -- task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list)); -- -- if (task == GDM_TASK (conversation)) { -+ if (login_window->priv->active_task == GDM_TASK (conversation)) { - gdm_greeter_login_window_start_session (login_window); - } - } -@@ -2539,9 +2557,7 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window, - g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added", - name, description); - -- gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list), -- GDM_TASK (extension)); -- -+ login_window->priv->tasks = g_list_append (login_window->priv->tasks, extension); - service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (extension)); - - if (gdm_task_is_choosable (GDM_TASK (extension))) { --- -1.7.4.1 - - -From e787f3bd631cdfb8aa090716992432c3bbf46d73 Mon Sep 17 00:00:00 2001 -From: Gal Hammer -Date: Thu, 21 Oct 2010 10:14:32 -0400 -Subject: [PATCH 20/20] smartcard: don't show extension if disabled in authconfig - -It was erroneously always returning TRUE instead of the the -value determined from reading authconfig's configuration. ---- - .../plugins/smartcard/gdm-smartcard-extension.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c -index 5e234b9..ef79c28 100644 ---- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c -+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c -@@ -391,7 +391,7 @@ gdm_smartcard_extension_is_visible (GdmTask *task) - - g_strfreev (lines); - -- return TRUE; -+ return ret; - } - - static void --- -1.7.4.1 - diff --git a/gdm.spec b/gdm.spec index 2b019f9..a2c4f7a 100644 --- a/gdm.spec +++ b/gdm.spec @@ -14,14 +14,14 @@ Summary: The GNOME Display Manager Name: gdm -Version: 3.0.4 +Version: 3.1.2 Release: 1%{?dist} Epoch: 1 License: GPLv2+ Group: User Interface/X URL: http://download.gnome.org/sources/gdm #VCS: git:git://git.gnome.org/gdm -Source: http://download.gnome.org/sources/gdm/2.91/gdm-%{version}.tar.bz2 +Source: http://download.gnome.org/sources/gdm/2.91/gdm-%{version}.tar.xz Source1: gdm-pam Source2: gdm-autologin-pam Source3: gdm-password.pam @@ -98,9 +98,7 @@ Requires: audit-libs >= %{libauditver} Requires: system-icon-theme Patch2: plymouth.patch -Patch3: fix-dconf-db-thing.patch -Patch96: gdm-multistack.patch # Fedora-specific Patch99: gdm-3.0.0-fedora-logo.patch @@ -129,8 +127,6 @@ The GDM fingerprint plugin provides functionality necessary to use a fingerprint %prep %setup -q %patch2 -p1 -b .plymouth -%patch3 -p1 -b .fix-dconf-db-thing -%patch96 -p1 -b .multistack %patch99 -p1 -b .fedora-logo autoreconf -i -f @@ -141,15 +137,16 @@ rm data/dconf-override-db %build cp -f %{SOURCE1} data/gdm cp -f %{SOURCE2} data/gdm-autologin -cp -f %{SOURCE3} gui/simple-greeter/plugins/password/gdm-password.pam -cp -f %{SOURCE4} gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam -cp -f %{SOURCE5} gui/simple-greeter/plugins/fingerprint/gdm-fingerprint.pam -cp -f %{SOURCE6} gui/simple-greeter/plugins/smartcard/icons/16x16/gdm-smartcard.png -cp -f %{SOURCE7} gui/simple-greeter/plugins/smartcard/icons/48x48/gdm-smartcard.png -cp -f %{SOURCE8} gui/simple-greeter/plugins/fingerprint/icons/16x16/gdm-fingerprint.png -cp -f %{SOURCE9} gui/simple-greeter/plugins/fingerprint/icons/48x48/gdm-fingerprint.png +cp -f %{SOURCE3} gui/simple-greeter/extensions/password/gdm-password.pam +cp -f %{SOURCE4} gui/simple-greeter/extensions/smartcard/gdm-smartcard.pam +cp -f %{SOURCE5} gui/simple-greeter/extensions/fingerprint/gdm-fingerprint.pam +cp -f %{SOURCE6} gui/simple-greeter/extensions/smartcard/icons/16x16/gdm-smartcard.png +cp -f %{SOURCE7} gui/simple-greeter/extensions/smartcard/icons/48x48/gdm-smartcard.png +cp -f %{SOURCE8} gui/simple-greeter/extensions/fingerprint/icons/16x16/gdm-fingerprint.png +cp -f %{SOURCE9} gui/simple-greeter/extensions/fingerprint/icons/48x48/gdm-fingerprint.png %configure --with-pam-prefix=%{_sysconfdir} \ + --enable-split-authentication \ --enable-profiling \ --enable-console-helper \ --disable-scrollkeeper \ @@ -198,7 +195,7 @@ rm -rf $RPM_BUILD_ROOT%{_localstatedir}/scrollkeeper find $RPM_BUILD_ROOT -name '*.a' -delete find $RPM_BUILD_ROOT -name '*.la' -delete -rm -f $RPM_BUILD_ROOT%{_includedir}/gdm/simple-greeter/gdm-greeter-extension.h +rm -f $RPM_BUILD_ROOT%{_includedir}/gdm/simple-greeter/gdm-login-extension.h rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/gdmsimplegreeter.pc %find_lang gdm --with-gnome @@ -299,6 +296,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor >&/dev/ull || : %{_datadir}/gnome-session/sessions/gdm.session %{_datadir}/pixmaps/*.png %{_datadir}/icons/hicolor/*/apps/*.png +%{_datadir}/glib-2.0/schemas/org.gnome.display-manager.extensions.fingerprint.gschema.xml +%{_datadir}/glib-2.0/schemas/org.gnome.display-manager.extensions.smartcard.gschema.xml +%{_datadir}/gdm/simple-greeter/extensions/unified/page.ui %{_libexecdir}/gdm-factory-slave %{_libexecdir}/gdm-host-chooser %{_libexecdir}/gdm-product-slave @@ -319,8 +319,8 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor >&/dev/ull || : %{_libdir}/libgdm*.so* %dir %{_libdir}/gdm %dir %{_libdir}/gdm/simple-greeter -%dir %{_libdir}/gdm/simple-greeter/plugins -%{_libdir}/gdm/simple-greeter/plugins/password.so +%dir %{_libdir}/gdm/simple-greeter/extensions +%{_libdir}/gdm/simple-greeter/extensions/libpassword.so %dir %{_datadir}/gdm/simple-greeter %dir %{_datadir}/gdm/simple-greeter/extensions %dir %{_datadir}/gdm/simple-greeter/extensions/password @@ -349,7 +349,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor >&/dev/ull || : %config %{_sysconfdir}/pam.d/gdm-smartcard %dir %{_datadir}/gdm/simple-greeter/extensions/smartcard %{_datadir}/gdm/simple-greeter/extensions/smartcard/page.ui -%{_libdir}/gdm/simple-greeter/plugins/smartcard.so +%{_libdir}/gdm/simple-greeter/extensions/libsmartcard.so %{_libexecdir}/gdm-smartcard-worker %files plugin-fingerprint @@ -357,9 +357,12 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor >&/dev/ull || : %config %{_sysconfdir}/pam.d/gdm-fingerprint %dir %{_datadir}/gdm/simple-greeter/extensions/fingerprint %{_datadir}/gdm/simple-greeter/extensions/fingerprint/page.ui -%{_libdir}/gdm/simple-greeter/plugins/fingerprint.so +%{_libdir}/gdm/simple-greeter/extensions/libfingerprint.so %changelog +* Mon Jun 13 2011 Ray Strode 3.1.2-1 +- Update for release + * Mon Jun 06 2011 Ray Strode 3.0.4-1 - Update to latest version Resolves CVE-2011-1709 diff --git a/sources b/sources index 0386cbb..007701c 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -020ca5a250a8bb1856e73aee5728a112 gdm-3.0.4.tar.bz2 +5475b1a747418c8a65639f6f6deebd53 gdm-3.1.2.tar.xz