aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy/empathy-tp-chat.c
diff options
context:
space:
mode:
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2011-04-20 15:49:52 +0800
committerGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2011-04-20 15:49:52 +0800
commitbdea54f59e52ebeaa0743674aa5998636f26a241 (patch)
treea1d5920da73c6737225bfa31b594cb4dd00f59c0 /libempathy/empathy-tp-chat.c
parent9d9cfc021b05fe9afbe8769d6e0c289cf1dc9734 (diff)
parenteb6ab4328849a0c5ee5959560f90f36fd71a815d (diff)
downloadgsoc2013-empathy-bdea54f59e52ebeaa0743674aa5998636f26a241.tar
gsoc2013-empathy-bdea54f59e52ebeaa0743674aa5998636f26a241.tar.gz
gsoc2013-empathy-bdea54f59e52ebeaa0743674aa5998636f26a241.tar.bz2
gsoc2013-empathy-bdea54f59e52ebeaa0743674aa5998636f26a241.tar.lz
gsoc2013-empathy-bdea54f59e52ebeaa0743674aa5998636f26a241.tar.xz
gsoc2013-empathy-bdea54f59e52ebeaa0743674aa5998636f26a241.tar.zst
gsoc2013-empathy-bdea54f59e52ebeaa0743674aa5998636f26a241.zip
Merge branch 'timestamp-648188'
Diffstat (limited to 'libempathy/empathy-tp-chat.c')
-rw-r--r--libempathy/empathy-tp-chat.c355
1 files changed, 157 insertions, 198 deletions
diff --git a/libempathy/empathy-tp-chat.c b/libempathy/empathy-tp-chat.c
index 1b2fe46b7..a56c08a32 100644
--- a/libempathy/empathy-tp-chat.c
+++ b/libempathy/empathy-tp-chat.c
@@ -47,7 +47,6 @@ typedef struct {
EmpathyContact *remote_contact;
GList *members;
TpChannel *channel;
- gboolean listing_pending_messages;
/* Queue of messages not signalled yet */
GQueue *messages_queue;
/* Queue of messages signalled but not acked yet */
@@ -280,149 +279,176 @@ tp_chat_got_sender_cb (TpConnection *connection,
static void
tp_chat_build_message (EmpathyTpChat *chat,
- gboolean incoming,
- guint id,
- guint type,
- guint timestamp,
- guint from_handle,
- const gchar *message_body,
- TpChannelTextMessageFlags flags)
+ TpMessage *msg,
+ gboolean incoming)
{
EmpathyTpChatPriv *priv;
EmpathyMessage *message;
+ TpContact *sender;
priv = GET_PRIV (chat);
- message = empathy_message_new (message_body);
- empathy_message_set_tptype (message, type);
+ message = empathy_message_new_from_tp_message (msg, incoming);
+ /* FIXME: this is actually a lie for incoming messages. */
empathy_message_set_receiver (message, priv->user);
- empathy_message_set_timestamp (message, timestamp);
- empathy_message_set_id (message, id);
- empathy_message_set_incoming (message, incoming);
- empathy_message_set_flags (message, flags);
-
- if (flags & TP_CHANNEL_TEXT_MESSAGE_FLAG_SCROLLBACK)
- empathy_message_set_is_backlog (message, TRUE);
g_queue_push_tail (priv->messages_queue, message);
- if (from_handle == 0) {
+ sender = tp_signalled_message_get_sender (msg);
+ g_assert (sender != NULL);
+
+ if (tp_contact_get_handle (sender) == 0) {
empathy_message_set_sender (message, priv->user);
tp_chat_emit_queued_messages (chat);
} else {
empathy_tp_contact_factory_get_from_handle (priv->connection,
- from_handle,
+ tp_contact_get_handle (sender),
tp_chat_got_sender_cb,
message, NULL, G_OBJECT (chat));
}
}
static void
-tp_chat_received_cb (TpChannel *channel,
- guint message_id,
- guint timestamp,
- guint from_handle,
- guint message_type,
- guint message_flags,
- const gchar *message_body,
- gpointer user_data,
- GObject *chat_)
-{
- EmpathyTpChat *chat = EMPATHY_TP_CHAT (chat_);
- EmpathyTpChatPriv *priv = GET_PRIV (chat);
+handle_delivery_report (EmpathyTpChat *self,
+ TpMessage *message)
+{
+ EmpathyTpChatPriv *priv = GET_PRIV (self);
+ TpDeliveryStatus delivery_status;
+ const GHashTable *header;
+ TpChannelTextSendError delivery_error;
+ gboolean valid;
+ GPtrArray *echo;
+ const gchar *message_body = NULL;
+
+ header = tp_message_peek (message, 0);
+ if (header == NULL)
+ goto out;
- if (priv->channel == NULL)
- return;
+ delivery_status = tp_asv_get_uint32 (header, "delivery-status", &valid);
+ if (!valid || delivery_status != TP_DELIVERY_STATUS_PERMANENTLY_FAILED)
+ goto out;
+
+ delivery_error = tp_asv_get_uint32 (header, "delivery-error", &valid);
+ if (!valid)
+ delivery_error = TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN;
- if (priv->listing_pending_messages) {
+ /* TODO: ideally we should use tp-glib API giving us the echoed message as a
+ * TpMessage. (fdo #35884) */
+ echo = tp_asv_get_boxed (header, "delivery-echo",
+ TP_ARRAY_TYPE_MESSAGE_PART_LIST);
+ if (echo != NULL && echo->len >= 1) {
+ const GHashTable *echo_body;
+
+ echo_body = g_ptr_array_index (echo, 1);
+ if (echo_body != NULL)
+ message_body = tp_asv_get_string (echo_body, "content");
+ }
+
+ g_signal_emit (self, signals[SEND_ERROR], 0, message_body, delivery_error);
+
+out:
+ tp_text_channel_ack_message_async (TP_TEXT_CHANNEL (priv->channel),
+ message, NULL, NULL);
+}
+
+static void
+handle_incoming_message (EmpathyTpChat *self,
+ TpMessage *message,
+ gboolean pending)
+{
+ EmpathyTpChatPriv *priv = GET_PRIV (self);
+ gchar *message_body;
+
+ if (tp_message_is_delivery_report (message)) {
+ handle_delivery_report (self, message);
return;
}
- DEBUG ("Message received from channel %s: %s",
- tp_proxy_get_object_path (channel), message_body);
+ message_body = tp_message_to_text (message, NULL);
- if (message_flags & TP_CHANNEL_TEXT_MESSAGE_FLAG_NON_TEXT_CONTENT &&
- !tp_strdiff (message_body, "")) {
- GArray *ids;
+ DEBUG ("Message %s (channel %s): %s",
+ pending ? "pending" : "received",
+ tp_proxy_get_object_path (priv->channel), message_body);
+ if (message_body == NULL) {
DEBUG ("Empty message with NonTextContent, ignoring and acking.");
- ids = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1);
- g_array_append_val (ids, message_id);
- acknowledge_messages (chat, ids);
- g_array_free (ids, TRUE);
-
+ tp_text_channel_ack_message_async (TP_TEXT_CHANNEL (priv->channel),
+ message, NULL, NULL);
return;
}
- tp_chat_build_message (chat,
- TRUE,
- message_id,
- message_type,
- timestamp,
- from_handle,
- message_body,
- message_flags);
+ tp_chat_build_message (self, message, TRUE);
+
+ g_free (message_body);
}
static void
-tp_chat_sent_cb (TpChannel *channel,
- guint timestamp,
- guint message_type,
- const gchar *message_body,
- gpointer user_data,
- GObject *chat_)
-{
- EmpathyTpChat *chat = EMPATHY_TP_CHAT (chat_);
- EmpathyTpChatPriv *priv = GET_PRIV (chat);
+message_received_cb (TpTextChannel *channel,
+ TpMessage *message,
+ EmpathyTpChat *chat)
+{
+ handle_incoming_message (chat, message, FALSE);
+}
- if (priv->channel == NULL)
- return;
+static void
+message_sent_cb (TpTextChannel *channel,
+ TpMessage *message,
+ TpMessageSendingFlags flags,
+ gchar *token,
+ EmpathyTpChat *chat)
+{
+ gchar *message_body;
+
+ message_body = tp_message_to_text (message, NULL);
DEBUG ("Message sent: %s", message_body);
- tp_chat_build_message (chat,
- FALSE,
- 0,
- message_type,
- timestamp,
- 0,
- message_body,
- 0);
+ tp_chat_build_message (chat, message, FALSE);
+
+ g_free (message_body);
}
-static void
-tp_chat_send_error_cb (TpChannel *channel,
- guint error_code,
- guint timestamp,
- guint message_type,
- const gchar *message_body,
- gpointer user_data,
- GObject *chat)
+static TpChannelTextSendError
+error_to_text_send_error (GError *error)
{
- EmpathyTpChatPriv *priv = GET_PRIV (chat);
-
- if (priv->channel == NULL)
- return;
+ if (error->domain != TP_ERRORS)
+ return TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN;
- DEBUG ("Error sending '%s' (%d)", message_body, error_code);
+ switch (error->code) {
+ case TP_ERROR_OFFLINE:
+ return TP_CHANNEL_TEXT_SEND_ERROR_OFFLINE;
+ case TP_ERROR_INVALID_HANDLE:
+ return TP_CHANNEL_TEXT_SEND_ERROR_INVALID_CONTACT;
+ case TP_ERROR_PERMISSION_DENIED:
+ return TP_CHANNEL_TEXT_SEND_ERROR_PERMISSION_DENIED;
+ case TP_ERROR_NOT_IMPLEMENTED:
+ return TP_CHANNEL_TEXT_SEND_ERROR_NOT_IMPLEMENTED;
+ }
- g_signal_emit (chat, signals[SEND_ERROR], 0, message_body, error_code);
+ return TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN;
}
static void
-tp_chat_send_cb (TpChannel *proxy,
- const GError *error,
- gpointer user_data,
- GObject *chat)
+message_send_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
- EmpathyMessage *message = EMPATHY_MESSAGE (user_data);
+ EmpathyTpChat *chat = user_data;
+ TpTextChannel *channel = (TpTextChannel *) source;
+ GError *error = NULL;
- if (error) {
+ if (!tp_text_channel_send_message_finish (channel, result, NULL, &error)) {
DEBUG ("Error: %s", error->message);
+
+ /* FIXME: we should use the body of the message as first argument of the
+ * signal but can't easily get it as we just get a user_data pointer. Once
+ * we'll have rebased EmpathyTpChat on top of TpTextChannel we'll be able
+ * to use the user_data pointer to pass the message and fix this. */
g_signal_emit (chat, signals[SEND_ERROR], 0,
- empathy_message_get_body (message),
- TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN);
+ NULL, error_to_text_send_error (error));
+
+ g_error_free (error);
}
}
@@ -457,86 +483,33 @@ static void
tp_chat_state_changed_cb (TpChannel *channel,
TpHandle handle,
TpChannelChatState state,
- gpointer user_data,
- GObject *chat)
+ EmpathyTpChat *chat)
{
EmpathyTpChatPriv *priv = GET_PRIV (chat);
empathy_tp_contact_factory_get_from_handle (priv->connection, handle,
tp_chat_state_changed_got_contact_cb, GUINT_TO_POINTER (state),
- NULL, chat);
+ NULL, G_OBJECT (chat));
}
static void
-tp_chat_list_pending_messages_cb (TpChannel *channel,
- const GPtrArray *messages_list,
- const GError *error,
- gpointer user_data,
- GObject *chat_)
+list_pending_messages (EmpathyTpChat *self)
{
- EmpathyTpChat *chat = EMPATHY_TP_CHAT (chat_);
- EmpathyTpChatPriv *priv = GET_PRIV (chat);
- guint i;
- GArray *empty_non_text_content_ids = NULL;
-
- priv->listing_pending_messages = FALSE;
-
- if (priv->channel == NULL)
- return;
-
- if (error) {
- DEBUG ("Error listing pending messages: %s", error->message);
- return;
- }
-
- for (i = 0; i < messages_list->len; i++) {
- GValueArray *message_struct;
- const gchar *message_body;
- guint message_id;
- guint timestamp;
- guint from_handle;
- guint message_type;
- guint message_flags;
-
- message_struct = g_ptr_array_index (messages_list, i);
-
- message_id = g_value_get_uint (g_value_array_get_nth (message_struct, 0));
- timestamp = g_value_get_uint (g_value_array_get_nth (message_struct, 1));
- from_handle = g_value_get_uint (g_value_array_get_nth (message_struct, 2));
- message_type = g_value_get_uint (g_value_array_get_nth (message_struct, 3));
- message_flags = g_value_get_uint (g_value_array_get_nth (message_struct, 4));
- message_body = g_value_get_string (g_value_array_get_nth (message_struct, 5));
-
- DEBUG ("Message pending: %s", message_body);
+ EmpathyTpChatPriv *priv = GET_PRIV (self);
+ GList *messages, *l;
- if (message_flags & TP_CHANNEL_TEXT_MESSAGE_FLAG_NON_TEXT_CONTENT &&
- !tp_strdiff (message_body, "")) {
- DEBUG ("Empty message with NonTextContent, ignoring and acking.");
+ g_assert (priv->channel != NULL);
- if (empty_non_text_content_ids == NULL) {
- empty_non_text_content_ids = g_array_new (FALSE, FALSE, sizeof (guint));
- }
+ messages = tp_text_channel_get_pending_messages (
+ TP_TEXT_CHANNEL (priv->channel));
- g_array_append_val (empty_non_text_content_ids, message_id);
- continue;
- }
+ for (l = messages; l != NULL; l = g_list_next (l)) {
+ TpMessage *message = l->data;
- tp_chat_build_message (chat,
- TRUE,
- message_id,
- message_type,
- timestamp,
- from_handle,
- message_body,
- message_flags);
+ handle_incoming_message (self, message, FALSE);
}
- if (empty_non_text_content_ids != NULL) {
- acknowledge_messages (chat, empty_non_text_content_ids);
- g_array_free (empty_non_text_content_ids, TRUE);
- }
-
- check_ready (chat);
+ g_list_free (messages);
}
static void
@@ -861,32 +834,22 @@ check_almost_ready (EmpathyTpChat *chat)
priv->remote_contact == NULL)
return;
- tp_cli_channel_type_text_connect_to_received (priv->channel,
- tp_chat_received_cb,
- NULL, NULL,
- G_OBJECT (chat), NULL);
- priv->listing_pending_messages = TRUE;
-
- /* TpChat will be ready once ListPendingMessages returned and all the messages
- * have been added to the pending messages queue. */
- tp_cli_channel_type_text_call_list_pending_messages (priv->channel, -1,
- FALSE,
- tp_chat_list_pending_messages_cb,
- NULL, NULL,
- G_OBJECT (chat));
-
- tp_cli_channel_type_text_connect_to_sent (priv->channel,
- tp_chat_sent_cb,
- NULL, NULL,
- G_OBJECT (chat), NULL);
- tp_cli_channel_type_text_connect_to_send_error (priv->channel,
- tp_chat_send_error_cb,
- NULL, NULL,
- G_OBJECT (chat), NULL);
- tp_cli_channel_interface_chat_state_connect_to_chat_state_changed (priv->channel,
- tp_chat_state_changed_cb,
- NULL, NULL,
- G_OBJECT (chat), NULL);
+ /* We use the default factory so this feature should have been prepared */
+ g_assert (tp_proxy_is_prepared (priv->channel,
+ TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES));
+
+ tp_g_signal_connect_object (priv->channel, "message-received",
+ G_CALLBACK (message_received_cb), chat, 0);
+
+ list_pending_messages (chat);
+
+ tp_g_signal_connect_object (priv->channel, "message-sent",
+ G_CALLBACK (message_sent_cb), chat, 0);
+
+ tp_g_signal_connect_object (priv->channel, "chat-state-changed",
+ G_CALLBACK (tp_chat_state_changed_cb), chat, 0);
+
+ check_ready (chat);
}
static void
@@ -1551,7 +1514,7 @@ empathy_tp_chat_new (TpAccount *account,
TpChannel *channel)
{
g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
- g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL);
+ g_return_val_if_fail (TP_IS_TEXT_CHANNEL (channel), NULL);
return g_object_new (EMPATHY_TYPE_TP_CHAT,
"account", account,
@@ -1630,27 +1593,23 @@ empathy_tp_chat_is_ready (EmpathyTpChat *chat)
void
empathy_tp_chat_send (EmpathyTpChat *chat,
- EmpathyMessage *message)
+ TpMessage *message)
{
EmpathyTpChatPriv *priv = GET_PRIV (chat);
- const gchar *message_body;
- TpChannelTextMessageType message_type;
+ gchar *message_body;
g_return_if_fail (EMPATHY_IS_TP_CHAT (chat));
- g_return_if_fail (EMPATHY_IS_MESSAGE (message));
+ g_return_if_fail (TP_IS_CLIENT_MESSAGE (message));
g_return_if_fail (priv->ready);
- message_body = empathy_message_get_body (message);
- message_type = empathy_message_get_tptype (message);
+ message_body = tp_message_to_text (message, NULL);
DEBUG ("Sending message: %s", message_body);
- tp_cli_channel_type_text_call_send (priv->channel, -1,
- message_type,
- message_body,
- tp_chat_send_cb,
- g_object_ref (message),
- (GDestroyNotify) g_object_unref,
- G_OBJECT (chat));
+
+ tp_text_channel_send_message_async (TP_TEXT_CHANNEL (priv->channel),
+ message, 0, message_send_cb, chat);
+
+ g_free (message_body);
}
void