diff options
author | Alberto Mardegan <alberto.mardegan@nokia.com> | 2009-01-12 11:07:53 +0200 |
---|---|---|
committer | Alberto Mardegan <alberto.mardegan@nokia.com> | 2009-01-12 11:07:53 +0200 |
commit | 56bcea4b8f64d8fea7bfc86e1de4dc7f99d594b0 (patch) | |
tree | 25710d1bda709e153ab55c16e5413e6d0618ad6a | |
parent | 0780d7766e92bb03fa41ddab4446b5dab9c54750 (diff) | |
parent | 16a3ca83a808e7ba051081657648691709fdeb5d (diff) | |
download | telepathy-mission-control-56bcea4b8f64d8fea7bfc86e1de4dc7f99d594b0.tar.gz |
Merge branch 'cancel'
-rw-r--r-- | examples/mc-example-3.c | 23 | ||||
-rw-r--r-- | libmcclient/mc-account-request.c | 29 | ||||
-rw-r--r-- | src/mcd-account-priv.h | 9 | ||||
-rw-r--r-- | src/mcd-account-requests.c | 113 | ||||
-rw-r--r-- | src/mcd-account.c | 13 | ||||
-rw-r--r-- | src/mcd-channel.c | 4 | ||||
-rw-r--r-- | src/mcd-channel.h | 3 | ||||
-rw-r--r-- | src/mcd-connection.c | 21 | ||||
-rw-r--r-- | src/mcd-dispatcher.c | 8 |
9 files changed, 203 insertions, 20 deletions
diff --git a/examples/mc-example-3.c b/examples/mc-example-3.c index e84e82eb..70b38940 100644 --- a/examples/mc-example-3.c +++ b/examples/mc-example-3.c @@ -33,6 +33,12 @@ #include <libmcclient/mc-profile.h> #include <telepathy-glib/interfaces.h> +typedef struct +{ + McAccount *account; + guint req_id; +} ReqData; + typedef struct _TestObjectClass { GObjectClass parent_class; } TestObjectClass; @@ -98,12 +104,24 @@ channel_request_cb (McAccount *account, guint request_id, mc_account_channelrequest_get_path (account, request_id)); } +static gboolean +cancel_request (gpointer user_data) +{ + ReqData *rd = user_data; + + g_debug ("%s called, cancelling %u", G_STRFUNC, rd->req_id); + mc_account_channelrequest_cancel (rd->account, rd->req_id); + g_slice_free (ReqData, rd); + return FALSE; +} + static void request_channel (McAccount *account, GQuark type, const gchar *contact) { McAccountChannelrequestData req; GObject *to; guint id; + ReqData *rd; to = g_object_new (TEST_TYPE_OBJECT, NULL); @@ -118,6 +136,11 @@ request_channel (McAccount *account, GQuark type, const gchar *contact) to); g_debug ("Request id = %x", id); g_timeout_add (10000, unref_test_object, to); + + rd = g_slice_new (ReqData); + rd->account = account; + rd->req_id = id; + g_timeout_add (500, cancel_request, rd); } static gboolean diff --git a/libmcclient/mc-account-request.c b/libmcclient/mc-account-request.c index 1daea23c..432cf2b6 100644 --- a/libmcclient/mc-account-request.c +++ b/libmcclient/mc-account-request.c @@ -40,6 +40,7 @@ typedef struct McAccount *account; gchar *request_path; GError *error; + gboolean cancelled; /* caller data */ McAccountChannelrequestCb callback; @@ -130,6 +131,16 @@ request_create_cb (TpProxy *proxy, const gchar *request_path, { McChannelRequest *req = user_data; + if (req->cancelled) + { + g_debug ("%s: cancelling %s", G_STRFUNC, request_path); + if (!error) + mc_cli_account_interface_channelrequests_call_cancel + (proxy, -1, request_path, NULL, NULL, NULL, NULL); + emit_request_event (req, MC_ACCOUNT_CR_CANCELLED); + return; + } + if (error) { /* the request hasn't even been created */ @@ -475,7 +486,23 @@ mc_account_channelrequest_add (McAccount *account, const gchar *object_path, void mc_account_channelrequest_cancel (McAccount *account, guint request_id) { - g_warning ("%s is not implemented yet", G_STRFUNC); + McChannelRequest *req; + + g_return_if_fail (MC_IS_ACCOUNT (account)); + g_return_if_fail (request_id != 0); + req = GUINT_TO_POINTER (request_id); + + if (req->request_path) + { + g_debug ("%s: %s", G_STRFUNC, req->request_path); + mc_cli_account_interface_channelrequests_call_cancel + (account, -1, req->request_path, NULL, NULL, NULL, NULL); + emit_request_event (req, MC_ACCOUNT_CR_CANCELLED); + } + else + { + req->cancelled = TRUE; + } } /** diff --git a/src/mcd-account-priv.h b/src/mcd-account-priv.h index 82efa43d..8017511a 100644 --- a/src/mcd-account-priv.h +++ b/src/mcd-account-priv.h @@ -55,6 +55,15 @@ G_GNUC_INTERNAL void _mcd_account_online_request_completed (McdAccount *account, GError *error); +typedef struct { + McdOnlineRequestCb callback; + gpointer user_data; +} McdOnlineRequestData; + +G_GNUC_INTERNAL +GList *_mcd_account_get_online_requests (McdAccount *account); + + static inline void mcd_account_write_conf (McdAccount *account) { diff --git a/src/mcd-account-requests.c b/src/mcd-account-requests.c index 8162b242..dd58bc94 100644 --- a/src/mcd-account-requests.c +++ b/src/mcd-account-requests.c @@ -50,8 +50,7 @@ online_request_cb (McdAccount *account, gpointer userdata, const GError *error) { g_warning ("%s: got error: %s", G_STRFUNC, error->message); _mcd_channel_set_error (channel, g_error_copy (error)); - /* no unref here, as this will invoke our handler which will - * unreference the channel */ + g_object_unref (channel); return; } g_debug ("%s called", G_STRFUNC); @@ -60,12 +59,60 @@ online_request_cb (McdAccount *account, gpointer userdata, const GError *error) g_return_if_fail (mcd_connection_get_connection_status (connection) == TP_CONNECTION_STATUS_CONNECTED); - /* the connection will take ownership of the channel, so let's keep a - * reference to it to make sure it's not destroyed while we are using it */ - g_object_ref (channel); + if (mcd_channel_get_status (channel) == MCD_CHANNEL_STATUS_FAILED) + { + g_debug ("%s: channel %p is failed", G_STRFUNC, channel); + g_object_unref (channel); + return; + } + + /* the connection will take ownership of the channel, so the reference we + * are holding is passed to it */ mcd_connection_request_channel (connection, channel); } +static McdChannel * +get_channel_from_request (McdAccount *account, const gchar *request_id) +{ + McdConnection *connection; + const GList *channels, *list; + + + connection = mcd_account_get_connection (account); + if (connection) + { + channels = mcd_operation_get_missions (MCD_OPERATION (connection)); + for (list = channels; list != NULL; list = list->next) + { + McdChannel *channel = MCD_CHANNEL (list->data); + + if (g_strcmp0 (_mcd_channel_get_request_path (channel), + request_id) == 0) + return channel; + } + } + + /* if we don't have a connection in connected state yet, the channel might + * be in the online requests queue */ + list = _mcd_account_get_online_requests (account); + while (list) + { + McdOnlineRequestData *data = list->data; + + if (data->callback == online_request_cb) + { + McdChannel *channel = MCD_CHANNEL (data->user_data); + + if (g_strcmp0 (_mcd_channel_get_request_path (channel), + request_id) == 0) + return channel; + } + + list = list->next; + } + return NULL; +} + static void on_channel_status_changed (McdChannel *channel, McdChannelStatus status, McdAccount *account) @@ -128,6 +175,13 @@ create_request (McdAccount *account, GHashTable *properties, /* no unref here, as this will invoke our handler which will * unreference the channel */ } + else + { + /* the channel must be kept alive until online_request_cb is called; + * this reference will be removed in that callback */ + g_object_ref (channel); + } + return channel; } @@ -190,11 +244,52 @@ account_request_cancel (McSvcAccountInterfaceChannelRequests *self, DBusGMethodInvocation *context) { GError *error; + McdChannel *channel; + McdChannelStatus status; + + g_debug ("%s called for %s", G_STRFUNC, request_id); + g_return_if_fail (request_id != NULL); + channel = get_channel_from_request (MCD_ACCOUNT (self), request_id); + if (!channel) + { + error = g_error_new (TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + "Request %s not found", request_id); + dbus_g_method_return_error (context, error); + g_error_free (error); + return; + } + + status = mcd_channel_get_status (channel); + g_debug ("channel %p is in status %u", channel, status); + if (status == MCD_CHANNEL_STATUS_REQUEST || + status == MCD_CHANNEL_STATUS_REQUESTED || + status == MCD_CHANNEL_STATUS_DISPATCHING) + { + g_object_ref (channel); + error = g_error_new (TP_ERRORS, TP_ERROR_CANCELLED, "Cancelled"); + _mcd_channel_set_error (channel, error); + + /* REQUESTED is a special case: the channel must not be aborted now, + * because we need to explicitly close the channel object when it will + * be created by the CM. In that case, mcd_mission_abort() will be + * called once the Create/EnsureChannel method returns, if the channel + * is ours */ + if (status != MCD_CHANNEL_STATUS_REQUESTED) + mcd_mission_abort (MCD_MISSION (channel)); + + g_object_unref (channel); + } + else + { + error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + "Request %s is not cancellable (%u)", + request_id, status); + dbus_g_method_return_error (context, error); + g_error_free (error); + return; + } - error = g_error_new (TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, - "%s is currently just a stub", G_STRFUNC); - dbus_g_method_return_error (context, error); - g_error_free (error); + mc_svc_account_interface_channelrequests_return_from_cancel (context); } void diff --git a/src/mcd-account.c b/src/mcd-account.c index eb105e27..6c072497 100644 --- a/src/mcd-account.c +++ b/src/mcd-account.c @@ -140,11 +140,6 @@ struct _McdAccountPrivate guint properties_source; }; -typedef struct { - McdOnlineRequestCb callback; - gpointer user_data; -} McdOnlineRequestData; - enum { PROP_0, @@ -2030,6 +2025,14 @@ _mcd_account_online_request_completed (McdAccount *account, GError *error) priv->online_requests = NULL; } +GList * +_mcd_account_get_online_requests (McdAccount *account) +{ + g_return_val_if_fail (MCD_IS_ACCOUNT (account), NULL); + + return account->priv->online_requests; +} + static inline void process_online_requests (McdAccount *account, TpConnectionStatus status, diff --git a/src/mcd-channel.c b/src/mcd-channel.c index 25960acf..9445d19b 100644 --- a/src/mcd-channel.c +++ b/src/mcd-channel.c @@ -606,7 +606,9 @@ mcd_channel_abort (McdMission *mission) g_debug ("%s: %p", G_STRFUNC, mission); /* If this is still a channel request, signal the failure */ if (priv->status == MCD_CHANNEL_STATUS_REQUEST || - priv->status == MCD_CHANNEL_STATUS_DISPATCHING) + priv->status == MCD_CHANNEL_STATUS_REQUESTED || + priv->status == MCD_CHANNEL_STATUS_DISPATCHING || + priv->status == MCD_CHANNEL_STATUS_HANDLER_INVOKED) { /* this code-path can only happen if the connection is aborted, as in * the other cases we handle the error in McdChannel; for this reason, diff --git a/src/mcd-channel.h b/src/mcd-channel.h index 15c05fd7..99cdfe48 100644 --- a/src/mcd-channel.h +++ b/src/mcd-channel.h @@ -53,8 +53,11 @@ typedef enum NewChannel signal before the connection is ready */ MCD_CHANNEL_STATUS_REQUEST, /* Telepathy channel is not yet created */ + MCD_CHANNEL_STATUS_REQUESTED, /* Channel has been requested from the CM + */ MCD_CHANNEL_STATUS_DISPATCHING, /* Telepathy channel is created and waiting dispatch */ + MCD_CHANNEL_STATUS_HANDLER_INVOKED, MCD_CHANNEL_STATUS_DISPATCHED, /* Channel has been dispatched to handler */ MCD_CHANNEL_STATUS_FAILED, /* Channel creation failed, or channel diff --git a/src/mcd-connection.c b/src/mcd-connection.c index c42a846d..432fa305 100644 --- a/src/mcd-connection.c +++ b/src/mcd-connection.c @@ -558,10 +558,13 @@ on_capabilities_timeout (McdConnection *connection) while (list) { McdChannel *channel = MCD_CHANNEL (list->data); + McdChannelStatus status; list_curr = list; list = list->next; - if (mcd_channel_get_status (channel) == MCD_CHANNEL_STATUS_REQUEST && + status = mcd_channel_get_status (channel); + if ((status == MCD_CHANNEL_STATUS_REQUEST || + status == MCD_CHANNEL_STATUS_REQUESTED) && on_channel_capabilities_timeout (channel, connection)) { mcd_mission_abort ((McdMission *)channel); @@ -2208,6 +2211,13 @@ common_request_channel_cb (TpConnection *proxy, gboolean yours, return; } + /* if the channel request was cancelled, abort the channel now */ + if (mcd_channel_get_status (channel) == MCD_CHANNEL_STATUS_FAILED) + { + g_debug ("Channel %p was cancelled, aborting", channel); + mcd_mission_abort (MCD_MISSION (channel)); + } + /* No dispatching here: the channel will be dispatched upon receiving the * NewChannels signal */ } @@ -2310,6 +2320,7 @@ mcd_connection_request_channel (McdConnection *connection, McdChannel *channel) { McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection); + gboolean ret; g_return_val_if_fail (priv->tp_conn != NULL, FALSE); g_return_val_if_fail (TP_IS_CONNECTION (priv->tp_conn), FALSE); @@ -2328,9 +2339,13 @@ mcd_connection_request_channel (McdConnection *connection, } if (priv->has_requests_if) - return request_channel_new_iface (connection, channel); + ret = request_channel_new_iface (connection, channel); else - return request_channel_old_iface (connection, channel); + ret = request_channel_old_iface (connection, channel); + + if (ret) + mcd_channel_set_status (channel, MCD_CHANNEL_STATUS_REQUESTED); + return ret; } gboolean diff --git a/src/mcd-dispatcher.c b/src/mcd-dispatcher.c index a4e08315..6f017cc9 100644 --- a/src/mcd-dispatcher.c +++ b/src/mcd-dispatcher.c @@ -274,8 +274,11 @@ mcd_dispatcher_context_handler_done (McdDispatcherContext *context) for (list = context->channels; list != NULL; list = list->next) { McdChannel *channel = MCD_CHANNEL (list->data); + McdChannelStatus status; - if (mcd_channel_get_status (channel) == MCD_CHANNEL_STATUS_DISPATCHING) + status = mcd_channel_get_status (channel); + if (status == MCD_CHANNEL_STATUS_DISPATCHING || + status == MCD_CHANNEL_STATUS_HANDLER_INVOKED) channels_left++; /* TODO: recognize those channels whose dispatch failed, and * re-dispatch them to another handler */ @@ -1214,6 +1217,9 @@ mcd_dispatcher_run_handler (McdDispatcherContext *context, user_time = _mcd_channel_get_request_user_action_time (channel); if (user_time) user_action_time = user_time; + + mcd_channel_set_status (channel, + MCD_CHANNEL_STATUS_HANDLER_INVOKED); } /* The callback needs to get the dispatcher context, and the channels |