telepathygabble/src/gabble-im-channel.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /*
       
     2  * gabble-im-channel.c - Source for GabbleIMChannel
       
     3  * Copyright (C) 2005 Collabora Ltd.
       
     4  * 
       
     5  *
       
     6  * This library is free software; you can redistribute it and/or
       
     7  * modify it under the terms of the GNU Lesser General Public
       
     8  * License as published by the Free Software Foundation; either
       
     9  * version 2.1 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This library is distributed in the hope that it will be useful,
       
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * Lesser General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU Lesser General Public
       
    17  * License along with this library; if not, write to the Free Software
       
    18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    19  */
       
    20 
       
    21 #include <dbus/dbus-glib.h>
       
    22 #include "loudmouth/loudmouth.h"
       
    23 #include <stdio.h>
       
    24 #include <string.h>
       
    25 #include <time.h>
       
    26 
       
    27 #define DEBUG_FLAG GABBLE_DEBUG_IM
       
    28 
       
    29 #include "debug.h"
       
    30 #include "disco.h"
       
    31 #include "gabble-connection.h"
       
    32 #include "gabble-presence.h"
       
    33 #include "gabble-presence-cache.h"
       
    34 #include "handles.h"
       
    35 #include "roster.h"
       
    36 #include "telepathy-constants.h"
       
    37 #include "telepathy-errors.h"
       
    38 #include "telepathy-helpers.h"
       
    39 #include "telepathy-interfaces.h"
       
    40 #include "tp-channel-iface.h"
       
    41 
       
    42 #include "gabble-im-channel.h"
       
    43 #include "gabble-im-channel-glue.h"
       
    44 #include "gabble-im-channel-signals-marshal.h"
       
    45 
       
    46 #include "gabble_enums.h"
       
    47 
       
    48 #ifndef EMULATOR
       
    49 G_DEFINE_TYPE_WITH_CODE (GabbleIMChannel, gabble_im_channel, G_TYPE_OBJECT,
       
    50     G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL));
       
    51     
       
    52 #endif
       
    53 
       
    54 /* signal enum */
       
    55 enum
       
    56 {
       
    57     CLOSED,
       
    58     LAST_SIGNAL 
       
    59 #ifdef EMULATOR    
       
    60     = LAST_SIGNAL_IM
       
    61 #endif
       
    62     
       
    63 };
       
    64 
       
    65 #ifdef EMULATOR
       
    66 #include "libgabble_wsd_solution.h"
       
    67 
       
    68 	GET_STATIC_ARRAY_FROM_TLS(signals,gabble_im,guint)
       
    69 	#define signals (GET_WSD_VAR_NAME(signals,gabble_im, s)())	
       
    70     
       
    71     GET_STATIC_VAR_FROM_TLS(gabble_im_channel_parent_class,gabble_im,gpointer)
       
    72 	#define gabble_im_channel_parent_class (*GET_WSD_VAR_NAME(gabble_im_channel_parent_class,gabble_im,s)())
       
    73 	
       
    74 	GET_STATIC_VAR_FROM_TLS(g_define_type_id,gabble_im,GType)
       
    75 	#define g_define_type_id (*GET_WSD_VAR_NAME(g_define_type_id,gabble_im,s)())
       
    76 
       
    77     
       
    78 static void gabble_im_channel_init (GabbleIMChannel *self); 
       
    79 static void gabble_im_channel_class_init (GabbleIMChannelClass *klass); 
       
    80 static void gabble_im_channel_class_intern_init (gpointer klass) 
       
    81 {
       
    82  gabble_im_channel_parent_class = g_type_class_peek_parent (klass); 
       
    83  gabble_im_channel_class_init ((GabbleIMChannelClass*) klass); 
       
    84  } 
       
    85  EXPORT_C GType gabble_im_channel_get_type (void) 
       
    86  {
       
    87   if ((g_define_type_id == 0)) 
       
    88   { static const GTypeInfo g_define_type_info = 
       
    89   		{ sizeof (GabbleIMChannelClass), (GBaseInitFunc) ((void *)0), (GBaseFinalizeFunc) ((void *)0), (GClassInitFunc) gabble_im_channel_class_intern_init, (GClassFinalizeFunc) ((void *)0), ((void *)0), sizeof (GabbleIMChannel), 0, (GInstanceInitFunc) gabble_im_channel_init, ((void *)0) }; g_define_type_id = g_type_register_static ( ((GType) ((20) << (2))), g_intern_static_string ("GabbleIMChannel"), &g_define_type_info, (GTypeFlags) 0); { { static const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc) ((void *)0) }; g_type_add_interface_static (g_define_type_id, tp_channel_iface_get_type(), &g_implement_interface_info); } ; } } return g_define_type_id; 
       
    90   		};
       
    91 	
       
    92 	
       
    93 		
       
    94 #else
       
    95 
       
    96 	static guint signals[LAST_SIGNAL] = {0};
       
    97 
       
    98 #endif
       
    99 
       
   100 /* properties */
       
   101 enum
       
   102 {
       
   103   PROP_OBJECT_PATH = 1,
       
   104   PROP_CHANNEL_TYPE,
       
   105   PROP_HANDLE_TYPE,
       
   106   PROP_HANDLE,
       
   107   PROP_CONNECTION,
       
   108   LAST_PROPERTY
       
   109 };
       
   110 
       
   111 /* private structure */
       
   112 typedef struct _GabbleIMChannelPrivate GabbleIMChannelPrivate;
       
   113 
       
   114 struct _GabbleIMChannelPrivate
       
   115 {
       
   116   GabbleConnection *conn;
       
   117   char *object_path;
       
   118   GabbleHandle handle;
       
   119 
       
   120   gchar *peer_jid;
       
   121 
       
   122   gboolean closed;
       
   123   gboolean dispose_has_run;
       
   124 };
       
   125 
       
   126 #define GABBLE_IM_CHANNEL_GET_PRIVATE(obj) \
       
   127     ((GabbleIMChannelPrivate *)obj->priv)
       
   128 
       
   129 static void
       
   130 gabble_im_channel_init (GabbleIMChannel *self)
       
   131 {
       
   132   GabbleIMChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
       
   133       GABBLE_TYPE_IM_CHANNEL, GabbleIMChannelPrivate);
       
   134 
       
   135   self->priv = priv;
       
   136 }
       
   137 
       
   138 static GObject *
       
   139 gabble_im_channel_constructor (GType type, guint n_props,
       
   140                                GObjectConstructParam *props)
       
   141 {
       
   142   GObject *obj;
       
   143   GabbleIMChannelPrivate *priv;
       
   144   DBusGConnection *bus;
       
   145   gboolean valid, send_nick;
       
   146 
       
   147   obj = G_OBJECT_CLASS (gabble_im_channel_parent_class)->
       
   148            constructor (type, n_props, props);
       
   149   priv = GABBLE_IM_CHANNEL_GET_PRIVATE (GABBLE_IM_CHANNEL (obj));
       
   150 
       
   151   valid = gabble_handle_ref (priv->conn->handles, TP_HANDLE_TYPE_CONTACT, priv->handle);
       
   152   g_assert (valid);
       
   153 
       
   154   priv->peer_jid = g_strdup (gabble_handle_inspect (priv->conn->handles,
       
   155         TP_HANDLE_TYPE_CONTACT, priv->handle));
       
   156 
       
   157   bus = tp_get_bus ();
       
   158   dbus_g_connection_register_g_object (bus, priv->object_path, obj);
       
   159 
       
   160   if (gabble_roster_handle_get_subscription (priv->conn->roster, priv->handle)
       
   161         & GABBLE_ROSTER_SUBSCRIPTION_FROM)
       
   162     send_nick = FALSE;
       
   163   else
       
   164     send_nick = TRUE;
       
   165 
       
   166   gabble_text_mixin_init (obj, G_STRUCT_OFFSET (GabbleIMChannel, text),
       
   167                           priv->conn->handles, send_nick);
       
   168 
       
   169   gabble_text_mixin_set_message_types (obj,
       
   170       TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
       
   171       TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION,
       
   172       TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE,
       
   173       G_MAXUINT);
       
   174 
       
   175   return obj;
       
   176 }
       
   177 
       
   178 static void
       
   179 gabble_im_channel_get_property (GObject    *object,
       
   180                                 guint       property_id,
       
   181                                 GValue     *value,
       
   182                                 GParamSpec *pspec)
       
   183 {
       
   184   GabbleIMChannel *chan = GABBLE_IM_CHANNEL (object);
       
   185   GabbleIMChannelPrivate *priv = GABBLE_IM_CHANNEL_GET_PRIVATE (chan);
       
   186 
       
   187   switch (property_id) {
       
   188     case PROP_OBJECT_PATH:
       
   189       g_value_set_string (value, priv->object_path);
       
   190       break;
       
   191     case PROP_CHANNEL_TYPE:
       
   192       g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT);
       
   193       break;
       
   194     case PROP_HANDLE_TYPE:
       
   195       g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT);
       
   196       break;
       
   197     case PROP_HANDLE:
       
   198       g_value_set_uint (value, priv->handle);
       
   199       break;
       
   200     case PROP_CONNECTION:
       
   201       g_value_set_object (value, priv->conn);
       
   202       break;
       
   203     default:
       
   204       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       
   205       break;
       
   206   }
       
   207 }
       
   208 
       
   209 static void
       
   210 gabble_im_channel_set_property (GObject     *object,
       
   211                                 guint        property_id,
       
   212                                 const GValue *value,
       
   213                                 GParamSpec   *pspec)
       
   214 {
       
   215   GabbleIMChannel *chan = GABBLE_IM_CHANNEL (object);
       
   216   GabbleIMChannelPrivate *priv = GABBLE_IM_CHANNEL_GET_PRIVATE (chan);
       
   217 
       
   218   switch (property_id) {
       
   219     case PROP_OBJECT_PATH:
       
   220       g_free (priv->object_path);
       
   221       priv->object_path = g_value_dup_string (value);
       
   222       break;
       
   223     case PROP_HANDLE:
       
   224       priv->handle = g_value_get_uint (value);
       
   225       break;
       
   226     case PROP_CONNECTION:
       
   227       priv->conn = g_value_get_object (value);
       
   228       break;
       
   229     default:
       
   230       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       
   231       break;
       
   232   }
       
   233 }
       
   234 
       
   235 static void gabble_im_channel_dispose (GObject *object);
       
   236 static void gabble_im_channel_finalize (GObject *object);
       
   237 
       
   238 static void
       
   239 gabble_im_channel_class_init (GabbleIMChannelClass *gabble_im_channel_class)
       
   240 {
       
   241   GObjectClass *object_class = G_OBJECT_CLASS (gabble_im_channel_class);
       
   242   GParamSpec *param_spec;
       
   243 
       
   244   g_type_class_add_private (gabble_im_channel_class, sizeof (GabbleIMChannelPrivate));
       
   245 
       
   246   object_class->constructor = gabble_im_channel_constructor;
       
   247 
       
   248   object_class->get_property = gabble_im_channel_get_property;
       
   249   object_class->set_property = gabble_im_channel_set_property;
       
   250 
       
   251   object_class->dispose = gabble_im_channel_dispose;
       
   252   object_class->finalize = gabble_im_channel_finalize;
       
   253 
       
   254   g_object_class_override_property (object_class, PROP_OBJECT_PATH, "object-path");
       
   255   g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type");
       
   256   g_object_class_override_property (object_class, PROP_HANDLE_TYPE, "handle-type");
       
   257   g_object_class_override_property (object_class, PROP_HANDLE, "handle");
       
   258 
       
   259   param_spec = g_param_spec_object ("connection", "GabbleConnection object",
       
   260                                     "Gabble connection object that owns this "
       
   261                                     "IM channel object.",
       
   262                                     GABBLE_TYPE_CONNECTION,
       
   263                                     G_PARAM_CONSTRUCT_ONLY |
       
   264                                     G_PARAM_READWRITE |
       
   265                                     G_PARAM_STATIC_NICK |
       
   266                                     G_PARAM_STATIC_BLURB);
       
   267   g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
       
   268 
       
   269   signals[CLOSED] =
       
   270     g_signal_new ("closed",
       
   271                   G_OBJECT_CLASS_TYPE (gabble_im_channel_class),
       
   272                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   273                   0,
       
   274                   NULL, NULL,
       
   275                   g_cclosure_marshal_VOID__VOID,
       
   276                   G_TYPE_NONE, 0);
       
   277 
       
   278   gabble_text_mixin_class_init (object_class, G_STRUCT_OFFSET (GabbleIMChannelClass, text_class));
       
   279 
       
   280   dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (gabble_im_channel_class), &dbus_glib_gabble_im_channel_object_info);
       
   281 }
       
   282 
       
   283 void
       
   284 gabble_im_channel_dispose (GObject *object)
       
   285 {
       
   286   GabbleIMChannel *self = GABBLE_IM_CHANNEL (object);
       
   287   GabbleIMChannelPrivate *priv = GABBLE_IM_CHANNEL_GET_PRIVATE (self);
       
   288   GabbleRosterSubscription subscription;
       
   289 
       
   290   if (priv->dispose_has_run)
       
   291     return;
       
   292 
       
   293   priv->dispose_has_run = TRUE;
       
   294 
       
   295   subscription = gabble_roster_handle_get_subscription (priv->conn->roster,
       
   296       priv->handle);
       
   297 
       
   298   if ((GABBLE_ROSTER_SUBSCRIPTION_TO & subscription) == 0)
       
   299     {
       
   300       GabblePresence *presence;
       
   301 
       
   302       presence = gabble_presence_cache_get (priv->conn->presence_cache,
       
   303           priv->handle);
       
   304 
       
   305       if (NULL != presence)
       
   306         {
       
   307           presence->keep_unavailable = FALSE;
       
   308           gabble_presence_cache_maybe_remove (priv->conn->presence_cache,
       
   309               priv->handle);
       
   310         }
       
   311     }
       
   312 
       
   313   if (!priv->closed)
       
   314     g_signal_emit(self, signals[CLOSED], 0);
       
   315 
       
   316   if (G_OBJECT_CLASS (gabble_im_channel_parent_class)->dispose)
       
   317     G_OBJECT_CLASS (gabble_im_channel_parent_class)->dispose (object);
       
   318 }
       
   319 
       
   320 void
       
   321 gabble_im_channel_finalize (GObject *object)
       
   322 {
       
   323   GabbleIMChannel *self = GABBLE_IM_CHANNEL (object);
       
   324   GabbleIMChannelPrivate *priv = GABBLE_IM_CHANNEL_GET_PRIVATE (self);
       
   325 
       
   326   /* free any data held directly by the object here */
       
   327 
       
   328   gabble_handle_unref (priv->conn->handles, TP_HANDLE_TYPE_CONTACT, priv->handle);
       
   329 
       
   330   g_free (priv->object_path);
       
   331   g_free (priv->peer_jid);
       
   332 
       
   333   gabble_text_mixin_finalize (object);
       
   334 
       
   335   G_OBJECT_CLASS (gabble_im_channel_parent_class)->finalize (object);
       
   336 }
       
   337 
       
   338 /**
       
   339  * _gabble_im_channel_receive
       
   340  *
       
   341  */
       
   342 gboolean _gabble_im_channel_receive (GabbleIMChannel *chan,
       
   343                                      TpChannelTextMessageType type,
       
   344                                      GabbleHandle sender,
       
   345                                      const char *from,
       
   346                                      time_t timestamp,
       
   347                                      const char *text)
       
   348 {
       
   349   GabbleIMChannelPrivate *priv;
       
   350 
       
   351   g_assert (GABBLE_IS_IM_CHANNEL (chan));
       
   352   priv = GABBLE_IM_CHANNEL_GET_PRIVATE (chan);
       
   353 
       
   354   /* update peer's full JID if it's changed */
       
   355   if (0 != strcmp (from, priv->peer_jid))
       
   356     {
       
   357       g_free (priv->peer_jid);
       
   358       priv->peer_jid = g_strdup (from);
       
   359     }
       
   360 
       
   361   if (timestamp == 0)
       
   362       timestamp = time (NULL);
       
   363 
       
   364   return gabble_text_mixin_receive (G_OBJECT (chan), type, sender, timestamp, text);
       
   365 }
       
   366 
       
   367 /**
       
   368  * gabble_im_channel_acknowledge_pending_messages
       
   369  *
       
   370  * Implements D-Bus method AcknowledgePendingMessages
       
   371  * on interface org.freedesktop.Telepathy.Channel.Type.Text
       
   372  *
       
   373  * @error: Used to return a pointer to a GError detailing any error
       
   374  *         that occurred, D-Bus will throw the error only if this
       
   375  *         function returns FALSE.
       
   376  *
       
   377  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   378  */
       
   379 gboolean
       
   380 gabble_im_channel_acknowledge_pending_messages (GabbleIMChannel *self,
       
   381                                                 const GArray *ids,
       
   382                                                 GError **error)
       
   383 {
       
   384   g_assert (GABBLE_IS_IM_CHANNEL (self));
       
   385 
       
   386   return gabble_text_mixin_acknowledge_pending_messages (G_OBJECT (self), ids,
       
   387       error);
       
   388 }
       
   389 
       
   390 
       
   391 /**
       
   392  * gabble_im_channel_close
       
   393  *
       
   394  * Implements D-Bus method Close
       
   395  * on interface org.freedesktop.Telepathy.Channel
       
   396  *
       
   397  * @error: Used to return a pointer to a GError detailing any error
       
   398  *         that occurred, D-Bus will throw the error only if this
       
   399  *         function returns FALSE.
       
   400  *
       
   401  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   402  */
       
   403 gboolean
       
   404 gabble_im_channel_close (GabbleIMChannel *self,
       
   405                          GError **error)
       
   406 {
       
   407   GabbleIMChannelPrivate *priv;
       
   408 
       
   409   g_assert (GABBLE_IS_IM_CHANNEL (self));
       
   410 
       
   411   gabble_debug (DEBUG_FLAG, "called on %p", self);
       
   412 
       
   413   priv = GABBLE_IM_CHANNEL_GET_PRIVATE (self);
       
   414   priv->closed = TRUE;
       
   415 
       
   416   g_signal_emit (self, signals[CLOSED], 0);
       
   417 
       
   418   return TRUE;
       
   419 }
       
   420 
       
   421 
       
   422 /**
       
   423  * gabble_im_channel_get_channel_type
       
   424  *
       
   425  * Implements D-Bus method GetChannelType
       
   426  * on interface org.freedesktop.Telepathy.Channel
       
   427  *
       
   428  * @error: Used to return a pointer to a GError detailing any error
       
   429  *         that occurred, D-Bus will throw the error only if this
       
   430  *         function returns FALSE.
       
   431  *
       
   432  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   433  */
       
   434 gboolean
       
   435 gabble_im_channel_get_channel_type (GabbleIMChannel *self,
       
   436                                     gchar **ret,
       
   437                                     GError **error)
       
   438 {
       
   439   *ret = g_strdup (TP_IFACE_CHANNEL_TYPE_TEXT);
       
   440 
       
   441   return TRUE;
       
   442 }
       
   443 
       
   444 
       
   445 /**
       
   446  * gabble_im_channel_get_handle
       
   447  *
       
   448  * Implements D-Bus method GetHandle
       
   449  * on interface org.freedesktop.Telepathy.Channel
       
   450  *
       
   451  * @error: Used to return a pointer to a GError detailing any error
       
   452  *         that occurred, D-Bus will throw the error only if this
       
   453  *         function returns FALSE.
       
   454  *
       
   455  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   456  */
       
   457 gboolean
       
   458 gabble_im_channel_get_handle (GabbleIMChannel *self,
       
   459                               guint *ret,
       
   460                               guint *ret1,
       
   461                               GError **error)
       
   462 {
       
   463   GabbleIMChannelPrivate *priv;
       
   464 
       
   465   g_assert (GABBLE_IS_IM_CHANNEL (self));
       
   466 
       
   467   priv = GABBLE_IM_CHANNEL_GET_PRIVATE (self);
       
   468 
       
   469   *ret = TP_HANDLE_TYPE_CONTACT;
       
   470   *ret1 = priv->handle;
       
   471 
       
   472   return TRUE;
       
   473 }
       
   474 
       
   475 
       
   476 /**
       
   477  * gabble_im_channel_get_interfaces
       
   478  *
       
   479  * Implements D-Bus method GetInterfaces
       
   480  * on interface org.freedesktop.Telepathy.Channel
       
   481  *
       
   482  * @error: Used to return a pointer to a GError detailing any error
       
   483  *         that occurred, D-Bus will throw the error only if this
       
   484  *         function returns FALSE.
       
   485  *
       
   486  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   487  */
       
   488 gboolean
       
   489 gabble_im_channel_get_interfaces (GabbleIMChannel *self,
       
   490                                   gchar ***ret,
       
   491                                   GError **error)
       
   492 {
       
   493   const char *interfaces[] = { NULL };
       
   494 
       
   495   *ret = g_strdupv ((gchar **) interfaces);
       
   496 
       
   497   return TRUE;
       
   498 }
       
   499 
       
   500 
       
   501 /**
       
   502  * gabble_im_channel_get_message_types
       
   503  *
       
   504  * Implements D-Bus method GetMessageTypes
       
   505  * on interface org.freedesktop.Telepathy.Channel.Type.Text
       
   506  *
       
   507  * @error: Used to return a pointer to a GError detailing any error
       
   508  *         that occurred, D-Bus will throw the error only if this
       
   509  *         function returns FALSE.
       
   510  *
       
   511  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   512  */
       
   513 gboolean
       
   514 gabble_im_channel_get_message_types (GabbleIMChannel *self,
       
   515                                      GArray **ret,
       
   516                                      GError **error)
       
   517 {
       
   518   return gabble_text_mixin_get_message_types (G_OBJECT (self), ret, error);
       
   519 }
       
   520 
       
   521 
       
   522 /**
       
   523  * gabble_im_channel_list_pending_messages
       
   524  *
       
   525  * Implements D-Bus method ListPendingMessages
       
   526  * on interface org.freedesktop.Telepathy.Channel.Type.Text
       
   527  *
       
   528  * @error: Used to return a pointer to a GError detailing any error
       
   529  *         that occurred, D-Bus will throw the error only if this
       
   530  *         function returns FALSE.
       
   531  *
       
   532  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   533  */
       
   534 gboolean
       
   535 gabble_im_channel_list_pending_messages (GabbleIMChannel *self,
       
   536                                          gboolean clear,
       
   537                                          GPtrArray **ret,
       
   538                                          GError **error)
       
   539 {
       
   540   g_assert (GABBLE_IS_IM_CHANNEL (self));
       
   541 
       
   542   return gabble_text_mixin_list_pending_messages (G_OBJECT (self), clear, ret,
       
   543       error);
       
   544 }
       
   545 
       
   546 
       
   547 /**
       
   548  * gabble_im_channel_send
       
   549  *
       
   550  * Implements D-Bus method Send
       
   551  * on interface org.freedesktop.Telepathy.Channel.Type.Text
       
   552  *
       
   553  * @error: Used to return a pointer to a GError detailing any error
       
   554  *         that occurred, D-Bus will throw the error only if this
       
   555  *         function returns FALSE.
       
   556  *
       
   557  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   558  */
       
   559 gboolean
       
   560 gabble_im_channel_send (GabbleIMChannel *self,
       
   561                         guint type,
       
   562                         const gchar *text,
       
   563                         GError **error)
       
   564 {
       
   565   GabbleIMChannelPrivate *priv;
       
   566 
       
   567   g_assert (GABBLE_IS_IM_CHANNEL (self));
       
   568   priv = GABBLE_IM_CHANNEL_GET_PRIVATE (self);
       
   569 
       
   570   return gabble_text_mixin_send (G_OBJECT (self), type, 0, priv->peer_jid,
       
   571       text, priv->conn, TRUE /* emit_signal */, error);
       
   572 }
       
   573