aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libempathy-gtk/empathy-chat.c96
-rw-r--r--libempathy-gtk/empathy-chat.h2
-rw-r--r--libempathy/empathy-tp-chat.c94
-rw-r--r--libempathy/empathy-tp-chat.h6
-rw-r--r--src/empathy-chat-window.c38
5 files changed, 208 insertions, 28 deletions
diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c
index 5c8bbce3b..3e8a9c70b 100644
--- a/libempathy-gtk/empathy-chat.c
+++ b/libempathy-gtk/empathy-chat.c
@@ -172,6 +172,7 @@ enum {
PROP_REMOTE_CONTACT,
PROP_SHOW_CONTACTS,
PROP_SMS_CHANNEL,
+ PROP_N_MESSAGES_SENDING,
};
static guint signals[LAST_SIGNAL] = { 0 };
@@ -214,6 +215,10 @@ chat_get_property (GObject *object,
case PROP_SMS_CHANNEL:
g_value_set_boolean (value, priv->sms_channel);
break;
+ case PROP_N_MESSAGES_SENDING:
+ g_value_set_uint (value,
+ empathy_chat_get_n_messages_sending (chat));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -1282,31 +1287,41 @@ static void
chat_send_error_cb (EmpathyTpChat *tp_chat,
const gchar *message_body,
TpChannelTextSendError error_code,
+ const gchar *dbus_error,
EmpathyChat *chat)
{
- const gchar *error;
+ const gchar *error = NULL;
gchar *str;
- switch (error_code) {
- case TP_CHANNEL_TEXT_SEND_ERROR_OFFLINE:
- error = _("offline");
- break;
- case TP_CHANNEL_TEXT_SEND_ERROR_INVALID_CONTACT:
- error = _("invalid contact");
- break;
- case TP_CHANNEL_TEXT_SEND_ERROR_PERMISSION_DENIED:
- error = _("permission denied");
- break;
- case TP_CHANNEL_TEXT_SEND_ERROR_TOO_LONG:
- error = _("too long message");
- break;
- case TP_CHANNEL_TEXT_SEND_ERROR_NOT_IMPLEMENTED:
- error = _("not implemented");
- break;
- case TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN:
- default:
- error = _("unknown");
- break;
+ if (!tp_strdiff (dbus_error, TP_ERROR_STR_INSUFFICIENT_BALANCE)) {
+ error = _("insufficient balance to send message");
+ } else if (!tp_strdiff (dbus_error, TP_ERROR_STR_NOT_CAPABLE)) {
+ error = _("not capable");
+ }
+
+ if (error == NULL) {
+ /* if we didn't find a dbus-error, try the old error */
+ switch (error_code) {
+ case TP_CHANNEL_TEXT_SEND_ERROR_OFFLINE:
+ error = _("offline");
+ break;
+ case TP_CHANNEL_TEXT_SEND_ERROR_INVALID_CONTACT:
+ error = _("invalid contact");
+ break;
+ case TP_CHANNEL_TEXT_SEND_ERROR_PERMISSION_DENIED:
+ error = _("permission denied");
+ break;
+ case TP_CHANNEL_TEXT_SEND_ERROR_TOO_LONG:
+ error = _("too long message");
+ break;
+ case TP_CHANNEL_TEXT_SEND_ERROR_NOT_IMPLEMENTED:
+ error = _("not implemented");
+ break;
+ case TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN:
+ default:
+ error = _("unknown");
+ break;
+ }
}
if (message_body != NULL) {
@@ -2982,6 +2997,14 @@ empathy_chat_class_init (EmpathyChatClass *klass)
FALSE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class,
+ PROP_N_MESSAGES_SENDING,
+ g_param_spec_uint ("n-messages-sending",
+ "Num Messages Sending",
+ "The number of messages being sent",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
signals[COMPOSING] =
g_signal_new ("composing",
G_OBJECT_CLASS_TYPE (object_class),
@@ -3487,6 +3510,12 @@ chat_sms_channel_changed_cb (EmpathyChat *self)
g_object_notify (G_OBJECT (self), "sms-channel");
}
+static void
+chat_n_messages_sending_changed_cb (EmpathyChat *self)
+{
+ g_object_notify (G_OBJECT (self), "n-messages-sending");
+}
+
void
empathy_chat_set_tp_chat (EmpathyChat *chat,
EmpathyTpChat *tp_chat)
@@ -3539,6 +3568,9 @@ empathy_chat_set_tp_chat (EmpathyChat *chat,
g_signal_connect_swapped (tp_chat, "notify::sms-channel",
G_CALLBACK (chat_sms_channel_changed_cb),
chat);
+ g_signal_connect_swapped (tp_chat, "notify::n-messages-sending",
+ G_CALLBACK (chat_n_messages_sending_changed_cb),
+ chat);
/* Get initial value of properties */
properties = empathy_tp_chat_get_properties (priv->tp_chat);
@@ -3863,3 +3895,25 @@ empathy_chat_is_sms_channel (EmpathyChat *self)
return priv->sms_channel;
}
+
+guint
+empathy_chat_get_n_messages_sending (EmpathyChat *self)
+{
+ EmpathyChatPriv *priv;
+
+ g_return_val_if_fail (EMPATHY_IS_CHAT (self), 0);
+
+ priv = GET_PRIV (self);
+
+ if (priv->tp_chat == NULL) {
+ return 0;
+ } else {
+ guint n_messages;
+
+ g_object_get (priv->tp_chat,
+ "n-messages-sending", &n_messages,
+ NULL);
+
+ return n_messages;
+ }
+}
diff --git a/libempathy-gtk/empathy-chat.h b/libempathy-gtk/empathy-chat.h
index 8da8004ec..a5c0148a1 100644
--- a/libempathy-gtk/empathy-chat.h
+++ b/libempathy-gtk/empathy-chat.h
@@ -96,6 +96,8 @@ void empathy_chat_messages_read (EmpathyChat *self);
gboolean empathy_chat_is_composing (EmpathyChat *chat);
gboolean empathy_chat_is_sms_channel (EmpathyChat *self);
+guint empathy_chat_get_n_messages_sending (EmpathyChat *self);
+
G_END_DECLS
#endif /* __EMPATHY_CHAT_H__ */
diff --git a/libempathy/empathy-tp-chat.c b/libempathy/empathy-tp-chat.c
index b8e4cdf0c..72c6bebf0 100644
--- a/libempathy/empathy-tp-chat.c
+++ b/libempathy/empathy-tp-chat.c
@@ -61,6 +61,8 @@ typedef struct {
gboolean can_upgrade_to_muc;
gboolean got_sms_channel;
gboolean sms_channel;
+
+ GHashTable *messages_being_sent;
} EmpathyTpChatPriv;
static void tp_chat_iface_init (EmpathyContactListIface *iface);
@@ -73,6 +75,7 @@ enum {
PROP_PASSWORD_NEEDED,
PROP_READY,
PROP_SMS_CHANNEL,
+ PROP_N_MESSAGES_SENDING,
};
enum {
@@ -93,6 +96,40 @@ G_DEFINE_TYPE_WITH_CODE (EmpathyTpChat, empathy_tp_chat, G_TYPE_OBJECT,
static void acknowledge_messages (EmpathyTpChat *chat, GArray *ids);
static void
+tp_chat_set_delivery_status (EmpathyTpChat *self,
+ const gchar *token,
+ EmpathyDeliveryStatus delivery_status)
+{
+ EmpathyTpChatPriv *priv = GET_PRIV (self);
+ TpDeliveryReportingSupportFlags flags =
+ tp_text_channel_get_delivery_reporting_support (
+ TP_TEXT_CHANNEL (priv->channel));
+
+ /* channel must support receiving failures and successes */
+ if (!tp_str_empty (token) &&
+ flags & TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_FAILURES &&
+ flags & TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_SUCCESSES) {
+
+ DEBUG ("Delivery status (%s) = %u", token, delivery_status);
+
+ switch (delivery_status) {
+ case EMPATHY_DELIVERY_STATUS_NONE:
+ g_hash_table_remove (priv->messages_being_sent,
+ token);
+ break;
+
+ default:
+ g_hash_table_insert (priv->messages_being_sent,
+ g_strdup (token),
+ GUINT_TO_POINTER (delivery_status));
+ break;
+ }
+
+ g_object_notify (G_OBJECT (self), "n-messages-sending");
+ }
+}
+
+static void
tp_chat_invalidated_cb (TpProxy *proxy,
guint domain,
gint code,
@@ -322,19 +359,38 @@ handle_delivery_report (EmpathyTpChat *self,
gboolean valid;
GPtrArray *echo;
const gchar *message_body = NULL;
+ const gchar *delivery_dbus_error;
+ const gchar *delivery_token = NULL;
header = tp_message_peek (message, 0);
if (header == NULL)
goto out;
+ delivery_token = tp_asv_get_string (header, "delivery-token");
delivery_status = tp_asv_get_uint32 (header, "delivery-status", &valid);
- if (!valid || delivery_status != TP_DELIVERY_STATUS_PERMANENTLY_FAILED)
+
+ if (!valid) {
+ goto out;
+ } else if (delivery_status == TP_DELIVERY_STATUS_ACCEPTED) {
+ DEBUG ("Accepted %s", delivery_token);
+ tp_chat_set_delivery_status (self, delivery_token,
+ EMPATHY_DELIVERY_STATUS_ACCEPTED);
+ goto out;
+ } else if (delivery_status == TP_DELIVERY_STATUS_DELIVERED) {
+ DEBUG ("Delivered %s", delivery_token);
+ tp_chat_set_delivery_status (self, delivery_token,
+ EMPATHY_DELIVERY_STATUS_NONE);
+ goto out;
+ } else if (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;
+ delivery_dbus_error = tp_asv_get_string (header, "delivery-dbus-error");
+
/* 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",
@@ -347,7 +403,10 @@ handle_delivery_report (EmpathyTpChat *self,
message_body = tp_asv_get_string (echo_body, "content");
}
- g_signal_emit (self, signals[SEND_ERROR], 0, message_body, delivery_error);
+ tp_chat_set_delivery_status (self, delivery_token,
+ EMPATHY_DELIVERY_STATUS_NONE);
+ g_signal_emit (self, signals[SEND_ERROR], 0, message_body,
+ delivery_error, delivery_dbus_error);
out:
tp_text_channel_ack_message_async (TP_TEXT_CHANNEL (priv->channel),
@@ -439,9 +498,10 @@ message_send_cb (GObject *source,
{
EmpathyTpChat *chat = user_data;
TpTextChannel *channel = (TpTextChannel *) source;
+ gchar *token = NULL;
GError *error = NULL;
- if (!tp_text_channel_send_message_finish (channel, result, NULL, &error)) {
+ if (!tp_text_channel_send_message_finish (channel, result, &token, &error)) {
DEBUG ("Error: %s", error->message);
/* FIXME: we should use the body of the message as first argument of the
@@ -449,10 +509,14 @@ message_send_cb (GObject *source,
* 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,
- NULL, error_to_text_send_error (error));
+ NULL, error_to_text_send_error (error), NULL);
g_error_free (error);
}
+
+ tp_chat_set_delivery_status (chat, token,
+ EMPATHY_DELIVERY_STATUS_SENDING);
+ g_free (token);
}
typedef struct {
@@ -812,6 +876,7 @@ tp_chat_finalize (GObject *object)
g_queue_free (priv->messages_queue);
g_queue_free (priv->pending_messages_queue);
+ g_hash_table_destroy (priv->messages_being_sent);
G_OBJECT_CLASS (empathy_tp_chat_parent_class)->finalize (object);
}
@@ -1415,6 +1480,10 @@ tp_chat_get_property (GObject *object,
case PROP_SMS_CHANNEL:
g_value_set_boolean (value, priv->sms_channel);
break;
+ case PROP_N_MESSAGES_SENDING:
+ g_value_set_uint (value,
+ g_hash_table_size (priv->messages_being_sent));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -1504,6 +1573,14 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
FALSE,
G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_N_MESSAGES_SENDING,
+ g_param_spec_uint ("n-messages-sending",
+ "Num Messages Sending",
+ "The number of messages being sent",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READABLE));
+
/* Signals */
signals[MESSAGE_RECEIVED] =
g_signal_new ("message-received",
@@ -1521,9 +1598,9 @@ empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
- _empathy_marshal_VOID__STRING_UINT,
+ _empathy_marshal_VOID__STRING_UINT_STRING,
G_TYPE_NONE,
- 2, G_TYPE_STRING, G_TYPE_UINT);
+ 3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING);
signals[CHAT_STATE_CHANGED] =
g_signal_new ("chat-state-changed",
@@ -1567,6 +1644,8 @@ empathy_tp_chat_init (EmpathyTpChat *chat)
chat->priv = priv;
priv->messages_queue = g_queue_new ();
priv->pending_messages_queue = g_queue_new ();
+ priv->messages_being_sent = g_hash_table_new_full (
+ g_str_hash, g_str_equal, g_free, NULL);
}
static void
@@ -1675,7 +1754,8 @@ empathy_tp_chat_send (EmpathyTpChat *chat,
DEBUG ("Sending message: %s", message_body);
tp_text_channel_send_message_async (TP_TEXT_CHANNEL (priv->channel),
- message, 0, message_send_cb, chat);
+ message, TP_MESSAGE_SENDING_FLAG_REPORT_DELIVERY,
+ message_send_cb, chat);
g_free (message_body);
}
diff --git a/libempathy/empathy-tp-chat.h b/libempathy/empathy-tp-chat.h
index 7ac1296e0..83c7fe7d1 100644
--- a/libempathy/empathy-tp-chat.h
+++ b/libempathy/empathy-tp-chat.h
@@ -59,6 +59,12 @@ typedef struct {
GValue *value;
} EmpathyTpChatProperty;
+typedef enum {
+ EMPATHY_DELIVERY_STATUS_NONE,
+ EMPATHY_DELIVERY_STATUS_SENDING,
+ EMPATHY_DELIVERY_STATUS_ACCEPTED
+} EmpathyDeliveryStatus;
+
GType empathy_tp_chat_get_type (void) G_GNUC_CONST;
EmpathyTpChat *empathy_tp_chat_new (TpAccount *account,
TpChannel *channel);
diff --git a/src/empathy-chat-window.c b/src/empathy-chat-window.c
index 2aef5d932..be83f4a29 100644
--- a/src/empathy-chat-window.c
+++ b/src/empathy-chat-window.c
@@ -311,6 +311,15 @@ chat_window_create_label (EmpathyChatWindow *window,
if (is_tab_label) {
GtkWidget *close_button;
+ GtkWidget *sending_spinner;
+
+ sending_spinner = gtk_spinner_new ();
+
+ gtk_box_pack_start (GTK_BOX (hbox), sending_spinner,
+ FALSE, FALSE, 0);
+ g_object_set_data (G_OBJECT (chat),
+ "chat-window-tab-sending-spinner",
+ sending_spinner);
close_button = gedit_close_button_new ();
g_object_set_data (G_OBJECT (chat), "chat-window-tab-close-button", close_button);
@@ -649,6 +658,8 @@ chat_window_update_chat_tab_full (EmpathyChat *chat,
const gchar *icon_name;
GtkWidget *tab_image;
GtkWidget *menu_image;
+ GtkWidget *sending_spinner;
+ guint nb_sending;
window = chat_window_find_chat (chat);
if (!window) {
@@ -697,6 +708,16 @@ chat_window_update_chat_tab_full (EmpathyChat *chat,
gtk_widget_hide (menu_image);
}
+ /* Update the sending spinner */
+ nb_sending = empathy_chat_get_n_messages_sending (chat);
+ sending_spinner = g_object_get_data (G_OBJECT (chat),
+ "chat-window-tab-sending-spinner");
+
+ g_object_set (sending_spinner,
+ "active", nb_sending > 0,
+ "visible", nb_sending > 0,
+ NULL);
+
/* Update tab tooltip */
tooltip = g_string_new (NULL);
@@ -716,6 +737,20 @@ chat_window_update_chat_tab_full (EmpathyChat *chat,
id,
tp_account_get_display_name (account));
+ if (nb_sending > 0) {
+ char *tmp = g_strdup_printf (
+ ngettext ("Sending %d message",
+ "Sending %d messages",
+ nb_sending),
+ nb_sending);
+
+ g_string_append (tooltip, "\n");
+ g_string_append (tooltip, tmp);
+
+ gtk_widget_set_tooltip_text (sending_spinner, tmp);
+ g_free (tmp);
+ }
+
if (!EMP_STR_EMPTY (status)) {
append_markup_printf (tooltip, "\n<i>%s</i>", status);
}
@@ -2243,6 +2278,9 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window,
g_signal_connect (chat, "notify::sms-channel",
G_CALLBACK (chat_window_chat_notify_cb),
NULL);
+ g_signal_connect (chat, "notify::n-messages-sending",
+ G_CALLBACK (chat_window_chat_notify_cb),
+ NULL);
chat_window_chat_notify_cb (chat);
gtk_notebook_append_page_menu (GTK_NOTEBOOK (priv->notebook), child, label, popup_label);