1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007-2008 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Authors: Xavier Claessens <xclaesse@gmail.com>
26 #include <telepathy-glib/channel.h>
27 #include <telepathy-glib/dbus.h>
28 #include <telepathy-glib/util.h>
30 #include "empathy-tp-chat.h"
31 #include "empathy-contact-factory.h"
32 #include "empathy-contact-monitor.h"
33 #include "empathy-contact-list.h"
34 #include "empathy-marshal.h"
35 #include "empathy-time.h"
36 #include "empathy-utils.h"
38 #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CHAT
39 #include "empathy-debug.h"
41 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpChat)
43 EmpathyContactFactory *factory;
44 EmpathyContactMonitor *contact_monitor;
46 EmpathyContact *remote_contact;
47 EmpathyTpGroup *group;
52 gboolean listing_pending_messages;
53 GSList *message_queue;
54 gboolean had_properties_list;
55 GPtrArray *properties;
63 TpPropertyFlags flags;
67 static void tp_chat_iface_init (EmpathyContactListIface *iface);
86 static guint signals[LAST_SIGNAL];
88 G_DEFINE_TYPE_WITH_CODE (EmpathyTpChat, empathy_tp_chat, G_TYPE_OBJECT,
89 G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
93 tp_chat_invalidated_cb (TpProxy *proxy,
99 DEBUG ("Channel invalidated: %s", message);
100 g_signal_emit (chat, signals[DESTROY], 0);
104 tp_chat_async_cb (TpChannel *proxy,
107 GObject *weak_object)
110 DEBUG ("Error %s: %s", (gchar*) user_data, error->message);
115 tp_chat_member_added_cb (EmpathyTpGroup *group,
116 EmpathyContact *contact,
117 EmpathyContact *actor,
119 const gchar *message,
122 EmpathyTpChatPriv *priv = GET_PRIV (chat);
123 guint handle_type = 0;
125 priv->members_count++;
126 g_signal_emit_by_name (chat, "members-changed",
127 contact, actor, reason, message,
130 g_object_get (priv->channel, "handle-type", &handle_type, NULL);
131 if (handle_type == TP_HANDLE_TYPE_ROOM) {
135 if (priv->members_count > 2 && priv->remote_contact) {
136 /* We now have more than 2 members, this is not a p2p chat
137 * anymore. Remove the remote-contact as it makes no sense, the
138 * EmpathyContactList interface must be used now. */
139 g_object_unref (priv->remote_contact);
140 priv->remote_contact = NULL;
141 g_object_notify (G_OBJECT (chat), "remote-contact");
143 if (priv->members_count <= 2 && !priv->remote_contact &&
144 !empathy_contact_is_user (contact)) {
145 /* This is a p2p chat, if it's not ourself that means this is
146 * the remote contact with who we are chatting. This is to
147 * avoid forcing the usage of the EmpathyContactList interface
149 priv->remote_contact = g_object_ref (contact);
150 g_object_notify (G_OBJECT (chat), "remote-contact");
155 tp_chat_member_removed_cb (EmpathyTpGroup *group,
156 EmpathyContact *contact,
157 EmpathyContact *actor,
159 const gchar *message,
162 EmpathyTpChatPriv *priv = GET_PRIV (chat);
163 guint handle_type = 0;
165 priv->members_count--;
166 g_signal_emit_by_name (chat, "members-changed",
167 contact, actor, reason, message,
170 g_object_get (priv->channel, "handle-type", &handle_type, NULL);
171 if (handle_type == TP_HANDLE_TYPE_ROOM) {
175 if (priv->members_count <= 2 && !priv->remote_contact) {
178 /* We are not a MUC anymore, get the remote contact back */
179 members = empathy_tp_group_get_members (group);
180 for (l = members; l; l = l->next) {
181 if (!empathy_contact_is_user (l->data)) {
182 priv->remote_contact = g_object_ref (l->data);
183 g_object_notify (G_OBJECT (chat), "remote-contact");
187 g_list_foreach (members, (GFunc) g_object_unref, NULL);
188 g_list_free (members);
193 tp_chat_local_pending_cb (EmpathyTpGroup *group,
194 EmpathyContact *contact,
195 EmpathyContact *actor,
197 const gchar *message,
200 g_signal_emit_by_name (chat, "pendings-changed",
201 contact, actor, reason, message,
206 tp_chat_add (EmpathyContactList *list,
207 EmpathyContact *contact,
208 const gchar *message)
210 EmpathyTpChatPriv *priv = GET_PRIV (list);
212 g_return_if_fail (EMPATHY_IS_TP_CHAT (list));
213 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
216 empathy_tp_group_add_member (priv->group, contact, message);
221 tp_chat_remove (EmpathyContactList *list,
222 EmpathyContact *contact,
223 const gchar *message)
225 EmpathyTpChatPriv *priv = GET_PRIV (list);
227 g_return_if_fail (EMPATHY_IS_TP_CHAT (list));
228 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
231 empathy_tp_group_remove_member (priv->group, contact, message);
236 tp_chat_get_members (EmpathyContactList *list)
238 EmpathyTpChatPriv *priv = GET_PRIV (list);
239 GList *members = NULL;
241 g_return_val_if_fail (EMPATHY_IS_TP_CHAT (list), NULL);
244 members = empathy_tp_group_get_members (priv->group);
246 members = g_list_prepend (members, g_object_ref (priv->user));
247 members = g_list_prepend (members, g_object_ref (priv->remote_contact));
253 static EmpathyContactMonitor *
254 tp_chat_get_monitor (EmpathyContactList *list)
256 EmpathyTpChatPriv *priv;
258 g_return_val_if_fail (EMPATHY_IS_TP_CHAT (list), NULL);
260 priv = GET_PRIV (list);
262 return priv->contact_monitor;
265 static EmpathyMessage *
266 tp_chat_build_message (EmpathyTpChat *chat,
270 const gchar *message_body)
272 EmpathyTpChatPriv *priv;
273 EmpathyMessage *message;
274 EmpathyContact *sender;
276 priv = GET_PRIV (chat);
278 if (from_handle == 0) {
279 sender = g_object_ref (priv->user);
281 sender = empathy_contact_factory_get_from_handle (priv->factory,
286 message = empathy_message_new (message_body);
287 empathy_message_set_tptype (message, type);
288 empathy_message_set_sender (message, sender);
289 empathy_message_set_receiver (message, priv->user);
290 empathy_message_set_timestamp (message, timestamp);
292 g_object_unref (sender);
298 tp_chat_sender_ready_notify_cb (EmpathyContact *contact,
299 GParamSpec *param_spec,
302 EmpathyTpChatPriv *priv = GET_PRIV (chat);
303 EmpathyMessage *message;
304 EmpathyContactReady ready;
305 EmpathyContact *sender = NULL;
306 gboolean removed = FALSE;
308 /* Emit all messages queued until we find a message with not
309 * ready sender (in case of a MUC we could have more than one sender).
310 * When leaving this loop, sender is the first not ready contact queued
311 * and removed tells if at least one message got removed
313 while (priv->message_queue) {
314 message = priv->message_queue->data;
315 sender = empathy_message_get_sender (message);
316 ready = empathy_contact_get_ready (sender);
318 if ((ready & EMPATHY_CONTACT_READY_NAME) == 0 ||
319 (ready & EMPATHY_CONTACT_READY_ID) == 0) {
323 DEBUG ("Queued message ready");
324 g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
325 priv->message_queue = g_slist_remove (priv->message_queue,
327 g_object_unref (message);
332 /* We removed at least one message from the queue, disconnect
333 * the ready signal from the previous contact */
334 g_signal_handlers_disconnect_by_func (contact,
335 tp_chat_sender_ready_notify_cb,
338 if (priv->message_queue) {
339 /* We still have queued message, connect the ready
340 * signal on the new first message sender. */
341 g_signal_connect (sender, "notify::ready",
342 G_CALLBACK (tp_chat_sender_ready_notify_cb),
349 tp_chat_emit_or_queue_message (EmpathyTpChat *chat,
350 EmpathyMessage *message)
352 EmpathyTpChatPriv *priv = GET_PRIV (chat);
353 EmpathyContact *sender;
354 EmpathyContactReady ready;
356 if (priv->message_queue != NULL) {
357 DEBUG ("Message queue not empty");
358 priv->message_queue = g_slist_append (priv->message_queue,
359 g_object_ref (message));
363 sender = empathy_message_get_sender (message);
364 ready = empathy_contact_get_ready (sender);
365 if ((ready & EMPATHY_CONTACT_READY_NAME) &&
366 (ready & EMPATHY_CONTACT_READY_ID)) {
367 DEBUG ("Message queue empty and sender ready");
368 g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
372 DEBUG ("Sender not ready");
373 priv->message_queue = g_slist_append (priv->message_queue,
374 g_object_ref (message));
375 g_signal_connect (sender, "notify::ready",
376 G_CALLBACK (tp_chat_sender_ready_notify_cb),
381 tp_chat_received_cb (TpChannel *channel,
387 const gchar *message_body,
391 EmpathyTpChatPriv *priv = GET_PRIV (chat);
392 EmpathyMessage *message;
394 if (priv->listing_pending_messages) {
398 DEBUG ("Message received: %s", message_body);
400 message = tp_chat_build_message (EMPATHY_TP_CHAT (chat),
406 tp_chat_emit_or_queue_message (EMPATHY_TP_CHAT (chat), message);
407 g_object_unref (message);
409 if (priv->acknowledge) {
412 message_ids = g_array_new (FALSE, FALSE, sizeof (guint));
413 g_array_append_val (message_ids, message_id);
414 tp_cli_channel_type_text_call_acknowledge_pending_messages (priv->channel,
418 "acknowledging received message",
421 g_array_free (message_ids, TRUE);
426 tp_chat_sent_cb (TpChannel *channel,
429 const gchar *message_body,
433 EmpathyMessage *message;
435 DEBUG ("Message sent: %s", message_body);
437 message = tp_chat_build_message (EMPATHY_TP_CHAT (chat),
443 tp_chat_emit_or_queue_message (EMPATHY_TP_CHAT (chat), message);
444 g_object_unref (message);
448 tp_chat_send_error_cb (TpChannel *channel,
452 const gchar *message_body,
456 EmpathyMessage *message;
458 DEBUG ("Message sent error: %s (%d)", message_body, error_code);
460 message = tp_chat_build_message (EMPATHY_TP_CHAT (chat),
466 g_signal_emit (chat, signals[SEND_ERROR], 0, message, error_code);
467 g_object_unref (message);
471 tp_chat_send_cb (TpChannel *proxy,
476 EmpathyMessage *message = EMPATHY_MESSAGE (user_data);
479 DEBUG ("Error: %s", error->message);
480 g_signal_emit (chat, signals[SEND_ERROR], 0, message,
481 TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN);
486 tp_chat_state_changed_cb (TpChannel *channel,
492 EmpathyTpChatPriv *priv = GET_PRIV (chat);
493 EmpathyContact *contact;
495 contact = empathy_contact_factory_get_from_handle (priv->factory,
499 DEBUG ("Chat state changed for %s (%d): %d",
500 empathy_contact_get_name (contact), handle, state);
502 g_signal_emit (chat, signals[CHAT_STATE_CHANGED], 0, contact, state);
503 g_object_unref (contact);
507 tp_chat_list_pending_messages_cb (TpChannel *channel,
508 const GPtrArray *messages_list,
513 EmpathyTpChatPriv *priv = GET_PRIV (chat);
515 GArray *message_ids = NULL;
517 priv->listing_pending_messages = FALSE;
520 DEBUG ("Error listing pending messages: %s", error->message);
524 if (priv->acknowledge) {
525 message_ids = g_array_sized_new (FALSE, FALSE, sizeof (guint),
529 for (i = 0; i < messages_list->len; i++) {
530 EmpathyMessage *message;
531 GValueArray *message_struct;
532 const gchar *message_body;
539 message_struct = g_ptr_array_index (messages_list, i);
541 message_id = g_value_get_uint (g_value_array_get_nth (message_struct, 0));
542 timestamp = g_value_get_uint (g_value_array_get_nth (message_struct, 1));
543 from_handle = g_value_get_uint (g_value_array_get_nth (message_struct, 2));
544 message_type = g_value_get_uint (g_value_array_get_nth (message_struct, 3));
545 message_flags = g_value_get_uint (g_value_array_get_nth (message_struct, 4));
546 message_body = g_value_get_string (g_value_array_get_nth (message_struct, 5));
548 DEBUG ("Message pending: %s", message_body);
551 g_array_append_val (message_ids, message_id);
554 message = tp_chat_build_message (EMPATHY_TP_CHAT (chat),
560 tp_chat_emit_or_queue_message (EMPATHY_TP_CHAT (chat), message);
561 g_object_unref (message);
565 tp_cli_channel_type_text_call_acknowledge_pending_messages (priv->channel,
569 "acknowledging pending messages",
572 g_array_free (message_ids, TRUE);
577 tp_chat_property_flags_changed_cb (TpProxy *proxy,
578 const GPtrArray *properties,
582 EmpathyTpChatPriv *priv = GET_PRIV (chat);
585 if (!priv->had_properties_list || !properties) {
589 for (i = 0; i < properties->len; i++) {
590 GValueArray *prop_struct;
591 TpChatProperty *property;
595 prop_struct = g_ptr_array_index (properties, i);
596 id = g_value_get_uint (g_value_array_get_nth (prop_struct, 0));
597 flags = g_value_get_uint (g_value_array_get_nth (prop_struct, 1));
599 for (j = 0; j < priv->properties->len; j++) {
600 property = g_ptr_array_index (priv->properties, j);
601 if (property->id == id) {
602 property->flags = flags;
603 DEBUG ("property %s flags changed: %d",
604 property->name, property->flags);
612 tp_chat_properties_changed_cb (TpProxy *proxy,
613 const GPtrArray *properties,
617 EmpathyTpChatPriv *priv = GET_PRIV (chat);
620 if (!priv->had_properties_list || !properties) {
624 for (i = 0; i < properties->len; i++) {
625 GValueArray *prop_struct;
626 TpChatProperty *property;
630 prop_struct = g_ptr_array_index (properties, i);
631 id = g_value_get_uint (g_value_array_get_nth (prop_struct, 0));
632 src_value = g_value_get_boxed (g_value_array_get_nth (prop_struct, 1));
634 for (j = 0; j < priv->properties->len; j++) {
635 property = g_ptr_array_index (priv->properties, j);
636 if (property->id == id) {
637 if (property->value) {
638 g_value_copy (src_value, property->value);
640 property->value = tp_g_value_slice_dup (src_value);
643 DEBUG ("property %s changed", property->name);
644 g_signal_emit (chat, signals[PROPERTY_CHANGED], 0,
645 property->name, property->value);
653 tp_chat_get_properties_cb (TpProxy *proxy,
654 const GPtrArray *properties,
660 DEBUG ("Error getting properties: %s", error->message);
664 tp_chat_properties_changed_cb (proxy, properties, user_data, chat);
668 tp_chat_list_properties_cb (TpProxy *proxy,
669 const GPtrArray *properties,
674 EmpathyTpChatPriv *priv = GET_PRIV (chat);
678 priv->had_properties_list = TRUE;
681 DEBUG ("Error listing properties: %s", error->message);
685 ids = g_array_sized_new (FALSE, FALSE, sizeof (guint), properties->len);
686 priv->properties = g_ptr_array_sized_new (properties->len);
687 for (i = 0; i < properties->len; i++) {
688 GValueArray *prop_struct;
689 TpChatProperty *property;
691 prop_struct = g_ptr_array_index (properties, i);
692 property = g_slice_new0 (TpChatProperty);
693 property->id = g_value_get_uint (g_value_array_get_nth (prop_struct, 0));
694 property->name = g_value_dup_string (g_value_array_get_nth (prop_struct, 1));
695 property->flags = g_value_get_uint (g_value_array_get_nth (prop_struct, 3));
697 DEBUG ("Adding property name=%s id=%d flags=%d",
698 property->name, property->id, property->flags);
699 g_ptr_array_add (priv->properties, property);
700 if (property->flags & TP_PROPERTY_FLAG_READ) {
701 g_array_append_val (ids, property->id);
705 tp_cli_properties_interface_call_get_properties (proxy, -1,
707 tp_chat_get_properties_cb,
711 g_array_free (ids, TRUE);
715 empathy_tp_chat_set_property (EmpathyTpChat *chat,
719 EmpathyTpChatPriv *priv = GET_PRIV (chat);
720 TpChatProperty *property;
723 g_return_if_fail (priv->ready);
725 for (i = 0; i < priv->properties->len; i++) {
726 property = g_ptr_array_index (priv->properties, i);
727 if (!tp_strdiff (property->name, name)) {
728 GPtrArray *properties;
731 GValue dest_value = {0, };
733 if (!(property->flags & TP_PROPERTY_FLAG_WRITE)) {
737 g_value_init (&id, G_TYPE_UINT);
738 g_value_init (&dest_value, G_TYPE_VALUE);
739 g_value_set_uint (&id, property->id);
740 g_value_set_boxed (&dest_value, value);
742 prop = g_value_array_new (2);
743 g_value_array_append (prop, &id);
744 g_value_array_append (prop, &dest_value);
746 properties = g_ptr_array_sized_new (1);
747 g_ptr_array_add (properties, prop);
749 DEBUG ("Set property %s", name);
750 tp_cli_properties_interface_call_set_properties (priv->channel, -1,
752 (tp_cli_properties_interface_callback_for_set_properties)
754 "Seting property", NULL,
757 g_ptr_array_free (properties, TRUE);
758 g_value_array_free (prop);
766 tp_chat_channel_ready_cb (EmpathyTpChat *chat)
768 EmpathyTpChatPriv *priv = GET_PRIV (chat);
769 TpConnection *connection;
770 guint handle, handle_type;
772 DEBUG ("Channel ready");
774 g_object_get (priv->channel,
775 "connection", &connection,
777 "handle_type", &handle_type,
780 if (handle_type != TP_HANDLE_TYPE_NONE && handle != 0) {
784 handles = g_array_new (FALSE, FALSE, sizeof (guint));
785 g_array_append_val (handles, handle);
786 tp_cli_connection_run_inspect_handles (connection, -1,
787 handle_type, handles,
790 g_array_free (handles, TRUE);
794 if (handle_type == TP_HANDLE_TYPE_CONTACT && handle != 0) {
795 priv->remote_contact = empathy_contact_factory_get_from_handle (priv->factory,
798 g_object_notify (G_OBJECT (chat), "remote-contact");
801 if (tp_proxy_has_interface_by_id (priv->channel,
802 TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP)) {
803 priv->group = empathy_tp_group_new (priv->channel);
805 g_signal_connect (priv->group, "member-added",
806 G_CALLBACK (tp_chat_member_added_cb),
808 g_signal_connect (priv->group, "member-removed",
809 G_CALLBACK (tp_chat_member_removed_cb),
811 g_signal_connect (priv->group, "local-pending",
812 G_CALLBACK (tp_chat_local_pending_cb),
814 empathy_run_until_ready (priv->group);
816 priv->members_count = 2;
819 if (tp_proxy_has_interface_by_id (priv->channel,
820 TP_IFACE_QUARK_PROPERTIES_INTERFACE)) {
821 tp_cli_properties_interface_call_list_properties (priv->channel, -1,
822 tp_chat_list_properties_cb,
825 tp_cli_properties_interface_connect_to_properties_changed (priv->channel,
826 tp_chat_properties_changed_cb,
828 G_OBJECT (chat), NULL);
829 tp_cli_properties_interface_connect_to_property_flags_changed (priv->channel,
830 tp_chat_property_flags_changed_cb,
832 G_OBJECT (chat), NULL);
835 priv->listing_pending_messages = TRUE;
836 tp_cli_channel_type_text_call_list_pending_messages (priv->channel, -1,
838 tp_chat_list_pending_messages_cb,
842 tp_cli_channel_type_text_connect_to_received (priv->channel,
845 G_OBJECT (chat), NULL);
846 tp_cli_channel_type_text_connect_to_sent (priv->channel,
849 G_OBJECT (chat), NULL);
850 tp_cli_channel_type_text_connect_to_send_error (priv->channel,
851 tp_chat_send_error_cb,
853 G_OBJECT (chat), NULL);
854 tp_cli_channel_interface_chat_state_connect_to_chat_state_changed (priv->channel,
855 tp_chat_state_changed_cb,
857 G_OBJECT (chat), NULL);
858 tp_cli_channel_interface_chat_state_connect_to_chat_state_changed (priv->channel,
859 tp_chat_state_changed_cb,
861 G_OBJECT (chat), NULL);
864 g_object_notify (G_OBJECT (chat), "ready");
868 tp_chat_finalize (GObject *object)
870 EmpathyTpChatPriv *priv = GET_PRIV (object);
873 DEBUG ("Finalize: %p", object);
875 if (priv->acknowledge && priv->channel) {
876 DEBUG ("Closing channel...");
877 tp_cli_channel_call_close (priv->channel, -1,
879 "closing channel", NULL,
884 g_signal_handlers_disconnect_by_func (priv->channel,
885 tp_chat_invalidated_cb,
887 g_object_unref (priv->channel);
890 if (priv->properties) {
891 for (i = 0; i < priv->properties->len; i++) {
892 TpChatProperty *property;
894 property = g_ptr_array_index (priv->properties, i);
895 g_free (property->name);
896 if (property->value) {
897 tp_g_value_slice_free (property->value);
899 g_slice_free (TpChatProperty, property);
901 g_ptr_array_free (priv->properties, TRUE);
904 if (priv->remote_contact) {
905 g_object_unref (priv->remote_contact);
908 g_object_unref (priv->group);
911 g_object_unref (priv->contact_monitor);
912 g_object_unref (priv->factory);
913 g_object_unref (priv->user);
914 g_object_unref (priv->account);
917 if (priv->message_queue) {
918 EmpathyMessage *message;
919 EmpathyContact *contact;
921 message = priv->message_queue->data;
922 contact = empathy_message_get_sender (message);
923 g_signal_handlers_disconnect_by_func (contact,
924 tp_chat_sender_ready_notify_cb,
927 g_slist_foreach (priv->message_queue, (GFunc) g_object_unref, NULL);
928 g_slist_free (priv->message_queue);
930 G_OBJECT_CLASS (empathy_tp_chat_parent_class)->finalize (object);
934 tp_chat_constructor (GType type,
936 GObjectConstructParam *props)
939 EmpathyTpChatPriv *priv;
940 gboolean channel_ready;
942 chat = G_OBJECT_CLASS (empathy_tp_chat_parent_class)->constructor (type, n_props, props);
944 priv = GET_PRIV (chat);
945 priv->account = empathy_channel_get_account (priv->channel);
946 priv->factory = empathy_contact_factory_new ();
947 priv->user = empathy_contact_factory_get_user (priv->factory, priv->account);
949 g_signal_connect (priv->channel, "invalidated",
950 G_CALLBACK (tp_chat_invalidated_cb),
953 g_object_get (priv->channel, "channel-ready", &channel_ready, NULL);
955 tp_chat_channel_ready_cb (EMPATHY_TP_CHAT (chat));
957 g_signal_connect_swapped (priv->channel, "notify::channel-ready",
958 G_CALLBACK (tp_chat_channel_ready_cb),
966 tp_chat_get_property (GObject *object,
971 EmpathyTpChatPriv *priv = GET_PRIV (object);
975 g_value_set_object (value, priv->channel);
977 case PROP_ACKNOWLEDGE:
978 g_value_set_boolean (value, priv->acknowledge);
980 case PROP_REMOTE_CONTACT:
981 g_value_set_object (value, priv->remote_contact);
984 g_value_set_boolean (value, priv->ready);
987 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
993 tp_chat_set_property (GObject *object,
998 EmpathyTpChatPriv *priv = GET_PRIV (object);
1002 priv->channel = g_object_ref (g_value_get_object (value));
1004 case PROP_ACKNOWLEDGE:
1005 priv->acknowledge = g_value_get_boolean (value);
1008 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1014 empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
1016 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1018 object_class->finalize = tp_chat_finalize;
1019 object_class->constructor = tp_chat_constructor;
1020 object_class->get_property = tp_chat_get_property;
1021 object_class->set_property = tp_chat_set_property;
1023 g_object_class_install_property (object_class,
1025 g_param_spec_object ("channel",
1026 "telepathy channel",
1027 "The text channel for the chat",
1030 G_PARAM_CONSTRUCT_ONLY));
1031 g_object_class_install_property (object_class,
1033 g_param_spec_boolean ("acknowledge",
1034 "acknowledge messages",
1035 "Wheter or not received messages should be acknowledged",
1037 G_PARAM_READWRITE));
1039 g_object_class_install_property (object_class,
1040 PROP_REMOTE_CONTACT,
1041 g_param_spec_object ("remote-contact",
1042 "The remote contact",
1043 "The remote contact if there is no group iface on the channel",
1044 EMPATHY_TYPE_CONTACT,
1046 g_object_class_install_property (object_class,
1048 g_param_spec_boolean ("ready",
1049 "Is the object ready",
1050 "This object can't be used until this becomes true",
1055 signals[MESSAGE_RECEIVED] =
1056 g_signal_new ("message-received",
1057 G_TYPE_FROM_CLASS (klass),
1061 g_cclosure_marshal_VOID__OBJECT,
1063 1, EMPATHY_TYPE_MESSAGE);
1065 signals[SEND_ERROR] =
1066 g_signal_new ("send-error",
1067 G_TYPE_FROM_CLASS (klass),
1071 _empathy_marshal_VOID__OBJECT_UINT,
1073 2, EMPATHY_TYPE_MESSAGE, G_TYPE_UINT);
1075 signals[CHAT_STATE_CHANGED] =
1076 g_signal_new ("chat-state-changed",
1077 G_TYPE_FROM_CLASS (klass),
1081 _empathy_marshal_VOID__OBJECT_UINT,
1083 2, EMPATHY_TYPE_CONTACT, G_TYPE_UINT);
1085 signals[PROPERTY_CHANGED] =
1086 g_signal_new ("property-changed",
1087 G_TYPE_FROM_CLASS (klass),
1091 _empathy_marshal_VOID__STRING_BOXED,
1093 2, G_TYPE_STRING, G_TYPE_VALUE);
1096 g_signal_new ("destroy",
1097 G_TYPE_FROM_CLASS (klass),
1101 g_cclosure_marshal_VOID__VOID,
1105 g_type_class_add_private (object_class, sizeof (EmpathyTpChatPriv));
1109 empathy_tp_chat_init (EmpathyTpChat *chat)
1111 EmpathyTpChatPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (chat,
1112 EMPATHY_TYPE_TP_CHAT, EmpathyTpChatPriv);
1115 priv->contact_monitor = empathy_contact_monitor_new_for_proxy (EMPATHY_CONTACT_LIST (chat));
1119 tp_chat_iface_init (EmpathyContactListIface *iface)
1121 iface->add = tp_chat_add;
1122 iface->remove = tp_chat_remove;
1123 iface->get_members = tp_chat_get_members;
1124 iface->get_monitor = tp_chat_get_monitor;
1128 empathy_tp_chat_new (TpChannel *channel)
1130 return g_object_new (EMPATHY_TYPE_TP_CHAT,
1136 empathy_tp_chat_get_id (EmpathyTpChat *chat)
1138 EmpathyTpChatPriv *priv = GET_PRIV (chat);
1140 g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL);
1141 g_return_val_if_fail (priv->ready, NULL);
1147 empathy_tp_chat_get_remote_contact (EmpathyTpChat *chat)
1149 EmpathyTpChatPriv *priv = GET_PRIV (chat);
1151 g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL);
1153 return priv->remote_contact;
1157 empathy_tp_chat_get_account (EmpathyTpChat *chat)
1159 EmpathyTpChatPriv *priv = GET_PRIV (chat);
1161 g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), FALSE);
1163 return priv->account;
1167 empathy_tp_chat_get_channel (EmpathyTpChat *chat)
1169 EmpathyTpChatPriv *priv = GET_PRIV (chat);
1171 g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL);
1173 return priv->channel;
1177 empathy_tp_chat_is_ready (EmpathyTpChat *chat)
1179 EmpathyTpChatPriv *priv = GET_PRIV (chat);
1181 g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), FALSE);
1187 empathy_tp_chat_get_members_count (EmpathyTpChat *chat)
1189 EmpathyTpChatPriv *priv = GET_PRIV (chat);
1191 g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), 0);
1193 return priv->members_count;
1197 empathy_tp_chat_set_acknowledge (EmpathyTpChat *chat,
1198 gboolean acknowledge)
1200 EmpathyTpChatPriv *priv = GET_PRIV (chat);
1202 g_return_if_fail (EMPATHY_IS_TP_CHAT (chat));
1204 priv->acknowledge = acknowledge;
1205 g_object_notify (G_OBJECT (chat), "acknowledge");
1209 empathy_tp_chat_emit_pendings (EmpathyTpChat *chat)
1211 EmpathyTpChatPriv *priv = GET_PRIV (chat);
1213 g_return_if_fail (EMPATHY_IS_TP_CHAT (chat));
1214 g_return_if_fail (priv->ready);
1216 if (priv->listing_pending_messages) {
1220 priv->listing_pending_messages = TRUE;
1221 tp_cli_channel_type_text_call_list_pending_messages (priv->channel, -1,
1223 tp_chat_list_pending_messages_cb,
1229 empathy_tp_chat_send (EmpathyTpChat *chat,
1230 EmpathyMessage *message)
1232 EmpathyTpChatPriv *priv = GET_PRIV (chat);
1233 const gchar *message_body;
1234 TpChannelTextMessageType message_type;
1236 g_return_if_fail (EMPATHY_IS_TP_CHAT (chat));
1237 g_return_if_fail (EMPATHY_IS_MESSAGE (message));
1238 g_return_if_fail (priv->ready);
1240 message_body = empathy_message_get_body (message);
1241 message_type = empathy_message_get_tptype (message);
1243 DEBUG ("Sending message: %s", message_body);
1244 tp_cli_channel_type_text_call_send (priv->channel, -1,
1248 g_object_ref (message),
1249 (GDestroyNotify) g_object_unref,
1254 empathy_tp_chat_set_state (EmpathyTpChat *chat,
1255 TpChannelChatState state)
1257 EmpathyTpChatPriv *priv = GET_PRIV (chat);
1259 g_return_if_fail (EMPATHY_IS_TP_CHAT (chat));
1260 g_return_if_fail (priv->ready);
1262 DEBUG ("Set state: %d", state);
1263 tp_cli_channel_interface_chat_state_call_set_chat_state (priv->channel, -1,
1266 "setting chat state",