]> git.0d.be Git - empathy.git/blob - libempathy/empathy-tp-chat.c
Queue received messages until the sender got his alias.
[empathy.git] / libempathy / empathy-tp-chat.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007-2008 Collabora Ltd.
4  *
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.
9  *
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.
14  *
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
18  * 
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include <config.h>
23
24 #include <string.h>
25
26 #include <telepathy-glib/channel.h>
27 #include <telepathy-glib/dbus.h>
28
29 #include "empathy-tp-chat.h"
30 #include "empathy-contact-factory.h"
31 #include "empathy-marshal.h"
32 #include "empathy-debug.h"
33 #include "empathy-time.h"
34 #include "empathy-utils.h"
35
36 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
37                        EMPATHY_TYPE_TP_CHAT, EmpathyTpChatPriv))
38
39 #define DEBUG_DOMAIN "TpChat"
40
41 struct _EmpathyTpChatPriv {
42         EmpathyContactFactory *factory;
43         EmpathyContact        *user;
44         McAccount             *account;
45         TpChannel             *channel;
46         gchar                 *id;
47         MissionControl        *mc;
48         gboolean               acknowledge;
49         TpChan                *tp_chan;
50         gboolean               had_pending_messages;
51         GSList                *message_queue;
52 };
53
54 static void empathy_tp_chat_class_init (EmpathyTpChatClass *klass);
55 static void empathy_tp_chat_init       (EmpathyTpChat      *chat);
56
57 enum {
58         PROP_0,
59         PROP_ACCOUNT,
60         PROP_CHANNEL,
61         PROP_ACKNOWLEDGE,
62 };
63
64 enum {
65         MESSAGE_RECEIVED,
66         SEND_ERROR,
67         CHAT_STATE_CHANGED,
68         DESTROY,
69         LAST_SIGNAL
70 };
71
72 static guint signals[LAST_SIGNAL];
73
74 G_DEFINE_TYPE (EmpathyTpChat, empathy_tp_chat, G_TYPE_OBJECT);
75
76 static void
77 tp_chat_invalidated_cb (TpProxy       *proxy,
78                         guint          domain,
79                         gint           code,
80                         gchar         *message,
81                         EmpathyTpChat *chat)
82 {
83         EmpathyTpChatPriv *priv = GET_PRIV (chat);
84
85         empathy_debug (DEBUG_DOMAIN, "Channel invalidated: %s", message);
86
87         g_object_unref (priv->channel);
88         g_object_unref (priv->tp_chan);
89         priv->channel = NULL;
90         priv->tp_chan = NULL;
91
92         g_signal_emit (chat, signals[DESTROY], 0);
93 }
94
95 static void
96 tp_chat_async_cb (TpChannel *proxy,
97                   const GError *error,
98                   gpointer user_data,
99                   GObject *weak_object)
100 {
101         if (error) {
102                 empathy_debug (DEBUG_DOMAIN, "Error %s: %s",
103                                user_data, error->message);
104         }
105 }
106
107 static EmpathyMessage *
108 tp_chat_build_message (EmpathyTpChat *chat,
109                        guint          type,
110                        guint          timestamp,
111                        guint          from_handle,
112                        const gchar   *message_body)
113 {
114         EmpathyTpChatPriv *priv;
115         EmpathyMessage    *message;
116         EmpathyContact    *sender;
117
118         priv = GET_PRIV (chat);
119
120         if (from_handle == 0) {
121                 sender = g_object_ref (priv->user);
122         } else {
123                 sender = empathy_contact_factory_get_from_handle (priv->factory,
124                                                                   priv->account,
125                                                                   from_handle);
126         }
127
128         message = empathy_message_new (message_body);
129         empathy_message_set_type (message, type);
130         empathy_message_set_sender (message, sender);
131         empathy_message_set_receiver (message, priv->user);
132         empathy_message_set_timestamp (message, timestamp);
133
134         g_object_unref (sender);
135
136         return message;
137 }
138
139 static void
140 tp_chat_sender_ready_notify_cb (EmpathyContact *contact,
141                                 GParamSpec     *param_spec,
142                                 EmpathyTpChat  *chat)
143 {
144         EmpathyTpChatPriv   *priv = GET_PRIV (chat);
145         EmpathyMessage      *message;
146         EmpathyContactReady  ready;
147         EmpathyContact      *sender;
148         gboolean             removed = FALSE;
149
150         /* Emit all messages queued until we find a message with not
151          * ready sender. When leaving this loop, sender is the first not ready
152          * contact queued and removed tells if at least one message got removed
153          * from the queue. */
154         while (priv->message_queue) {
155                 message = priv->message_queue->data;
156                 sender = empathy_message_get_sender (message);
157                 ready = empathy_contact_get_ready (sender);
158
159                 if (!(ready & EMPATHY_CONTACT_READY_NAME)) {
160                         break;
161                 }
162
163                 empathy_debug (DEBUG_DOMAIN, "Queued message ready");
164                 g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
165                 priv->message_queue = g_slist_remove (priv->message_queue,
166                                                       message);
167                 g_object_unref (message);
168                 removed = TRUE;
169         }
170
171         if (removed) {
172                 g_signal_handlers_disconnect_by_func (contact,
173                                                       tp_chat_sender_ready_notify_cb,
174                                                       chat);
175
176                 if (priv->message_queue) {
177                         g_signal_connect (sender, "notify::ready",
178                                           G_CALLBACK (tp_chat_sender_ready_notify_cb),
179                                           chat);
180                 }
181         }
182 }
183
184 static void
185 tp_chat_emit_or_queue_message (EmpathyTpChat  *chat,
186                                EmpathyMessage *message)
187 {
188         EmpathyTpChatPriv   *priv = GET_PRIV (chat);
189         EmpathyContact      *sender;
190         EmpathyContactReady  ready;
191
192         if (priv->message_queue != NULL) {
193                 empathy_debug (DEBUG_DOMAIN, "Message queue not empty");
194                 priv->message_queue = g_slist_append (priv->message_queue,
195                                                       g_object_ref (message));
196                 return;
197         }
198
199         sender = empathy_message_get_sender (message);
200         ready = empathy_contact_get_ready (sender);
201         if (ready & EMPATHY_CONTACT_READY_NAME) {
202                 empathy_debug (DEBUG_DOMAIN, "Message queue empty and sender ready");
203                 g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
204                 return;
205         }
206
207         empathy_debug (DEBUG_DOMAIN, "Sender not ready");
208         priv->message_queue = g_slist_append (priv->message_queue, 
209                                               g_object_ref (message));
210         g_signal_connect (sender, "notify::ready",
211                           G_CALLBACK (tp_chat_sender_ready_notify_cb),
212                           chat);
213 }
214
215 static void
216 tp_chat_received_cb (TpChannel   *channel,
217                      guint        message_id,
218                      guint        timestamp,
219                      guint        from_handle,
220                      guint        message_type,
221                      guint        message_flags,
222                      const gchar *message_body,
223                      gpointer     user_data,
224                      GObject     *chat)
225 {
226         EmpathyTpChatPriv *priv = GET_PRIV (chat);
227         EmpathyMessage    *message;
228
229         if (!priv->had_pending_messages) {
230                 return;
231         }
232  
233         empathy_debug (DEBUG_DOMAIN, "Message received: %s", message_body);
234
235         message = tp_chat_build_message (EMPATHY_TP_CHAT (chat),
236                                          message_type,
237                                          timestamp,
238                                          from_handle,
239                                          message_body);
240
241         tp_chat_emit_or_queue_message (EMPATHY_TP_CHAT (chat), message);
242         g_object_unref (message);
243
244         if (priv->acknowledge) {
245                 GArray *message_ids;
246
247                 message_ids = g_array_new (FALSE, FALSE, sizeof (guint));
248                 g_array_append_val (message_ids, message_id);
249                 tp_cli_channel_type_text_call_acknowledge_pending_messages (priv->channel,
250                                                                             -1,
251                                                                             message_ids,
252                                                                             tp_chat_async_cb,
253                                                                             "acknowledging pending messages",
254                                                                             NULL,
255                                                                             chat);
256                 g_array_free (message_ids, TRUE);
257         }
258 }
259
260 static void
261 tp_chat_sent_cb (TpChannel   *channel,
262                  guint        timestamp,
263                  guint        message_type,
264                  const gchar *message_body,
265                  gpointer     user_data,
266                  GObject     *chat)
267 {
268         EmpathyMessage *message;
269
270         empathy_debug (DEBUG_DOMAIN, "Message sent: %s", message_body);
271
272         message = tp_chat_build_message (EMPATHY_TP_CHAT (chat),
273                                          message_type,
274                                          timestamp,
275                                          0,
276                                          message_body);
277
278         tp_chat_emit_or_queue_message (EMPATHY_TP_CHAT (chat), message);
279         g_object_unref (message);
280 }
281
282 static void
283 tp_chat_send_error_cb (TpChannel   *channel,
284                        guint        error_code,
285                        guint        timestamp,
286                        guint        message_type,
287                        const gchar *message_body,
288                        gpointer     user_data,
289                        GObject     *chat)
290 {
291         EmpathyMessage *message;
292
293         empathy_debug (DEBUG_DOMAIN, "Message sent error: %s (%d)",
294                        message_body, error_code);
295
296         message = tp_chat_build_message (EMPATHY_TP_CHAT (chat),
297                                          message_type,
298                                          timestamp,
299                                          0,
300                                          message_body);
301
302         g_signal_emit (chat, signals[SEND_ERROR], 0, message, error_code);
303         g_object_unref (message);
304 }
305
306 static void
307 tp_chat_state_changed_cb (TpChannel *channel,
308                           guint      handle,
309                           guint      state,
310                           gpointer   user_data,
311                           GObject   *chat)
312 {
313         EmpathyTpChatPriv *priv = GET_PRIV (chat);
314         EmpathyContact    *contact;
315
316         contact = empathy_contact_factory_get_from_handle (priv->factory,
317                                                            priv->account,
318                                                            handle);
319
320         empathy_debug (DEBUG_DOMAIN, "Chat state changed for %s (%d): %d",
321                       empathy_contact_get_name (contact),
322                       handle, state);
323
324         g_signal_emit (chat, signals[CHAT_STATE_CHANGED], 0, contact, state);
325         g_object_unref (contact);
326 }
327
328 static void
329 tp_chat_list_pending_messages_cb (TpChannel       *channel,
330                                   const GPtrArray *messages_list,
331                                   const GError    *error,
332                                   gpointer         user_data,
333                                   GObject         *chat)
334 {
335         EmpathyTpChatPriv *priv = GET_PRIV (chat);
336         guint              i;
337
338         priv->had_pending_messages = TRUE;
339
340         for (i = 0; i < messages_list->len; i++) {
341                 EmpathyMessage *message;
342                 GValueArray    *message_struct;
343                 const gchar    *message_body;
344                 guint           message_id;
345                 guint           timestamp;
346                 guint           from_handle;
347                 guint           message_type;
348                 guint           message_flags;
349
350                 message_struct = g_ptr_array_index (messages_list, i);
351
352                 message_id = g_value_get_uint (g_value_array_get_nth (message_struct, 0));
353                 timestamp = g_value_get_uint (g_value_array_get_nth (message_struct, 1));
354                 from_handle = g_value_get_uint (g_value_array_get_nth (message_struct, 2));
355                 message_type = g_value_get_uint (g_value_array_get_nth (message_struct, 3));
356                 message_flags = g_value_get_uint (g_value_array_get_nth (message_struct, 4));
357                 message_body = g_value_get_string (g_value_array_get_nth (message_struct, 5));
358
359                 empathy_debug (DEBUG_DOMAIN, "Message pending: %s", message_body);
360
361                 message = tp_chat_build_message (EMPATHY_TP_CHAT (chat),
362                                                  message_type,
363                                                  timestamp,
364                                                  from_handle,
365                                                  message_body);
366
367                 tp_chat_emit_or_queue_message (EMPATHY_TP_CHAT (chat), message);
368                 g_object_unref (message);
369         }
370 }
371
372 static gboolean
373 tp_chat_channel_ready_cb (EmpathyTpChat *chat)
374 {
375         EmpathyTpChatPriv *priv = GET_PRIV (chat);
376
377         empathy_debug (DEBUG_DOMAIN, "Channel ready");
378
379         tp_cli_channel_type_text_call_list_pending_messages (priv->channel, -1,
380                                                              priv->acknowledge,
381                                                              tp_chat_list_pending_messages_cb,
382                                                              NULL, NULL,
383                                                              G_OBJECT (chat));
384
385         tp_cli_channel_type_text_connect_to_received (priv->channel,
386                                                       tp_chat_received_cb,
387                                                       NULL, NULL,
388                                                       G_OBJECT (chat), NULL);
389         tp_cli_channel_type_text_connect_to_sent (priv->channel,
390                                                   tp_chat_sent_cb,
391                                                   NULL, NULL,
392                                                   G_OBJECT (chat), NULL);
393         tp_cli_channel_type_text_connect_to_send_error (priv->channel,
394                                                         tp_chat_send_error_cb,
395                                                         NULL, NULL,
396                                                         G_OBJECT (chat), NULL);
397         tp_cli_channel_interface_chat_state_connect_to_chat_state_changed (priv->channel,
398                                                                            tp_chat_state_changed_cb,
399                                                                            NULL, NULL,
400                                                                            G_OBJECT (chat), NULL);
401
402         return FALSE;
403 }
404
405 static void
406 tp_chat_finalize (GObject *object)
407 {
408         EmpathyTpChatPriv *priv = GET_PRIV (object);
409
410         if (priv->acknowledge) {
411                 empathy_debug (DEBUG_DOMAIN, "Closing channel...");
412                 tp_cli_channel_call_close (priv->channel, -1,
413                                            tp_chat_async_cb,
414                                            "closing channel", NULL,
415                                            NULL);
416         }
417
418         if (priv->channel) {
419                 g_signal_handlers_disconnect_by_func (priv->channel,
420                                                       tp_chat_invalidated_cb,
421                                                       object);
422                 g_object_unref (priv->channel);
423         }
424         if (priv->tp_chan) {
425                 g_object_unref (priv->tp_chan);
426         }
427
428         g_object_unref (priv->factory);
429         g_object_unref (priv->user);
430         g_object_unref (priv->account);
431         g_object_unref (priv->mc);
432         g_free (priv->id);
433
434         G_OBJECT_CLASS (empathy_tp_chat_parent_class)->finalize (object);
435 }
436
437 static GObject *
438 tp_chat_constructor (GType                  type,
439                      guint                  n_props,
440                      GObjectConstructParam *props)
441 {
442         GObject           *chat;
443         EmpathyTpChatPriv *priv;
444         gboolean           channel_ready;
445
446         chat = G_OBJECT_CLASS (empathy_tp_chat_parent_class)->constructor (type, n_props, props);
447
448         priv = GET_PRIV (chat);
449         priv->factory = empathy_contact_factory_new ();
450         priv->user = empathy_contact_factory_get_user (priv->factory, priv->account);
451         priv->mc = empathy_mission_control_new ();
452
453         g_signal_connect (priv->channel, "invalidated",
454                           G_CALLBACK (tp_chat_invalidated_cb),
455                           chat);
456
457         g_object_get (priv->channel, "channel-ready", &channel_ready, NULL);
458         if (channel_ready) {
459                 /* FIXME: We do that in a cb to let time to set the acknowledge
460                  * property, this property should be required for construct. */
461                 g_idle_add ((GSourceFunc) tp_chat_channel_ready_cb, chat);
462         } else {
463                 g_signal_connect_swapped (priv->channel, "notify::channel-ready",
464                                           G_CALLBACK (tp_chat_channel_ready_cb),
465                                           chat);
466         }
467
468         /* FIXME: We do that in a cb to let time to set the acknowledge
469          * property, this property should be required for construct. */
470         g_idle_add ((GSourceFunc) empathy_tp_chat_get_pendings, chat);
471
472         return chat;
473 }
474
475 static void
476 tp_chat_get_property (GObject    *object,
477                       guint       param_id,
478                       GValue     *value,
479                       GParamSpec *pspec)
480 {
481         EmpathyTpChatPriv *priv = GET_PRIV (object);
482
483         switch (param_id) {
484         case PROP_ACCOUNT:
485                 g_value_set_object (value, priv->account);
486                 break;
487         case PROP_CHANNEL:
488                 g_value_set_object (value, priv->channel);
489                 break;
490         case PROP_ACKNOWLEDGE:
491                 g_value_set_boolean (value, priv->acknowledge);
492                 break;
493         default:
494                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
495                 break;
496         };
497 }
498
499 static void
500 tp_chat_set_property (GObject      *object,
501                       guint         param_id,
502                       const GValue *value,
503                       GParamSpec   *pspec)
504 {
505         EmpathyTpChatPriv *priv = GET_PRIV (object);
506
507         switch (param_id) {
508         case PROP_ACCOUNT:
509                 priv->account = g_object_ref (g_value_get_object (value));
510                 break;
511         case PROP_CHANNEL:
512                 priv->channel = g_object_ref (g_value_get_object (value));
513                 break;
514         case PROP_ACKNOWLEDGE:
515                 empathy_tp_chat_set_acknowledge (EMPATHY_TP_CHAT (object),
516                                                  g_value_get_boolean (value));
517                 break;
518         default:
519                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
520                 break;
521         };
522 }
523
524 static void
525 empathy_tp_chat_class_init (EmpathyTpChatClass *klass)
526 {
527         GObjectClass *object_class = G_OBJECT_CLASS (klass);
528
529         object_class->finalize = tp_chat_finalize;
530         object_class->constructor = tp_chat_constructor;
531         object_class->get_property = tp_chat_get_property;
532         object_class->set_property = tp_chat_set_property;
533
534         /* Construct properties */
535         g_object_class_install_property (object_class,
536                                          PROP_ACCOUNT,
537                                          g_param_spec_object ("account",
538                                                               "channel Account",
539                                                               "The account associated with the channel",
540                                                               MC_TYPE_ACCOUNT,
541                                                               G_PARAM_READWRITE |
542                                                               G_PARAM_CONSTRUCT_ONLY));
543         g_object_class_install_property (object_class,
544                                          PROP_CHANNEL,
545                                          g_param_spec_object ("channel",
546                                                               "telepathy channel",
547                                                               "The text channel for the chat",
548                                                               TP_TYPE_CHANNEL,
549                                                               G_PARAM_READWRITE |
550                                                               G_PARAM_CONSTRUCT_ONLY));
551
552         g_object_class_install_property (object_class,
553                                          PROP_ACKNOWLEDGE,
554                                          g_param_spec_boolean ("acknowledge",
555                                                                "acknowledge messages",
556                                                                "Wheter or not received messages should be acknowledged",
557                                                                FALSE,
558                                                                G_PARAM_READWRITE |
559                                                                G_PARAM_CONSTRUCT));
560
561         /* Signals */
562         signals[MESSAGE_RECEIVED] =
563                 g_signal_new ("message-received",
564                               G_TYPE_FROM_CLASS (klass),
565                               G_SIGNAL_RUN_LAST,
566                               0,
567                               NULL, NULL,
568                               g_cclosure_marshal_VOID__OBJECT,
569                               G_TYPE_NONE,
570                               1, EMPATHY_TYPE_MESSAGE);
571
572         signals[SEND_ERROR] =
573                 g_signal_new ("send-error",
574                               G_TYPE_FROM_CLASS (klass),
575                               G_SIGNAL_RUN_LAST,
576                               0,
577                               NULL, NULL,
578                               _empathy_marshal_VOID__OBJECT_UINT,
579                               G_TYPE_NONE,
580                               2, EMPATHY_TYPE_MESSAGE, G_TYPE_UINT);
581
582         signals[CHAT_STATE_CHANGED] =
583                 g_signal_new ("chat-state-changed",
584                               G_TYPE_FROM_CLASS (klass),
585                               G_SIGNAL_RUN_LAST,
586                               0,
587                               NULL, NULL,
588                               _empathy_marshal_VOID__OBJECT_UINT,
589                               G_TYPE_NONE,
590                               2, EMPATHY_TYPE_CONTACT, G_TYPE_UINT);
591
592         signals[DESTROY] =
593                 g_signal_new ("destroy",
594                               G_TYPE_FROM_CLASS (klass),
595                               G_SIGNAL_RUN_LAST,
596                               0,
597                               NULL, NULL,
598                               g_cclosure_marshal_VOID__VOID,
599                               G_TYPE_NONE,
600                               0);
601
602         g_type_class_add_private (object_class, sizeof (EmpathyTpChatPriv));
603 }
604
605 static void
606 empathy_tp_chat_init (EmpathyTpChat *chat)
607 {
608 }
609
610 EmpathyTpChat *
611 empathy_tp_chat_new (McAccount *account,
612                      TpChan    *tp_chan)
613 {
614         EmpathyTpChat     *chat;
615         EmpathyTpChatPriv *priv;
616         TpChannel         *channel;
617         TpConnection      *connection;
618         MissionControl    *mc;
619         TpConn            *tp_conn;
620
621         mc = empathy_mission_control_new ();
622         tp_conn = mission_control_get_connection (mc, account, NULL);
623         connection = tp_conn_dup_connection (tp_conn);
624         channel = tp_chan_dup_channel (tp_chan, connection, NULL);
625
626         chat = g_object_new (EMPATHY_TYPE_TP_CHAT, 
627                              "account", account,
628                              "channel", channel,
629                              NULL);
630
631         priv = GET_PRIV (chat);
632         priv->tp_chan = g_object_ref (tp_chan);
633
634         g_object_unref (channel);
635         g_object_unref (tp_conn);
636         g_object_unref (connection);
637         g_object_unref (mc);
638
639         return chat;
640 }
641
642 EmpathyTpChat *
643 empathy_tp_chat_new_with_contact (EmpathyContact *contact)
644 {
645         EmpathyTpChat  *chat;
646         MissionControl *mc;
647         McAccount      *account;
648         TpConn         *tp_conn;
649         TpChan         *text_chan;
650         const gchar    *bus_name;
651         guint           handle;
652
653         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
654
655         mc = empathy_mission_control_new ();
656         account = empathy_contact_get_account (contact);
657
658         if (mission_control_get_connection_status (mc, account, NULL) != 0) {
659                 /* The account is not connected. */
660                 return NULL;
661         }
662
663         tp_conn = mission_control_get_connection (mc, account, NULL);
664         g_return_val_if_fail (tp_conn != NULL, NULL);
665         bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (tp_conn));
666         handle = empathy_contact_get_handle (contact);
667
668         text_chan = tp_conn_new_channel (tp_get_bus (),
669                                          tp_conn,
670                                          bus_name,
671                                          TP_IFACE_CHANNEL_TYPE_TEXT,
672                                          TP_HANDLE_TYPE_CONTACT,
673                                          handle,
674                                          TRUE);
675
676         chat = empathy_tp_chat_new (account, text_chan);
677
678         g_object_unref (tp_conn);
679         g_object_unref (text_chan);
680         g_object_unref (mc);
681
682         return chat;
683 }
684
685 gboolean
686 empathy_tp_chat_get_acknowledge (EmpathyTpChat *chat)
687 {
688         EmpathyTpChatPriv *priv;
689
690         g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), FALSE);
691
692         priv = GET_PRIV (chat);
693
694         return priv->acknowledge;
695 }
696
697 void
698 empathy_tp_chat_set_acknowledge (EmpathyTpChat *chat,
699                                  gboolean       acknowledge)
700 {
701         EmpathyTpChatPriv *priv;
702
703         g_return_if_fail (EMPATHY_IS_TP_CHAT (chat));
704
705         priv = GET_PRIV (chat);
706
707         priv->acknowledge = acknowledge;
708         g_object_notify (G_OBJECT (chat), "acknowledge");
709 }
710
711 TpChan *
712 empathy_tp_chat_get_channel (EmpathyTpChat *chat)
713 {
714         EmpathyTpChatPriv *priv;
715
716         g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL);
717
718         priv = GET_PRIV (chat);
719
720         return priv->tp_chan;
721 }
722
723 McAccount *
724 empathy_tp_chat_get_account (EmpathyTpChat *chat)
725 {
726         EmpathyTpChatPriv *priv;
727
728         g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL);
729
730         priv = GET_PRIV (chat);
731
732         return priv->account;
733 }
734
735 void
736 empathy_tp_chat_send (EmpathyTpChat *chat,
737                       EmpathyMessage *message)
738 {
739         EmpathyTpChatPriv  *priv;
740         const gchar        *message_body;
741         EmpathyMessageType  message_type;
742
743         g_return_if_fail (EMPATHY_IS_TP_CHAT (chat));
744         g_return_if_fail (EMPATHY_IS_MESSAGE (message));
745
746         priv = GET_PRIV (chat);
747
748         message_body = empathy_message_get_body (message);
749         message_type = empathy_message_get_type (message);
750
751         empathy_debug (DEBUG_DOMAIN, "Sending message: %s", message_body);
752         tp_cli_channel_type_text_call_send (priv->channel, -1,
753                                             message_type,
754                                             message_body,
755                                             tp_chat_async_cb,
756                                             "sending message", NULL,
757                                             G_OBJECT (chat));
758 }
759
760 void
761 empathy_tp_chat_set_state (EmpathyTpChat      *chat,
762                            TpChannelChatState  state)
763 {
764         EmpathyTpChatPriv *priv;
765
766         g_return_if_fail (EMPATHY_IS_TP_CHAT (chat));
767
768         priv = GET_PRIV (chat);
769
770         empathy_debug (DEBUG_DOMAIN, "Set state: %d", state);
771         tp_cli_channel_interface_chat_state_call_set_chat_state (priv->channel, -1,
772                                                                  state,
773                                                                  tp_chat_async_cb,
774                                                                  "setting chat state",
775                                                                  NULL,
776                                                                  G_OBJECT (chat));
777 }
778
779 const gchar *
780 empathy_tp_chat_get_id (EmpathyTpChat *chat)
781 {
782         EmpathyTpChatPriv *priv;
783
784         g_return_val_if_fail (EMPATHY_IS_TP_CHAT (chat), NULL);
785
786         priv = GET_PRIV (chat);
787
788         if (!priv->id) {
789                 priv->id = empathy_inspect_channel (priv->account, priv->tp_chan);
790         }
791
792         return priv->id;
793 }
794