summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlberto Mardegan <alberto.mardegan@nokia.com>2009-01-12 11:07:53 +0200
committerAlberto Mardegan <alberto.mardegan@nokia.com>2009-01-12 11:07:53 +0200
commit56bcea4b8f64d8fea7bfc86e1de4dc7f99d594b0 (patch)
tree25710d1bda709e153ab55c16e5413e6d0618ad6a
parent0780d7766e92bb03fa41ddab4446b5dab9c54750 (diff)
parent16a3ca83a808e7ba051081657648691709fdeb5d (diff)
downloadtelepathy-mission-control-56bcea4b8f64d8fea7bfc86e1de4dc7f99d594b0.tar.gz
Merge branch 'cancel'
-rw-r--r--examples/mc-example-3.c23
-rw-r--r--libmcclient/mc-account-request.c29
-rw-r--r--src/mcd-account-priv.h9
-rw-r--r--src/mcd-account-requests.c113
-rw-r--r--src/mcd-account.c13
-rw-r--r--src/mcd-channel.c4
-rw-r--r--src/mcd-channel.h3
-rw-r--r--src/mcd-connection.c21
-rw-r--r--src/mcd-dispatcher.c8
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