diff options
author | Xavier Claessens <xclaesse@gmail.com> | 2010-07-15 16:24:02 +0200 |
---|---|---|
committer | Xavier Claessens <xclaesse@gmail.com> | 2010-07-15 16:24:02 +0200 |
commit | 78223787a6e711da1774ba33091ba736d9d44d54 (patch) | |
tree | a4252f570245cfa76aa55202563746e5a25d9c1f | |
parent | bff3545d10ccbf9569ff1cd0018ba459b254b023 (diff) |
Pass a ClientContext everywhere to keep our data
-rw-r--r-- | src/client.c | 335 |
1 files changed, 185 insertions, 150 deletions
diff --git a/src/client.c b/src/client.c index 9bc4394..56a2d35 100644 --- a/src/client.c +++ b/src/client.c @@ -30,28 +30,43 @@ #include "common.h" -static gboolean success = TRUE; -static GMainLoop *loop = NULL; -static gchar *unix_path = NULL; +typedef struct +{ + GMainLoop *loop; + + gchar *account_id; + gchar *contact_id; + gchar *login; + + TpBaseClient *client; + + GList *accounts; + guint n_readying_connections; + TpAccount *account; + + gchar *unix_path; + GSocketConnection *tube_connection; + GSocketConnection *ssh_connection; + + gboolean success:1; +} ClientContext; static void -remove_unix_path (void) +throw_error (ClientContext *context, + const GError *error) { - gchar *p; - - g_unlink (unix_path); - p = g_strrstr (unix_path, G_DIR_SEPARATOR_S); - *p = '\0'; - g_rmdir (unix_path); - g_free (unix_path); + g_debug ("Error: %s", error ? error->message : "No error message"); + context->success = FALSE; + g_main_loop_quit (context->loop); } static void -throw_error (const GError *error) +throw_error_message (ClientContext *context, + const gchar *message) { - g_debug ("Error: %s", error ? error->message : "No error message"); - success = FALSE; - g_main_loop_quit (loop); + g_debug ("Error: %s", message); + context->success = FALSE; + g_main_loop_quit (context->loop); } static void @@ -60,10 +75,12 @@ splice_cb (GIOStream *stream1, const GError *error, gpointer user_data) { + ClientContext *context = user_data; + if (error != NULL) - throw_error (error); + throw_error (context, error); else - g_main_loop_quit (loop); + g_main_loop_quit (context->loop); } static void @@ -71,22 +88,21 @@ ssh_socket_connected_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { + ClientContext *context = user_data; GSocketListener *listener = G_SOCKET_LISTENER (source_object); - GSocketConnection *tube_connection = user_data; - GSocketConnection *ssh_connection; GError *error = NULL; - ssh_connection = g_socket_listener_accept_finish (listener, res, NULL, &error); - if (ssh_connection == NULL) + context->ssh_connection = g_socket_listener_accept_finish (listener, res, + NULL, &error); + if (context->ssh_connection == NULL) { - throw_error (error); - g_object_unref (tube_connection); + throw_error (context, error); return; } /* Splice tube and ssh connections */ - _g_io_stream_splice (G_IO_STREAM (tube_connection), - G_IO_STREAM (ssh_connection), splice_cb, NULL); + _g_io_stream_splice (G_IO_STREAM (context->tube_connection), + G_IO_STREAM (context->ssh_connection), splice_cb, context); } static void @@ -94,16 +110,17 @@ tube_socket_connected_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { + ClientContext *context = user_data; GSocketListener *listener = G_SOCKET_LISTENER (source_object); - GSocketConnection *tube_connection; GSocket *socket = NULL; GInetAddress * inet_address = NULL; GSocketAddress *socket_address = NULL; guint port; GError *error = NULL; - tube_connection = g_socket_listener_accept_finish (listener, res, NULL, &error); - if (tube_connection == NULL) + context->tube_connection = g_socket_listener_accept_finish (listener, res, + NULL, &error); + if (context->tube_connection == NULL) goto OUT; /* Create the IPv4 socket, and listen for connection on it */ @@ -128,7 +145,7 @@ tube_socket_connected_cb (GObject *source_object, port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (socket_address)); g_socket_listener_accept_async (listener, NULL, - ssh_socket_connected_cb, g_object_ref (tube_connection)); + ssh_socket_connected_cb, context); /* Start ssh client, it will connect on our IPv4 socket */ if (fork() == 0) @@ -141,7 +158,9 @@ tube_socket_connected_cb (GObject *source_object, OUT: - tp_clear_object (&tube_connection); + if (error != NULL) + throw_error (context, error); + tp_clear_object (&socket); tp_clear_object (&inet_address); tp_clear_object (&socket_address); @@ -154,8 +173,10 @@ offer_tube_cb (TpChannel *channel, gpointer user_data, GObject *weak_object) { + ClientContext *context = user_data; + if (error != NULL) - throw_error (error); + throw_error (context, error); } static void @@ -163,16 +184,17 @@ channel_invalidated_cb (TpProxy *proxy, guint domain, gint code, gchar *message, - gpointer user_data) + ClientContext *context) { const GError *error; error = tp_proxy_get_invalidated (proxy); - throw_error (error); + throw_error (context, error); } static void -handle_channel (TpChannel *channel) +handle_channel (ClientContext *context, + TpChannel *channel) { gchar *dir; GSocketListener *listener = NULL; @@ -183,7 +205,7 @@ handle_channel (TpChannel *channel) GError *error = NULL; g_signal_connect (channel, "invalidated", - G_CALLBACK (channel_invalidated_cb), NULL); + G_CALLBACK (channel_invalidated_cb), context); /* We are client side, but we have to offer a socket... So we offer an unix * socket on which the service side can connect. We also create an IPv4 socket @@ -198,8 +220,7 @@ handle_channel (TpChannel *channel) /* Create temporary file for our unix socket */ dir = g_build_filename (g_get_tmp_dir (), "telepathy-ssh-XXXXXX", NULL); dir = mkdtemp (dir); - unix_path = g_build_filename (dir, "unix-socket", NULL); - g_atexit (remove_unix_path); + context->unix_path = g_build_filename (dir, "unix-socket", NULL); g_free (dir); /* Create the unix socket, and listen for connection on it */ @@ -207,7 +228,7 @@ handle_channel (TpChannel *channel) G_SOCKET_PROTOCOL_DEFAULT, &error); if (socket == NULL) goto OUT; - socket_address = g_unix_socket_address_new (unix_path); + socket_address = g_unix_socket_address_new (context->unix_path); if (!g_socket_bind (socket, socket_address, FALSE, &error)) goto OUT; if (!g_socket_listen (socket, &error)) @@ -216,7 +237,7 @@ handle_channel (TpChannel *channel) goto OUT; g_socket_listener_accept_async (listener, NULL, - tube_socket_connected_cb, NULL); + tube_socket_connected_cb, context); /* Offer the socket */ address = tp_address_variant_from_g_socket_address (socket_address, @@ -227,14 +248,14 @@ handle_channel (TpChannel *channel) tp_cli_channel_type_stream_tube_call_offer (channel, -1, TP_SOCKET_ADDRESS_TYPE_UNIX, address, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, parameters, - offer_tube_cb, NULL, NULL, NULL); + offer_tube_cb, context, NULL, NULL); tp_g_value_slice_free (address); g_hash_table_unref (parameters); OUT: if (error != NULL) - throw_error (error); + throw_error (context, error); tp_clear_object (&listener); tp_clear_object (&socket); @@ -249,9 +270,10 @@ got_channel_cb (TpSimpleHandler *handler, GList *channels, GList *requests_satisfied, gint64 user_action_time, - TpHandleChannelsContext *context, + TpHandleChannelsContext *channel_context, gpointer user_data) { + ClientContext *context = user_data; GList *l; for (l = channels; l != NULL; l = l->next) @@ -262,24 +284,24 @@ got_channel_cb (TpSimpleHandler *handler, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) continue; - handle_channel (channel); + handle_channel (context, channel); } - tp_handle_channels_context_accept (context); + tp_handle_channels_context_accept (channel_context); } static void -channel_request_invalidated (TpProxy *proxy, +channel_request_invalidated_cb (TpProxy *proxy, guint domain, gint code, gchar *message, - gpointer user_data) + ClientContext *context) { const GError *error; error = tp_proxy_get_invalidated (proxy); if (!g_error_matches (error, TP_DBUS_ERRORS, TP_DBUS_ERROR_OBJECT_REMOVED)) - throw_error (error); + throw_error (context, error); g_object_unref (proxy); } @@ -290,8 +312,10 @@ request_proceed_cb (TpChannelRequest *request, gpointer user_data, GObject *weak_object) { + ClientContext *context = user_data; + if (error != NULL) - throw_error (error); + throw_error (context, error); } static void @@ -301,13 +325,14 @@ create_channel_cb (TpChannelDispatcher *dispatcher, gpointer user_data, GObject *weak_object) { + ClientContext *context = user_data; TpDBusDaemon *dbus; TpChannelRequest *request; GError *err = NULL; if (error != NULL) { - throw_error (error); + throw_error (context, error); return; } @@ -315,32 +340,20 @@ create_channel_cb (TpChannelDispatcher *dispatcher, request = tp_channel_request_new (dbus, request_path, NULL, &err); if (request == NULL) { - throw_error (err); + throw_error (context, err); g_clear_error (&err); return; } g_signal_connect (request, "invalidated", - G_CALLBACK (channel_request_invalidated), NULL); + G_CALLBACK (channel_request_invalidated_cb), context); tp_cli_channel_request_call_proceed (request, -1, request_proceed_cb, - NULL, NULL, NULL); + context, NULL, NULL); } -typedef struct -{ - TpBaseClient *client; - gchar *account_id; - gchar *contact_id; - - GList *accounts; - guint n_readying_connections; - - TpAccount *account; -} RequestData; - static void -request_channel (RequestData *data) +request_channel (ClientContext *context) { TpDBusDaemon *dbus = NULL; TpChannelDispatcher *dispatcher = NULL; @@ -354,15 +367,15 @@ request_channel (RequestData *data) TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, TP_PROP_CHANNEL_TARGET_ID, G_TYPE_STRING, - data->contact_id, + context->contact_id, TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE, G_TYPE_STRING, TUBE_SERVICE, NULL); tp_cli_channel_dispatcher_call_create_channel (dispatcher, -1, - tp_proxy_get_object_path (TP_PROXY (data->account)), request, G_MAXINT64, - tp_base_client_get_bus_name (data->client), create_channel_cb, - NULL, NULL, NULL); + tp_proxy_get_object_path (TP_PROXY (context->account)), request, G_MAXINT64, + tp_base_client_get_bus_name (context->client), create_channel_cb, + context, NULL, NULL); g_object_unref (dbus); g_object_unref (dispatcher); @@ -409,7 +422,7 @@ got_contacts_cb (TpConnection *connection, gpointer user_data, GObject *weak_object) { - RequestData *data = user_data; + ClientContext *context = user_data; guint i; GList *candidates = NULL, *l; guint count = 0; @@ -418,7 +431,7 @@ got_contacts_cb (TpConnection *connection, if (error != NULL) { - throw_error (error); + throw_error (context, error); return; } @@ -429,8 +442,7 @@ got_contacts_cb (TpConnection *connection, if (candidates == NULL) { - g_print ("No suitable contact, abort\n"); - g_main_loop_quit (loop); + throw_error_message (context, "No suitable contact"); return; } @@ -452,13 +464,12 @@ got_contacts_cb (TpConnection *connection, } if (l == NULL) { - g_print ("Invalid contact number\n"); - g_main_loop_quit (loop); + throw_error_message (context, "Invalid contact number"); return; } - data->contact_id = g_strdup (tp_contact_get_identifier (l->data)); - request_channel (data); + context->contact_id = g_strdup (tp_contact_get_identifier (l->data)); + request_channel (context); g_list_free (candidates); } @@ -468,6 +479,7 @@ stored_channel_prepare_cb (GObject *object, GAsyncResult *res, gpointer user_data) { + ClientContext *context = user_data; TpChannel *channel = TP_CHANNEL (object); TpConnection *connection; TpContactFeature features[] = { TP_CONTACT_FEATURE_ALIAS, @@ -478,7 +490,7 @@ stored_channel_prepare_cb (GObject *object, if (!tp_proxy_prepare_finish (channel, res, &error)) { - throw_error (error); + throw_error (context, error); g_clear_error (&error); return; } @@ -489,7 +501,7 @@ stored_channel_prepare_cb (GObject *object, tp_connection_get_contacts_by_handle (connection, handles->len, (TpHandle *) handles->data, G_N_ELEMENTS (features), features, - got_contacts_cb, user_data, NULL, NULL); + got_contacts_cb, context, NULL, NULL); g_array_unref (handles); } @@ -503,13 +515,14 @@ ensure_stored_channel_cb (TpConnection *connection, gpointer user_data, GObject *weak_object) { + ClientContext *context = user_data; TpChannel *channel; GQuark features[] = { TP_CHANNEL_FEATURE_GROUP, 0 }; GError *err = NULL; if (error != NULL) { - throw_error (error); + throw_error (context, error); return; } @@ -517,26 +530,26 @@ ensure_stored_channel_cb (TpConnection *connection, properties, &err); if (channel == NULL) { - throw_error (err); + throw_error (context, err); g_clear_error (&err); return; } tp_proxy_prepare_async (TP_PROXY (channel), features, - stored_channel_prepare_cb, user_data); + stored_channel_prepare_cb, context); g_object_unref (channel); } static void -chooser_contact (RequestData *data) +chooser_contact (ClientContext *context) { TpConnection *connection; GHashTable *request; /* If a contact ID was passed in the options, use it */ - if (data->contact_id != NULL) - request_channel (data); + if (context->contact_id != NULL) + request_channel (context); /* Otherwise, we'll get TpContact objects for all stored contacts on that * account. */ @@ -549,29 +562,28 @@ chooser_contact (RequestData *data) "stored", NULL); - connection = tp_account_get_connection (data->account); + connection = tp_account_get_connection (context->account); tp_cli_connection_interface_requests_call_ensure_channel (connection, -1, - request, ensure_stored_channel_cb, data, NULL, NULL); + request, ensure_stored_channel_cb, context, NULL, NULL); g_hash_table_unref (request); } static void -chooser_account (RequestData *data) +chooser_account (ClientContext *context) { GList *l; guint count = 0; gchar buffer[10]; gchar *str; - if (data->accounts == NULL) + if (context->accounts == NULL) { - g_print ("No suitable account, abort\n"); - g_main_loop_quit (loop); + throw_error_message (context, "No suitable account"); return; } - for (l = data->accounts; l != NULL; l = l->next) + for (l = context->accounts; l != NULL; l = l->next) { g_print ("%d) %s (%s)\n", ++count, tp_account_get_display_name (l->data), @@ -583,30 +595,29 @@ chooser_account (RequestData *data) if (str != NULL) { str[strlen (str) - 1] = '\0'; - l = g_list_nth (data->accounts, atoi (str) - 1); + l = g_list_nth (context->accounts, atoi (str) - 1); } if (l == NULL) { - g_print ("Invalid account number\n"); - g_main_loop_quit (loop); + throw_error_message (context, "Invalid account number"); return; } - data->account = g_object_ref (l->data); + context->account = g_object_ref (l->data); /* If the account id was not in the options, print it now. It makes easier to * copy/paste later. */ - if (data->account_id == NULL) + if (context->account_id == NULL) { const gchar *account_path; - account_path = tp_proxy_get_object_path (data->account); - data->account_id = g_strdup (account_path + + account_path = tp_proxy_get_object_path (context->account); + context->account_id = g_strdup (account_path + strlen (TP_ACCOUNT_OBJECT_PATH_BASE)); - g_print ("Going to use account: '%s'\n", data->account_id); + g_print ("Going to use account: '%s'\n", context->account_id); } - chooser_contact (data); + chooser_contact (context); } static void @@ -615,7 +626,7 @@ connection_prepare_cb (GObject *object, gpointer user_data) { TpConnection *connection = TP_CONNECTION (object); - RequestData *data = user_data; + ClientContext *context = user_data; if (!tp_proxy_prepare_finish (TP_PROXY (connection), res, NULL) || !has_stream_tube_cap (tp_connection_get_capabilities (connection))) @@ -623,17 +634,17 @@ connection_prepare_cb (GObject *object, GList *l; /* Remove the account that has that connection from the list */ - for (l = data->accounts; l != NULL; l = l->next) + for (l = context->accounts; l != NULL; l = l->next) if (tp_account_get_connection (l->data) == connection) { g_object_unref (l->data); - data->accounts = g_list_delete_link (data->accounts, l); + context->accounts = g_list_delete_link (context->accounts, l); break; } } - if (--data->n_readying_connections == 0) - chooser_account (data); + if (--context->n_readying_connections == 0) + chooser_account (context); } static void @@ -642,25 +653,25 @@ account_manager_prepare_cb (GObject *object, gpointer user_data) { TpAccountManager *manager = TP_ACCOUNT_MANAGER (object); - RequestData *data = user_data; + ClientContext *context = user_data; GList *l, *next; GError *error = NULL; if (!tp_proxy_prepare_finish (TP_PROXY (manager), res, &error)) { - throw_error (error); + throw_error (context, error); g_clear_error (&error); return; } /* We want to list all accounts which has a connection that have StreamTube * support. So first we prepare all connections, and we keep in - * data->accounts those that are suitable. */ + * context->accounts those that are suitable. */ - data->accounts = tp_account_manager_get_valid_accounts (manager); - g_list_foreach (data->accounts, (GFunc) g_object_ref, NULL); + context->accounts = tp_account_manager_get_valid_accounts (manager); + g_list_foreach (context->accounts, (GFunc) g_object_ref, NULL); - for (l = data->accounts; l != NULL; l = next) + for (l = context->accounts; l != NULL; l = next) { GQuark features[] = { TP_CONNECTION_FEATURE_CAPABILITIES, 0 }; TpAccount *account = l->data; @@ -672,17 +683,17 @@ account_manager_prepare_cb (GObject *object, if (connection == NULL) { g_object_unref (account); - data->accounts = g_list_delete_link (data->accounts, l); + context->accounts = g_list_delete_link (context->accounts, l); continue; } - data->n_readying_connections++; + context->n_readying_connections++; tp_proxy_prepare_async (TP_PROXY (connection), features, - connection_prepare_cb, data); + connection_prepare_cb, context); } - if (data->n_readying_connections == 0) - chooser_account (data); + if (context->n_readying_connections == 0) + chooser_account (context); } static void @@ -691,7 +702,7 @@ account_prepare_cb (GObject *object, gpointer user_data) { TpAccount *account = TP_ACCOUNT (object); - RequestData *data = user_data; + ClientContext *context = user_data; GQuark features[] = { TP_CONNECTION_FEATURE_CAPABILITIES, 0 }; TpConnection *connection; GError *error = NULL; @@ -702,23 +713,50 @@ account_prepare_cb (GObject *object, if (!tp_proxy_prepare_finish (TP_PROXY (account), res, &error)) { - throw_error (error); + throw_error (context, error); return; } connection = tp_account_get_connection (account); if (connection == NULL) { - g_debug ("Account not online"); - g_main_loop_quit (loop); + throw_error_message (context, "Account not online"); return; } /* Prepare account's connection with caps feature */ - data->accounts = g_list_prepend (NULL, g_object_ref (account)); - data->n_readying_connections = 1; + context->accounts = g_list_prepend (NULL, g_object_ref (account)); + context->n_readying_connections = 1; tp_proxy_prepare_async (TP_PROXY (connection), features, - connection_prepare_cb, data); + connection_prepare_cb, context); +} + +static void +client_context_clear (ClientContext *context) +{ + tp_clear_pointer (&context->loop, g_main_loop_unref); + g_free (context->account_id); + g_free (context->contact_id); + g_free (context->login); + + tp_clear_object (&context->client); + + g_list_foreach (context->accounts, (GFunc) g_object_unref, NULL); + g_list_free (context->accounts); + tp_clear_object (&context->account); + + if (context->unix_path != NULL) + { + gchar *p; + + g_unlink (context->unix_path); + p = g_strrstr (context->unix_path, G_DIR_SEPARATOR_S); + *p = '\0'; + g_rmdir (context->unix_path); + g_free (context->unix_path); + } + tp_clear_object (&context->tube_connection); + tp_clear_object (&context->ssh_connection); } int @@ -726,17 +764,21 @@ main (gint argc, gchar *argv[]) { TpDBusDaemon *dbus = NULL; GError *error = NULL; - RequestData data = { 0, }; + ClientContext context = { 0, }; GOptionContext *optcontext; GOptionEntry options[] = { { "account", 'a', - 0, G_OPTION_ARG_STRING, &data.account_id, + 0, G_OPTION_ARG_STRING, &context.account_id, "The account ID", NULL }, { "contact", 'c', - 0, G_OPTION_ARG_STRING, &data.contact_id, + 0, G_OPTION_ARG_STRING, &context.contact_id, "The contact ID", NULL }, + { "login", 'l', + 0, G_OPTION_ARG_STRING, &context.login, + "Specifies the user to log in as on the remote machine", + NULL }, { NULL } }; @@ -759,10 +801,10 @@ main (gint argc, gchar *argv[]) if (dbus == NULL) goto OUT; - data.client = tp_simple_handler_new (dbus, FALSE, FALSE, "SSHContactClient", - TRUE, got_channel_cb, NULL, NULL); + context.client = tp_simple_handler_new (dbus, FALSE, FALSE, + "SSHContactClient", TRUE, got_channel_cb, &context, NULL); - tp_base_client_take_handler_filter (data.client, tp_asv_new ( + tp_base_client_take_handler_filter (context.client, tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, @@ -773,23 +815,23 @@ main (gint argc, gchar *argv[]) TRUE, NULL)); - if (!tp_base_client_register (data.client, &error)) + if (!tp_base_client_register (context.client, &error)) goto OUT; /* If an account id was specified in options, then prepare it, otherwise * we get the account manager to get a list of all accounts */ - if (data.account_id != NULL) + if (context.account_id != NULL) { gchar *account_path; - account_path = g_strconcat (TP_ACCOUNT_OBJECT_PATH_BASE, data.account_id, + account_path = g_strconcat (TP_ACCOUNT_OBJECT_PATH_BASE, context.account_id, NULL); - data.account = tp_account_new (dbus, account_path, &error); - if (data.account == NULL) + context.account = tp_account_new (dbus, account_path, &error); + if (context.account == NULL) goto OUT; - tp_proxy_prepare_async (TP_PROXY (data.account), NULL, - account_prepare_cb, &data); + tp_proxy_prepare_async (TP_PROXY (context.account), NULL, + account_prepare_cb, &context); g_free (account_path); } @@ -799,33 +841,26 @@ main (gint argc, gchar *argv[]) manager = tp_account_manager_new (dbus); tp_proxy_prepare_async (TP_PROXY (manager), NULL, - account_manager_prepare_cb, &data); + account_manager_prepare_cb, &context); g_object_unref (manager); } - loop = g_main_loop_new (NULL, FALSE); - g_main_loop_run (loop); + context.loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (context.loop); OUT: if (error != NULL) { - success = FALSE; + context.success = FALSE; g_debug ("Error: %s", error->message); } - tp_clear_pointer (&loop, g_main_loop_unref); tp_clear_object (&dbus); g_clear_error (&error); + client_context_clear (&context); - tp_clear_object (&data.client); - g_free (data.account_id); - g_free (data.contact_id); - g_list_foreach (data.accounts, (GFunc) g_object_unref, NULL); - g_list_free (data.accounts); - tp_clear_object (&data.account); - - return success ? EXIT_SUCCESS : EXIT_FAILURE; + return context.success ? EXIT_SUCCESS : EXIT_FAILURE; } |