summaryrefslogtreecommitdiff
path: root/liblightdm-gobject/greeter.c
diff options
context:
space:
mode:
authorRobert Ancell <robert.ancell@canonical.com>2014-04-04 12:57:54 +1300
committerRobert Ancell <robert.ancell@canonical.com>2014-04-04 12:57:54 +1300
commit70882eb2977885286c7f5e618dc15b12e4599ed9 (patch)
treeb7af091d816574b589c05d3d08400d3f976da3bd /liblightdm-gobject/greeter.c
parent74b7b8be90d9d4e2700b1e6d44afc9684e333a2d (diff)
downloadlightdm-git-70882eb2977885286c7f5e618dc15b12e4599ed9.tar.gz
Add asynchronous liblightdm-gobject methods
Diffstat (limited to 'liblightdm-gobject/greeter.c')
-rw-r--r--liblightdm-gobject/greeter.c658
1 files changed, 505 insertions, 153 deletions
diff --git a/liblightdm-gobject/greeter.c b/liblightdm-gobject/greeter.c
index c02f73ef..7eb726cf 100644
--- a/liblightdm-gobject/greeter.c
+++ b/liblightdm-gobject/greeter.c
@@ -45,16 +45,38 @@ static guint signals[LAST_SIGNAL] = { 0 };
typedef struct
{
- gboolean connected;
+ /* Channel to write to daemon */
+ GIOChannel *to_server_channel;
+
+ /* Channel to read from daemon */
+ GIOChannel *from_server_channel;
- GIOChannel *to_server_channel, *from_server_channel;
+ /* Data read from the daemon */
guint8 *read_buffer;
gsize n_read;
gsize n_responses_waiting;
GList *responses_received;
+ /* TRUE if have got a connect response */
+ gboolean connected;
+
+ /* Pending connect requests */
+ GList *connect_requests;
+
+ /* Pending start session requests */
+ GList *start_session_requests;
+
+ /* Pending ensure shared data dir requests */
+ GList *ensure_shared_data_dir_requests;
+
+ /* Mapping of username to shared data directories */
+ GHashTable *shared_data_dirs;
+
+ /* Hints provided by the daemon */
GHashTable *hints;
+
+ /* Timeout source to notify greeter to autologin */
guint autologin_timeout;
gchar *authentication_user;
@@ -95,6 +117,25 @@ typedef enum
SERVER_MESSAGE_SHARED_DIR_RESULT,
} ServerMessage;
+/* Request to connect */
+typedef struct
+{
+ GCancellable *cancellable;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+ gboolean complete;
+ guint32 return_code;
+ gchar *dir;
+} Request;
+typedef struct
+{
+ GObjectClass parent_class;
+} RequestClass;
+GType request_get_type (void);
+static void request_iface_init (GAsyncResultIface *iface);
+#define REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), request_get_type (), Request))
+G_DEFINE_TYPE_WITH_CODE (Request, request, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, request_iface_init));
+
/**
* lightdm_greeter_new:
*
@@ -103,11 +144,37 @@ typedef enum
* Return value: the new #LightDMGreeter
**/
LightDMGreeter *
-lightdm_greeter_new ()
+lightdm_greeter_new (void)
{
return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
}
+static Request *
+request_new (GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+ Request *request;
+
+ request = g_object_new (request_get_type (), NULL);
+ if (cancellable)
+ request->cancellable = g_object_ref (cancellable);
+ request->callback = callback;
+ request->user_data = user_data;
+
+ return request;
+}
+
+static gboolean
+request_call_callback (Request *request)
+{
+ if (!request->callback)
+ return FALSE;
+
+ if (request->cancellable && g_cancellable_is_cancelled (request->cancellable))
+ return FALSE;
+
+ return TRUE;
+}
+
static gboolean
timed_login_cb (gpointer data)
{
@@ -215,14 +282,17 @@ get_message_length (guint8 *message, gsize message_length)
return read_int (message, message_length, &offset);
}
-static void
-write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
+static gboolean
+send_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
{
LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
GIOStatus status;
GError *error = NULL;
guint32 stated_length;
+ if (!priv->to_server_channel)
+ return FALSE;
+
/* Double check that we're sending well-formed messages. If we say we're
sending more than we do, we end up DOS'ing lightdm as it waits for the
rest. If we say we're sending less than we do, we confuse the heck out
@@ -232,16 +302,20 @@ write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
if (stated_length != message_length)
{
g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length);
- return;
+ return FALSE;
}
status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error);
if (error)
g_warning ("Error writing to daemon: %s", error->message);
g_clear_error (&error);
- if (status == G_IO_STATUS_NORMAL)
- g_debug ("Wrote %zi bytes to daemon", message_length);
+ if (status != G_IO_STATUS_NORMAL)
+ return FALSE;
+
+ g_debug ("Wrote %zi bytes to daemon", message_length);
g_io_channel_flush (priv->to_server_channel, NULL);
+
+ return TRUE;
}
static void
@@ -251,6 +325,7 @@ handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length
gchar *version;
GString *hint_string;
int timeout;
+ Request *request;
version = read_string (message, message_length, offset);
hint_string = g_string_new ("");
@@ -264,6 +339,7 @@ handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length
g_string_append_printf (hint_string, " %s=%s", name, value);
}
+ priv->connected = TRUE;
g_debug ("Connected version=%s%s", version, hint_string->str);
g_free (version);
g_string_free (hint_string, TRUE);
@@ -275,6 +351,17 @@ handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length
g_debug ("Setting autologin timer for %d seconds", timeout);
priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
}
+
+ /* Notify asynchronous caller */
+ request = g_list_nth_data (priv->connect_requests, 0);
+ if (request)
+ {
+ request->complete = TRUE;
+ if (request_call_callback (request))
+ request->callback (G_OBJECT (greeter), G_ASYNC_RESULT (request), request->user_data);
+ priv->connect_requests = g_list_remove (priv->connect_requests, request);
+ g_object_unref (request);
+ }
}
static void
@@ -381,14 +468,92 @@ handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize messa
g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
}
+static void
+handle_session_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
+{
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+ Request *request;
+
+ /* Notify asynchronous caller */
+ request = g_list_nth_data (priv->start_session_requests, 0);
+ if (request)
+ {
+ request->return_code = read_int (message, message_length, offset);
+ request->complete = TRUE;
+ if (request_call_callback (request))
+ request->callback (G_OBJECT (greeter), G_ASYNC_RESULT (request), request->user_data);
+ priv->start_session_requests = g_list_remove (priv->start_session_requests, request);
+ g_object_unref (request);
+ }
+}
+
+static void
+handle_shared_dir_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
+{
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+ Request *request;
+
+ /* Notify asynchronous caller */
+ request = g_list_nth_data (priv->ensure_shared_data_dir_requests, 0);
+ if (request)
+ {
+ request->dir = read_string (message, message_length, offset);
+ /* Blank data dir means invalid user */
+ if (g_strcmp0 (request->dir, "") == 0)
+ {
+ g_free (request->dir);
+ request->dir = NULL;
+ }
+ request->complete = TRUE;
+ if (request_call_callback (request))
+ request->callback (G_OBJECT (greeter), G_ASYNC_RESULT (request), request->user_data);
+ priv->ensure_shared_data_dir_requests = g_list_remove (priv->ensure_shared_data_dir_requests, request);
+ g_object_unref (request);
+ }
+}
+
+static void
+handle_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
+{
+ gsize offset = 0;
+ guint32 id;
+
+ id = read_int (message, message_length, &offset);
+ read_int (message, message_length, &offset);
+ switch (id)
+ {
+ case SERVER_MESSAGE_CONNECTED:
+ handle_connected (greeter, message, message_length, &offset);
+ break;
+ case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
+ handle_prompt_authentication (greeter, message, message_length, &offset);
+ break;
+ case SERVER_MESSAGE_END_AUTHENTICATION:
+ handle_end_authentication (greeter, message, message_length, &offset);
+ break;
+ case SERVER_MESSAGE_SESSION_RESULT:
+ handle_session_result (greeter, message, message_length, &offset);
+ break;
+ case SERVER_MESSAGE_SHARED_DIR_RESULT:
+ handle_shared_dir_result (greeter, message, message_length, &offset);
+ break;
+ default:
+ g_warning ("Unknown message from server: %d", id);
+ break;
+ }
+}
+
static guint8 *
-read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
+recv_message (LightDMGreeter *greeter, gsize *length, gboolean block)
{
LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
gsize n_to_read, n_read;
guint8 *buffer;
GError *error = NULL;
+ if (!priv->from_server_channel)
+ return NULL;
+
/* Read the header, or the whole message if we already have that */
n_to_read = HEADER_SIZE;
if (priv->n_read >= HEADER_SIZE)
@@ -424,7 +589,7 @@ read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
if (n_to_read > 0)
{
priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
- return read_message (greeter, length, block);
+ return recv_message (greeter, length, block);
}
}
@@ -442,33 +607,104 @@ from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
{
LightDMGreeter *greeter = data;
guint8 *message;
- gsize message_length, offset;
- guint32 id;
-
- message = read_message (greeter, &message_length, FALSE);
- if (!message)
- return TRUE;
+ gsize message_length;
- offset = 0;
- id = read_int (message, message_length, &offset);
- read_int (message, message_length, &offset);
- switch (id)
+ /* Read one message and process it */
+ message = recv_message (greeter, &message_length, FALSE);
+ if (message)
{
- case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
- handle_prompt_authentication (greeter, message, message_length, &offset);
- break;
- case SERVER_MESSAGE_END_AUTHENTICATION:
- handle_end_authentication (greeter, message, message_length, &offset);
- break;
- default:
- g_warning ("Unknown message from server: %d", id);
- break;
+ handle_message (greeter, message, message_length);
+ g_free (message);
}
- g_free (message);
return TRUE;
}
+static gboolean
+send_connect (LightDMGreeter *greeter)
+{
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ g_debug ("Connecting to display manager...");
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
+ return send_message (greeter, message, offset);
+}
+
+static gboolean
+send_start_session (LightDMGreeter *greeter, const gchar *session)
+{
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ if (session)
+ g_debug ("Starting session %s", session);
+ else
+ g_debug ("Starting default session");
+
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
+ return send_message (greeter, message, offset);
+}
+
+static gboolean
+send_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username)
+{
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ g_debug ("Ensuring data directory for user %s", username);
+
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
+ return send_message (greeter, message, offset);
+}
+
+/**
+ * lightdm_greeter_connect:
+ * @greeter: The greeter to connect
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
+ * @user_data: (allow-none): data to pass to the @callback or %NULL.
+ *
+ * Asynchronously connects the greeter to the display manager.
+ *
+ * When the operation is finished, @callback will be invoked. You can then call lightdm_greeter_connect_finish() to get the result of the operation.
+ *
+ * See lightdm_greeter_connect_sync() for the synchronous version.
+ **/
+void
+lightdm_greeter_connect (LightDMGreeter *greeter, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+ LightDMGreeterPrivate *priv;
+ Request *request;
+
+ g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+ priv = GET_PRIVATE (greeter);
+
+ request = request_new (cancellable, callback, user_data);
+ priv->connect_requests = g_list_append (priv->connect_requests, request);
+ send_connect (greeter);
+}
+
+/**
+ * lightdm_greeter_connect_finish:
+ * @result: A #GAsyncResult.
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes an operation started with lightdm_greeter_connect().
+ *
+ * Return value: #TRUE if successfully connected
+ **/
+gboolean
+lightdm_greeter_connect_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
+{
+ g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+ return REQUEST (result)->complete;
+}
+
/**
* lightdm_greeter_connect_sync:
* @greeter: The greeter to connect
@@ -482,59 +718,31 @@ gboolean
lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
{
LightDMGreeterPrivate *priv;
- const gchar *fd;
- guint8 message[MAX_MESSAGE_LENGTH];
- guint8 *response;
- gsize response_length, offset = 0;
- guint32 id;
+ Request *request;
g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
priv = GET_PRIVATE (greeter);
- fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
- if (!fd)
+ /* Read until we are connected */
+ send_connect (greeter);
+ request = request_new (NULL, NULL, NULL);
+ priv->connect_requests = g_list_append (priv->connect_requests, g_object_ref (request));
+ do
{
- g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
- return FALSE;
- }
- priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
- g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
+ guint8 *message;
+ gsize message_length;
- fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
- if (!fd)
- {
- g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
- return FALSE;
- }
- priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
- g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
- g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
-
- g_debug ("Connecting to display manager...");
- write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
- write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
- write_message (greeter, message, offset);
-
- response = read_message (greeter, &response_length, TRUE);
- if (!response)
- return FALSE;
-
- offset = 0;
- id = read_int (response, response_length, &offset);
- read_int (response, response_length, &offset);
- if (id == SERVER_MESSAGE_CONNECTED)
- handle_connected (greeter, response, response_length, &offset);
- g_free (response);
- if (id != SERVER_MESSAGE_CONNECTED)
- {
- g_warning ("Expected CONNECTED message, got %d", id);
- return FALSE;
- }
+ message = recv_message (greeter, &message_length, TRUE);
+ if (!message)
+ break;
+ handle_message (greeter, message, message_length);
+ g_free (message);
+ } while (!request->complete);
- priv->connected = TRUE;
+ g_object_unref (request);
- return TRUE;
+ return request->complete;
}
/**
@@ -819,7 +1027,7 @@ lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username)
write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
- write_message (greeter, message, offset);
+ send_message (greeter, message, offset);
}
/**
@@ -851,7 +1059,7 @@ lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
g_debug ("Starting authentication for guest account...");
write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
- write_message (greeter, message, offset);
+ send_message (greeter, message, offset);
}
/**
@@ -908,7 +1116,7 @@ lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *sessi
write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
- write_message (greeter, message, offset);
+ send_message (greeter, message, offset);
}
/**
@@ -938,27 +1146,23 @@ lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
if (priv->n_responses_waiting == 0)
{
- guint32 msg_length;
- GList *iter;
-
- g_debug ("Providing response to display manager");
-
- msg_length = int_length ();
- for (iter = priv->responses_received; iter; iter = iter->next)
- {
- msg_length += string_length ((gchar *)iter->data);
- }
-
- write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset);
- write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset);
- for (iter = priv->responses_received; iter; iter = iter->next)
- {
- write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset);
- }
- write_message (greeter, message, offset);
-
- g_list_free_full (priv->responses_received, g_free);
- priv->responses_received = NULL;
+ guint32 msg_length;
+ GList *iter;
+
+ g_debug ("Providing response to display manager");
+
+ msg_length = int_length ();
+ for (iter = priv->responses_received; iter; iter = iter->next)
+ msg_length += string_length ((gchar *)iter->data);
+
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset);
+ write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset);
+ for (iter = priv->responses_received; iter; iter = iter->next)
+ write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset);
+ send_message (greeter, message, offset);
+
+ g_list_free_full (priv->responses_received, g_free);
+ priv->responses_received = NULL;
}
}
@@ -983,7 +1187,7 @@ lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
priv->cancelling_authentication = TRUE;
write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
- write_message (greeter, message, offset);
+ send_message (greeter, message, offset);
}
/**
@@ -1053,7 +1257,53 @@ lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
- write_message (greeter, message, offset);
+ send_message (greeter, message, offset);
+}
+
+/**
+ * lightdm_greeter_start_session:
+ * @greeter: A #LightDMGreeter
+ * @session: (allow-none): The session to log into or #NULL to use the default.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
+ * @user_data: (allow-none): data to pass to the @callback or %NULL.
+ *
+ * Asynchronously start a session for the authenticated user.
+ *
+ * When the operation is finished, @callback will be invoked. You can then call lightdm_greeter_start_session_finish() to get the result of the operation.
+ *
+ * See lightdm_greeter_start_session_sync() for the synchronous version.
+ **/
+void
+lightdm_greeter_start_session (LightDMGreeter *greeter, const gchar *session, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+ LightDMGreeterPrivate *priv;
+ Request *request;
+
+ g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+ priv = GET_PRIVATE (greeter);
+
+ send_start_session (greeter, session);
+ request = request_new (cancellable, callback, user_data);
+ priv->start_session_requests = g_list_append (priv->start_session_requests, request);
+}
+
+/**
+ * lightdm_greeter_start_session_finish:
+ * @greeter: A #LightDMGreeter
+ * @result: A #GAsyncResult.
+ * @error: return location for a #GError, or %NULL
+ *
+ * Start a session for the authenticated user.
+ *
+ * Return value: TRUE if the session was started.
+ **/
+gboolean
+lightdm_greeter_start_session_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
+{
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+ return REQUEST (result)->return_code == 0;
}
/**
@@ -1070,10 +1320,8 @@ gboolean
lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
{
LightDMGreeterPrivate *priv;
- guint8 message[MAX_MESSAGE_LENGTH];
- guint8 *response;
- gsize response_length, offset = 0;
- guint32 id, return_code = 1;
+ Request *request;
+ guint32 return_code;
g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
@@ -1082,30 +1330,75 @@ lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *sessio
g_return_val_if_fail (priv->connected, FALSE);
g_return_val_if_fail (priv->is_authenticated, FALSE);
- if (session)
- g_debug ("Starting session %s", session);
- else
- g_debug ("Starting default session");
+ /* Read until the session is started */
+ send_start_session (greeter, session);
+ request = request_new (NULL, NULL, NULL);
+ priv->start_session_requests = g_list_append (priv->start_session_requests, g_object_ref (request));
+ do
+ {
+ guint8 *message;
+ gsize message_length;
- write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
- write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
- write_message (greeter, message, offset);
+ message = recv_message (greeter, &message_length, TRUE);
+ if (!message)
+ break;
+ handle_message (greeter, message, message_length);
+ g_free (message);
+ } while (!request->complete);
- response = read_message (greeter, &response_length, TRUE);
- if (!response)
- return FALSE;
+ return_code = request->return_code;
+ g_object_unref (request);
- offset = 0;
- id = read_int (response, response_length, &offset);
- read_int (response, response_length, &offset);
- if (id == SERVER_MESSAGE_SESSION_RESULT)
- return_code = read_int (response, response_length, &offset);
- else
- g_warning ("Expected SESSION_RESULT message, got %d", id);
+ return return_code == 0;
+}
- g_free (response);
+/**
+ * lightdm_greeter_ensure_shared_data_dir:
+ * @greeter: A #LightDMGreeter
+ * @username: A username
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
+ * @user_data: (allow-none): data to pass to the @callback or %NULL.
+ *
+ * Ensure that a shared data dir for the given user is available. Both the
+ * greeter user and @username will have write access to that folder. The
+ * intention is that larger pieces of shared data would be stored there (files
+ * that the greeter creates but wants to give to a user -- like camera
+ * photos -- or files that the user creates but wants the greeter to
+ * see -- like contact avatars).
+ *
+ * LightDM will automatically create these if the user actually logs in, so
+ * greeters only need to call this method if they want to store something in
+ * the directory themselves.
+ **/
+void
+lightdm_greeter_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+ LightDMGreeterPrivate *priv;
+ Request *request;
- return return_code == 0;
+ g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+ priv = GET_PRIVATE (greeter);
+
+ send_ensure_shared_data_dir (greeter, username);
+ request = request_new (cancellable, callback, user_data);
+ priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, request);
+}
+
+/**
+ * lightdm_greeter_ensure_shared_data_dir_finish:
+ * @result: A #GAsyncResult.
+ * @greeter: A #LightDMGreeter
+ *
+ *
+ * Return value: The path to the shared directory, free with g_free.
+ **/
+gchar *
+lightdm_greeter_ensure_shared_data_dir_finish (LightDMGreeter *greeter, GAsyncResult *result)
+{
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
+ return g_strdup (REQUEST (result)->dir);
}
/**
@@ -1124,17 +1417,14 @@ lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *sessio
* greeters only need to call this method if they want to store something in
* the directory themselves.
*
- * Return value: The path to the shared directory, free with g_free
+ * Return value: The path to the shared directory, free with g_free.
**/
gchar *
lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gchar *username)
{
LightDMGreeterPrivate *priv;
- guint8 message[MAX_MESSAGE_LENGTH];
- guint8 *response;
- gsize response_length, offset = 0;
- guint32 id;
- gchar *data_dir = NULL;
+ Request *request;
+ gchar *data_dir;
g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
@@ -1142,32 +1432,24 @@ lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gcha
g_return_val_if_fail (priv->connected, NULL);
- g_debug ("Ensuring data directory for user %s", username);
-
- write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset);
- write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
- write_message (greeter, message, offset);
-
- response = read_message (greeter, &response_length, TRUE);
- if (!response)
- return NULL;
-
- offset = 0;
- id = read_int (response, response_length, &offset);
- read_int (response, response_length, &offset);
- if (id == SERVER_MESSAGE_SHARED_DIR_RESULT)
- data_dir = read_string (response, response_length, &offset);
- else
- g_warning ("Expected SHARED_DIR_RESULT message, got %d", id);
-
- /* Blank data dir means invalid user */
- if (g_strcmp0 (data_dir, "") == 0)
+ /* Read until a response */
+ send_ensure_shared_data_dir (greeter, username);
+ request = request_new (NULL, NULL, NULL);
+ priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, g_object_ref (request));
+ do
{
- g_free (data_dir);
- data_dir = NULL;
- }
+ guint8 *message;
+ gsize message_length;
- g_free (response);
+ message = recv_message (greeter, &message_length, TRUE);
+ if (!message)
+ break;
+ handle_message (greeter, message, message_length);
+ g_free (message);
+ } while (!request->complete);
+
+ data_dir = g_strdup (request->dir);
+ g_object_unref (request);
return data_dir;
}
@@ -1176,9 +1458,29 @@ static void
lightdm_greeter_init (LightDMGreeter *greeter)
{
LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+ const gchar *fd;
priv->read_buffer = g_malloc (HEADER_SIZE);
priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
+ if (fd)
+ {
+ priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
+ g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
+ }
+ else
+ g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
+
+ fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
+ if (fd)
+ {
+ priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
+ g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
+ g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
+ }
+ else
+ g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
}
static void
@@ -1461,3 +1763,53 @@ lightdm_greeter_class_init (LightDMGreeterClass *klass)
NULL,
G_TYPE_NONE, 0);
}
+
+static void
+request_init (Request *request)
+{
+}
+
+static void
+request_finalize (GObject *object)
+{
+ Request *request = REQUEST (object);
+
+ g_free (request->dir);
+ if (request->cancellable)
+ g_object_unref (request->cancellable);
+
+ G_OBJECT_CLASS (request_parent_class)->finalize (object);
+}
+
+static void
+request_class_init (RequestClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = request_finalize;
+}
+
+static gpointer
+request_get_user_data (GAsyncResult *result)
+{
+ return REQUEST (result)->user_data;
+}
+
+static GObject *
+request_get_source_object (GAsyncResult *res)
+{
+ return NULL;
+}
+
+static gboolean
+request_is_tagged (GAsyncResult *res, gpointer source_tag)
+{
+ return FALSE;
+}
+
+static void
+request_iface_init (GAsyncResultIface *iface)
+{
+ iface->get_user_data = request_get_user_data;
+ iface->get_source_object = request_get_source_object;
+ iface->is_tagged = request_is_tagged;
+}