142
95
G_DEFINE_TYPE (EmpathyTpChat, empathy_tp_chat, G_TYPE_OBJECT);
145
empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
147
GObjectClass *object_class = G_OBJECT_CLASS (klass);
149
object_class->finalize = tp_chat_finalize;
150
object_class->constructor = tp_chat_constructor;
151
object_class->get_property = tp_chat_get_property;
152
object_class->set_property = tp_chat_set_property;
154
/* Construct-only properties */
155
g_object_class_install_property (object_class,
157
g_param_spec_object ("account",
159
"The account associated with the channel",
162
G_PARAM_CONSTRUCT_ONLY));
163
g_object_class_install_property (object_class,
165
g_param_spec_object ("tp-chan",
167
"The text channel for the chat",
170
G_PARAM_CONSTRUCT_ONLY));
172
/* Normal properties */
173
g_object_class_install_property (object_class,
175
g_param_spec_boolean ("acknowledge",
181
/* Properties of Text Channel */
182
g_object_class_install_property (object_class,
184
g_param_spec_boolean ("anonymous",
189
g_object_class_install_property (object_class,
191
g_param_spec_boolean ("invite-only",
196
g_object_class_install_property (object_class,
198
g_param_spec_uint ("limit",
205
g_object_class_install_property (object_class,
207
g_param_spec_boolean ("limited",
212
g_object_class_install_property (object_class,
214
g_param_spec_boolean ("moderated",
219
g_object_class_install_property (object_class,
221
g_param_spec_string ("name",
226
g_object_class_install_property (object_class,
228
g_param_spec_string ("description",
233
g_object_class_install_property (object_class,
235
g_param_spec_string ("password",
240
g_object_class_install_property (object_class,
241
PROP_PASSWORD_REQUIRED,
242
g_param_spec_boolean ("password-required",
247
g_object_class_install_property (object_class,
249
g_param_spec_boolean ("persistent",
254
g_object_class_install_property (object_class,
256
g_param_spec_boolean ("private",
262
g_object_class_install_property (object_class,
264
g_param_spec_string ("subject",
269
g_object_class_install_property (object_class,
270
PROP_SUBJECT_CONTACT,
271
g_param_spec_uint ("subject-contact",
278
g_object_class_install_property (object_class,
279
PROP_SUBJECT_TIMESTAMP,
280
g_param_spec_uint ("subject-timestamp",
289
signals[MESSAGE_RECEIVED] =
290
g_signal_new ("message-received",
291
G_TYPE_FROM_CLASS (klass),
295
g_cclosure_marshal_VOID__OBJECT,
297
1, EMPATHY_TYPE_MESSAGE);
299
signals[SEND_ERROR] =
300
g_signal_new ("send-error",
301
G_TYPE_FROM_CLASS (klass),
305
_empathy_marshal_VOID__OBJECT_UINT,
307
2, EMPATHY_TYPE_MESSAGE, G_TYPE_UINT);
309
signals[CHAT_STATE_CHANGED] =
310
g_signal_new ("chat-state-changed",
311
G_TYPE_FROM_CLASS (klass),
315
_empathy_marshal_VOID__OBJECT_UINT,
317
2, EMPATHY_TYPE_CONTACT, G_TYPE_UINT);
320
g_signal_new ("destroy",
321
G_TYPE_FROM_CLASS (klass),
325
g_cclosure_marshal_VOID__VOID,
329
g_type_class_add_private (object_class, sizeof (EmpathyTpChatPriv));
333
empathy_tp_chat_init (EmpathyTpChat *chat)
98
tp_chat_destroy_cb (TpChan *text_chan,
101
EmpathyTpChatPriv *priv;
103
priv = GET_PRIV (chat);
105
empathy_debug (DEBUG_DOMAIN, "Channel Closed or CM crashed");
107
g_object_unref (priv->tp_chan);
108
priv->tp_chan = NULL;
109
priv->text_iface = NULL;
110
priv->chat_state_iface = NULL;
111
priv->props_iface = NULL;
113
g_signal_emit (chat, signals[DESTROY], 0);
117
tp_chat_closed_cb (TpChan *text_chan,
120
EmpathyTpChatPriv *priv;
122
priv = GET_PRIV (chat);
124
/* The channel is closed, do just like if the proxy was destroyed */
125
g_signal_handlers_disconnect_by_func (priv->tp_chan,
128
tp_chat_destroy_cb (text_chan, chat);
131
static EmpathyMessage *
132
tp_chat_build_message (EmpathyTpChat *chat,
136
const gchar *message_body)
138
EmpathyTpChatPriv *priv;
139
EmpathyMessage *message;
140
EmpathyContact *sender;
142
priv = GET_PRIV (chat);
144
if (from_handle == 0) {
145
sender = g_object_ref (priv->user);
147
sender = empathy_contact_factory_get_from_handle (priv->factory,
152
message = empathy_message_new (message_body);
153
empathy_message_set_type (message, type);
154
empathy_message_set_sender (message, sender);
155
empathy_message_set_receiver (message, priv->user);
156
empathy_message_set_timestamp (message, timestamp);
158
g_object_unref (sender);
164
tp_chat_sender_ready_notify_cb (EmpathyContact *contact,
165
GParamSpec *param_spec,
168
EmpathyTpChatPriv *priv = GET_PRIV (chat);
169
EmpathyMessage *message;
170
EmpathyContact *sender;
171
gboolean removed = FALSE;
172
const gchar *name, *id;
174
/* Emit all messages queued until we find a message with not
175
* ready sender. When leaving this loop, sender is the first not ready
176
* contact queued and removed tells if at least one message got removed
178
while (priv->message_queue) {
179
message = priv->message_queue->data;
180
sender = empathy_message_get_sender (message);
181
name = empathy_contact_get_name (sender);
182
id = empathy_contact_get_id (sender);
184
if (!tp_strdiff (name, id)) {
188
empathy_debug (DEBUG_DOMAIN, "Queued message ready");
189
g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
190
priv->message_queue = g_slist_remove (priv->message_queue,
192
g_object_unref (message);
197
g_signal_handlers_disconnect_by_func (contact,
198
tp_chat_sender_ready_notify_cb,
201
if (priv->message_queue) {
202
g_signal_connect (sender, "notify::name",
203
G_CALLBACK (tp_chat_sender_ready_notify_cb),
210
tp_chat_emit_or_queue_message (EmpathyTpChat *chat,
211
EmpathyMessage *message)
213
EmpathyTpChatPriv *priv = GET_PRIV (chat);
214
EmpathyContact *sender;
215
const gchar *name, *id;
217
if (priv->message_queue != NULL) {
218
empathy_debug (DEBUG_DOMAIN, "Message queue not empty");
219
priv->message_queue = g_slist_append (priv->message_queue,
220
g_object_ref (message));
224
sender = empathy_message_get_sender (message);
225
name = empathy_contact_get_name (sender);
226
id = empathy_contact_get_id (sender);
227
if (tp_strdiff (name, id)) {
228
empathy_debug (DEBUG_DOMAIN, "Message queue empty and sender ready");
229
g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
233
empathy_debug (DEBUG_DOMAIN, "Sender not ready");
234
priv->message_queue = g_slist_append (priv->message_queue,
235
g_object_ref (message));
236
g_signal_connect (sender, "notify::name",
237
G_CALLBACK (tp_chat_sender_ready_notify_cb),
242
tp_chat_received_cb (DBusGProxy *text_iface,
251
EmpathyTpChatPriv *priv;
252
EmpathyMessage *message;
254
priv = GET_PRIV (chat);
256
if (!priv->had_pending_messages) {
260
empathy_debug (DEBUG_DOMAIN, "Message received: %s", message_body);
262
message = tp_chat_build_message (chat,
268
tp_chat_emit_or_queue_message (EMPATHY_TP_CHAT (chat), message);
269
g_object_unref (message);
271
if (priv->acknowledge) {
274
message_ids = g_array_new (FALSE, FALSE, sizeof (guint));
275
g_array_append_val (message_ids, message_id);
276
tp_chan_type_text_acknowledge_pending_messages (priv->text_iface,
278
g_array_free (message_ids, TRUE);
283
tp_chat_sent_cb (DBusGProxy *text_iface,
289
EmpathyMessage *message;
291
empathy_debug (DEBUG_DOMAIN, "Message sent: %s", message_body);
293
message = tp_chat_build_message (chat,
299
tp_chat_emit_or_queue_message (EMPATHY_TP_CHAT (chat), message);
300
g_object_unref (message);
304
tp_chat_send_error_cb (DBusGProxy *text_iface,
311
EmpathyMessage *message;
313
empathy_debug (DEBUG_DOMAIN, "Message sent error: %s (%d)",
314
message_body, error_code);
316
message = tp_chat_build_message (chat,
322
g_signal_emit (chat, signals[SEND_ERROR], 0, message, error_code);
323
g_object_unref (message);
327
tp_chat_state_changed_cb (DBusGProxy *chat_state_iface,
329
TpChannelChatState state,
332
EmpathyTpChatPriv *priv;
333
EmpathyContact *contact;
335
priv = GET_PRIV (chat);
337
contact = empathy_contact_factory_get_from_handle (priv->factory,
341
empathy_debug (DEBUG_DOMAIN, "Chat state changed for %s (%d): %d",
342
empathy_contact_get_name (contact),
346
g_signal_emit (chat, signals[CHAT_STATE_CHANGED], 0, contact, state);
347
g_object_unref (contact);
351
tp_chat_list_pending_messages_cb (DBusGProxy *proxy,
352
GPtrArray *messages_list,
356
EmpathyTpChatPriv *priv = GET_PRIV (chat);
359
priv->had_pending_messages = TRUE;
361
for (i = 0; i < messages_list->len; i++) {
362
EmpathyMessage *message;
363
GValueArray *message_struct;
364
const gchar *message_body;
371
message_struct = g_ptr_array_index (messages_list, i);
373
message_id = g_value_get_uint (g_value_array_get_nth (message_struct, 0));
374
timestamp = g_value_get_uint (g_value_array_get_nth (message_struct, 1));
375
from_handle = g_value_get_uint (g_value_array_get_nth (message_struct, 2));
376
message_type = g_value_get_uint (g_value_array_get_nth (message_struct, 3));
377
message_flags = g_value_get_uint (g_value_array_get_nth (message_struct, 4));
378
message_body = g_value_get_string (g_value_array_get_nth (message_struct, 5));
380
empathy_debug (DEBUG_DOMAIN, "Message pending: %s", message_body);
382
message = tp_chat_build_message (chat,
388
tp_chat_emit_or_queue_message (chat, message);
389
g_object_unref (message);
391
g_value_array_free (message_struct);
394
g_ptr_array_free (messages_list, TRUE);
398
tp_chat_properties_ready_cb (TpPropsIface *props_iface,
401
g_object_notify (G_OBJECT (chat), "anonymous");
402
g_object_notify (G_OBJECT (chat), "invite-only");
403
g_object_notify (G_OBJECT (chat), "limit");
404
g_object_notify (G_OBJECT (chat), "limited");
405
g_object_notify (G_OBJECT (chat), "moderated");
406
g_object_notify (G_OBJECT (chat), "name");
407
g_object_notify (G_OBJECT (chat), "description");
408
g_object_notify (G_OBJECT (chat), "password");
409
g_object_notify (G_OBJECT (chat), "password-required");
410
g_object_notify (G_OBJECT (chat), "persistent");
411
g_object_notify (G_OBJECT (chat), "private");
412
g_object_notify (G_OBJECT (chat), "subject");
413
g_object_notify (G_OBJECT (chat), "subject-contact");
414
g_object_notify (G_OBJECT (chat), "subject-timestamp");
418
tp_chat_properties_changed_cb (TpPropsIface *props_iface,
425
g_object_notify (G_OBJECT (chat), "anonymous");
427
case PROP_INVITE_ONLY:
428
g_object_notify (G_OBJECT (chat), "invite-only");
431
g_object_notify (G_OBJECT (chat), "limit");
434
g_object_notify (G_OBJECT (chat), "limited");
437
g_object_notify (G_OBJECT (chat), "moderated");
440
g_object_notify (G_OBJECT (chat), "name");
442
case PROP_DESCRIPTION:
443
g_object_notify (G_OBJECT (chat), "description");
446
g_object_notify (G_OBJECT (chat), "password");
448
case PROP_PASSWORD_REQUIRED:
449
g_object_notify (G_OBJECT (chat), "password-required");
451
case PROP_PERSISTENT:
452
g_object_notify (G_OBJECT (chat), "persistent");
455
g_object_notify (G_OBJECT (chat), "private");
458
g_object_notify (G_OBJECT (chat), "subject");
460
case PROP_SUBJECT_CONTACT:
461
g_object_notify (G_OBJECT (chat), "subject-contact");
463
case PROP_SUBJECT_TIMESTAMP:
464
g_object_notify (G_OBJECT (chat), "subject-timestamp");
339
470
tp_chat_finalize (GObject *object)
682
empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
684
GObjectClass *object_class = G_OBJECT_CLASS (klass);
686
object_class->finalize = tp_chat_finalize;
687
object_class->constructor = tp_chat_constructor;
688
object_class->get_property = tp_chat_get_property;
689
object_class->set_property = tp_chat_set_property;
691
/* Construct-only properties */
692
g_object_class_install_property (object_class,
694
g_param_spec_object ("account",
696
"The account associated with the channel",
699
G_PARAM_CONSTRUCT_ONLY));
700
g_object_class_install_property (object_class,
702
g_param_spec_object ("tp-chan",
704
"The text channel for the chat",
707
G_PARAM_CONSTRUCT_ONLY));
709
/* Normal properties */
710
g_object_class_install_property (object_class,
712
g_param_spec_boolean ("acknowledge",
718
/* Properties of Text Channel */
719
g_object_class_install_property (object_class,
721
g_param_spec_boolean ("anonymous",
726
g_object_class_install_property (object_class,
728
g_param_spec_boolean ("invite-only",
733
g_object_class_install_property (object_class,
735
g_param_spec_uint ("limit",
742
g_object_class_install_property (object_class,
744
g_param_spec_boolean ("limited",
749
g_object_class_install_property (object_class,
751
g_param_spec_boolean ("moderated",
756
g_object_class_install_property (object_class,
758
g_param_spec_string ("name",
763
g_object_class_install_property (object_class,
765
g_param_spec_string ("description",
770
g_object_class_install_property (object_class,
772
g_param_spec_string ("password",
777
g_object_class_install_property (object_class,
778
PROP_PASSWORD_REQUIRED,
779
g_param_spec_boolean ("password-required",
784
g_object_class_install_property (object_class,
786
g_param_spec_boolean ("persistent",
791
g_object_class_install_property (object_class,
793
g_param_spec_boolean ("private",
799
g_object_class_install_property (object_class,
801
g_param_spec_string ("subject",
806
g_object_class_install_property (object_class,
807
PROP_SUBJECT_CONTACT,
808
g_param_spec_uint ("subject-contact",
815
g_object_class_install_property (object_class,
816
PROP_SUBJECT_TIMESTAMP,
817
g_param_spec_uint ("subject-timestamp",
826
signals[MESSAGE_RECEIVED] =
827
g_signal_new ("message-received",
828
G_TYPE_FROM_CLASS (klass),
832
g_cclosure_marshal_VOID__OBJECT,
834
1, EMPATHY_TYPE_MESSAGE);
836
signals[SEND_ERROR] =
837
g_signal_new ("send-error",
838
G_TYPE_FROM_CLASS (klass),
842
_empathy_marshal_VOID__OBJECT_UINT,
844
2, EMPATHY_TYPE_MESSAGE, G_TYPE_UINT);
846
signals[CHAT_STATE_CHANGED] =
847
g_signal_new ("chat-state-changed",
848
G_TYPE_FROM_CLASS (klass),
852
_empathy_marshal_VOID__OBJECT_UINT,
854
2, EMPATHY_TYPE_CONTACT, G_TYPE_UINT);
857
g_signal_new ("destroy",
858
G_TYPE_FROM_CLASS (klass),
862
g_cclosure_marshal_VOID__VOID,
866
g_type_class_add_private (object_class, sizeof (EmpathyTpChatPriv));
870
empathy_tp_chat_init (EmpathyTpChat *chat)
555
875
empathy_tp_chat_new (McAccount *account,
787
1060
return priv->id;
791
tp_chat_destroy_cb (TpChan *text_chan,
794
EmpathyTpChatPriv *priv;
796
priv = GET_PRIV (chat);
798
empathy_debug (DEBUG_DOMAIN, "Channel Closed or CM crashed");
800
g_object_unref (priv->tp_chan);
801
priv->tp_chan = NULL;
802
priv->text_iface = NULL;
803
priv->chat_state_iface = NULL;
804
priv->props_iface = NULL;
806
g_signal_emit (chat, signals[DESTROY], 0);
810
tp_chat_closed_cb (TpChan *text_chan,
813
EmpathyTpChatPriv *priv;
815
priv = GET_PRIV (chat);
817
/* The channel is closed, do just like if the proxy was destroyed */
818
g_signal_handlers_disconnect_by_func (priv->tp_chan,
821
tp_chat_destroy_cb (text_chan, chat);
825
tp_chat_received_cb (DBusGProxy *text_iface,
834
EmpathyTpChatPriv *priv;
835
EmpathyMessage *message;
837
priv = GET_PRIV (chat);
839
empathy_debug (DEBUG_DOMAIN, "Message received: %s", message_body);
841
message = tp_chat_build_message (chat,
847
g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
848
g_object_unref (message);
850
if (priv->acknowledge) {
853
message_ids = g_array_new (FALSE, FALSE, sizeof (guint));
854
g_array_append_val (message_ids, message_id);
855
tp_chan_type_text_acknowledge_pending_messages (priv->text_iface,
857
g_array_free (message_ids, TRUE);
862
tp_chat_sent_cb (DBusGProxy *text_iface,
868
EmpathyMessage *message;
870
empathy_debug (DEBUG_DOMAIN, "Message sent: %s", message_body);
872
message = tp_chat_build_message (chat,
878
g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
879
g_object_unref (message);
883
tp_chat_send_error_cb (DBusGProxy *text_iface,
890
EmpathyMessage *message;
892
empathy_debug (DEBUG_DOMAIN, "Message sent error: %s (%d)",
893
message_body, error_code);
895
message = tp_chat_build_message (chat,
901
g_signal_emit (chat, signals[SEND_ERROR], 0, message, error_code);
902
g_object_unref (message);
906
tp_chat_state_changed_cb (DBusGProxy *chat_state_iface,
908
TpChannelChatState state,
911
EmpathyTpChatPriv *priv;
912
EmpathyContact *contact;
914
priv = GET_PRIV (chat);
916
contact = empathy_contact_factory_get_from_handle (priv->factory,
920
empathy_debug (DEBUG_DOMAIN, "Chat state changed for %s (%d): %d",
921
empathy_contact_get_name (contact),
925
g_signal_emit (chat, signals[CHAT_STATE_CHANGED], 0, contact, state);
926
g_object_unref (contact);
929
static EmpathyMessage *
930
tp_chat_build_message (EmpathyTpChat *chat,
934
const gchar *message_body)
936
EmpathyTpChatPriv *priv;
937
EmpathyMessage *message;
938
EmpathyContact *sender;
940
priv = GET_PRIV (chat);
942
if (from_handle == 0) {
943
sender = g_object_ref (priv->user);
945
sender = empathy_contact_factory_get_from_handle (priv->factory,
950
message = empathy_message_new (message_body);
951
empathy_message_set_type (message, type);
952
empathy_message_set_sender (message, sender);
953
empathy_message_set_receiver (message, priv->user);
954
empathy_message_set_timestamp (message, timestamp);
956
g_object_unref (sender);
962
tp_chat_properties_ready_cb (TpPropsIface *props_iface,
965
g_object_notify (G_OBJECT (chat), "anonymous");
966
g_object_notify (G_OBJECT (chat), "invite-only");
967
g_object_notify (G_OBJECT (chat), "limit");
968
g_object_notify (G_OBJECT (chat), "limited");
969
g_object_notify (G_OBJECT (chat), "moderated");
970
g_object_notify (G_OBJECT (chat), "name");
971
g_object_notify (G_OBJECT (chat), "description");
972
g_object_notify (G_OBJECT (chat), "password");
973
g_object_notify (G_OBJECT (chat), "password-required");
974
g_object_notify (G_OBJECT (chat), "persistent");
975
g_object_notify (G_OBJECT (chat), "private");
976
g_object_notify (G_OBJECT (chat), "subject");
977
g_object_notify (G_OBJECT (chat), "subject-contact");
978
g_object_notify (G_OBJECT (chat), "subject-timestamp");
982
tp_chat_properties_changed_cb (TpPropsIface *props_iface,
989
g_object_notify (G_OBJECT (chat), "anonymous");
991
case PROP_INVITE_ONLY:
992
g_object_notify (G_OBJECT (chat), "invite-only");
995
g_object_notify (G_OBJECT (chat), "limit");
998
g_object_notify (G_OBJECT (chat), "limited");
1000
case PROP_MODERATED:
1001
g_object_notify (G_OBJECT (chat), "moderated");
1004
g_object_notify (G_OBJECT (chat), "name");
1006
case PROP_DESCRIPTION:
1007
g_object_notify (G_OBJECT (chat), "description");
1010
g_object_notify (G_OBJECT (chat), "password");
1012
case PROP_PASSWORD_REQUIRED:
1013
g_object_notify (G_OBJECT (chat), "password-required");
1015
case PROP_PERSISTENT:
1016
g_object_notify (G_OBJECT (chat), "persistent");
1019
g_object_notify (G_OBJECT (chat), "private");
1022
g_object_notify (G_OBJECT (chat), "subject");
1024
case PROP_SUBJECT_CONTACT:
1025
g_object_notify (G_OBJECT (chat), "subject-contact");
1027
case PROP_SUBJECT_TIMESTAMP:
1028
g_object_notify (G_OBJECT (chat), "subject-timestamp");