telepathygabble/src/gabble-roster-channel.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /*
       
     2  * gabble-roster-channel.c - Source for GabbleRosterChannel
       
     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 <stdio.h>
       
    23 #include <stdlib.h>
       
    24 
       
    25 #define DEBUG_FLAG GABBLE_DEBUG_ROSTER
       
    26 
       
    27 #include "debug.h"
       
    28 #include "gabble-connection.h"
       
    29 #include "gintset.h"
       
    30 #include "group-mixin.h"
       
    31 #include "handle-set.h"
       
    32 #include "roster.h"
       
    33 #include "telepathy-errors.h"
       
    34 #include "telepathy-helpers.h"
       
    35 #include "telepathy-interfaces.h"
       
    36 #include "tp-channel-iface.h"
       
    37 #include "util.h"
       
    38 
       
    39 #include "gabble-roster-channel.h"
       
    40 #include "gabble-roster-channel-glue.h"
       
    41 #include "gabble-roster-channel-signals-marshal.h"
       
    42 
       
    43 #include "gabble_enums.h"
       
    44 
       
    45 #ifndef EMULATOR
       
    46 G_DEFINE_TYPE_WITH_CODE (GabbleRosterChannel, gabble_roster_channel,
       
    47     G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL));
       
    48 #endif
       
    49 
       
    50 /* signal enum */
       
    51 enum
       
    52 {
       
    53     CLOSED,
       
    54     GROUP_FLAGS_CHANGED,
       
    55     MEMBERS_CHANGED,
       
    56     LAST_SIGNAL 
       
    57 #ifdef EMULATOR    
       
    58     = LAST_SIGNAL_ROS_CHNL
       
    59 #endif
       
    60     
       
    61 };
       
    62 
       
    63 
       
    64 #ifdef EMULATOR
       
    65 #include "libgabble_wsd_solution.h"
       
    66 
       
    67 	GET_STATIC_ARRAY_FROM_TLS(signals,gabble_ros_chnl,guint)
       
    68 	#define signals (GET_WSD_VAR_NAME(signals,gabble_ros_chnl, s)())	
       
    69 	
       
    70 	GET_STATIC_VAR_FROM_TLS(gabble_roster_channel_parent_class,gabble_ros_chnl,gpointer)
       
    71 	#define gabble_roster_channel_parent_class (*GET_WSD_VAR_NAME(gabble_roster_channel_parent_class,gabble_ros_chnl,s)())
       
    72 	
       
    73 	GET_STATIC_VAR_FROM_TLS(g_define_type_id,gabble_ros_chnl,GType)
       
    74 	#define g_define_type_id (*GET_WSD_VAR_NAME(g_define_type_id,gabble_ros_chnl,s)())
       
    75 
       
    76 static void gabble_roster_channel_init (GabbleRosterChannel *self); 
       
    77 static void gabble_roster_channel_class_init (GabbleRosterChannelClass *klass); 
       
    78 static void gabble_roster_channel_class_intern_init (gpointer klass) 
       
    79 {
       
    80  gabble_roster_channel_parent_class = g_type_class_peek_parent (klass); 
       
    81  gabble_roster_channel_class_init ((GabbleRosterChannelClass*) klass);
       
    82   }
       
    83    
       
    84  EXPORT_C GType gabble_roster_channel_get_type (void) 
       
    85  {
       
    86   if ((g_define_type_id == 0)) { static const GTypeInfo g_define_type_info = { sizeof (GabbleRosterChannelClass), (GBaseInitFunc) ((void *)0), (GBaseFinalizeFunc) ((void *)0), (GClassInitFunc) gabble_roster_channel_class_intern_init, (GClassFinalizeFunc) ((void *)0), ((void *)0), sizeof (GabbleRosterChannel), 0, (GInstanceInitFunc) gabble_roster_channel_init, ((void *)0) }; g_define_type_id = g_type_register_static ( ((GType) ((20) << (2))), g_intern_static_string ("GabbleRosterChannel"), &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; }    ;
       
    87 		
       
    88 #else
       
    89 
       
    90 	static guint signals[LAST_SIGNAL] = {0};
       
    91 
       
    92 #endif
       
    93 
       
    94 
       
    95 
       
    96 /* properties */
       
    97 enum
       
    98 {
       
    99   PROP_OBJECT_PATH = 1,
       
   100   PROP_CHANNEL_TYPE,
       
   101   PROP_HANDLE_TYPE,
       
   102   PROP_HANDLE,
       
   103   PROP_CONNECTION,
       
   104   LAST_PROPERTY
       
   105 };
       
   106 
       
   107 /* private structure */
       
   108 typedef struct _GabbleRosterChannelPrivate GabbleRosterChannelPrivate;
       
   109 
       
   110 struct _GabbleRosterChannelPrivate
       
   111 {
       
   112   GabbleConnection *conn;
       
   113   char *object_path;
       
   114   GabbleHandle handle;
       
   115 
       
   116   gboolean dispose_has_run;
       
   117 };
       
   118 
       
   119 #define GABBLE_ROSTER_CHANNEL_GET_PRIVATE(obj) \
       
   120     ((GabbleRosterChannelPrivate *)obj->priv)
       
   121 
       
   122 static void
       
   123 gabble_roster_channel_init (GabbleRosterChannel *self)
       
   124 {
       
   125   GabbleRosterChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
       
   126       GABBLE_TYPE_ROSTER_CHANNEL, GabbleRosterChannelPrivate);
       
   127 
       
   128   self->priv = priv;
       
   129 
       
   130   /* allocate any data required by the object here */
       
   131 }
       
   132 
       
   133 static GObject *
       
   134 gabble_roster_channel_constructor (GType type, guint n_props,
       
   135                                    GObjectConstructParam *props)
       
   136 {
       
   137   GObject *obj;
       
   138   GabbleRosterChannelPrivate *priv;
       
   139   DBusGConnection *bus;
       
   140   GabbleHandleRepo *handles;
       
   141   gboolean valid;
       
   142   GabbleHandle self_handle;
       
   143 
       
   144   obj = G_OBJECT_CLASS (gabble_roster_channel_parent_class)->
       
   145            constructor (type, n_props, props);
       
   146   priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (GABBLE_ROSTER_CHANNEL (obj));
       
   147   handles = priv->conn->handles;
       
   148   self_handle = priv->conn->self_handle;
       
   149 
       
   150   /* register object on the bus */
       
   151   bus = tp_get_bus ();
       
   152   dbus_g_connection_register_g_object (bus, priv->object_path, obj);
       
   153 
       
   154   /* ref our list handle */
       
   155   valid = gabble_handle_ref (handles, TP_HANDLE_TYPE_LIST, priv->handle);
       
   156   g_assert (valid);
       
   157 
       
   158   /* initialize group mixin */
       
   159   gabble_group_mixin_init (obj, G_STRUCT_OFFSET (GabbleRosterChannel, group),
       
   160                            handles, self_handle);
       
   161 
       
   162   if (GABBLE_LIST_HANDLE_PUBLISH == priv->handle)
       
   163     {
       
   164       gabble_group_mixin_change_flags (obj,
       
   165           TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
       
   166           TP_CHANNEL_GROUP_FLAG_MESSAGE_ACCEPT |
       
   167           TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE,
       
   168           0);
       
   169     }
       
   170   else if (GABBLE_LIST_HANDLE_SUBSCRIBE == priv->handle)
       
   171     {
       
   172       gabble_group_mixin_change_flags (obj,
       
   173           TP_CHANNEL_GROUP_FLAG_CAN_ADD |
       
   174           TP_CHANNEL_GROUP_FLAG_CAN_REMOVE |
       
   175           TP_CHANNEL_GROUP_FLAG_CAN_RESCIND |
       
   176           TP_CHANNEL_GROUP_FLAG_MESSAGE_ADD |
       
   177           TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE |
       
   178           TP_CHANNEL_GROUP_FLAG_MESSAGE_RESCIND,
       
   179           0);
       
   180     }
       
   181   else if (GABBLE_LIST_HANDLE_KNOWN == priv->handle)
       
   182     {
       
   183       gabble_group_mixin_change_flags (obj,
       
   184           TP_CHANNEL_GROUP_FLAG_CAN_REMOVE,
       
   185           0);
       
   186     }
       
   187   else if (GABBLE_LIST_HANDLE_DENY == priv->handle)
       
   188     {
       
   189       gabble_group_mixin_change_flags (obj,
       
   190           TP_CHANNEL_GROUP_FLAG_CAN_ADD |
       
   191           TP_CHANNEL_GROUP_FLAG_CAN_REMOVE,
       
   192           0);
       
   193     }
       
   194   else
       
   195     {
       
   196       g_assert_not_reached ();
       
   197     }
       
   198 
       
   199   return obj;
       
   200 }
       
   201 
       
   202 static void
       
   203 gabble_roster_channel_get_property (GObject    *object,
       
   204                                     guint       property_id,
       
   205                                     GValue     *value,
       
   206                                     GParamSpec *pspec)
       
   207 {
       
   208   GabbleRosterChannel *chan = GABBLE_ROSTER_CHANNEL (object);
       
   209   GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (chan);
       
   210 
       
   211   switch (property_id) {
       
   212     case PROP_OBJECT_PATH:
       
   213       g_value_set_string (value, priv->object_path);
       
   214       break;
       
   215     case PROP_CHANNEL_TYPE:
       
   216       g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_CONTACT_LIST);
       
   217       break;
       
   218     case PROP_HANDLE_TYPE:
       
   219       g_value_set_uint (value, TP_HANDLE_TYPE_LIST);
       
   220       break;
       
   221     case PROP_HANDLE:
       
   222       g_value_set_uint (value, priv->handle);
       
   223       break;
       
   224     case PROP_CONNECTION:
       
   225       g_value_set_object (value, priv->conn);
       
   226       break;
       
   227     default:
       
   228       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       
   229       break;
       
   230   }
       
   231 }
       
   232 
       
   233 static void
       
   234 gabble_roster_channel_set_property (GObject     *object,
       
   235                                     guint        property_id,
       
   236                                     const GValue *value,
       
   237                                     GParamSpec   *pspec)
       
   238 {
       
   239   GabbleRosterChannel *chan = GABBLE_ROSTER_CHANNEL (object);
       
   240   GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (chan);
       
   241 
       
   242   switch (property_id) {
       
   243     case PROP_OBJECT_PATH:
       
   244       g_free (priv->object_path);
       
   245       priv->object_path = g_value_dup_string (value);
       
   246       break;
       
   247     case PROP_HANDLE:
       
   248       priv->handle = g_value_get_uint (value);
       
   249       break;
       
   250     case PROP_CONNECTION:
       
   251       priv->conn = g_value_get_object (value);
       
   252       break;
       
   253     default:
       
   254       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       
   255       break;
       
   256   }
       
   257 }
       
   258 
       
   259 static void gabble_roster_channel_dispose (GObject *object);
       
   260 static void gabble_roster_channel_finalize (GObject *object);
       
   261 
       
   262 static gboolean _gabble_roster_channel_add_member_cb (GObject *obj, GabbleHandle handle, const gchar *message, GError **error);
       
   263 static gboolean _gabble_roster_channel_remove_member_cb (GObject *obj, GabbleHandle handle, const gchar *message, GError **error);
       
   264 
       
   265 static void
       
   266 gabble_roster_channel_class_init (GabbleRosterChannelClass *gabble_roster_channel_class)
       
   267 {
       
   268   GObjectClass *object_class = G_OBJECT_CLASS (gabble_roster_channel_class);
       
   269   GParamSpec *param_spec;
       
   270 
       
   271   g_type_class_add_private (gabble_roster_channel_class, sizeof (GabbleRosterChannelPrivate));
       
   272 
       
   273   object_class->constructor = gabble_roster_channel_constructor;
       
   274 
       
   275   object_class->get_property = gabble_roster_channel_get_property;
       
   276   object_class->set_property = gabble_roster_channel_set_property;
       
   277 
       
   278   object_class->dispose = gabble_roster_channel_dispose;
       
   279   object_class->finalize = gabble_roster_channel_finalize;
       
   280 
       
   281   param_spec = g_param_spec_object ("connection", "GabbleConnection object",
       
   282                                     "Gabble connection object that owns this "
       
   283                                     "Roster channel object.",
       
   284                                     GABBLE_TYPE_CONNECTION,
       
   285                                     G_PARAM_CONSTRUCT_ONLY |
       
   286                                     G_PARAM_READWRITE |
       
   287                                     G_PARAM_STATIC_NICK |
       
   288                                     G_PARAM_STATIC_BLURB);
       
   289   g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
       
   290 
       
   291   g_object_class_override_property (object_class, PROP_OBJECT_PATH, "object-path");
       
   292   g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type");
       
   293   g_object_class_override_property (object_class, PROP_HANDLE_TYPE, "handle-type");
       
   294   g_object_class_override_property (object_class, PROP_HANDLE, "handle");
       
   295 
       
   296   signals[CLOSED] =
       
   297     g_signal_new ("closed",
       
   298                   G_OBJECT_CLASS_TYPE (gabble_roster_channel_class),
       
   299                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   300                   0,
       
   301                   NULL, NULL,
       
   302                   g_cclosure_marshal_VOID__VOID,
       
   303                   G_TYPE_NONE, 0);
       
   304 
       
   305   gabble_group_mixin_class_init (object_class,
       
   306                                  G_STRUCT_OFFSET (GabbleRosterChannelClass, group_class),
       
   307                                  _gabble_roster_channel_add_member_cb,
       
   308                                  _gabble_roster_channel_remove_member_cb);
       
   309 
       
   310   dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (gabble_roster_channel_class), &dbus_glib_gabble_roster_channel_object_info);
       
   311 }
       
   312 
       
   313 void
       
   314 gabble_roster_channel_dispose (GObject *object)
       
   315 {
       
   316   GabbleRosterChannel *self = GABBLE_ROSTER_CHANNEL (object);
       
   317   GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (self);
       
   318 
       
   319   if (priv->dispose_has_run)
       
   320     return;
       
   321 
       
   322   priv->dispose_has_run = TRUE;
       
   323 
       
   324   g_signal_emit(self, signals[CLOSED], 0);
       
   325 
       
   326   /* release any references held by the object here */
       
   327 
       
   328   if (G_OBJECT_CLASS (gabble_roster_channel_parent_class)->dispose)
       
   329     G_OBJECT_CLASS (gabble_roster_channel_parent_class)->dispose (object);
       
   330 }
       
   331 
       
   332 void
       
   333 gabble_roster_channel_finalize (GObject *object)
       
   334 {
       
   335   GabbleRosterChannel *self = GABBLE_ROSTER_CHANNEL (object);
       
   336   GabbleRosterChannelPrivate *priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (self);
       
   337 
       
   338   /* free any data held directly by the object here */
       
   339 
       
   340   g_free (priv->object_path);
       
   341 
       
   342   gabble_handle_unref (priv->conn->handles, TP_HANDLE_TYPE_LIST, priv->handle);
       
   343 
       
   344   gabble_group_mixin_finalize (object);
       
   345 
       
   346   G_OBJECT_CLASS (gabble_roster_channel_parent_class)->finalize (object);
       
   347 }
       
   348 
       
   349 
       
   350 static gboolean
       
   351 _gabble_roster_channel_send_presence (GabbleRosterChannel *chan,
       
   352                                       LmMessageSubType sub_type,
       
   353                                       GabbleHandle handle,
       
   354                                       const gchar *status,
       
   355                                       GError **error)
       
   356 {
       
   357   GabbleRosterChannelPrivate *priv;
       
   358   GabbleHandleRepo *repo;
       
   359   const char *contact;
       
   360   LmMessage *message;
       
   361   gboolean result;
       
   362 
       
   363   priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (chan);
       
   364   repo = priv->conn->handles;
       
   365   contact = gabble_handle_inspect (repo, TP_HANDLE_TYPE_CONTACT, handle);
       
   366 
       
   367   message = lm_message_new_with_sub_type (contact,
       
   368       LM_MESSAGE_TYPE_PRESENCE,
       
   369       sub_type);
       
   370 
       
   371   if (LM_MESSAGE_SUB_TYPE_SUBSCRIBE == sub_type)
       
   372     lm_message_node_add_own_nick (message->node, priv->conn);
       
   373 
       
   374   if (status != NULL && status[0] != '\0')
       
   375     lm_message_node_add_child (message->node, "status", status);
       
   376 
       
   377   result = _gabble_connection_send (priv->conn, message, error);
       
   378 
       
   379   lm_message_unref (message);
       
   380 
       
   381   return result;
       
   382 }
       
   383 
       
   384 
       
   385 /**
       
   386  * _gabble_roster_channel_add_member_cb
       
   387  *
       
   388  * Called by the group mixin to add one member.
       
   389  */
       
   390 static gboolean
       
   391 _gabble_roster_channel_add_member_cb (GObject *obj,
       
   392                                       GabbleHandle handle,
       
   393                                       const gchar *message,
       
   394                                       GError **error)
       
   395 {
       
   396   GabbleRosterChannelPrivate *priv;
       
   397   GabbleHandleRepo *repo;
       
   398   gboolean ret = FALSE;
       
   399 
       
   400   priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (GABBLE_ROSTER_CHANNEL (obj));
       
   401 
       
   402   repo = priv->conn->handles;
       
   403 
       
   404   gabble_debug (DEBUG_FLAG, "called on %s with handle %u (%s) \"%s\"", gabble_handle_inspect (repo, TP_HANDLE_TYPE_LIST, priv->handle), handle,
       
   405       gabble_handle_inspect (repo, TP_HANDLE_TYPE_CONTACT, handle), message);
       
   406 
       
   407   /* publish list */
       
   408   if (GABBLE_LIST_HANDLE_PUBLISH == priv->handle)
       
   409     {
       
   410       /* send <presence type="subscribed"> */
       
   411       ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
       
   412           LM_MESSAGE_SUB_TYPE_SUBSCRIBED, handle, message, error);
       
   413     }
       
   414   /* subscribe list */
       
   415   else if (GABBLE_LIST_HANDLE_SUBSCRIBE == priv->handle)
       
   416     {
       
   417       /* add item to the roster (GTalk depends on this, clearing the H flag) */
       
   418       gabble_roster_handle_add (priv->conn->roster, handle, NULL);
       
   419 
       
   420       /* send <presence type="subscribe"> */
       
   421       ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
       
   422           LM_MESSAGE_SUB_TYPE_SUBSCRIBE, handle, message, error);
       
   423     }
       
   424   /* deny list */
       
   425   else if (GABBLE_LIST_HANDLE_DENY == priv->handle)
       
   426     {
       
   427       /* block contact */
       
   428       ret = gabble_roster_handle_set_blocked (priv->conn->roster, handle, TRUE,
       
   429           error);
       
   430     }
       
   431   else
       
   432     {
       
   433       g_assert_not_reached ();
       
   434     }
       
   435 
       
   436   return ret;
       
   437 }
       
   438 
       
   439 
       
   440 /**
       
   441  * _gabble_roster_channel_remove_member_cb
       
   442  *
       
   443  * Called by the group mixin to remove one member.
       
   444  */
       
   445 static gboolean
       
   446 _gabble_roster_channel_remove_member_cb (GObject *obj,
       
   447                                          GabbleHandle handle,
       
   448                                          const gchar *message,
       
   449                                          GError **error)
       
   450 {
       
   451   GabbleRosterChannelPrivate *priv;
       
   452   GabbleHandleRepo *repo;
       
   453   gboolean ret = FALSE;
       
   454 
       
   455   priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (GABBLE_ROSTER_CHANNEL (obj));
       
   456 
       
   457   repo = priv->conn->handles;
       
   458 
       
   459   gabble_debug (DEBUG_FLAG, "called on %s with handle %u (%s) \"%s\"", gabble_handle_inspect (repo, TP_HANDLE_TYPE_LIST, priv->handle), handle,
       
   460       gabble_handle_inspect (repo, TP_HANDLE_TYPE_CONTACT, handle), message);
       
   461 
       
   462   /* publish list */
       
   463   if (GABBLE_LIST_HANDLE_PUBLISH == priv->handle)
       
   464     {
       
   465       /* send <presence type="unsubscribed"> */
       
   466       ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
       
   467           LM_MESSAGE_SUB_TYPE_UNSUBSCRIBED, handle, message, error);
       
   468 
       
   469       /* remove it from local_pending here, because roster callback doesn't
       
   470          know if it can (subscription='none' is used both during request and
       
   471          when it's rejected) */
       
   472       if (handle_set_is_member (GABBLE_ROSTER_CHANNEL (obj)->group.local_pending, handle))
       
   473         {
       
   474           GIntSet *rem = g_intset_new ();
       
   475 
       
   476           g_intset_add (rem, handle);
       
   477           gabble_group_mixin_change_members (obj, "", NULL, rem, NULL, NULL,
       
   478               0, 0);
       
   479 
       
   480           g_intset_destroy (rem);
       
   481         }
       
   482     }
       
   483   /* subscribe list */
       
   484   else if (GABBLE_LIST_HANDLE_SUBSCRIBE == priv->handle)
       
   485     {
       
   486       /* send <presence type="unsubscribe"> */
       
   487       ret = _gabble_roster_channel_send_presence (GABBLE_ROSTER_CHANNEL (obj),
       
   488           LM_MESSAGE_SUB_TYPE_UNSUBSCRIBE, handle, message, error);
       
   489     }
       
   490   /* known list */
       
   491   else if (GABBLE_LIST_HANDLE_KNOWN == priv->handle)
       
   492     {
       
   493       /* send roster subscription=remove IQ */
       
   494       ret = gabble_roster_handle_remove (priv->conn->roster, handle, error);
       
   495     }
       
   496   /* deny list */
       
   497   else if (GABBLE_LIST_HANDLE_DENY == priv->handle)
       
   498     {
       
   499       /* unblock contact */
       
   500       ret = gabble_roster_handle_set_blocked (priv->conn->roster, handle, FALSE,
       
   501           error);
       
   502     }
       
   503   else
       
   504     {
       
   505       g_assert_not_reached ();
       
   506     }
       
   507 
       
   508   return ret;
       
   509 }
       
   510 
       
   511 
       
   512 /**
       
   513  * gabble_roster_channel_add_members
       
   514  *
       
   515  * Implements D-Bus method AddMembers
       
   516  * on interface org.freedesktop.Telepathy.Channel.Interface.Group
       
   517  *
       
   518  * @error: Used to return a pointer to a GError detailing any error
       
   519  *         that occurred, D-Bus will throw the error only if this
       
   520  *         function returns FALSE.
       
   521  *
       
   522  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   523  */
       
   524 gboolean
       
   525 gabble_roster_channel_add_members (GabbleRosterChannel *self,
       
   526                                    const GArray *contacts,
       
   527                                    const gchar *message,
       
   528                                    GError **error)
       
   529 {
       
   530   return gabble_group_mixin_add_members (G_OBJECT (self), contacts, message,
       
   531       error);
       
   532 }
       
   533 
       
   534 
       
   535 /**
       
   536  * gabble_roster_channel_close
       
   537  *
       
   538  * Implements D-Bus method Close
       
   539  * on interface org.freedesktop.Telepathy.Channel
       
   540  *
       
   541  * @error: Used to return a pointer to a GError detailing any error
       
   542  *         that occurred, D-Bus will throw the error only if this
       
   543  *         function returns FALSE.
       
   544  *
       
   545  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   546  */
       
   547 gboolean
       
   548 gabble_roster_channel_close (GabbleRosterChannel *self,
       
   549                              GError **error)
       
   550 {
       
   551   g_set_error (error, TELEPATHY_ERRORS, NotImplemented,
       
   552       "you may not close contact list channels");
       
   553 
       
   554   return FALSE;
       
   555 }
       
   556 
       
   557 
       
   558 /**
       
   559  * gabble_roster_channel_get_all_members
       
   560  *
       
   561  * Implements D-Bus method GetAllMembers
       
   562  * on interface org.freedesktop.Telepathy.Channel.Interface.Group
       
   563  *
       
   564  * @error: Used to return a pointer to a GError detailing any error
       
   565  *         that occurred, D-Bus will throw the error only if this
       
   566  *         function returns FALSE.
       
   567  *
       
   568  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   569  */
       
   570 gboolean
       
   571 gabble_roster_channel_get_all_members (GabbleRosterChannel *self,
       
   572                                        GArray **ret,
       
   573                                        GArray **ret1,
       
   574                                        GArray **ret2,
       
   575                                        GError **error)
       
   576 {
       
   577   return gabble_group_mixin_get_all_members (G_OBJECT (self), ret, ret1, ret2,
       
   578       error);
       
   579 }
       
   580 
       
   581 
       
   582 /**
       
   583  * gabble_roster_channel_get_channel_type
       
   584  *
       
   585  * Implements D-Bus method GetChannelType
       
   586  * on interface org.freedesktop.Telepathy.Channel
       
   587  *
       
   588  * @error: Used to return a pointer to a GError detailing any error
       
   589  *         that occurred, D-Bus will throw the error only if this
       
   590  *         function returns FALSE.
       
   591  *
       
   592  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   593  */
       
   594 gboolean
       
   595 gabble_roster_channel_get_channel_type (GabbleRosterChannel *self,
       
   596                                         gchar **ret,
       
   597                                         GError **error)
       
   598 {
       
   599   *ret = g_strdup (TP_IFACE_CHANNEL_TYPE_CONTACT_LIST);
       
   600 
       
   601   return TRUE;
       
   602 }
       
   603 
       
   604 
       
   605 /**
       
   606  * gabble_roster_channel_get_group_flags
       
   607  *
       
   608  * Implements D-Bus method GetGroupFlags
       
   609  * on interface org.freedesktop.Telepathy.Channel.Interface.Group
       
   610  *
       
   611  * @error: Used to return a pointer to a GError detailing any error
       
   612  *         that occurred, D-Bus will throw the error only if this
       
   613  *         function returns FALSE.
       
   614  *
       
   615  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   616  */
       
   617 gboolean
       
   618 gabble_roster_channel_get_group_flags (GabbleRosterChannel *self,
       
   619                                        guint *ret,
       
   620                                        GError **error)
       
   621 {
       
   622   return gabble_group_mixin_get_group_flags (G_OBJECT (self), ret, error);
       
   623 }
       
   624 
       
   625 
       
   626 /**
       
   627  * gabble_roster_channel_get_handle
       
   628  *
       
   629  * Implements D-Bus method GetHandle
       
   630  * on interface org.freedesktop.Telepathy.Channel
       
   631  *
       
   632  * @error: Used to return a pointer to a GError detailing any error
       
   633  *         that occurred, D-Bus will throw the error only if this
       
   634  *         function returns FALSE.
       
   635  *
       
   636  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   637  */
       
   638 gboolean
       
   639 gabble_roster_channel_get_handle (GabbleRosterChannel *self,
       
   640                                   guint *ret,
       
   641                                   guint *ret1,
       
   642                                   GError **error)
       
   643 {
       
   644   GabbleRosterChannelPrivate *priv;
       
   645 
       
   646   g_assert (GABBLE_IS_ROSTER_CHANNEL (self));
       
   647 
       
   648   priv = GABBLE_ROSTER_CHANNEL_GET_PRIVATE (self);
       
   649 
       
   650   *ret = TP_HANDLE_TYPE_LIST;
       
   651   *ret1 = priv->handle;
       
   652 
       
   653   return TRUE;
       
   654 }
       
   655 
       
   656 
       
   657 /**
       
   658  * gabble_roster_channel_get_handle_owners
       
   659  *
       
   660  * Implements D-Bus method GetHandleOwners
       
   661  * on interface org.freedesktop.Telepathy.Channel.Interface.Group
       
   662  *
       
   663  * @error: Used to return a pointer to a GError detailing any error
       
   664  *         that occurred, D-Bus will throw the error only if this
       
   665  *         function returns FALSE.
       
   666  *
       
   667  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   668  */
       
   669 gboolean
       
   670 gabble_roster_channel_get_handle_owners (GabbleRosterChannel *self,
       
   671                                          const GArray *handles,
       
   672                                          GArray **ret,
       
   673                                          GError **error)
       
   674 {
       
   675   return gabble_group_mixin_get_handle_owners (G_OBJECT (self), handles, ret,
       
   676       error);
       
   677 }
       
   678 
       
   679 
       
   680 /**
       
   681  * gabble_roster_channel_get_interfaces
       
   682  *
       
   683  * Implements D-Bus method GetInterfaces
       
   684  * on interface org.freedesktop.Telepathy.Channel
       
   685  *
       
   686  * @error: Used to return a pointer to a GError detailing any error
       
   687  *         that occurred, D-Bus will throw the error only if this
       
   688  *         function returns FALSE.
       
   689  *
       
   690  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   691  */
       
   692 gboolean
       
   693 gabble_roster_channel_get_interfaces (GabbleRosterChannel *self,
       
   694                                       gchar ***ret,
       
   695                                       GError **error)
       
   696 {
       
   697   const char *interfaces[] = { TP_IFACE_CHANNEL_INTERFACE_GROUP, NULL };
       
   698 
       
   699   *ret = g_strdupv ((gchar **) interfaces);
       
   700 
       
   701   return TRUE;
       
   702 }
       
   703 
       
   704 
       
   705 /**
       
   706  * gabble_roster_channel_get_local_pending_members
       
   707  *
       
   708  * Implements D-Bus method GetLocalPendingMembers
       
   709  * on interface org.freedesktop.Telepathy.Channel.Interface.Group
       
   710  *
       
   711  * @error: Used to return a pointer to a GError detailing any error
       
   712  *         that occurred, D-Bus will throw the error only if this
       
   713  *         function returns FALSE.
       
   714  *
       
   715  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   716  */
       
   717 gboolean
       
   718 gabble_roster_channel_get_local_pending_members (GabbleRosterChannel *self,
       
   719                                                  GArray **ret,
       
   720                                                  GError **error)
       
   721 {
       
   722   return gabble_group_mixin_get_local_pending_members (G_OBJECT (self), ret,
       
   723       error);
       
   724 }
       
   725 
       
   726 
       
   727 /**
       
   728  * gabble_roster_channel_get_members
       
   729  *
       
   730  * Implements D-Bus method GetMembers
       
   731  * on interface org.freedesktop.Telepathy.Channel.Interface.Group
       
   732  *
       
   733  * @error: Used to return a pointer to a GError detailing any error
       
   734  *         that occurred, D-Bus will throw the error only if this
       
   735  *         function returns FALSE.
       
   736  *
       
   737  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   738  */
       
   739 gboolean
       
   740 gabble_roster_channel_get_members (GabbleRosterChannel *self,
       
   741                                    GArray **ret,
       
   742                                    GError **error)
       
   743 {
       
   744   return gabble_group_mixin_get_members (G_OBJECT (self), ret, error);
       
   745 }
       
   746 
       
   747 
       
   748 /**
       
   749  * gabble_roster_channel_get_remote_pending_members
       
   750  *
       
   751  * Implements D-Bus method GetRemotePendingMembers
       
   752  * on interface org.freedesktop.Telepathy.Channel.Interface.Group
       
   753  *
       
   754  * @error: Used to return a pointer to a GError detailing any error
       
   755  *         that occurred, D-Bus will throw the error only if this
       
   756  *         function returns FALSE.
       
   757  *
       
   758  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   759  */
       
   760 gboolean
       
   761 gabble_roster_channel_get_remote_pending_members (GabbleRosterChannel *self,
       
   762                                                   GArray **ret,
       
   763                                                   GError **error)
       
   764 {
       
   765   return gabble_group_mixin_get_remote_pending_members (G_OBJECT (self), ret,
       
   766       error);
       
   767 }
       
   768 
       
   769 
       
   770 /**
       
   771  * gabble_roster_channel_get_self_handle
       
   772  *
       
   773  * Implements D-Bus method GetSelfHandle
       
   774  * on interface org.freedesktop.Telepathy.Channel.Interface.Group
       
   775  *
       
   776  * @error: Used to return a pointer to a GError detailing any error
       
   777  *         that occurred, D-Bus will throw the error only if this
       
   778  *         function returns FALSE.
       
   779  *
       
   780  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   781  */
       
   782 gboolean
       
   783 gabble_roster_channel_get_self_handle (GabbleRosterChannel *self,
       
   784                                        guint *ret,
       
   785                                        GError **error)
       
   786 {
       
   787   return gabble_group_mixin_get_self_handle (G_OBJECT (self), ret, error);
       
   788 }
       
   789 
       
   790 
       
   791 /**
       
   792  * gabble_roster_channel_remove_members
       
   793  *
       
   794  * Implements D-Bus method RemoveMembers
       
   795  * on interface org.freedesktop.Telepathy.Channel.Interface.Group
       
   796  *
       
   797  * @error: Used to return a pointer to a GError detailing any error
       
   798  *         that occurred, D-Bus will throw the error only if this
       
   799  *         function returns FALSE.
       
   800  *
       
   801  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   802  */
       
   803 gboolean
       
   804 gabble_roster_channel_remove_members (GabbleRosterChannel *self,
       
   805                                       const GArray *contacts,
       
   806                                       const gchar *message,
       
   807                                       GError **error)
       
   808 {
       
   809   return gabble_group_mixin_remove_members (G_OBJECT (self), contacts, message,
       
   810       error);
       
   811 }
       
   812