telepathygabble/src/gabble-connection.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /*
       
     2  * gabble-connection.c - Source for GabbleConnection
       
     3  * Copyright (C) 2005 Collabora Ltd.
       
     4  *  and/or its subsidiary/subsidiaries. All rights reserved.
       
     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 "config.h"
       
    22 
       
    23 #include <dbus/dbus-glib.h>
       
    24 #include <dbus/dbus-glib-lowlevel.h>
       
    25 #include <glib-object.h>
       
    26 #include "loudmouth/loudmouth.h"
       
    27 #include <stdlib.h>
       
    28 #include <string.h>
       
    29 #include <stdio.h>
       
    30 
       
    31 
       
    32 #include "handles.h"
       
    33 #include "handle-set.h"
       
    34 #include "telepathy-constants.h"
       
    35 #include "telepathy-errors.h"
       
    36 #include "telepathy-helpers.h"
       
    37 #include "telepathy-interfaces.h"
       
    38 #include "loudmouth/lm-connection.h"
       
    39 
       
    40 #include "tp-channel-iface.h"
       
    41 #include "tp-channel-factory-iface.h"
       
    42 
       
    43 #include "gabble-connection.h"
       
    44 #include "gabble-connection-glue.h"
       
    45 #include "gabble-connection-signals-marshal.h"
       
    46 
       
    47 
       
    48 #include "capabilities.h"
       
    49 #include "debug.h"
       
    50 #include "disco.h"
       
    51 #include "gabble-presence-cache.h"
       
    52 #include "gabble-presence.h"
       
    53 #include "gabble-register.h"
       
    54 #include "im-factory.h"
       
    55 #include "search-factory.h"
       
    56 #include "jingle-info.h"
       
    57 #include "media-factory.h"
       
    58 #include "muc-factory.h"
       
    59 #include "namespaces.h"
       
    60 #include "roster.h"
       
    61 #include "util.h"
       
    62 #include "vcard-manager.h"
       
    63 #include "search-keys-info.h"
       
    64 
       
    65 #include "gabble-media-channel.h"
       
    66 #include "gabble-roomlist-channel.h"
       
    67 
       
    68 #include "gabble_enums.h"
       
    69 #include "sha1.h"
       
    70 #include "base64.h"
       
    71 
       
    72 #define DEBUG_FLAG GABBLE_DEBUG_CONNECTION
       
    73 #define DBUS_API_SUBJECT_TO_CHANGE
       
    74 #define BUS_NAME        "org.freedesktop.Telepathy.Connection.gabble"
       
    75 #define OBJECT_PATH     "/org/freedesktop/Telepathy/Connection/gabble"
       
    76 
       
    77 #define TP_ALIAS_PAIR_TYPE (dbus_g_type_get_struct ("GValueArray", \
       
    78       G_TYPE_UINT, G_TYPE_STRING, G_TYPE_INVALID))
       
    79 #define TP_CAPABILITY_PAIR_TYPE (dbus_g_type_get_struct ("GValueArray", \
       
    80       G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID))
       
    81 #define TP_CAPABILITIES_CHANGED_MONSTER_TYPE (dbus_g_type_get_struct \
       
    82     ("GValueArray", G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, \
       
    83                     G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID))
       
    84 #define TP_GET_CAPABILITIES_MONSTER_TYPE (dbus_g_type_get_struct \
       
    85     ("GValueArray", G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, \
       
    86                     G_TYPE_INVALID))
       
    87 #define TP_CHANNEL_LIST_ENTRY_TYPE (dbus_g_type_get_struct ("GValueArray", \
       
    88       DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, \
       
    89       G_TYPE_INVALID))
       
    90 
       
    91 #define ERROR_IF_NOT_CONNECTED(CONN, ERROR) \
       
    92   if ((CONN)->status != TP_CONN_STATUS_CONNECTED) \
       
    93     { \
       
    94       gabble_debug (DEBUG_FLAG, "rejected request as disconnected"); \
       
    95       g_set_error (ERROR, TELEPATHY_ERRORS, NotAvailable, \
       
    96           "Connection is disconnected"); \
       
    97       return FALSE; \
       
    98     }
       
    99 
       
   100 #define ERROR_IF_NOT_CONNECTED_ASYNC(CONN, ERROR, CONTEXT) \
       
   101   if ((CONN)->status != TP_CONN_STATUS_CONNECTED) \
       
   102     { \
       
   103       gabble_debug (DEBUG_FLAG, "rejected request as disconnected"); \
       
   104       (ERROR) = g_error_new (TELEPATHY_ERRORS, NotAvailable, \
       
   105           "Connection is disconnected"); \
       
   106       dbus_g_method_return_error ((CONTEXT), (ERROR)); \
       
   107       g_error_free ((ERROR)); \
       
   108       return; \
       
   109     }
       
   110 
       
   111 #ifdef DEBUG_FLAG
       
   112 //#define DEBUG(format, ...)
       
   113 #define DEBUGGING 0
       
   114 #define NODE_DEBUG(n, s)
       
   115 #endif /* DEBUG_FLAG */
       
   116 
       
   117 #ifndef EMULATOR
       
   118 G_DEFINE_TYPE(GabbleConnection, gabble_connection, G_TYPE_OBJECT)
       
   119 #endif
       
   120 
       
   121 typedef struct _StatusInfo StatusInfo;
       
   122 
       
   123 struct _StatusInfo
       
   124 {
       
   125   const gchar *name;
       
   126   TpConnectionPresenceType presence_type;
       
   127   const gboolean self;
       
   128   const gboolean exclusive;
       
   129 };
       
   130 
       
   131 /* order must match PresenceId enum in gabble-connection.h */
       
   132 /* in increasing order of presence */
       
   133 static const StatusInfo gabble_statuses[LAST_GABBLE_PRESENCE] = {
       
   134  { "offline",   TP_CONN_PRESENCE_TYPE_OFFLINE,       TRUE, TRUE },
       
   135  { "hidden",    TP_CONN_PRESENCE_TYPE_HIDDEN,        TRUE, TRUE },
       
   136  { "xa",        TP_CONN_PRESENCE_TYPE_EXTENDED_AWAY, TRUE, TRUE },
       
   137  { "away",      TP_CONN_PRESENCE_TYPE_AWAY,          TRUE, TRUE },
       
   138  { "dnd",       TP_CONN_PRESENCE_TYPE_AWAY,          TRUE, TRUE },
       
   139  { "available", TP_CONN_PRESENCE_TYPE_AVAILABLE,     TRUE, TRUE },
       
   140  { "chat",      TP_CONN_PRESENCE_TYPE_AVAILABLE,     TRUE, TRUE }
       
   141 };
       
   142 
       
   143 /* signal enum */
       
   144 enum
       
   145 {
       
   146     ALIASES_CHANGED,
       
   147     CAPABILITIES_CHANGED,
       
   148     NEW_CHANNEL,
       
   149     PRESENCE_UPDATE,
       
   150     STATUS_CHANGED,
       
   151     DISCONNECTED,
       
   152     LAST_SIGNAL 
       
   153 #ifdef EMULATOR    
       
   154     = LAST_SIGNAL_CON
       
   155 #endif
       
   156     
       
   157 };
       
   158 
       
   159 
       
   160 #ifdef EMULATOR
       
   161 #include "libgabble_wsd_solution.h"
       
   162 
       
   163 	GET_STATIC_ARRAY_FROM_TLS(signals,gabble_con,guint)
       
   164 	#define signals (GET_WSD_VAR_NAME(signals,gabble_con, s)())	
       
   165 	
       
   166 	
       
   167 	GET_STATIC_VAR_FROM_TLS(arguments,gabble_con,GHashTable*)
       
   168 	#define arguments (*GET_WSD_VAR_NAME(arguments,gabble_con, s)())	
       
   169 	
       
   170 	GET_STATIC_VAR_FROM_TLS(gabble_connection_parent_class,gabble_con,gpointer)
       
   171 	#define gabble_connection_parent_class (*GET_WSD_VAR_NAME(gabble_connection_parent_class,gabble_con,s)())
       
   172 	
       
   173 	GET_STATIC_VAR_FROM_TLS(g_define_type_id,gabble_con,GType)
       
   174 	#define g_define_type_id (*GET_WSD_VAR_NAME(g_define_type_id,gabble_con,s)())
       
   175 	
       
   176 	//GET_STATIC_ARRAY_FROM_TLS(assumed_caps,gabble_con,gchar*)
       
   177 	/*gchar** _s_gabble_con_assumed_caps() { return (gchar**)((libgabble_ImpurePtr()->_s_gabble_con_assumed_caps)); }
       
   178 
       
   179 	#define assumed_caps (GET_WSD_VAR_NAME(assumed_caps,gabble_con, s)())	*/
       
   180 	
       
   181 	
       
   182 			
       
   183 static void gabble_connection_init (GabbleConnection *self); 
       
   184 static void gabble_connection_class_init (GabbleConnectionClass *klass); 
       
   185 static void gabble_connection_class_intern_init (gpointer klass) 
       
   186 { 
       
   187 gabble_connection_parent_class = g_type_class_peek_parent (klass); 
       
   188 gabble_connection_class_init ((GabbleConnectionClass*) klass); 
       
   189 } 
       
   190 EXPORT_C GType gabble_connection_get_type (void) 
       
   191 { 
       
   192 
       
   193 if ((g_define_type_id == 0)) 
       
   194 { 
       
   195 static const GTypeInfo g_define_type_info = 
       
   196 	{ sizeof (GabbleConnectionClass), (GBaseInitFunc) ((void *)0), (GBaseFinalizeFunc) ((void *)0), (GClassInitFunc) gabble_connection_class_intern_init, (GClassFinalizeFunc) ((void *)0), ((void *)0), sizeof (GabbleConnection), 0, (GInstanceInitFunc) gabble_connection_init, ((void *)0) }; g_define_type_id = g_type_register_static ( ((GType) ((20) << (2))), g_intern_static_string ("GabbleConnection"), &g_define_type_info, (GTypeFlags) 0); { {} ; } } return g_define_type_id; 
       
   197 	} ;
       
   198 	
       
   199 #else
       
   200 
       
   201 	static guint signals[LAST_SIGNAL] = {0};
       
   202 
       
   203 #endif	
       
   204 
       
   205 /* properties */
       
   206 enum
       
   207 {
       
   208     PROP_PROTOCOL = 1,
       
   209     PROP_CONNECT_SERVER,
       
   210     PROP_PORT,
       
   211     PROP_OLD_SSL,
       
   212     PROP_REGISTER,
       
   213     PROP_LOW_BANDWIDTH,
       
   214     PROP_STREAM_SERVER,
       
   215     PROP_USERNAME,
       
   216     PROP_PASSWORD,
       
   217     PROP_RESOURCE,
       
   218     PROP_PRIORITY,
       
   219     PROP_HTTPS_PROXY_SERVER,
       
   220     PROP_HTTPS_PROXY_PORT,
       
   221     PROP_FALLBACK_CONFERENCE_SERVER,
       
   222     PROP_STUN_SERVER,
       
   223     PROP_STUN_PORT,
       
   224     PROP_STUN_RELAY_MAGIC_COOKIE,
       
   225     PROP_STUN_RELAY_SERVER,
       
   226     PROP_STUN_RELAY_UDP_PORT,
       
   227     PROP_STUN_RELAY_TCP_PORT,
       
   228     PROP_STUN_RELAY_SSLTCP_PORT,
       
   229     PROP_STUN_RELAY_USERNAME,
       
   230     PROP_STUN_RELAY_PASSWORD,
       
   231     PROP_IGNORE_SSL_ERRORS,
       
   232     PROP_ALIAS,
       
   233 
       
   234     LAST_PROPERTY
       
   235 };
       
   236 
       
   237 /* TP properties */
       
   238 enum
       
   239 {
       
   240   CONN_PROP_STUN_SERVER = 0,
       
   241   CONN_PROP_STUN_PORT,
       
   242   CONN_PROP_STUN_RELAY_MAGIC_COOKIE,
       
   243   CONN_PROP_STUN_RELAY_SERVER,
       
   244   CONN_PROP_STUN_RELAY_UDP_PORT,
       
   245   CONN_PROP_STUN_RELAY_TCP_PORT,
       
   246   CONN_PROP_STUN_RELAY_SSLTCP_PORT,
       
   247   CONN_PROP_STUN_RELAY_USERNAME,
       
   248   CONN_PROP_STUN_RELAY_PASSWORD,
       
   249 
       
   250   NUM_CONN_PROPS,
       
   251 
       
   252   INVALID_CONN_PROP,
       
   253 };
       
   254 
       
   255 const GabblePropertySignature connection_property_signatures[NUM_CONN_PROPS] = {
       
   256       { "stun-server",                  G_TYPE_STRING },
       
   257       { "stun-port",                    G_TYPE_UINT   },
       
   258       { "stun-relay-magic-cookie",      G_TYPE_STRING },
       
   259       { "stun-relay-server",            G_TYPE_STRING },
       
   260       { "stun-relay-udp-port",          G_TYPE_UINT   },
       
   261       { "stun-relay-tcp-port",          G_TYPE_UINT   },
       
   262       { "stun-relay-ssltcp-port",       G_TYPE_UINT   },
       
   263       { "stun-relay-username",          G_TYPE_STRING },
       
   264       { "stun-relay-password",          G_TYPE_STRING },
       
   265 };
       
   266 
       
   267 /* private structure */
       
   268 typedef struct _GabbleConnectionPrivate GabbleConnectionPrivate;
       
   269 
       
   270 struct _GabbleConnectionPrivate
       
   271 {
       
   272   LmMessageHandler *iq_jingle_info_cb;
       
   273   LmMessageHandler *iq_search_keys_cb;
       
   274   LmMessageHandler *iq_disco_cb;
       
   275   LmMessageHandler *iq_unknown_cb;
       
   276   LmMessageHandler *stream_error_cb;
       
   277 
       
   278   /* telepathy properties */
       
   279   gchar *protocol;
       
   280 
       
   281   /* connection properties */
       
   282   gchar *connect_server;
       
   283   guint port;
       
   284   gboolean old_ssl;
       
   285 
       
   286   gboolean ignore_ssl_errors;
       
   287   TpConnectionStatusReason ssl_error;
       
   288 
       
   289   gboolean do_register;
       
   290 
       
   291   gboolean low_bandwidth;
       
   292 
       
   293   gchar *https_proxy_server;
       
   294   guint https_proxy_port;
       
   295 
       
   296   gchar *fallback_conference_server;
       
   297 
       
   298   /* authentication properties */
       
   299   gchar *stream_server;
       
   300   gchar *username;
       
   301   gchar *password;
       
   302   gchar *resource;
       
   303   gint8 priority;
       
   304   gchar *alias;
       
   305 
       
   306   /* reference to conference server name */
       
   307   const gchar *conference_server;
       
   308 
       
   309   /* channel factories */
       
   310   GPtrArray *channel_factories;
       
   311   GPtrArray *channel_requests;
       
   312   gboolean suppress_next_handler;
       
   313 
       
   314   /* serial number of current advertised caps */
       
   315   guint caps_serial;
       
   316 
       
   317   /* gobject housekeeping */
       
   318   gboolean dispose_has_run;
       
   319 };
       
   320 
       
   321 #define GABBLE_CONNECTION_GET_PRIVATE(obj) \
       
   322     ((GabbleConnectionPrivate *)obj->priv)
       
   323 
       
   324 typedef struct _ChannelRequest ChannelRequest;
       
   325 
       
   326 struct _ChannelRequest
       
   327 {
       
   328   DBusGMethodInvocation *context;
       
   329   gchar *channel_type;
       
   330   guint handle_type;
       
   331   guint handle;
       
   332   gboolean suppress_handler;
       
   333 };
       
   334 
       
   335 static void connection_new_channel_cb (TpChannelFactoryIface *, GObject *, gpointer);
       
   336 static void connection_channel_error_cb (TpChannelFactoryIface *, GObject *, GError *, gpointer);
       
   337 static void connection_nickname_update_cb (GObject *, GabbleHandle, gpointer);
       
   338 static void connection_presence_update_cb (GabblePresenceCache *, GabbleHandle, gpointer);
       
   339 static void connection_capabilities_update_cb (GabblePresenceCache *, GabbleHandle, GabblePresenceCapabilities, GabblePresenceCapabilities, gpointer);
       
   340 
       
   341 static void
       
   342 gabble_connection_init (GabbleConnection *self)
       
   343 {
       
   344   GabbleConnectionPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
       
   345       GABBLE_TYPE_CONNECTION, GabbleConnectionPrivate);
       
   346   guint i;
       
   347   GValue val = { 0, };
       
   348 
       
   349   self->priv = priv;
       
   350   self->lmconn = lm_connection_new (NULL);
       
   351   self->status = TP_CONN_STATUS_NEW;
       
   352   self->handles = gabble_handle_repo_new ();
       
   353   self->disco = gabble_disco_new (self);
       
   354   self->vcard_manager = gabble_vcard_manager_new (self);
       
   355   self->search_instr = NULL;
       
   356   self->search_key_names = NULL;
       
   357   self->search_reported_fields = NULL;
       
   358   self->search_form = FALSE;
       
   359   self->search_service_jid = NULL;
       
   360   self->self_avatar_sha1 = NULL;
       
   361   self->self_handle = 0;
       
   362   g_signal_connect (self->vcard_manager, "nickname-update", G_CALLBACK
       
   363       (connection_nickname_update_cb), self);
       
   364 
       
   365   self->presence_cache = gabble_presence_cache_new (self);
       
   366   g_signal_connect (self->presence_cache, "nickname-update", G_CALLBACK
       
   367       (connection_nickname_update_cb), self);
       
   368   g_signal_connect (self->presence_cache, "presence-update", G_CALLBACK
       
   369       (connection_presence_update_cb), self);
       
   370   g_signal_connect (self->presence_cache, "capabilities-update", G_CALLBACK
       
   371       (connection_capabilities_update_cb), self);
       
   372 
       
   373   capabilities_fill_cache (self->presence_cache);
       
   374 
       
   375   self->roster = gabble_roster_new (self);
       
   376   g_signal_connect (self->roster, "nickname-update", G_CALLBACK
       
   377       (connection_nickname_update_cb), self);
       
   378 
       
   379   priv->channel_factories = g_ptr_array_sized_new (1);
       
   380 
       
   381   g_ptr_array_add (priv->channel_factories, self->roster);
       
   382 
       
   383   g_ptr_array_add (priv->channel_factories,
       
   384                    g_object_new (GABBLE_TYPE_MUC_FACTORY,
       
   385                                  "connection", self,
       
   386                                  NULL));
       
   387 
       
   388   g_ptr_array_add (priv->channel_factories,
       
   389                    g_object_new (GABBLE_TYPE_MEDIA_FACTORY,
       
   390                                  "connection", self,
       
   391                                  NULL));
       
   392 
       
   393   g_ptr_array_add (priv->channel_factories,
       
   394                    g_object_new (GABBLE_TYPE_IM_FACTORY,
       
   395                                  "connection", self,
       
   396                                  NULL));
       
   397                                  
       
   398   //add for search here	
       
   399   g_ptr_array_add (priv->channel_factories,
       
   400                     g_object_new (GABBLE_TYPE_SEARCH_FACTORY,
       
   401                                  "connection", self,
       
   402                                  NULL));                               
       
   403 
       
   404   for (i = 0; i < priv->channel_factories->len; i++)
       
   405     {
       
   406       GObject *factory = g_ptr_array_index (priv->channel_factories, i);
       
   407       g_signal_connect (factory, "new-channel", G_CALLBACK
       
   408           (connection_new_channel_cb), self);
       
   409       g_signal_connect (factory, "channel-error", G_CALLBACK
       
   410           (connection_channel_error_cb), self);
       
   411     }
       
   412 
       
   413   priv->channel_requests = g_ptr_array_new ();
       
   414 
       
   415   /* Set default parameters for optional parameters */
       
   416   priv->resource = g_strdup (GABBLE_PARAMS_DEFAULT_RESOURCE);
       
   417   priv->port = GABBLE_PARAMS_DEFAULT_PORT;
       
   418   priv->https_proxy_port = GABBLE_PARAMS_DEFAULT_HTTPS_PROXY_PORT;
       
   419 
       
   420   /* initialize properties mixin */
       
   421   gabble_properties_mixin_init (G_OBJECT (self), G_STRUCT_OFFSET (
       
   422         GabbleConnection, properties));
       
   423 
       
   424   g_value_init (&val, G_TYPE_UINT);
       
   425   g_value_set_uint (&val, GABBLE_PARAMS_DEFAULT_STUN_PORT);
       
   426 
       
   427   gabble_properties_mixin_change_value (G_OBJECT (self), CONN_PROP_STUN_PORT,
       
   428                                         &val, NULL);
       
   429   gabble_properties_mixin_change_flags (G_OBJECT (self), CONN_PROP_STUN_PORT,
       
   430                                         TP_PROPERTY_FLAG_READ, 0, NULL);
       
   431 
       
   432   g_value_unset (&val);
       
   433 
       
   434   priv->caps_serial = 1;
       
   435 }
       
   436 
       
   437 static void
       
   438 gabble_connection_get_property (GObject    *object,
       
   439                                 guint       property_id,
       
   440                                 GValue     *value,
       
   441                                 GParamSpec *pspec)
       
   442 {
       
   443   GabbleConnection *self = (GabbleConnection *) object;
       
   444   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
   445   const gchar *param_name;
       
   446   guint tp_property_id;
       
   447 
       
   448   switch (property_id) {
       
   449     case PROP_PROTOCOL:
       
   450       g_value_set_string (value, priv->protocol);
       
   451       break;
       
   452     case PROP_CONNECT_SERVER:
       
   453       g_value_set_string (value, priv->connect_server);
       
   454       break;
       
   455     case PROP_STREAM_SERVER:
       
   456       g_value_set_string (value, priv->stream_server);
       
   457       break;
       
   458     case PROP_PORT:
       
   459       g_value_set_uint (value, priv->port);
       
   460       break;
       
   461     case PROP_OLD_SSL:
       
   462       g_value_set_boolean (value, priv->old_ssl);
       
   463       break;
       
   464     case PROP_REGISTER:
       
   465       g_value_set_boolean (value, priv->do_register);
       
   466       break;
       
   467     case PROP_LOW_BANDWIDTH:
       
   468       g_value_set_boolean (value, priv->low_bandwidth);
       
   469       break;
       
   470     case PROP_USERNAME:
       
   471       g_value_set_string (value, priv->username);
       
   472       break;
       
   473     case PROP_PASSWORD:
       
   474       g_value_set_string (value, priv->password);
       
   475       break;
       
   476     case PROP_RESOURCE:
       
   477       g_value_set_string (value, priv->resource);
       
   478       break;
       
   479     case PROP_PRIORITY:
       
   480       g_value_set_int (value, priv->priority);
       
   481       break;
       
   482     case PROP_HTTPS_PROXY_SERVER:
       
   483       g_value_set_string (value, priv->https_proxy_server);
       
   484       break;
       
   485     case PROP_HTTPS_PROXY_PORT:
       
   486       g_value_set_uint (value, priv->https_proxy_port);
       
   487       break;
       
   488     case PROP_FALLBACK_CONFERENCE_SERVER:
       
   489       g_value_set_string (value, priv->fallback_conference_server);
       
   490       break;
       
   491     case PROP_IGNORE_SSL_ERRORS:
       
   492       g_value_set_boolean (value, priv->ignore_ssl_errors);
       
   493       break;
       
   494     case PROP_ALIAS:
       
   495       g_value_set_string (value, priv->alias);
       
   496       break;
       
   497     default:
       
   498       param_name = g_param_spec_get_name (pspec);
       
   499 
       
   500       if (gabble_properties_mixin_has_property (object, param_name,
       
   501             &tp_property_id))
       
   502         {
       
   503           GValue *tp_property_value =
       
   504             self->properties.properties[tp_property_id].value;
       
   505 
       
   506           if (tp_property_value)
       
   507             {
       
   508               g_value_copy (tp_property_value, value);
       
   509               return;
       
   510             }
       
   511         }
       
   512 
       
   513       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       
   514       break;
       
   515   }
       
   516 }
       
   517 
       
   518 static void
       
   519 gabble_connection_set_property (GObject      *object,
       
   520                                 guint         property_id,
       
   521                                 const GValue *value,
       
   522                                 GParamSpec   *pspec)
       
   523 {
       
   524   GabbleConnection *self = (GabbleConnection *) object;
       
   525   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
   526   const gchar *param_name;
       
   527   guint tp_property_id;
       
   528 
       
   529   switch (property_id) {
       
   530     case PROP_PROTOCOL:
       
   531       g_free (priv->protocol);
       
   532       priv->protocol = g_value_dup_string (value);
       
   533       break;
       
   534     case PROP_CONNECT_SERVER:
       
   535       g_free (priv->connect_server);
       
   536       priv->connect_server = g_value_dup_string (value);
       
   537       break;
       
   538     case PROP_PORT:
       
   539       priv->port = g_value_get_uint (value);
       
   540       break;
       
   541     case PROP_OLD_SSL:
       
   542       priv->old_ssl = g_value_get_boolean (value);
       
   543       break;
       
   544     case PROP_REGISTER:
       
   545       priv->do_register = g_value_get_boolean (value);
       
   546       break;
       
   547     case PROP_LOW_BANDWIDTH:
       
   548       priv->low_bandwidth = g_value_get_boolean (value);
       
   549       break;
       
   550     case PROP_STREAM_SERVER:
       
   551       g_free (priv->stream_server);
       
   552       priv->stream_server = g_value_dup_string (value);
       
   553       break;
       
   554     case PROP_USERNAME:
       
   555       g_free (priv->username);
       
   556       priv->username = g_value_dup_string (value);
       
   557       break;
       
   558    case PROP_PASSWORD:
       
   559       g_free (priv->password);
       
   560       priv->password = g_value_dup_string (value);
       
   561       break;
       
   562     case PROP_RESOURCE:
       
   563       g_free (priv->resource);
       
   564       priv->resource = g_value_dup_string (value);
       
   565       break;
       
   566     case PROP_PRIORITY:
       
   567       priv->priority = CLAMP (g_value_get_int (value), G_MININT8, G_MAXINT8);
       
   568       break;
       
   569     case PROP_HTTPS_PROXY_SERVER:
       
   570       g_free (priv->https_proxy_server);
       
   571       priv->https_proxy_server = g_value_dup_string (value);
       
   572       break;
       
   573     case PROP_HTTPS_PROXY_PORT:
       
   574       priv->https_proxy_port = g_value_get_uint (value);
       
   575       break;
       
   576     case PROP_FALLBACK_CONFERENCE_SERVER:
       
   577       g_free (priv->fallback_conference_server);
       
   578       priv->fallback_conference_server = g_value_dup_string (value);
       
   579       break;
       
   580     case PROP_IGNORE_SSL_ERRORS:
       
   581       priv->ignore_ssl_errors = g_value_get_boolean (value);
       
   582       break;
       
   583    case PROP_ALIAS:
       
   584       g_free (priv->alias);
       
   585       priv->alias = g_value_dup_string (value);
       
   586       break;
       
   587     default:
       
   588       param_name = g_param_spec_get_name (pspec);
       
   589 
       
   590       if (gabble_properties_mixin_has_property (object, param_name,
       
   591             &tp_property_id))
       
   592         {
       
   593           gabble_properties_mixin_change_value (object, tp_property_id, value,
       
   594                                                 NULL);
       
   595           gabble_properties_mixin_change_flags (object, tp_property_id,
       
   596                                                 TP_PROPERTY_FLAG_READ,
       
   597                                                 0, NULL);
       
   598 
       
   599           return;
       
   600         }
       
   601 
       
   602       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       
   603       break;
       
   604   }
       
   605 }
       
   606 
       
   607 static void gabble_connection_dispose (GObject *object);
       
   608 static void gabble_connection_finalize (GObject *object);
       
   609 
       
   610 static void
       
   611 gabble_connection_class_init (GabbleConnectionClass *gabble_connection_class)
       
   612 {
       
   613   GObjectClass *object_class = G_OBJECT_CLASS (gabble_connection_class);
       
   614   GParamSpec *param_spec;
       
   615 
       
   616   object_class->get_property = gabble_connection_get_property;
       
   617   object_class->set_property = gabble_connection_set_property;
       
   618 
       
   619   g_type_class_add_private (gabble_connection_class, sizeof (GabbleConnectionPrivate));
       
   620 
       
   621   object_class->dispose = gabble_connection_dispose;
       
   622   object_class->finalize = gabble_connection_finalize;
       
   623 
       
   624   param_spec = g_param_spec_string ("protocol", "Telepathy identifier for protocol",
       
   625                                     "Identifier string used when the protocol "
       
   626                                     "name is required. Unused internally.",
       
   627                                     NULL,
       
   628                                     G_PARAM_READWRITE |
       
   629                                     G_PARAM_STATIC_NAME |
       
   630                                     G_PARAM_STATIC_BLURB);
       
   631   g_object_class_install_property (object_class, PROP_PROTOCOL, param_spec);
       
   632 
       
   633   param_spec = g_param_spec_string ("connect-server", "Hostname or IP of Jabber server",
       
   634                                     "The server used when establishing a connection.",
       
   635                                     NULL,
       
   636                                     G_PARAM_READWRITE |
       
   637                                     G_PARAM_STATIC_NAME |
       
   638                                     G_PARAM_STATIC_BLURB);
       
   639   g_object_class_install_property (object_class, PROP_CONNECT_SERVER, param_spec);
       
   640 
       
   641   param_spec = g_param_spec_uint ("port", "Jabber server port",
       
   642                                   "The port used when establishing a connection.",
       
   643                                   0, G_MAXUINT16, GABBLE_PARAMS_DEFAULT_PORT,
       
   644                                   G_PARAM_READWRITE |
       
   645                                   G_PARAM_STATIC_NAME |
       
   646                                   G_PARAM_STATIC_BLURB);
       
   647   g_object_class_install_property (object_class, PROP_PORT, param_spec);
       
   648 
       
   649   param_spec = g_param_spec_boolean ("old-ssl", "Old-style SSL tunneled connection",
       
   650                                      "Establish the entire connection to the server "
       
   651                                      "within an SSL-encrypted tunnel. Note that this "
       
   652                                      "is not the same as connecting with TLS, which "
       
   653                                      "is not yet supported.", FALSE,
       
   654                                      G_PARAM_READWRITE |
       
   655                                      G_PARAM_STATIC_NAME |
       
   656                                      G_PARAM_STATIC_BLURB);
       
   657   g_object_class_install_property (object_class, PROP_OLD_SSL, param_spec);
       
   658 
       
   659   param_spec = g_param_spec_boolean ("register", "Register account on server",
       
   660                                      "Register a new account on server.", FALSE,
       
   661                                      G_PARAM_READWRITE |
       
   662                                      G_PARAM_STATIC_NAME |
       
   663                                      G_PARAM_STATIC_BLURB);
       
   664   g_object_class_install_property (object_class, PROP_REGISTER, param_spec);
       
   665 
       
   666   param_spec = g_param_spec_boolean ("low-bandwidth", "Low bandwidth mode",
       
   667                                      "Determines whether we are in low "
       
   668                                      "bandwidth mode. This influences "
       
   669                                      "polling behaviour.", FALSE,
       
   670                                      G_PARAM_READWRITE |
       
   671                                      G_PARAM_STATIC_NAME |
       
   672                                      G_PARAM_STATIC_BLURB);
       
   673   g_object_class_install_property (object_class, PROP_LOW_BANDWIDTH, param_spec);
       
   674 
       
   675   param_spec = g_param_spec_string ("stream-server", "The server name used to initialise the stream.",
       
   676                                     "The server name used when initialising the stream, "
       
   677                                     "which is usually the part after the @ in the user's JID.",
       
   678                                     NULL,
       
   679                                     G_PARAM_READWRITE |
       
   680                                     G_PARAM_STATIC_NAME |
       
   681                                     G_PARAM_STATIC_BLURB);
       
   682   g_object_class_install_property (object_class, PROP_STREAM_SERVER, param_spec);
       
   683 
       
   684   param_spec = g_param_spec_string ("username", "Jabber username",
       
   685                                     "The username used when authenticating.",
       
   686                                     NULL,
       
   687                                     G_PARAM_READWRITE |
       
   688                                     G_PARAM_STATIC_NAME |
       
   689                                     G_PARAM_STATIC_BLURB);
       
   690   g_object_class_install_property (object_class, PROP_USERNAME, param_spec);
       
   691 
       
   692   param_spec = g_param_spec_string ("password", "Jabber password",
       
   693                                     "The password used when authenticating.",
       
   694                                     NULL,
       
   695                                     G_PARAM_READWRITE |
       
   696                                     G_PARAM_STATIC_NAME |
       
   697                                     G_PARAM_STATIC_BLURB);
       
   698   g_object_class_install_property (object_class, PROP_PASSWORD, param_spec);
       
   699 
       
   700   param_spec = g_param_spec_string ("resource", "Jabber resource",
       
   701                                     "The Jabber resource used when authenticating.",
       
   702                                     "Telepathy",
       
   703                                     G_PARAM_READWRITE |
       
   704                                     G_PARAM_STATIC_NAME |
       
   705                                     G_PARAM_STATIC_BLURB);
       
   706   g_object_class_install_property (object_class, PROP_RESOURCE, param_spec);
       
   707 
       
   708   param_spec = g_param_spec_int ("priority", "Jabber presence priority",
       
   709                                  "The default priority used when reporting our presence.",
       
   710                                  G_MININT8, G_MAXINT8, 0,
       
   711                                  G_PARAM_READWRITE |
       
   712                                  G_PARAM_STATIC_NAME |
       
   713                                  G_PARAM_STATIC_BLURB);
       
   714   g_object_class_install_property (object_class, PROP_PRIORITY, param_spec);
       
   715 
       
   716   param_spec = g_param_spec_string ("https-proxy-server", "The server name "
       
   717                                     "used as an HTTPS proxy server",
       
   718                                     "The server name used as an HTTPS proxy "
       
   719                                     "server.",
       
   720                                     NULL,
       
   721                                     G_PARAM_READWRITE |
       
   722                                     G_PARAM_STATIC_NAME |
       
   723                                     G_PARAM_STATIC_BLURB);
       
   724   g_object_class_install_property (object_class, PROP_HTTPS_PROXY_SERVER, param_spec);
       
   725 
       
   726   param_spec = g_param_spec_uint ("https-proxy-port", "The HTTP proxy server "
       
   727                                   "port", "The HTTP proxy server port.",
       
   728                                   0, G_MAXUINT16, 0,
       
   729                                   G_PARAM_READWRITE |
       
   730                                   G_PARAM_STATIC_NAME |
       
   731                                   G_PARAM_STATIC_BLURB);
       
   732   g_object_class_install_property (object_class, PROP_HTTPS_PROXY_PORT, param_spec);
       
   733 
       
   734   param_spec = g_param_spec_string ("fallback-conference-server",
       
   735                                     "The conference server used as fallback",
       
   736                                     "The conference server used as fallback when "
       
   737                                     "everything else fails.",
       
   738                                     NULL,
       
   739                                     G_PARAM_READWRITE |
       
   740                                     G_PARAM_STATIC_NAME |
       
   741                                     G_PARAM_STATIC_BLURB);
       
   742   g_object_class_install_property (object_class, PROP_FALLBACK_CONFERENCE_SERVER,
       
   743                                    param_spec);
       
   744 
       
   745   param_spec = g_param_spec_string ("stun-server",
       
   746                                     "STUN server",
       
   747                                     "STUN server.",
       
   748                                     NULL,
       
   749                                     G_PARAM_READWRITE |
       
   750                                     G_PARAM_STATIC_NAME |
       
   751                                     G_PARAM_STATIC_BLURB);
       
   752   g_object_class_install_property (object_class, PROP_STUN_SERVER, param_spec);
       
   753 
       
   754   param_spec = g_param_spec_uint ("stun-port",
       
   755                                   "STUN port",
       
   756                                   "STUN port.",
       
   757                                   0, G_MAXUINT16, 0,
       
   758                                   G_PARAM_READWRITE |
       
   759                                   G_PARAM_STATIC_NAME |
       
   760                                   G_PARAM_STATIC_BLURB);
       
   761   g_object_class_install_property (object_class, PROP_STUN_PORT, param_spec);
       
   762 
       
   763   param_spec = g_param_spec_string ("stun-relay-magic-cookie",
       
   764                                     "STUN relay magic cookie",
       
   765                                     "STUN relay magic cookie.",
       
   766                                     NULL,
       
   767                                     G_PARAM_READWRITE |
       
   768                                     G_PARAM_STATIC_NAME |
       
   769                                     G_PARAM_STATIC_BLURB);
       
   770   g_object_class_install_property (object_class, PROP_STUN_RELAY_MAGIC_COOKIE,
       
   771                                    param_spec);
       
   772 
       
   773   param_spec = g_param_spec_string ("stun-relay-server",
       
   774                                     "STUN relay server",
       
   775                                     "STUN relay server.",
       
   776                                     NULL,
       
   777                                     G_PARAM_READWRITE |
       
   778                                     G_PARAM_STATIC_NAME |
       
   779                                     G_PARAM_STATIC_BLURB);
       
   780   g_object_class_install_property (object_class, PROP_STUN_RELAY_SERVER,
       
   781                                    param_spec);
       
   782 
       
   783   param_spec = g_param_spec_uint ("stun-relay-udp-port",
       
   784                                   "STUN relay UDP port",
       
   785                                   "STUN relay UDP port.",
       
   786                                   0, G_MAXUINT16, 0,
       
   787                                   G_PARAM_READWRITE |
       
   788                                   G_PARAM_STATIC_NAME |
       
   789                                   G_PARAM_STATIC_BLURB);
       
   790   g_object_class_install_property (object_class, PROP_STUN_RELAY_UDP_PORT,
       
   791                                    param_spec);
       
   792 
       
   793   param_spec = g_param_spec_uint ("stun-relay-tcp-port",
       
   794                                   "STUN relay TCP port",
       
   795                                   "STUN relay TCP port.",
       
   796                                   0, G_MAXUINT16, 0,
       
   797                                   G_PARAM_READWRITE |
       
   798                                   G_PARAM_STATIC_NAME |
       
   799                                   G_PARAM_STATIC_BLURB);
       
   800   g_object_class_install_property (object_class, PROP_STUN_RELAY_TCP_PORT,
       
   801                                    param_spec);
       
   802 
       
   803   param_spec = g_param_spec_uint ("stun-relay-ssltcp-port",
       
   804                                   "STUN relay SSL-TCP port",
       
   805                                   "STUN relay SSL-TCP port.",
       
   806                                   0, G_MAXUINT16, 0,
       
   807                                   G_PARAM_READWRITE |
       
   808                                   G_PARAM_STATIC_NAME |
       
   809                                   G_PARAM_STATIC_BLURB);
       
   810   g_object_class_install_property (object_class, PROP_STUN_RELAY_SSLTCP_PORT,
       
   811                                    param_spec);
       
   812 
       
   813   param_spec = g_param_spec_string ("stun-relay-username",
       
   814                                     "STUN relay username",
       
   815                                     "STUN relay username.",
       
   816                                     NULL,
       
   817                                     G_PARAM_READWRITE |
       
   818                                     G_PARAM_STATIC_NAME |
       
   819                                     G_PARAM_STATIC_BLURB);
       
   820   g_object_class_install_property (object_class, PROP_STUN_RELAY_USERNAME,
       
   821                                    param_spec);
       
   822 
       
   823   param_spec = g_param_spec_string ("stun-relay-password",
       
   824                                     "STUN relay password",
       
   825                                     "STUN relay password.",
       
   826                                     NULL,
       
   827                                     G_PARAM_READWRITE |
       
   828                                     G_PARAM_STATIC_NAME |
       
   829                                     G_PARAM_STATIC_BLURB);
       
   830   g_object_class_install_property (object_class, PROP_STUN_RELAY_PASSWORD,
       
   831                                    param_spec);
       
   832 
       
   833   param_spec = g_param_spec_boolean ("ignore-ssl-errors", "Ignore SSL errors",
       
   834                                      "Continue connecting even if the server's "
       
   835                                      "SSL certificate is invalid or missing.",
       
   836                                      FALSE,
       
   837                                      G_PARAM_READWRITE |
       
   838                                      G_PARAM_STATIC_NAME |
       
   839                                      G_PARAM_STATIC_BLURB);
       
   840   g_object_class_install_property (object_class, PROP_IGNORE_SSL_ERRORS, param_spec);
       
   841 
       
   842   param_spec = g_param_spec_string ("alias",
       
   843                                     "Alias/nick for local user",
       
   844                                     "Alias/nick for local user",
       
   845                                     NULL,
       
   846                                     G_PARAM_READWRITE |
       
   847                                     G_PARAM_STATIC_NAME |
       
   848                                     G_PARAM_STATIC_BLURB);
       
   849   g_object_class_install_property (object_class, PROP_ALIAS, param_spec);
       
   850 
       
   851   /* signal definitions */
       
   852 
       
   853   signals[ALIASES_CHANGED] =
       
   854     g_signal_new ("aliases-changed",
       
   855                   G_OBJECT_CLASS_TYPE (gabble_connection_class),
       
   856                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   857                   0,
       
   858                   NULL, NULL,
       
   859                   g_cclosure_marshal_VOID__BOXED,
       
   860                   G_TYPE_NONE, 1, (dbus_g_type_get_collection ("GPtrArray", (dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT, G_TYPE_STRING, G_TYPE_INVALID)))));
       
   861 
       
   862   signals[CAPABILITIES_CHANGED] =
       
   863     g_signal_new ("capabilities-changed",
       
   864                   G_OBJECT_CLASS_TYPE (gabble_connection_class),
       
   865                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   866                   0,
       
   867                   NULL, NULL,
       
   868                   g_cclosure_marshal_VOID__BOXED,
       
   869                   G_TYPE_NONE, 1, (dbus_g_type_get_collection ("GPtrArray", (dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID)))));
       
   870 
       
   871   signals[NEW_CHANNEL] =
       
   872     g_signal_new ("new-channel",
       
   873                   G_OBJECT_CLASS_TYPE (gabble_connection_class),
       
   874                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   875                   0,
       
   876                   NULL, NULL,
       
   877                   gabble_connection_marshal_VOID__STRING_STRING_UINT_UINT_BOOLEAN,
       
   878                   G_TYPE_NONE, 5, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN);
       
   879 
       
   880   signals[PRESENCE_UPDATE] =
       
   881     g_signal_new ("presence-update",
       
   882                   G_OBJECT_CLASS_TYPE (gabble_connection_class),
       
   883                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   884                   0,
       
   885                   NULL, NULL,
       
   886                   g_cclosure_marshal_VOID__BOXED,
       
   887                   G_TYPE_NONE, 1, (dbus_g_type_get_map ("GHashTable", G_TYPE_UINT, (dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT, (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)))), G_TYPE_INVALID)))));
       
   888 
       
   889   signals[STATUS_CHANGED] =
       
   890     g_signal_new ("status-changed",
       
   891                   G_OBJECT_CLASS_TYPE (gabble_connection_class),
       
   892                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   893                   0,
       
   894                   NULL, NULL,
       
   895                   gabble_connection_marshal_VOID__UINT_UINT,
       
   896                   G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
       
   897 
       
   898   signals[DISCONNECTED] =
       
   899     g_signal_new ("disconnected",
       
   900                   G_OBJECT_CLASS_TYPE (gabble_connection_class),
       
   901                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   902                   0,
       
   903                   NULL, NULL,
       
   904                   g_cclosure_marshal_VOID__VOID,
       
   905                   G_TYPE_NONE, 0);
       
   906 
       
   907   dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (gabble_connection_class), &dbus_glib_gabble_connection_object_info);
       
   908 
       
   909   gabble_properties_mixin_class_init (G_OBJECT_CLASS (gabble_connection_class),
       
   910                                       G_STRUCT_OFFSET (GabbleConnectionClass, properties_class),
       
   911                                       connection_property_signatures, NUM_CONN_PROPS,
       
   912                                       NULL);
       
   913 }
       
   914 
       
   915 static gboolean
       
   916 _unref_lm_connection (gpointer data)
       
   917 {
       
   918   LmConnection *conn = (LmConnection *) data;
       
   919 
       
   920   lm_connection_unref (conn);
       
   921   return FALSE;
       
   922 }
       
   923 
       
   924 void
       
   925 gabble_connection_dispose (GObject *object)
       
   926 {
       
   927   GabbleConnection *self = GABBLE_CONNECTION (object);
       
   928   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
   929   DBusGProxy *bus_proxy;
       
   930   guint i;
       
   931   bus_proxy = tp_get_bus_proxy ();
       
   932 
       
   933   if (priv->dispose_has_run)
       
   934     return;
       
   935 
       
   936   priv->dispose_has_run = TRUE;
       
   937 
       
   938   gabble_debug (DEBUG_FLAG, "called");
       
   939 
       
   940   g_message("1 Inside gabble_connection_dispose() method");
       
   941   
       
   942   //<todo> are these asserts a valid one ?
       
   943   //As in case of lm_connection_open these will not be valid assertions ?
       
   944   //to remove these?
       
   945   g_assert ((self->status == TP_CONN_STATUS_DISCONNECTED) ||
       
   946             (self->status == TP_CONN_STATUS_NEW));
       
   947   //This is not a valid statement as the self_handle is set to a value in _gabble_connection_connect which wil call 
       
   948   //lm_connection_open(within do_connect). If the call fails then control comes here.. in which case self_handle can be other 
       
   949   //than 0)
       
   950   //g_assert (self->self_handle == 0);
       
   951 
       
   952   g_message("after assert");
       
   953   if (priv->channel_requests)
       
   954     {
       
   955       g_assert (priv->channel_requests->len == 0);
       
   956       g_ptr_array_free (priv->channel_requests, TRUE);
       
   957       priv->channel_requests = NULL;
       
   958     }
       
   959 
       
   960   g_ptr_array_foreach (priv->channel_factories, (GFunc) g_object_unref, NULL);
       
   961   g_ptr_array_free (priv->channel_factories, TRUE);
       
   962   priv->channel_factories = NULL;
       
   963   g_message("unrefed channel factories");
       
   964   if(self->search_instr)
       
   965 	  {
       
   966 	    g_free( self->search_instr );
       
   967 	  	self->search_instr = NULL;
       
   968 	  }
       
   969 	 
       
   970   if(self->search_key_names)
       
   971 	  {
       
   972 	  	for( i=0; self->search_key_names[i]; i++ )
       
   973 			{
       
   974 			g_free( self->search_key_names[i] );
       
   975 			self->search_key_names[i] = NULL;
       
   976 			}
       
   977 	  	g_free( self->search_key_names );
       
   978 	  	self->search_key_names = NULL;	
       
   979 	  }
       
   980   g_message("freed search keys");
       
   981   if ( self->self_avatar_sha1 )
       
   982       {
       
   983       g_free ( self->self_avatar_sha1 );
       
   984       }
       
   985   if(self->search_key_ht)
       
   986 	  {
       
   987 	   g_hash_table_destroy (self->search_key_ht);
       
   988 	   self->search_key_ht = NULL;	
       
   989 	  }	  
       
   990   if(self->search_service_jid)
       
   991 	  {
       
   992 	   g_free(self->search_service_jid);
       
   993 	   self->search_service_jid = NULL;	
       
   994 	  }
       
   995   /* unreffing channel factories frees the roster */
       
   996   self->roster = NULL;
       
   997 
       
   998   g_object_unref (self->disco);
       
   999   self->disco = NULL;
       
  1000 
       
  1001   g_object_unref (self->vcard_manager);
       
  1002   self->vcard_manager = NULL;
       
  1003 
       
  1004   g_object_unref (self->presence_cache);
       
  1005   self->presence_cache = NULL;
       
  1006 
       
  1007   /* if this is not already the case, we'll crash anyway */
       
  1008   g_assert (!lm_connection_is_open (self->lmconn));
       
  1009   g_assert (priv->iq_search_keys_cb == NULL);
       
  1010   g_assert (priv->iq_jingle_info_cb == NULL);
       
  1011   g_assert (priv->iq_disco_cb == NULL);
       
  1012   g_assert (priv->iq_unknown_cb == NULL);
       
  1013   g_assert (priv->stream_error_cb == NULL);
       
  1014 
       
  1015   /*
       
  1016    * The Loudmouth connection can't be unref'd immediately because this
       
  1017    * function might (indirectly) return into Loudmouth code which expects the
       
  1018    * connection to always be there.
       
  1019    */
       
  1020   g_idle_add (_unref_lm_connection, self->lmconn);
       
  1021 
       
  1022   if (NULL != self->bus_name)
       
  1023     {
       
  1024       dbus_g_proxy_call_no_reply (bus_proxy, "ReleaseName",
       
  1025                                   G_TYPE_STRING, self->bus_name,
       
  1026                                   G_TYPE_INVALID);
       
  1027     }
       
  1028 
       
  1029   if (G_OBJECT_CLASS (gabble_connection_parent_class)->dispose)
       
  1030     G_OBJECT_CLASS (gabble_connection_parent_class)->dispose (object);
       
  1031   
       
  1032   g_message("out of the method");
       
  1033 }
       
  1034 
       
  1035 void
       
  1036 gabble_connection_finalize (GObject *object)
       
  1037 {
       
  1038   GabbleConnection *self = GABBLE_CONNECTION (object);
       
  1039   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  1040 
       
  1041   gabble_debug (DEBUG_FLAG, "called with %p", object);
       
  1042 
       
  1043   g_free (self->bus_name);
       
  1044   g_free (self->object_path);
       
  1045 
       
  1046   g_free (priv->protocol);
       
  1047   g_free (priv->connect_server);
       
  1048   g_free (priv->stream_server);
       
  1049   g_free (priv->username);
       
  1050   g_free (priv->password);
       
  1051   g_free (priv->resource);
       
  1052 
       
  1053   g_free (priv->https_proxy_server);
       
  1054   g_free (priv->fallback_conference_server);
       
  1055 
       
  1056   g_free (priv->alias);
       
  1057 
       
  1058   gabble_properties_mixin_finalize (object);
       
  1059 
       
  1060   gabble_handle_repo_destroy (self->handles);
       
  1061 
       
  1062   G_OBJECT_CLASS (gabble_connection_parent_class)->finalize (object);
       
  1063 }
       
  1064 
       
  1065 /**
       
  1066  * _gabble_connection_set_properties_from_account
       
  1067  *
       
  1068  * Parses an account string which may be one of the following forms:
       
  1069  *  username
       
  1070  *  username/resource
       
  1071  *  username@server
       
  1072  *  username@server/resource
       
  1073  * and sets the properties for username, stream server and resource
       
  1074  * appropriately. Also sets the connect server to the stream server if one has
       
  1075  * not yet been specified.
       
  1076  */
       
  1077 
       
  1078 gboolean
       
  1079 _gabble_connection_set_properties_from_account (GabbleConnection *conn,
       
  1080                                                 const gchar      *account,
       
  1081                                                 GError          **error)
       
  1082 {
       
  1083   GabbleConnectionPrivate *priv;
       
  1084   char *username, *server, *resource;
       
  1085   gboolean result;
       
  1086 
       
  1087   g_assert (GABBLE_IS_CONNECTION (conn));
       
  1088   g_assert (account != NULL);
       
  1089 
       
  1090   priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  1091 
       
  1092   username = server = resource = NULL;
       
  1093   result = TRUE;
       
  1094 
       
  1095   gabble_decode_jid (account, &username, &server, &resource);
       
  1096 
       
  1097   if (username == NULL || server == NULL ||
       
  1098       *username == '\0' || *server == '\0')
       
  1099     {
       
  1100       g_set_error (error, TELEPATHY_ERRORS, InvalidArgument,
       
  1101           "unable to get username and server from account");
       
  1102       result = FALSE;
       
  1103       goto OUT;
       
  1104     }
       
  1105 
       
  1106   g_object_set (G_OBJECT (conn),
       
  1107                 "username", username,
       
  1108                 "stream-server", server,
       
  1109                 NULL);
       
  1110 
       
  1111   /* only override the default resource if we actually got one */
       
  1112   if (resource)
       
  1113     g_object_set (G_OBJECT (conn), "resource", resource, NULL);
       
  1114 
       
  1115 OUT:
       
  1116   g_free (username);
       
  1117   g_free (server);
       
  1118   g_free (resource);
       
  1119 
       
  1120   return result;
       
  1121 }
       
  1122 
       
  1123 /**
       
  1124  * _gabble_connection_register
       
  1125  *
       
  1126  * Make the connection object appear on the bus, returning the bus
       
  1127  * name and object path used.
       
  1128  */
       
  1129 gboolean
       
  1130 _gabble_connection_register (GabbleConnection *conn,
       
  1131                              gchar           **bus_name,
       
  1132                              gchar           **object_path,
       
  1133                              GError          **error)
       
  1134 {
       
  1135   DBusGConnection *bus;
       
  1136   DBusGProxy *bus_proxy;
       
  1137   GabbleConnectionPrivate *priv;
       
  1138   const char *allowed_chars = "_1234567890"
       
  1139                               "abcdefghijklmnopqrstuvwxyz"
       
  1140                               "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
       
  1141   char *safe_proto;
       
  1142   char *unique_name;
       
  1143   guint request_name_result;
       
  1144   GError *request_error;
       
  1145 
       
  1146   g_message("1 Inside _gabble_connection_register() method");
       
  1147   g_assert (GABBLE_IS_CONNECTION (conn));
       
  1148 
       
  1149   bus = tp_get_bus ();
       
  1150   bus_proxy = tp_get_bus_proxy ();
       
  1151   priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  1152 
       
  1153   safe_proto = g_strdup (priv->protocol);
       
  1154   g_strcanon (safe_proto, allowed_chars, '_');
       
  1155 
       
  1156   unique_name = g_strdup_printf ("_%s_%s_%s",
       
  1157                                  priv->username,
       
  1158                                  priv->stream_server,
       
  1159                                  priv->resource);
       
  1160   g_strcanon (unique_name, allowed_chars, '_');
       
  1161 
       
  1162   conn->bus_name = g_strdup_printf (BUS_NAME ".%s.%s",
       
  1163                                     safe_proto,
       
  1164                                     unique_name);
       
  1165   conn->object_path = g_strdup_printf (OBJECT_PATH "/%s/%s",
       
  1166                                        safe_proto,
       
  1167                                        unique_name);
       
  1168 
       
  1169   g_free (safe_proto);
       
  1170   g_free (unique_name);
       
  1171 
       
  1172   if (!dbus_g_proxy_call (bus_proxy, "RequestName", &request_error,
       
  1173                           G_TYPE_STRING, conn->bus_name,
       
  1174                           G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE,
       
  1175                           G_TYPE_INVALID,
       
  1176                           G_TYPE_UINT, &request_name_result,
       
  1177                           G_TYPE_INVALID))
       
  1178     {
       
  1179       g_set_error (error, TELEPATHY_ERRORS, NotAvailable,
       
  1180           "Error acquiring bus name %s: %s", conn->bus_name,
       
  1181           request_error->message);
       
  1182 
       
  1183       g_error_free (request_error);
       
  1184 
       
  1185       g_free (conn->bus_name);
       
  1186       conn->bus_name = NULL;
       
  1187 
       
  1188       return FALSE;
       
  1189     }
       
  1190 
       
  1191   if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
       
  1192     {
       
  1193       gchar *msg;
       
  1194 
       
  1195       switch (request_name_result)
       
  1196         {
       
  1197         case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
       
  1198           msg = "Request has been queued, though we request non-queueing.";
       
  1199           break;
       
  1200         case DBUS_REQUEST_NAME_REPLY_EXISTS:
       
  1201           msg = "A connection manger already has this busname.";
       
  1202           break;
       
  1203         case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
       
  1204           msg = "Connection manager already has a connection to this account.";
       
  1205           break;
       
  1206         default:
       
  1207           msg = "Unknown error return from ReleaseName";
       
  1208         }
       
  1209 
       
  1210       g_set_error (error, TELEPATHY_ERRORS, NotAvailable,
       
  1211           "Error acquiring bus name %s: %s", conn->bus_name, msg);
       
  1212 
       
  1213       g_free (conn->bus_name);
       
  1214       conn->bus_name = NULL;
       
  1215 
       
  1216       return FALSE;
       
  1217     }
       
  1218 
       
  1219   gabble_debug (DEBUG_FLAG, "bus name %s", conn->bus_name);
       
  1220 
       
  1221   dbus_g_connection_register_g_object (bus, conn->object_path, G_OBJECT (conn));
       
  1222 
       
  1223   gabble_debug (DEBUG_FLAG, "object path %s", conn->object_path);
       
  1224 
       
  1225   *bus_name = g_strdup (conn->bus_name);
       
  1226   *object_path = g_strdup (conn->object_path);
       
  1227 
       
  1228   return TRUE;
       
  1229 }
       
  1230 
       
  1231 
       
  1232 /**
       
  1233  * _gabble_connection_send
       
  1234  *
       
  1235  * Send an LmMessage and trap network errors appropriately.
       
  1236  */
       
  1237 gboolean
       
  1238 _gabble_connection_send (GabbleConnection *conn, LmMessage *msg, GError **error)
       
  1239 {
       
  1240   GabbleConnectionPrivate *priv;
       
  1241   GError *lmerror = NULL;
       
  1242 
       
  1243   g_assert (GABBLE_IS_CONNECTION (conn));
       
  1244 
       
  1245   priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  1246 
       
  1247   if (!lm_connection_send (conn->lmconn, msg, &lmerror))
       
  1248     {
       
  1249       gabble_debug (DEBUG_FLAG, "failed: %s", lmerror->message);
       
  1250 
       
  1251       g_set_error (error, TELEPATHY_ERRORS, NetworkError,
       
  1252           "message send failed: %s", lmerror->message);
       
  1253 
       
  1254       g_error_free (lmerror);
       
  1255 
       
  1256       return FALSE;
       
  1257     }
       
  1258 
       
  1259   return TRUE;
       
  1260 }
       
  1261 
       
  1262 typedef struct {
       
  1263     GabbleConnectionMsgReplyFunc reply_func;
       
  1264 
       
  1265     GabbleConnection *conn;
       
  1266     LmMessage *sent_msg;
       
  1267     gpointer user_data;
       
  1268 
       
  1269     GObject *object;
       
  1270     gboolean object_alive;
       
  1271 } GabbleMsgHandlerData;
       
  1272 
       
  1273 static LmHandlerResult
       
  1274 message_send_reply_cb (LmMessageHandler *handler,
       
  1275                        LmConnection *connection,
       
  1276                        LmMessage *reply_msg,
       
  1277                        gpointer user_data)
       
  1278 {
       
  1279   GabbleMsgHandlerData *handler_data = user_data;
       
  1280   LmMessageSubType sub_type;
       
  1281 
       
  1282   sub_type = lm_message_get_sub_type (reply_msg);
       
  1283 
       
  1284   /* Is it a reply to this message? If we're talking to another loudmouth,
       
  1285    * they can send us messages which have the same ID as ones we send. :-O */
       
  1286   if (sub_type != LM_MESSAGE_SUB_TYPE_RESULT &&
       
  1287       sub_type != LM_MESSAGE_SUB_TYPE_ERROR)
       
  1288     {
       
  1289       return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  1290     }
       
  1291 
       
  1292   if (handler_data->object_alive)
       
  1293     {
       
  1294       return handler_data->reply_func (handler_data->conn,
       
  1295                                        handler_data->sent_msg,
       
  1296                                        reply_msg,
       
  1297                                        handler_data->object,
       
  1298                                        handler_data->user_data);
       
  1299     }
       
  1300 
       
  1301   return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
  1302 }
       
  1303 
       
  1304 static void
       
  1305 message_send_object_destroy_notify_cb (gpointer data,
       
  1306                                        GObject *where_the_object_was)
       
  1307 {
       
  1308   GabbleMsgHandlerData *handler_data = data;
       
  1309 
       
  1310   handler_data->object = NULL;
       
  1311   handler_data->object_alive = FALSE;
       
  1312 }
       
  1313 
       
  1314 static void
       
  1315 message_send_handler_destroy_cb (gpointer data)
       
  1316 {
       
  1317   GabbleMsgHandlerData *handler_data = data;
       
  1318 
       
  1319   lm_message_unref (handler_data->sent_msg);
       
  1320 
       
  1321   if (handler_data->object != NULL)
       
  1322     {
       
  1323       g_object_weak_unref (handler_data->object,
       
  1324                            message_send_object_destroy_notify_cb,
       
  1325                            handler_data);
       
  1326     }
       
  1327 
       
  1328   g_free (handler_data);
       
  1329 }
       
  1330 
       
  1331 /**
       
  1332  * _gabble_connection_send_with_reply
       
  1333  *
       
  1334  * Send a tracked LmMessage and trap network errors appropriately.
       
  1335  *
       
  1336  * If object is non-NULL the handler will follow the lifetime of that object,
       
  1337  * which means that if the object is destroyed the callback will not be invoked.
       
  1338  */
       
  1339 gboolean
       
  1340 _gabble_connection_send_with_reply (GabbleConnection *conn,
       
  1341                                     LmMessage *msg,
       
  1342                                     GabbleConnectionMsgReplyFunc reply_func,
       
  1343                                     GObject *object,
       
  1344                                     gpointer user_data,
       
  1345                                     GError **error)
       
  1346 {
       
  1347   GabbleConnectionPrivate *priv;
       
  1348   LmMessageHandler *handler;
       
  1349   GabbleMsgHandlerData *handler_data;
       
  1350   gboolean ret;
       
  1351   GError *lmerror = NULL;
       
  1352 
       
  1353   g_assert (GABBLE_IS_CONNECTION (conn));
       
  1354 
       
  1355   priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  1356 
       
  1357   lm_message_ref (msg);
       
  1358 
       
  1359   handler_data = g_new (GabbleMsgHandlerData, 1);
       
  1360   handler_data->reply_func = reply_func;
       
  1361   handler_data->conn = conn;
       
  1362   handler_data->sent_msg = msg;
       
  1363   handler_data->user_data = user_data;
       
  1364 
       
  1365   handler_data->object = object;
       
  1366   handler_data->object_alive = TRUE;
       
  1367 
       
  1368   if (object != NULL)
       
  1369     {
       
  1370       g_object_weak_ref (object, message_send_object_destroy_notify_cb,
       
  1371                          handler_data);
       
  1372     }
       
  1373 
       
  1374   handler = lm_message_handler_new (message_send_reply_cb, handler_data,
       
  1375                                     message_send_handler_destroy_cb);
       
  1376 
       
  1377   ret = lm_connection_send_with_reply (conn->lmconn, msg, handler, &lmerror);
       
  1378   if (!ret)
       
  1379     {
       
  1380       gabble_debug (DEBUG_FLAG, "failed: %s", lmerror->message);
       
  1381 
       
  1382       if (error)
       
  1383         {
       
  1384           g_set_error (error, TELEPATHY_ERRORS, NetworkError,
       
  1385               "message send failed: %s", lmerror->message);
       
  1386         }
       
  1387 
       
  1388       g_error_free (lmerror);
       
  1389     }
       
  1390 
       
  1391   lm_message_handler_unref (handler);
       
  1392 
       
  1393   return ret;
       
  1394 }
       
  1395 
       
  1396 static LmHandlerResult connection_iq_disco_cb (LmMessageHandler*, LmConnection*, LmMessage*, gpointer);
       
  1397 static LmHandlerResult connection_iq_unknown_cb (LmMessageHandler*, LmConnection*, LmMessage*, gpointer);
       
  1398 static LmHandlerResult connection_stream_error_cb (LmMessageHandler*, LmConnection*, LmMessage*, gpointer);
       
  1399 static LmSSLResponse connection_ssl_cb (LmSSL*, LmSSLStatus, gpointer);
       
  1400 static void connection_open_cb (LmConnection*, gboolean, gpointer);
       
  1401 static void connection_auth_cb (LmConnection*, gboolean, gpointer);
       
  1402 static void connection_disco_cb (GabbleDisco *, GabbleDiscoRequest *, const gchar *, const gchar *, LmMessageNode *, GError *, gpointer);
       
  1403 static void connection_disconnected_cb (LmConnection *, LmDisconnectReason, gpointer);
       
  1404 static void connection_status_change (GabbleConnection *, TpConnectionStatus, TpConnectionStatusReason);
       
  1405 
       
  1406 static void channel_request_cancel (gpointer data, gpointer user_data);
       
  1407 
       
  1408 static void emit_one_presence_update (GabbleConnection *self, GabbleHandle handle);
       
  1409 
       
  1410 
       
  1411 static gboolean
       
  1412 do_connect (GabbleConnection *conn, GError **error)
       
  1413 {
       
  1414   GError *lmerror = NULL;
       
  1415 
       
  1416   gabble_debug (DEBUG_FLAG, "calling lm_connection_open");
       
  1417 	g_message("**gabble do_connect: before calling lm_connection_open\n");	
       
  1418 
       
  1419   if (!lm_connection_open (conn->lmconn, connection_open_cb,
       
  1420                            conn, NULL, &lmerror))
       
  1421     {
       
  1422       gabble_debug (DEBUG_FLAG, "lm_connection_open failed %s", lmerror->message);
       
  1423 
       
  1424       g_set_error (error, TELEPATHY_ERRORS, NetworkError,
       
  1425           "lm_connection_open failed: %s", lmerror->message);
       
  1426 
       
  1427       g_signal_emit (conn, signals[DISCONNECTED], 0);
       
  1428       g_error_free (lmerror);
       
  1429 
       
  1430       return FALSE;
       
  1431     }
       
  1432 
       
  1433 	g_message("**gabble do_connect: after calling lm_connection_open and it passed\n");	
       
  1434 
       
  1435   return TRUE;
       
  1436 }
       
  1437 
       
  1438 static void
       
  1439 connect_callbacks (GabbleConnection *conn)
       
  1440 {
       
  1441   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  1442 
       
  1443   g_message("inside connect_callbacks\n");
       
  1444   g_assert (priv->iq_search_keys_cb == NULL);
       
  1445   g_assert (priv->iq_jingle_info_cb == NULL);
       
  1446   g_assert (priv->iq_disco_cb == NULL);
       
  1447   g_assert (priv->iq_unknown_cb == NULL);
       
  1448   g_assert (priv->stream_error_cb == NULL);
       
  1449   
       
  1450   
       
  1451   
       
  1452   priv->iq_search_keys_cb = lm_message_handler_new (search_keys_iq_cb,
       
  1453                                                     conn, NULL);
       
  1454   lm_connection_register_message_handler (conn->lmconn,
       
  1455                                           priv->iq_search_keys_cb,
       
  1456                                           LM_MESSAGE_TYPE_IQ,
       
  1457                                           LM_HANDLER_PRIORITY_NORMAL);
       
  1458 
       
  1459   priv->iq_jingle_info_cb = lm_message_handler_new (jingle_info_iq_callback,
       
  1460                                                     conn, NULL);
       
  1461   lm_connection_register_message_handler (conn->lmconn,
       
  1462                                           priv->iq_jingle_info_cb,
       
  1463                                           LM_MESSAGE_TYPE_IQ,
       
  1464                                           LM_HANDLER_PRIORITY_NORMAL);
       
  1465 
       
  1466   priv->iq_disco_cb = lm_message_handler_new (connection_iq_disco_cb,
       
  1467                                               conn, NULL);
       
  1468   lm_connection_register_message_handler (conn->lmconn, priv->iq_disco_cb,
       
  1469                                           LM_MESSAGE_TYPE_IQ,
       
  1470                                           LM_HANDLER_PRIORITY_NORMAL);
       
  1471 
       
  1472   priv->iq_unknown_cb = lm_message_handler_new (connection_iq_unknown_cb,
       
  1473                                             conn, NULL);
       
  1474   lm_connection_register_message_handler (conn->lmconn, priv->iq_unknown_cb,
       
  1475                                           LM_MESSAGE_TYPE_IQ,
       
  1476                                           LM_HANDLER_PRIORITY_LAST);
       
  1477 
       
  1478   priv->stream_error_cb = lm_message_handler_new (connection_stream_error_cb,
       
  1479                                             conn, NULL);
       
  1480   lm_connection_register_message_handler (conn->lmconn, priv->stream_error_cb,
       
  1481                                           LM_MESSAGE_TYPE_STREAM_ERROR,
       
  1482                                           LM_HANDLER_PRIORITY_LAST);
       
  1483   g_message("leaving connect_callbacks\n");
       
  1484 }
       
  1485 
       
  1486 static void
       
  1487 disconnect_callbacks (GabbleConnection *conn)
       
  1488 {
       
  1489   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  1490   g_message("[disconnect_callbacks]");
       
  1491   g_assert (priv->iq_search_keys_cb != NULL);
       
  1492   g_assert (priv->iq_jingle_info_cb != NULL);
       
  1493   g_assert (priv->iq_disco_cb != NULL);
       
  1494   g_assert (priv->iq_unknown_cb != NULL);
       
  1495   g_assert (priv->stream_error_cb != NULL);
       
  1496   
       
  1497   lm_connection_unregister_message_handler (conn->lmconn, priv->iq_search_keys_cb,
       
  1498                                             LM_MESSAGE_TYPE_IQ);
       
  1499   lm_message_handler_unref (priv->iq_search_keys_cb);
       
  1500   priv->iq_search_keys_cb = NULL;
       
  1501 
       
  1502   lm_connection_unregister_message_handler (conn->lmconn, priv->iq_jingle_info_cb,
       
  1503                                             LM_MESSAGE_TYPE_IQ);
       
  1504   lm_message_handler_unref (priv->iq_jingle_info_cb);
       
  1505   priv->iq_jingle_info_cb = NULL;
       
  1506 
       
  1507   lm_connection_unregister_message_handler (conn->lmconn, priv->iq_disco_cb,
       
  1508                                             LM_MESSAGE_TYPE_IQ);
       
  1509   lm_message_handler_unref (priv->iq_disco_cb);
       
  1510   priv->iq_disco_cb = NULL;
       
  1511 
       
  1512   lm_connection_unregister_message_handler (conn->lmconn, priv->iq_unknown_cb,
       
  1513                                             LM_MESSAGE_TYPE_IQ);
       
  1514   lm_message_handler_unref (priv->iq_unknown_cb);
       
  1515   priv->iq_unknown_cb = NULL;
       
  1516 
       
  1517   lm_connection_unregister_message_handler (conn->lmconn, priv->stream_error_cb,
       
  1518                                             LM_MESSAGE_TYPE_STREAM_ERROR);
       
  1519   lm_message_handler_unref (priv->stream_error_cb);
       
  1520   priv->stream_error_cb = NULL;
       
  1521 }
       
  1522 
       
  1523 /**
       
  1524  * _gabble_connection_connect
       
  1525  *
       
  1526  * Use the stored server & authentication details to commence
       
  1527  * the stages for connecting to the server and authenticating. Will
       
  1528  * re-use an existing LmConnection if it is present, or create it
       
  1529  * if necessary.
       
  1530  *
       
  1531  * Stage 1 is _gabble_connection_connect calling lm_connection_open
       
  1532  * Stage 2 is connection_open_cb calling lm_connection_authenticate
       
  1533  * Stage 3 is connection_auth_cb initiating service discovery
       
  1534  * Stage 4 is connection_disco_cb advertising initial presence, requesting
       
  1535  *   the roster and setting the CONNECTED state
       
  1536  */
       
  1537 static gboolean
       
  1538 _gabble_connection_connect (GabbleConnection *conn,
       
  1539                             GError          **error)
       
  1540 {
       
  1541   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  1542   char *jid;
       
  1543   GabblePresence *presence;
       
  1544   g_message("[_gabble_connection_connect]");
       
  1545   g_assert (priv->port > 0 && priv->port <= G_MAXUINT16);
       
  1546   g_assert (priv->stream_server != NULL);
       
  1547   g_assert (priv->username != NULL);
       
  1548   g_assert (priv->password != NULL);
       
  1549   g_assert (priv->resource != NULL);
       
  1550   g_assert (lm_connection_is_open (conn->lmconn) == FALSE);
       
  1551 
       
  1552   g_message("In _gabble_connection_connect" );
       
  1553   
       
  1554   jid = g_strdup_printf ("%s@%s", priv->username, priv->stream_server);
       
  1555   lm_connection_set_jid (conn->lmconn, jid);
       
  1556 
       
  1557   conn->self_handle = gabble_handle_for_contact (conn->handles,
       
  1558                                                  jid, FALSE);
       
  1559   g_free (jid);
       
  1560 
       
  1561   if (conn->self_handle == 0)
       
  1562     {
       
  1563       g_set_error (error, TELEPATHY_ERRORS, InvalidArgument,
       
  1564           "Invalid JID: %s@%s", priv->username, priv->stream_server);
       
  1565       return FALSE;
       
  1566     }
       
  1567   gabble_handle_ref (conn->handles, TP_HANDLE_TYPE_CONTACT, conn->self_handle);
       
  1568 
       
  1569   /* set initial presence */
       
  1570   /* TODO: some way for the user to set this */
       
  1571   gabble_presence_cache_update (conn->presence_cache, conn->self_handle,
       
  1572       priv->resource, GABBLE_PRESENCE_AVAILABLE, NULL, priv->priority);
       
  1573   emit_one_presence_update (conn, conn->self_handle);
       
  1574 
       
  1575   /* set initial capabilities */
       
  1576   presence = gabble_presence_cache_get (conn->presence_cache, conn->self_handle);
       
  1577 
       
  1578   gabble_presence_set_capabilities (presence, priv->resource,
       
  1579       capabilities_get_initial_caps (), priv->caps_serial++);
       
  1580 
       
  1581   /* always override server and port if one was forced upon us */
       
  1582   if (priv->connect_server != NULL)
       
  1583     {
       
  1584       lm_connection_set_server (conn->lmconn, priv->connect_server);
       
  1585       lm_connection_set_port (conn->lmconn, priv->port);
       
  1586       g_message("LM Server is %s \n",priv->connect_server );
       
  1587   	  g_message("LM port is %ld \n",priv->port);
       
  1588     }
       
  1589   /* otherwise set the server & port to the stream server,
       
  1590    * if one didn't appear from a SRV lookup */
       
  1591   else if (lm_connection_get_server (conn->lmconn) == NULL)
       
  1592     {
       
  1593       lm_connection_set_server (conn->lmconn, priv->stream_server);
       
  1594       lm_connection_set_port (conn->lmconn, priv->port);
       
  1595     }
       
  1596 
       
  1597   
       
  1598   if (priv->https_proxy_server)
       
  1599     {
       
  1600       LmProxy *proxy;
       
  1601 
       
  1602       proxy = lm_proxy_new_with_server (LM_PROXY_TYPE_HTTP,
       
  1603           priv->https_proxy_server, priv->https_proxy_port);
       
  1604 
       
  1605       lm_connection_set_proxy (conn->lmconn, proxy);
       
  1606 
       
  1607       lm_proxy_unref (proxy);
       
  1608     }
       
  1609 
       
  1610   if (priv->old_ssl)
       
  1611     {
       
  1612       LmSSL *ssl = lm_ssl_new (NULL, connection_ssl_cb, conn, NULL);
       
  1613       lm_connection_set_ssl (conn->lmconn, ssl);
       
  1614       lm_ssl_unref (ssl);
       
  1615     }
       
  1616   else //if we want to use tls (not old ssl?) then need to set tls flags.
       
  1617     {
       
  1618       LmSSL *ssl = lm_ssl_new (NULL, connection_ssl_cb, conn, NULL);
       
  1619       lm_connection_set_ssl (conn->lmconn, ssl);
       
  1620 
       
  1621       lm_ssl_use_starttls (ssl, TRUE, TRUE);
       
  1622 
       
  1623 	  lm_ssl_unref (ssl);
       
  1624     }
       
  1625 
       
  1626   /* send whitespace to the server every 30 seconds */
       
  1627   //lm_connection_set_keep_alive_rate (conn->lmconn, 45);
       
  1628 
       
  1629   lm_connection_set_disconnect_function (conn->lmconn,
       
  1630                                          connection_disconnected_cb,
       
  1631                                          conn,
       
  1632                                          NULL);
       
  1633 
       
  1634   if (do_connect (conn, error))
       
  1635     {
       
  1636       gboolean valid;
       
  1637 
       
  1638       connection_status_change (conn,
       
  1639           TP_CONN_STATUS_CONNECTING,
       
  1640           TP_CONN_STATUS_REASON_REQUESTED);
       
  1641 
       
  1642       valid = gabble_handle_ref (conn->handles,
       
  1643                                  TP_HANDLE_TYPE_CONTACT,
       
  1644                                  conn->self_handle);
       
  1645       g_message("before after valid assert" );
       
  1646       g_assert (valid);
       
  1647       g_message("In after valid assert" );
       
  1648     }
       
  1649   else
       
  1650     {
       
  1651       return FALSE;
       
  1652     }
       
  1653   g_message("Out _gabble_connection_connect" );
       
  1654   return TRUE;
       
  1655 }
       
  1656 
       
  1657 
       
  1658 
       
  1659 static void
       
  1660 connection_disconnected_cb (LmConnection *lmconn,
       
  1661                             LmDisconnectReason lm_reason,
       
  1662                             gpointer user_data)
       
  1663 {
       
  1664   GabbleConnection *conn = GABBLE_CONNECTION (user_data);
       
  1665   g_message("[connection_disconnected_cb]\n");
       
  1666   g_assert (conn->lmconn == lmconn);
       
  1667  
       
  1668   gabble_debug (DEBUG_FLAG, "called with reason %u", lm_reason);
       
  1669 
       
  1670   /* if we were expecting this disconnection, we're done so can tell
       
  1671    * the connection manager to unref us. otherwise it's a network error
       
  1672    * or some other screw up we didn't expect, so we emit the status
       
  1673    * change */
       
  1674   if (conn->status == TP_CONN_STATUS_DISCONNECTED)
       
  1675     {
       
  1676       g_message("[connection_disconnected_cb]expected; emitting DISCONNECTED");
       
  1677       g_signal_emit (conn, signals[DISCONNECTED], 0);
       
  1678     }
       
  1679   else
       
  1680     {
       
  1681       g_message("[connection_disconnected_cb]unexpected; calling connection_status_change");
       
  1682       connection_status_change (conn,
       
  1683           TP_CONN_STATUS_DISCONNECTED,
       
  1684           TP_CONN_STATUS_REASON_NETWORK_ERROR);
       
  1685     }
       
  1686 }
       
  1687 
       
  1688 
       
  1689 /**
       
  1690  * connection_status_change:
       
  1691  * @conn: a #GabbleConnection
       
  1692  * @status: new status to advertise
       
  1693  * @reason: reason for new status
       
  1694  *
       
  1695  * Compares status with current status. If different, emits a signal
       
  1696  * for the new status, and updates it in the #GabbleConnection.
       
  1697  */
       
  1698 static void
       
  1699 connection_status_change (GabbleConnection        *conn,
       
  1700                           TpConnectionStatus       status,
       
  1701                           TpConnectionStatusReason reason)
       
  1702 {
       
  1703   GabbleConnectionPrivate *priv;
       
  1704 
       
  1705   g_assert (GABBLE_IS_CONNECTION (conn));
       
  1706 
       
  1707   priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  1708 
       
  1709   g_message ("[connection_status_change]status %u reason %u", status, reason);
       
  1710 
       
  1711   g_assert (status != TP_CONN_STATUS_NEW);
       
  1712 
       
  1713   if (conn->status != status)
       
  1714     {
       
  1715       if ((status == TP_CONN_STATUS_DISCONNECTED) &&
       
  1716           (conn->status == TP_CONN_STATUS_NEW))
       
  1717         {
       
  1718           g_message("[connection_status_change] line 1721");
       
  1719           conn->status = status;
       
  1720 
       
  1721           /* unref our self handle if it's set */
       
  1722           if (conn->self_handle != 0)
       
  1723             {
       
  1724               gabble_handle_unref (conn->handles, TP_HANDLE_TYPE_CONTACT,
       
  1725                   conn->self_handle);
       
  1726               conn->self_handle = 0;
       
  1727             }
       
  1728 
       
  1729           g_message("[connection_status_change]new connection closed; emitting DISCONNECTED");
       
  1730           g_signal_emit (conn, signals[DISCONNECTED], 0);
       
  1731           return;
       
  1732         }
       
  1733 
       
  1734       conn->status = status;
       
  1735 
       
  1736       if (status == TP_CONN_STATUS_DISCONNECTED)
       
  1737         {
       
  1738           /* remove the channels so we don't get any race conditions where
       
  1739            * method calls are delivered to a channel after we've started
       
  1740            * disconnecting */
       
  1741         g_message("[connection_status_change] TP_CONN_STATUS_DISCONNECTED");
       
  1742 
       
  1743           /* trigger close_all on all channel factories */
       
  1744           g_ptr_array_foreach (priv->channel_factories, (GFunc)
       
  1745               tp_channel_factory_iface_close_all, NULL);
       
  1746 
       
  1747           /* cancel all queued channel requests */
       
  1748           if (priv->channel_requests->len > 0)
       
  1749             {
       
  1750               g_ptr_array_foreach (priv->channel_requests, (GFunc)
       
  1751                 channel_request_cancel, NULL);
       
  1752               g_ptr_array_remove_range (priv->channel_requests, 0,
       
  1753                 priv->channel_requests->len);
       
  1754             }
       
  1755 
       
  1756           /* unref our self handle */
       
  1757           gabble_handle_unref (conn->handles, TP_HANDLE_TYPE_CONTACT,
       
  1758               conn->self_handle);
       
  1759           conn->self_handle = 0;
       
  1760         }
       
  1761 
       
  1762       g_message("[connection_status_change]emitting status-changed with status %u reason %u",
       
  1763                status, reason);
       
  1764 
       
  1765       g_signal_emit (conn, signals[STATUS_CHANGED], 0, status, reason);
       
  1766 
       
  1767       if (status == TP_CONN_STATUS_CONNECTING)
       
  1768         {
       
  1769           /* add our callbacks */
       
  1770           connect_callbacks (conn);
       
  1771 
       
  1772           /* trigger connecting on all channel factories */
       
  1773           g_ptr_array_foreach (priv->channel_factories, (GFunc)
       
  1774               tp_channel_factory_iface_connecting, NULL);
       
  1775         }
       
  1776       else if (status == TP_CONN_STATUS_CONNECTED)
       
  1777         {
       
  1778         /* send whitespace to the server every 30 seconds resetting to 30*/
       
  1779           lm_connection_set_keep_alive_rate (conn->lmconn, 10);
       
  1780           
       
  1781           /* trigger connected on all channel factories */
       
  1782           g_ptr_array_foreach (priv->channel_factories, (GFunc)
       
  1783               tp_channel_factory_iface_connected, NULL);
       
  1784         }
       
  1785       else if (status == TP_CONN_STATUS_DISCONNECTED)
       
  1786         {
       
  1787           /* remove our callbacks */
       
  1788           disconnect_callbacks (conn);
       
  1789 
       
  1790           /* trigger disconnected on all channel factories */
       
  1791           g_ptr_array_foreach (priv->channel_factories, (GFunc)
       
  1792               tp_channel_factory_iface_disconnected, NULL);
       
  1793 
       
  1794           /* if the connection is open, this function will close it for you.
       
  1795            * if it's already closed (eg network error) then we're done, so
       
  1796            * can emit DISCONNECTED and have the connection manager unref us */
       
  1797           if (lm_connection_is_open (conn->lmconn))
       
  1798             {
       
  1799               g_message ("still open; calling lm_connection_close");
       
  1800               lm_connection_close (conn->lmconn, NULL);
       
  1801             }
       
  1802           else
       
  1803             {
       
  1804               /* lm_connection_is_open() returns FALSE if LmConnection is in the
       
  1805                * middle of connecting, so call this just in case */
       
  1806               lm_connection_cancel_open (conn->lmconn);
       
  1807               g_message ("closed; emitting DISCONNECTED");
       
  1808               g_signal_emit (conn, signals[DISCONNECTED], 0);
       
  1809             }
       
  1810         }
       
  1811     }
       
  1812   else
       
  1813     {
       
  1814       g_warning ("%s: attempted to re-emit the current status %u reason %u",
       
  1815           G_STRFUNC, status, reason);
       
  1816     }
       
  1817   g_message("[connection_status_change]");
       
  1818   g_message ("out connection status changed ");
       
  1819 }
       
  1820 
       
  1821 static ChannelRequest *
       
  1822 channel_request_new (DBusGMethodInvocation *context,
       
  1823                      const char *channel_type,
       
  1824                      guint handle_type,
       
  1825                      guint handle,
       
  1826                      gboolean suppress_handler)
       
  1827 {
       
  1828   ChannelRequest *ret;
       
  1829 
       
  1830   g_assert (NULL != context);
       
  1831   g_assert (NULL != channel_type);
       
  1832 
       
  1833   ret = g_new0 (ChannelRequest, 1);
       
  1834   ret->context = context;
       
  1835   ret->channel_type = g_strdup (channel_type);
       
  1836   ret->handle_type = handle_type;
       
  1837   ret->handle = handle;
       
  1838   ret->suppress_handler = suppress_handler;
       
  1839 
       
  1840   return ret;
       
  1841 }
       
  1842 
       
  1843 static void
       
  1844 channel_request_free (ChannelRequest *request)
       
  1845 {
       
  1846   g_assert (NULL == request->context);
       
  1847   g_free (request->channel_type);
       
  1848   g_free (request);
       
  1849 }
       
  1850 
       
  1851 static void
       
  1852 channel_request_cancel (gpointer data, gpointer user_data)
       
  1853 {
       
  1854   ChannelRequest *request = (ChannelRequest *) data;
       
  1855   GError *error = NULL;
       
  1856 
       
  1857   gabble_debug (DEBUG_FLAG, "cancelling request for %s/%d/%d", request->channel_type, request->handle_type, request->handle);
       
  1858 
       
  1859   error = g_error_new (TELEPATHY_ERRORS, Disconnected, "unable to "
       
  1860       "service this channel request, we're disconnecting!");
       
  1861 
       
  1862   dbus_g_method_return_error (request->context, error);
       
  1863   request->context = NULL;
       
  1864 
       
  1865   g_error_free (error);
       
  1866   channel_request_free (request);
       
  1867 }
       
  1868 
       
  1869 static GPtrArray *
       
  1870 find_matching_channel_requests (GabbleConnection *conn,
       
  1871                                 const gchar *channel_type,
       
  1872                                 guint handle_type,
       
  1873                                 guint handle,
       
  1874                                 gboolean *suppress_handler)
       
  1875 {
       
  1876   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  1877   GPtrArray *requests;
       
  1878   guint i;
       
  1879 
       
  1880   requests = g_ptr_array_sized_new (1);
       
  1881 
       
  1882   for (i = 0; i < priv->channel_requests->len; i++)
       
  1883     {
       
  1884       ChannelRequest *request = g_ptr_array_index (priv->channel_requests, i);
       
  1885 
       
  1886       if (0 != strcmp (request->channel_type, channel_type))
       
  1887         continue;
       
  1888 
       
  1889       if (handle_type != request->handle_type)
       
  1890         continue;
       
  1891 
       
  1892       if (handle != request->handle)
       
  1893         continue;
       
  1894 
       
  1895       if (request->suppress_handler && suppress_handler)
       
  1896         *suppress_handler = TRUE;
       
  1897 
       
  1898       g_ptr_array_add (requests, request);
       
  1899     }
       
  1900 
       
  1901   return requests;
       
  1902 }
       
  1903 
       
  1904 static void
       
  1905 connection_new_channel_cb (TpChannelFactoryIface *factory,
       
  1906                            GObject *chan,
       
  1907                            gpointer data)
       
  1908 {
       
  1909   GabbleConnection *conn = GABBLE_CONNECTION (data);
       
  1910   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  1911   gchar *object_path = NULL, *channel_type = NULL;
       
  1912   guint handle_type = 0, handle = 0;
       
  1913   gboolean suppress_handler = priv->suppress_next_handler;
       
  1914   GPtrArray *tmp;
       
  1915   guint i;
       
  1916 
       
  1917   g_object_get (chan,
       
  1918       "object-path", &object_path,
       
  1919       "channel-type", &channel_type,
       
  1920       "handle-type", &handle_type,
       
  1921       "handle", &handle,
       
  1922       NULL);
       
  1923 
       
  1924   gabble_debug (DEBUG_FLAG, "called for %s", object_path);
       
  1925 
       
  1926   tmp = find_matching_channel_requests (conn, channel_type, handle_type,
       
  1927                                         handle, &suppress_handler);
       
  1928 
       
  1929   g_signal_emit (conn, signals[NEW_CHANNEL], 0,
       
  1930                  object_path, channel_type,
       
  1931                  handle_type, handle,
       
  1932                  suppress_handler);
       
  1933 
       
  1934   for (i = 0; i < tmp->len; i++)
       
  1935     {
       
  1936       ChannelRequest *request = g_ptr_array_index (tmp, i);
       
  1937 
       
  1938       gabble_debug (DEBUG_FLAG, "completing queued request, channel_type=%s, handle_type=%u, "
       
  1939           "handle=%u, suppress_handler=%u", request->channel_type,
       
  1940           request->handle_type, request->handle, request->suppress_handler);
       
  1941 
       
  1942       dbus_g_method_return (request->context, object_path);
       
  1943       request->context = NULL;
       
  1944 
       
  1945       g_ptr_array_remove (priv->channel_requests, request);
       
  1946 
       
  1947       channel_request_free (request);
       
  1948     }
       
  1949 
       
  1950   g_ptr_array_free (tmp, TRUE);
       
  1951 
       
  1952   g_free (object_path);
       
  1953   g_free (channel_type);
       
  1954 }
       
  1955 
       
  1956 static void
       
  1957 connection_channel_error_cb (TpChannelFactoryIface *factory,
       
  1958                              GObject *chan,
       
  1959                              GError *error,
       
  1960                              gpointer data)
       
  1961 {
       
  1962   GabbleConnection *conn = GABBLE_CONNECTION (data);
       
  1963   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  1964   gchar *channel_type = NULL;
       
  1965   guint handle_type = 0, handle = 0;
       
  1966   GPtrArray *tmp;
       
  1967   guint i;
       
  1968 
       
  1969   gabble_debug (DEBUG_FLAG, "channel_type=%s, handle_type=%u, handle=%u, error_code=%u, "
       
  1970       "error_message=\"%s\"", channel_type, handle_type, handle,
       
  1971       error->code, error->message);
       
  1972 
       
  1973   g_object_get (chan,
       
  1974       "channel-type", &channel_type,
       
  1975       "handle-type", &handle_type,
       
  1976       "handle", &handle,
       
  1977       NULL);
       
  1978 
       
  1979   tmp = find_matching_channel_requests (conn, channel_type, handle_type,
       
  1980                                         handle, NULL);
       
  1981 
       
  1982   for (i = 0; i < tmp->len; i++)
       
  1983     {
       
  1984       ChannelRequest *request = g_ptr_array_index (tmp, i);
       
  1985 
       
  1986       gabble_debug (DEBUG_FLAG, "completing queued request %p, channel_type=%s, "
       
  1987           "handle_type=%u, handle=%u, suppress_handler=%u",
       
  1988           request, request->channel_type,
       
  1989           request->handle_type, request->handle, request->suppress_handler);
       
  1990 
       
  1991       dbus_g_method_return_error (request->context, error);
       
  1992       request->context = NULL;
       
  1993 
       
  1994       g_ptr_array_remove (priv->channel_requests, request);
       
  1995 
       
  1996       channel_request_free (request);
       
  1997     }
       
  1998 
       
  1999   g_ptr_array_free (tmp, TRUE);
       
  2000   g_free (channel_type);
       
  2001 }
       
  2002 
       
  2003 static void
       
  2004 connection_presence_update_cb (GabblePresenceCache *cache, GabbleHandle handle, gpointer user_data)
       
  2005 {
       
  2006   GabbleConnection *conn = GABBLE_CONNECTION (user_data);
       
  2007 
       
  2008   emit_one_presence_update (conn, handle);
       
  2009 }
       
  2010 
       
  2011 GabbleConnectionAliasSource
       
  2012 _gabble_connection_get_cached_alias (GabbleConnection *conn,
       
  2013                                      GabbleHandle handle,
       
  2014                                      gchar **alias)
       
  2015 {
       
  2016   GabbleConnectionPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (conn,
       
  2017       GABBLE_TYPE_CONNECTION, GabbleConnectionPrivate);
       
  2018   GabbleConnectionAliasSource ret = GABBLE_CONNECTION_ALIAS_NONE;
       
  2019   GabblePresence *pres;
       
  2020   const gchar *tmp;
       
  2021   gchar *user = NULL, *resource = NULL;
       
  2022 
       
  2023   g_return_val_if_fail (NULL != conn, GABBLE_CONNECTION_ALIAS_NONE);
       
  2024   g_return_val_if_fail (GABBLE_IS_CONNECTION (conn), GABBLE_CONNECTION_ALIAS_NONE);
       
  2025   g_return_val_if_fail (gabble_handle_is_valid (conn->handles,
       
  2026         TP_HANDLE_TYPE_CONTACT, handle, NULL), GABBLE_CONNECTION_ALIAS_NONE);
       
  2027 
       
  2028   tmp = gabble_roster_handle_get_name (conn->roster, handle);
       
  2029   if (NULL != tmp)
       
  2030     {
       
  2031       ret = GABBLE_CONNECTION_ALIAS_FROM_ROSTER;
       
  2032 
       
  2033       if (NULL != alias)
       
  2034         *alias = g_strdup (tmp);
       
  2035 
       
  2036       goto OUT;
       
  2037     }
       
  2038 
       
  2039   pres = gabble_presence_cache_get (conn->presence_cache, handle);
       
  2040   if (NULL != pres && NULL != pres->nickname)
       
  2041     {
       
  2042       ret = GABBLE_CONNECTION_ALIAS_FROM_PRESENCE;
       
  2043 
       
  2044       if (NULL != alias)
       
  2045         *alias = g_strdup (pres->nickname);
       
  2046 
       
  2047       goto OUT;
       
  2048     }
       
  2049 
       
  2050   /* if it's our own handle, use alias passed to the connmgr, if any */
       
  2051   if (handle == conn->self_handle && priv->alias != NULL)
       
  2052     {
       
  2053       ret = GABBLE_CONNECTION_ALIAS_FROM_CONNMGR;
       
  2054 
       
  2055       if (NULL != alias)
       
  2056         *alias = g_strdup (priv->alias);
       
  2057 
       
  2058       goto OUT;
       
  2059     }
       
  2060 
       
  2061   /* if we've seen a nickname in their vCard, use that */
       
  2062   tmp = gabble_vcard_manager_get_cached_alias (conn->vcard_manager, handle);
       
  2063   if (NULL != tmp)
       
  2064     {
       
  2065       ret = GABBLE_CONNECTION_ALIAS_FROM_VCARD;
       
  2066 
       
  2067       if (NULL != alias)
       
  2068         *alias = g_strdup (tmp);
       
  2069 
       
  2070       goto OUT;
       
  2071     }
       
  2072 
       
  2073   /* fallback to JID */
       
  2074   tmp = gabble_handle_inspect (conn->handles, TP_HANDLE_TYPE_CONTACT, handle);
       
  2075   g_assert (NULL != tmp);
       
  2076 
       
  2077   gabble_decode_jid (tmp, &user, NULL, &resource);
       
  2078 
       
  2079   /* MUC handles have the nickname in the resource */
       
  2080   if (NULL != resource)
       
  2081     {
       
  2082       ret = GABBLE_CONNECTION_ALIAS_FROM_JID;
       
  2083 
       
  2084       if (NULL != alias)
       
  2085         {
       
  2086           *alias = resource;
       
  2087           resource = NULL;
       
  2088         }
       
  2089 
       
  2090       goto OUT;
       
  2091     }
       
  2092 
       
  2093   /* otherwise just take their local part */
       
  2094   if (NULL != user)
       
  2095     {
       
  2096       ret = GABBLE_CONNECTION_ALIAS_FROM_JID;
       
  2097 
       
  2098       if (NULL != alias)
       
  2099         {
       
  2100           *alias = user;
       
  2101           user = NULL;
       
  2102         }
       
  2103 
       
  2104       goto OUT;
       
  2105     }
       
  2106 
       
  2107 OUT:
       
  2108   g_free (user);
       
  2109   g_free (resource);
       
  2110   return ret;
       
  2111 }
       
  2112 
       
  2113 static void
       
  2114 connection_nickname_update_cb (GObject *object,
       
  2115                                GabbleHandle handle,
       
  2116                                gpointer user_data)
       
  2117 {
       
  2118   GabbleConnection *conn = GABBLE_CONNECTION (user_data);
       
  2119   GabbleConnectionAliasSource signal_source, real_source;
       
  2120   gchar *alias = NULL;
       
  2121   GPtrArray *aliases;
       
  2122   GValue entry = { 0, };
       
  2123 
       
  2124   if (object == G_OBJECT (conn->roster))
       
  2125     {
       
  2126       signal_source = GABBLE_CONNECTION_ALIAS_FROM_ROSTER;
       
  2127     }
       
  2128   else if (object == G_OBJECT (conn->presence_cache))
       
  2129     {
       
  2130       signal_source = GABBLE_CONNECTION_ALIAS_FROM_PRESENCE;
       
  2131     }
       
  2132    else if (object == G_OBJECT (conn->vcard_manager))
       
  2133      {
       
  2134        signal_source = GABBLE_CONNECTION_ALIAS_FROM_VCARD;
       
  2135      }
       
  2136   else
       
  2137     {
       
  2138       g_assert_not_reached ();
       
  2139       return;
       
  2140     }
       
  2141 
       
  2142   real_source = _gabble_connection_get_cached_alias (conn, handle, &alias);
       
  2143 
       
  2144   g_assert (real_source != GABBLE_CONNECTION_ALIAS_NONE);
       
  2145 
       
  2146   /* if the active alias for this handle is already known and from
       
  2147    * a higher priority, this signal is not interesting so we do
       
  2148    * nothing */
       
  2149   if (real_source > signal_source)
       
  2150     {
       
  2151       gabble_debug (DEBUG_FLAG, "ignoring boring alias change for handle %u, signal from %u "
       
  2152           "but source %u has alias \"%s\"", handle, signal_source,
       
  2153           real_source, alias);
       
  2154       goto OUT;
       
  2155     }
       
  2156 
       
  2157   g_value_init (&entry, TP_ALIAS_PAIR_TYPE);
       
  2158   g_value_take_boxed (&entry, dbus_g_type_specialized_construct
       
  2159       (TP_ALIAS_PAIR_TYPE));
       
  2160 
       
  2161   dbus_g_type_struct_set (&entry,
       
  2162       0, handle,
       
  2163       1, alias,
       
  2164       G_MAXUINT);
       
  2165 
       
  2166   aliases = g_ptr_array_sized_new (1);
       
  2167   g_ptr_array_add (aliases, g_value_get_boxed (&entry));
       
  2168 
       
  2169   g_signal_emit (conn, signals[ALIASES_CHANGED], 0, aliases);
       
  2170 
       
  2171   g_value_unset (&entry);
       
  2172   g_ptr_array_free (aliases, TRUE);
       
  2173 
       
  2174 OUT:
       
  2175   g_free (alias);
       
  2176 }
       
  2177 
       
  2178 /**
       
  2179  * status_is_available
       
  2180  *
       
  2181  * Returns a boolean to indicate whether the given gabble status is
       
  2182  * available on this connection.
       
  2183  */
       
  2184 static gboolean
       
  2185 status_is_available (GabbleConnection *conn, int status)
       
  2186 {
       
  2187   GabbleConnectionPrivate *priv;
       
  2188 
       
  2189   g_assert (GABBLE_IS_CONNECTION (conn));
       
  2190   g_assert (status < LAST_GABBLE_PRESENCE);
       
  2191   priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  2192 
       
  2193   if (gabble_statuses[status].presence_type == TP_CONN_PRESENCE_TYPE_HIDDEN &&
       
  2194       (conn->features & GABBLE_CONNECTION_FEATURES_PRESENCE_INVISIBLE) == 0)
       
  2195     return FALSE;
       
  2196   else
       
  2197     return TRUE;
       
  2198 }
       
  2199 
       
  2200 /**
       
  2201  * destroy_the_bastard:
       
  2202  * @data: a GValue to destroy
       
  2203  *
       
  2204  * destroys a GValue allocated on the heap
       
  2205  */
       
  2206 static void
       
  2207 destroy_the_bastard (GValue *value)
       
  2208 {
       
  2209   g_value_unset (value);
       
  2210   g_free (value);
       
  2211 }
       
  2212 
       
  2213 static GHashTable *
       
  2214 construct_presence_hash (GabbleConnection *self,
       
  2215                          const GArray *contact_handles)
       
  2216 {
       
  2217   guint i;
       
  2218   GabbleHandle handle;
       
  2219   GHashTable *presence_hash, *contact_status, *parameters;
       
  2220   GValueArray *vals;
       
  2221   GValue *message;
       
  2222   GabblePresence *presence;
       
  2223   GabblePresenceId status;
       
  2224   const gchar *status_message;
       
  2225   /* this is never set at the moment*/
       
  2226   guint timestamp = 0;
       
  2227 
       
  2228   g_assert (gabble_handles_are_valid (self->handles, TP_HANDLE_TYPE_CONTACT,
       
  2229         contact_handles, FALSE, NULL));
       
  2230 
       
  2231   presence_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
       
  2232       (GDestroyNotify) g_value_array_free);
       
  2233 
       
  2234   for (i = 0; i < contact_handles->len; i++)
       
  2235     {
       
  2236       handle = g_array_index (contact_handles, GabbleHandle, i);
       
  2237       presence = gabble_presence_cache_get (self->presence_cache, handle);
       
  2238 
       
  2239       if (presence)
       
  2240         {
       
  2241           status = presence->status;
       
  2242           status_message = presence->status_message;
       
  2243         }
       
  2244       else
       
  2245         {
       
  2246           status = GABBLE_PRESENCE_OFFLINE;
       
  2247           status_message = NULL;
       
  2248         }
       
  2249 
       
  2250       message = g_new0 (GValue, 1);
       
  2251       g_value_init (message, G_TYPE_STRING);
       
  2252       g_value_set_static_string (message, status_message);
       
  2253 
       
  2254       parameters = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
       
  2255           (GDestroyNotify) destroy_the_bastard);
       
  2256 
       
  2257       g_hash_table_insert (parameters, "message", message);
       
  2258 
       
  2259       contact_status = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
       
  2260           (GDestroyNotify) g_hash_table_destroy);
       
  2261       g_hash_table_insert (contact_status,
       
  2262           (gchar *) gabble_statuses[status].name, parameters);
       
  2263 
       
  2264       vals = g_value_array_new (2);
       
  2265 
       
  2266       g_value_array_append (vals, NULL);
       
  2267       g_value_init (g_value_array_get_nth (vals, 0), G_TYPE_UINT);
       
  2268       g_value_set_uint (g_value_array_get_nth (vals, 0), timestamp);
       
  2269 
       
  2270       g_value_array_append (vals, NULL);
       
  2271       g_value_init (g_value_array_get_nth (vals, 1),
       
  2272           dbus_g_type_get_map ("GHashTable", G_TYPE_STRING,
       
  2273             dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)));
       
  2274       g_value_take_boxed (g_value_array_get_nth (vals, 1), contact_status);
       
  2275 
       
  2276       g_hash_table_insert (presence_hash, GINT_TO_POINTER (handle), vals);
       
  2277     }
       
  2278 
       
  2279   return presence_hash;
       
  2280 }
       
  2281 
       
  2282 /**
       
  2283  * emit_presence_update:
       
  2284  * @self: A #GabbleConnection
       
  2285  * @contact_handles: A zero-terminated array of #GabbleHandle for
       
  2286  *                    the contacts to emit presence for
       
  2287  *
       
  2288  * Emits the Telepathy PresenceUpdate signal with the current
       
  2289  * stored presence information for the given contact.
       
  2290  */
       
  2291 static void
       
  2292 emit_presence_update (GabbleConnection *self,
       
  2293                       const GArray *contact_handles)
       
  2294 {
       
  2295   GHashTable *presence_hash;
       
  2296 
       
  2297   presence_hash = construct_presence_hash (self, contact_handles);
       
  2298   g_signal_emit (self, signals[PRESENCE_UPDATE], 0, presence_hash);
       
  2299   g_hash_table_destroy (presence_hash);
       
  2300 }
       
  2301 
       
  2302 /**
       
  2303  * emit_one_presence_update:
       
  2304  * Convenience function for calling emit_presence_update with one handle.
       
  2305  */
       
  2306 
       
  2307 static void
       
  2308 emit_one_presence_update (GabbleConnection *self,
       
  2309                           GabbleHandle handle)
       
  2310 {
       
  2311   GArray *handles = g_array_sized_new (FALSE, FALSE, sizeof (GabbleHandle), 1);
       
  2312 
       
  2313   g_array_insert_val (handles, 0, handle);
       
  2314   emit_presence_update (self, handles);
       
  2315   g_array_free (handles, TRUE);
       
  2316 }
       
  2317 
       
  2318 /**
       
  2319  * signal_own_presence:
       
  2320  * @self: A #GabbleConnection
       
  2321  * @error: pointer in which to return a GError in case of failure.
       
  2322  *
       
  2323  * Signal the user's stored presence to the jabber server
       
  2324  *
       
  2325  * Retuns: FALSE if an error occurred
       
  2326  */
       
  2327 static gboolean
       
  2328 signal_own_presence (GabbleConnection *self, GError **error)
       
  2329 {
       
  2330   
       
  2331   GabblePresence *presence;
       
  2332   LmMessage *message;
       
  2333   LmMessageNode *node;
       
  2334   gboolean ret;
       
  2335   gchar *ext_string = NULL;
       
  2336   GSList *features, *i;
       
  2337   GabbleConnectionPrivate *priv;
       
  2338   
       
  2339   if ( NULL == self )
       
  2340       {
       
  2341       g_debug ("%s: accesing after dereferenced connection", G_STRFUNC);
       
  2342       return FALSE;
       
  2343       }
       
  2344   
       
  2345   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  2346 
       
  2347   presence = gabble_presence_cache_get (self->presence_cache, self->self_handle);
       
  2348   message = gabble_presence_as_message (presence, priv->resource);
       
  2349   node = lm_message_get_node (message);
       
  2350   
       
  2351   if (presence->status == GABBLE_PRESENCE_HIDDEN)
       
  2352     {
       
  2353       if ((self->features & GABBLE_CONNECTION_FEATURES_PRESENCE_INVISIBLE) != 0)
       
  2354         lm_message_node_set_attribute (node, "type", "invisible");
       
  2355     }
       
  2356 
       
  2357   features = capabilities_get_features (presence->caps);
       
  2358 
       
  2359   for (i = features; NULL != i; i = i->next)
       
  2360     {
       
  2361       const Feature *feat = (const Feature *) i->data;
       
  2362 
       
  2363       if ((NULL != feat->bundle) && g_strdiff (VERSION, feat->bundle))
       
  2364         {
       
  2365           if (NULL != ext_string)
       
  2366             {
       
  2367               gchar *tmp = ext_string;
       
  2368               ext_string = g_strdup_printf ("%s %s", ext_string, feat->bundle);
       
  2369               g_free (tmp);
       
  2370             }
       
  2371           else
       
  2372             {
       
  2373               ext_string = g_strdup (feat->bundle);
       
  2374             }
       
  2375         }
       
  2376     }
       
  2377 
       
  2378   node = lm_message_node_add_child (node, "c", NULL);
       
  2379   lm_message_node_set_attributes (
       
  2380     node,
       
  2381     "xmlns", NS_CAPS,
       
  2382     "node",  NS_GABBLE_CAPS,
       
  2383     "ver",   VERSION,
       
  2384     NULL);
       
  2385 
       
  2386   if (NULL != ext_string)
       
  2387       lm_message_node_set_attribute (node, "ext", ext_string);
       
  2388 
       
  2389   ret = _gabble_connection_send (self, message, error);
       
  2390 
       
  2391   lm_message_unref (message);
       
  2392 
       
  2393   g_free (ext_string);
       
  2394   g_slist_free (features);
       
  2395 
       
  2396   return ret;
       
  2397 }
       
  2398 
       
  2399 static LmMessage *_lm_iq_message_make_result (LmMessage *iq_message);
       
  2400 
       
  2401 /**
       
  2402  * _gabble_connection_send_iq_result
       
  2403  *
       
  2404  * Function used to acknowledge an IQ stanza.
       
  2405  */
       
  2406 void
       
  2407 _gabble_connection_acknowledge_set_iq (GabbleConnection *conn,
       
  2408                                        LmMessage *iq)
       
  2409 {
       
  2410   LmMessage *result;
       
  2411 
       
  2412   g_assert (LM_MESSAGE_TYPE_IQ == lm_message_get_type (iq));
       
  2413   g_assert (LM_MESSAGE_SUB_TYPE_SET == lm_message_get_sub_type (iq));
       
  2414 
       
  2415   result = _lm_iq_message_make_result (iq);
       
  2416 
       
  2417   if (NULL != result)
       
  2418     {
       
  2419       _gabble_connection_send (conn, result, NULL);
       
  2420       lm_message_unref (result);
       
  2421     }
       
  2422 }
       
  2423 
       
  2424 
       
  2425 /**
       
  2426  * _gabble_connection_send_iq_error
       
  2427  *
       
  2428  * Function used to acknowledge an IQ stanza with an error.
       
  2429  */
       
  2430 void
       
  2431 _gabble_connection_send_iq_error (GabbleConnection *conn,
       
  2432                                   LmMessage *message,
       
  2433                                   GabbleXmppError error,
       
  2434                                   const gchar *errmsg)
       
  2435 {
       
  2436   const gchar *to, *id;
       
  2437   LmMessage *msg;
       
  2438   LmMessageNode *iq_node;
       
  2439 
       
  2440   iq_node = lm_message_get_node (message);
       
  2441   to = lm_message_node_get_attribute (iq_node, "from");
       
  2442   id = lm_message_node_get_attribute (iq_node, "id");
       
  2443 
       
  2444   if (id == NULL)
       
  2445     {
       
  2446       NODE_DEBUG (iq_node, "can't acknowledge IQ with no id");
       
  2447       return;
       
  2448     }
       
  2449 
       
  2450   msg = lm_message_new_with_sub_type (to, LM_MESSAGE_TYPE_IQ,
       
  2451                                       LM_MESSAGE_SUB_TYPE_ERROR);
       
  2452 
       
  2453   lm_message_node_set_attribute (msg->node, "id", id);
       
  2454 
       
  2455   lm_message_node_steal_children (msg->node, iq_node);
       
  2456 
       
  2457   gabble_xmpp_error_to_node (error, msg->node, errmsg);
       
  2458 
       
  2459   _gabble_connection_send (conn, msg, NULL);
       
  2460 
       
  2461   lm_message_unref (msg);
       
  2462 }
       
  2463 
       
  2464 static LmMessage *
       
  2465 _lm_iq_message_make_result (LmMessage *iq_message)
       
  2466 {
       
  2467   LmMessage *result;
       
  2468   LmMessageNode *iq, *result_iq;
       
  2469   const gchar *from_jid, *id;
       
  2470 
       
  2471   g_assert (lm_message_get_type (iq_message) == LM_MESSAGE_TYPE_IQ);
       
  2472   g_assert (lm_message_get_sub_type (iq_message) == LM_MESSAGE_SUB_TYPE_GET ||
       
  2473             lm_message_get_sub_type (iq_message) == LM_MESSAGE_SUB_TYPE_SET);
       
  2474 
       
  2475   iq = lm_message_get_node (iq_message);
       
  2476   id = lm_message_node_get_attribute (iq, "id");
       
  2477 
       
  2478   if (id == NULL)
       
  2479     {
       
  2480       NODE_DEBUG (iq, "can't acknowledge IQ with no id");
       
  2481       return NULL;
       
  2482     }
       
  2483 
       
  2484   from_jid = lm_message_node_get_attribute (iq, "from");
       
  2485 
       
  2486   result = lm_message_new_with_sub_type (from_jid, LM_MESSAGE_TYPE_IQ,
       
  2487                                          LM_MESSAGE_SUB_TYPE_RESULT);
       
  2488   result_iq = lm_message_get_node (result);
       
  2489   lm_message_node_set_attribute (result_iq, "id", id);
       
  2490 
       
  2491   return result;
       
  2492 }
       
  2493 
       
  2494 /**
       
  2495  * connection_iq_disco_cb
       
  2496  *
       
  2497  * Called by loudmouth when we get an incoming <iq>. This handler handles
       
  2498  * disco-related IQs.
       
  2499  */
       
  2500 static LmHandlerResult
       
  2501 connection_iq_disco_cb (LmMessageHandler *handler,
       
  2502                         LmConnection *connection,
       
  2503                         LmMessage *message,
       
  2504                         gpointer user_data)
       
  2505 {
       
  2506   GabbleConnection *conn = GABBLE_CONNECTION (user_data);
       
  2507   LmMessage *result;
       
  2508   LmMessageNode *iq, *result_iq, *query, *result_query;
       
  2509   const gchar *node, *suffix;
       
  2510   GSList *features;
       
  2511   GSList *i;
       
  2512   GabblePresence *pres;
       
  2513   
       
  2514   if ( NULL == conn )
       
  2515         {
       
  2516         return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  2517         }
       
  2518 
       
  2519   if (lm_message_get_sub_type (message) != LM_MESSAGE_SUB_TYPE_GET)
       
  2520     return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  2521 
       
  2522   iq = lm_message_get_node (message);
       
  2523   query = lm_message_node_get_child_with_namespace (iq, "query",
       
  2524       NS_DISCO_INFO);
       
  2525 
       
  2526   if (!query)
       
  2527     return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  2528 
       
  2529   node = lm_message_node_get_attribute (query, "node");
       
  2530 
       
  2531   if (node && (
       
  2532       0 != strncmp (node, NS_GABBLE_CAPS "#", strlen (NS_GABBLE_CAPS) + 1) ||
       
  2533       strlen(node) < strlen (NS_GABBLE_CAPS) + 2))
       
  2534     {
       
  2535       NODE_DEBUG (iq, "got iq disco query with unexpected node attribute");
       
  2536       return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  2537     }
       
  2538 
       
  2539   if (node == NULL)
       
  2540     suffix = NULL;
       
  2541   else
       
  2542     suffix = node + strlen (NS_GABBLE_CAPS) + 1;
       
  2543 
       
  2544   result = _lm_iq_message_make_result (message);
       
  2545   result_iq = lm_message_get_node (result);
       
  2546   result_query = lm_message_node_add_child (result_iq, "query", NULL);
       
  2547   lm_message_node_set_attribute (result_query, "xmlns", NS_DISCO_INFO);
       
  2548 
       
  2549   pres = gabble_presence_cache_get (conn->presence_cache, conn->self_handle);
       
  2550   gabble_debug (DEBUG_FLAG, "got disco request for bundle %s, caps are %x", node, pres->caps);
       
  2551   features = capabilities_get_features (pres->caps);
       
  2552 
       
  2553   g_debug("%s: caps now %u", G_STRFUNC, pres->caps);
       
  2554 
       
  2555   for (i = features; NULL != i; i = i->next)
       
  2556     {
       
  2557       const Feature *feature = (const Feature *) i->data;
       
  2558 
       
  2559       if (NULL == node || !g_strdiff (suffix, feature->bundle))
       
  2560         {
       
  2561           LmMessageNode *node = lm_message_node_add_child (result_query,
       
  2562               "feature", NULL);
       
  2563           lm_message_node_set_attribute (node, "var", feature->ns);
       
  2564         }
       
  2565     }
       
  2566 
       
  2567   NODE_DEBUG (result_iq, "sending disco response");
       
  2568 
       
  2569   if (!lm_connection_send (conn->lmconn, result, NULL))
       
  2570     gabble_debug (DEBUG_FLAG, "sending disco response failed");
       
  2571 
       
  2572   g_slist_free (features);
       
  2573 
       
  2574   return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
  2575 }
       
  2576 
       
  2577 /**
       
  2578  * connection_iq_unknown_cb
       
  2579  *
       
  2580  * Called by loudmouth when we get an incoming <iq>. This handler is
       
  2581  * at a lower priority than the others, and should reply with an error
       
  2582  * about unsupported get/set attempts.
       
  2583  */
       
  2584 static LmHandlerResult
       
  2585 connection_iq_unknown_cb (LmMessageHandler *handler,
       
  2586                           LmConnection *connection,
       
  2587                           LmMessage *message,
       
  2588                           gpointer user_data)
       
  2589 {
       
  2590   GabbleConnection *conn = GABBLE_CONNECTION (user_data);
       
  2591 
       
  2592   g_assert (connection == conn->lmconn);
       
  2593 
       
  2594   NODE_DEBUG (message->node, "got unknown iq");
       
  2595 
       
  2596   switch (lm_message_get_sub_type (message))
       
  2597     {
       
  2598     case LM_MESSAGE_SUB_TYPE_GET:
       
  2599     case LM_MESSAGE_SUB_TYPE_SET:
       
  2600       _gabble_connection_send_iq_error (conn, message,
       
  2601           XMPP_ERROR_SERVICE_UNAVAILABLE, NULL);
       
  2602       break;
       
  2603     default:
       
  2604       break;
       
  2605     }
       
  2606 
       
  2607   return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
  2608 }
       
  2609 
       
  2610 /**
       
  2611  * connection_stream_error_cb
       
  2612  *
       
  2613  * Called by loudmouth when we get stream error, which means that
       
  2614  * we're about to close the connection. The message contains the reason
       
  2615  * for the connection hangup.
       
  2616  */
       
  2617 static LmHandlerResult
       
  2618 connection_stream_error_cb (LmMessageHandler *handler,
       
  2619                             LmConnection *connection,
       
  2620                             LmMessage *message,
       
  2621                             gpointer user_data)
       
  2622 {
       
  2623   GabbleConnection *conn = GABBLE_CONNECTION (user_data);
       
  2624   LmMessageNode *conflict_node;
       
  2625 
       
  2626   g_assert (connection == conn->lmconn);
       
  2627 
       
  2628   NODE_DEBUG (message->node, "got stream error");
       
  2629 
       
  2630   conflict_node = lm_message_node_get_child (message->node, "conflict");
       
  2631   if (conflict_node)
       
  2632     {
       
  2633       gabble_debug (DEBUG_FLAG, "found conflict node, emiting status change");
       
  2634 
       
  2635       /* Another client with the same resource just
       
  2636        * appeared, we're going down. */
       
  2637         connection_status_change (conn,
       
  2638             TP_CONN_STATUS_DISCONNECTED,
       
  2639             TP_CONN_STATUS_REASON_NAME_IN_USE);
       
  2640         return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
  2641     }
       
  2642 
       
  2643   return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  2644 }
       
  2645 
       
  2646 
       
  2647 /**
       
  2648  * connection_ssl_cb
       
  2649  *
       
  2650  * If we're doing old SSL, this function gets called if the certificate
       
  2651  * is dodgy.
       
  2652  */
       
  2653 static LmSSLResponse
       
  2654 connection_ssl_cb (LmSSL      *lmssl,
       
  2655                    LmSSLStatus status,
       
  2656                    gpointer    data)
       
  2657 {
       
  2658   GabbleConnection *conn = GABBLE_CONNECTION (data);
       
  2659   
       
  2660   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  2661   const char *reason;
       
  2662   TpConnectionStatusReason tp_reason;
       
  2663 
       
  2664   g_message("inside ssl_cb\n");
       
  2665   switch (status) {
       
  2666     case LM_SSL_STATUS_NO_CERT_FOUND:
       
  2667       reason = "The server doesn't provide a certificate.";
       
  2668       tp_reason = TP_CONN_STATUS_REASON_CERT_NOT_PROVIDED;
       
  2669       break;
       
  2670     case LM_SSL_STATUS_UNTRUSTED_CERT:
       
  2671       reason = "The certificate can not be trusted.";
       
  2672       tp_reason = TP_CONN_STATUS_REASON_CERT_UNTRUSTED;
       
  2673       break;
       
  2674     case LM_SSL_STATUS_CERT_EXPIRED:
       
  2675       reason = "The certificate has expired.";
       
  2676       tp_reason = TP_CONN_STATUS_REASON_CERT_EXPIRED;
       
  2677       break;
       
  2678     case LM_SSL_STATUS_CERT_NOT_ACTIVATED:
       
  2679       reason = "The certificate has not been activated.";
       
  2680       tp_reason = TP_CONN_STATUS_REASON_CERT_NOT_ACTIVATED;
       
  2681       break;
       
  2682     case LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH:
       
  2683       reason = "The server hostname doesn't match the one in the certificate.";
       
  2684       tp_reason = TP_CONN_STATUS_REASON_CERT_HOSTNAME_MISMATCH;
       
  2685       break;
       
  2686     case LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH:
       
  2687       reason = "The fingerprint doesn't match the expected value.";
       
  2688       tp_reason = TP_CONN_STATUS_REASON_CERT_FINGERPRINT_MISMATCH;
       
  2689       break;
       
  2690     case LM_SSL_STATUS_GENERIC_ERROR:
       
  2691       reason = "An unknown SSL error occurred.";
       
  2692       tp_reason = TP_CONN_STATUS_REASON_CERT_OTHER_ERROR;
       
  2693       break;
       
  2694     default:
       
  2695       g_assert_not_reached();
       
  2696       reason = "Unknown SSL error code from Loudmouth.";
       
  2697       tp_reason = TP_CONN_STATUS_REASON_ENCRYPTION_ERROR;
       
  2698       break;
       
  2699   }
       
  2700 
       
  2701   gabble_debug (DEBUG_FLAG, "called: %s", reason);
       
  2702 
       
  2703   if (priv->ignore_ssl_errors)
       
  2704     {
       
  2705       return LM_SSL_RESPONSE_CONTINUE;
       
  2706     }
       
  2707   else
       
  2708     {
       
  2709       priv->ssl_error = tp_reason;
       
  2710       return LM_SSL_RESPONSE_STOP;
       
  2711     }
       
  2712 }
       
  2713 
       
  2714 static void
       
  2715 do_auth (GabbleConnection *conn)
       
  2716 {
       
  2717   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  2718   GError *error = NULL;
       
  2719 
       
  2720   gabble_debug (DEBUG_FLAG, "authenticating with username: %s, password: <hidden>, resource: %s",
       
  2721            priv->username, priv->resource);
       
  2722 
       
  2723   if (!lm_connection_authenticate (conn->lmconn, priv->username, priv->password,
       
  2724                                    priv->resource, connection_auth_cb,
       
  2725                                    conn, NULL, &error))
       
  2726     {
       
  2727       gabble_debug (DEBUG_FLAG, "failed: %s", error->message);
       
  2728       g_error_free (error);
       
  2729 
       
  2730       /* the reason this function can fail is through network errors,
       
  2731        * authentication failures are reported to our auth_cb */
       
  2732       connection_status_change (conn,
       
  2733           TP_CONN_STATUS_DISCONNECTED,
       
  2734           TP_CONN_STATUS_REASON_NETWORK_ERROR);
       
  2735     }
       
  2736 }
       
  2737 
       
  2738 static void
       
  2739 registration_finished_cb (GabbleRegister *reg,
       
  2740                           gboolean success,
       
  2741                           gint err_code,
       
  2742                           const gchar *err_msg,
       
  2743                           gpointer user_data)
       
  2744 {
       
  2745   GabbleConnection *conn = GABBLE_CONNECTION (user_data);
       
  2746 
       
  2747   g_message("registration_finished_cb\n");
       
  2748   if (conn->status != TP_CONN_STATUS_CONNECTING)
       
  2749     {
       
  2750       g_assert (conn->status == TP_CONN_STATUS_DISCONNECTED);
       
  2751       return;
       
  2752     }
       
  2753 
       
  2754   gabble_debug (DEBUG_FLAG, "%s", (success) ? "succeeded" : "failed");
       
  2755 
       
  2756   g_object_unref (reg);
       
  2757 
       
  2758   if (success)
       
  2759     {
       
  2760       do_auth (conn);
       
  2761     }
       
  2762   else
       
  2763     {
       
  2764       gabble_debug (DEBUG_FLAG, "err_code = %d, err_msg = '%s'",
       
  2765                err_code, err_msg);
       
  2766 
       
  2767       connection_status_change (conn,
       
  2768           TP_CONN_STATUS_DISCONNECTED,
       
  2769           (err_code == InvalidArgument) ? TP_CONN_STATUS_REASON_NAME_IN_USE :
       
  2770             TP_CONN_STATUS_REASON_AUTHENTICATION_FAILED);
       
  2771     }
       
  2772 }
       
  2773 
       
  2774 static void
       
  2775 do_register (GabbleConnection *conn)
       
  2776 {
       
  2777   GabbleRegister *reg;
       
  2778 
       
  2779   reg = gabble_register_new (conn);
       
  2780 
       
  2781   g_signal_connect (reg, "finished", (GCallback) registration_finished_cb,
       
  2782                     conn);
       
  2783 
       
  2784   gabble_register_start (reg);
       
  2785 }
       
  2786 
       
  2787 /**
       
  2788  * connection_open_cb
       
  2789  *
       
  2790  * Stage 2 of connecting, this function is called by loudmouth after the
       
  2791  * result of the non-blocking lm_connection_open call is known. It makes
       
  2792  * a request to authenticate the user with the server, or optionally
       
  2793  * registers user on the server first.
       
  2794  */
       
  2795 static void
       
  2796 connection_open_cb (LmConnection *lmconn,
       
  2797                     gboolean      success,
       
  2798                     gpointer      data)
       
  2799 {
       
  2800   GabbleConnection *conn = GABBLE_CONNECTION (data);
       
  2801   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  2802   g_message("[connection_open_cb]");
       
  2803   if ((conn->status != TP_CONN_STATUS_CONNECTING) &&
       
  2804       (conn->status != TP_CONN_STATUS_NEW))
       
  2805     {
       
  2806       g_assert (conn->status == TP_CONN_STATUS_DISCONNECTED);
       
  2807       return;
       
  2808     }
       
  2809 
       
  2810   g_assert (priv);
       
  2811   g_assert (lmconn == conn->lmconn);
       
  2812 
       
  2813   if (!success)
       
  2814     {
       
  2815       if (lm_connection_get_proxy (lmconn))
       
  2816         {
       
  2817           g_message ("failed, retrying without proxy");
       
  2818 
       
  2819           lm_connection_set_proxy (lmconn, NULL);
       
  2820 
       
  2821           if (do_connect (conn, NULL))
       
  2822             {
       
  2823               return;
       
  2824             }
       
  2825         }
       
  2826       else
       
  2827         {
       
  2828           g_message ("failed");
       
  2829         }
       
  2830 
       
  2831       if (priv->ssl_error)
       
  2832         {
       
  2833         g_message ("[connection_open_cb] priv->ssl_error");
       
  2834           connection_status_change (conn,
       
  2835             TP_CONN_STATUS_DISCONNECTED,
       
  2836             priv->ssl_error);
       
  2837         }
       
  2838       else
       
  2839         {
       
  2840         g_message ("[connection_open_cb] reached else");
       
  2841           connection_status_change (conn,
       
  2842               TP_CONN_STATUS_DISCONNECTED,
       
  2843               TP_CONN_STATUS_REASON_NETWORK_ERROR);
       
  2844         }
       
  2845 
       
  2846       return;
       
  2847     }
       
  2848 
       
  2849   if (!priv->do_register)
       
  2850     do_auth (conn);
       
  2851   else
       
  2852     do_register (conn);
       
  2853 }
       
  2854 
       
  2855 /**
       
  2856  * connection_auth_cb
       
  2857  *
       
  2858  * Stage 3 of connecting, this function is called by loudmouth after the
       
  2859  * result of the non-blocking lm_connection_authenticate call is known.
       
  2860  * It sends a discovery request to find the server's features.
       
  2861  */
       
  2862 static void
       
  2863 connection_auth_cb (LmConnection *lmconn,
       
  2864                     gboolean      success,
       
  2865                     gpointer      data)
       
  2866 {
       
  2867   GabbleConnection *conn = GABBLE_CONNECTION (data);
       
  2868   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  2869   GError *error = NULL;
       
  2870 
       
  2871   g_message("In connection_auth_cb\n");
       
  2872 
       
  2873   if (conn->status != TP_CONN_STATUS_CONNECTING)
       
  2874     {
       
  2875       g_assert (conn->status == TP_CONN_STATUS_DISCONNECTED);
       
  2876       return;
       
  2877     }
       
  2878 
       
  2879   g_assert (priv);
       
  2880   g_assert (lmconn == conn->lmconn);
       
  2881 
       
  2882   if (!success)
       
  2883     {
       
  2884       gabble_debug (DEBUG_FLAG, "failed");
       
  2885 	  g_message("Inside !success\n");
       
  2886 
       
  2887       connection_status_change (conn,
       
  2888           TP_CONN_STATUS_DISCONNECTED,
       
  2889           TP_CONN_STATUS_REASON_AUTHENTICATION_FAILED);
       
  2890 
       
  2891       return;
       
  2892     }
       
  2893 
       
  2894   if (!gabble_disco_request_with_timeout (conn->disco, GABBLE_DISCO_TYPE_INFO,
       
  2895                                           priv->stream_server, NULL, 5000,
       
  2896                                           connection_disco_cb, conn,
       
  2897                                           G_OBJECT (conn), &error))
       
  2898     {
       
  2899       gabble_debug (DEBUG_FLAG, "sending disco request failed: %s",
       
  2900           error->message);
       
  2901 	  g_message("sending disco request failed\n");
       
  2902 
       
  2903       g_error_free (error);
       
  2904 
       
  2905       connection_status_change (conn,
       
  2906           TP_CONN_STATUS_DISCONNECTED,
       
  2907           TP_CONN_STATUS_REASON_NETWORK_ERROR);
       
  2908     }
       
  2909 }
       
  2910 
       
  2911 /**
       
  2912  * connection_disco_cb
       
  2913  *
       
  2914  * Stage 4 of connecting, this function is called by GabbleDisco after the
       
  2915  * result of the non-blocking server feature discovery call is known. It sends
       
  2916  * the user's initial presence to the server, marking them as available,
       
  2917  * and requests the roster.
       
  2918  */
       
  2919 static void
       
  2920 connection_disco_cb (GabbleDisco *disco,
       
  2921                      GabbleDiscoRequest *request,
       
  2922                      const gchar *jid,
       
  2923                      const gchar *node,
       
  2924                      LmMessageNode *result,
       
  2925                      GError *disco_error,
       
  2926                      gpointer user_data)
       
  2927 {
       
  2928   GabbleConnection *conn = user_data;
       
  2929   GabbleConnectionPrivate *priv;
       
  2930   GError *error = NULL;
       
  2931 
       
  2932 	g_message("Inside connection_disco_cb\n");
       
  2933 	
       
  2934   if ( NULL == conn )
       
  2935       {
       
  2936       return;
       
  2937       }
       
  2938   if (conn->status != TP_CONN_STATUS_CONNECTING)
       
  2939     {
       
  2940       g_assert (conn->status == TP_CONN_STATUS_DISCONNECTED);
       
  2941       return;
       
  2942     }
       
  2943 
       
  2944   g_assert (GABBLE_IS_CONNECTION (conn));
       
  2945   priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  2946 
       
  2947   if (disco_error)
       
  2948     {
       
  2949 		g_message("got disco error, setting no features\n");
       
  2950       gabble_debug (DEBUG_FLAG, "got disco error, setting no features: %s", disco_error->message);
       
  2951     }
       
  2952   else
       
  2953     {
       
  2954       LmMessageNode *iter;
       
  2955 
       
  2956       NODE_DEBUG (result, "got");
       
  2957 
       
  2958       for (iter = result->children; iter != NULL; iter = iter->next)
       
  2959         {
       
  2960           if (0 == strcmp (iter->name, "feature"))
       
  2961             {
       
  2962               const gchar *var = lm_message_node_get_attribute (iter, "var");
       
  2963 
       
  2964               if (var == NULL)
       
  2965                 continue;
       
  2966 
       
  2967               if (0 == strcmp (var, NS_GOOGLE_JINGLE_INFO))
       
  2968                 conn->features |= GABBLE_CONNECTION_FEATURES_GOOGLE_JINGLE_INFO;
       
  2969               else if (0 == strcmp (var, NS_GOOGLE_ROSTER))
       
  2970                 conn->features |= GABBLE_CONNECTION_FEATURES_GOOGLE_ROSTER;
       
  2971               else if (0 == strcmp (var, NS_PRESENCE_INVISIBLE))
       
  2972                 conn->features |= GABBLE_CONNECTION_FEATURES_PRESENCE_INVISIBLE;
       
  2973               else if (0 == strcmp (var, NS_PRIVACY))
       
  2974                 conn->features |= GABBLE_CONNECTION_FEATURES_PRIVACY;
       
  2975               else if (0 == strcmp (var, NS_SEARCH))
       
  2976                 conn->features |= GABBLE_CONNECTION_FEATURES_SEARCH;
       
  2977             }
       
  2978         }
       
  2979 
       
  2980       gabble_debug (DEBUG_FLAG, "set features flags to %d", conn->features);
       
  2981     }
       
  2982 
       
  2983 		g_message("before signal_own_presence\n");
       
  2984 
       
  2985   /* send presence to the server to indicate availability */
       
  2986   if (!signal_own_presence (conn, &error))
       
  2987     {
       
  2988       gabble_debug (DEBUG_FLAG, "sending initial presence failed: %s", error->message);
       
  2989 		g_message("sending initial presence failed\n");
       
  2990       goto ERROR;
       
  2991     }
       
  2992 
       
  2993 		g_message("after signal_own_presence\n");
       
  2994 
       
  2995   /* go go gadget on-line */
       
  2996   connection_status_change (conn, TP_CONN_STATUS_CONNECTED, TP_CONN_STATUS_REASON_REQUESTED);
       
  2997 
       
  2998   if (conn->features & GABBLE_CONNECTION_FEATURES_GOOGLE_JINGLE_INFO)
       
  2999     {
       
  3000       jingle_info_discover_servers (conn);
       
  3001     }
       
  3002   
       
  3003   if(conn->features & GABBLE_CONNECTION_FEATURES_SEARCH)
       
  3004 	{
       
  3005 	get_search_keys_info(conn,jid);
       
  3006 	}
       
  3007 
       
  3008   return;
       
  3009 
       
  3010 ERROR:
       
  3011   if (error)
       
  3012     g_error_free (error);
       
  3013 
       
  3014   connection_status_change (conn,
       
  3015       TP_CONN_STATUS_DISCONNECTED,
       
  3016       TP_CONN_STATUS_REASON_NETWORK_ERROR);
       
  3017 
       
  3018   return;
       
  3019 }
       
  3020 
       
  3021 
       
  3022 static GHashTable *
       
  3023 get_statuses_arguments()
       
  3024 {
       
  3025 
       
  3026 #ifndef EMULATOR
       
  3027   static GHashTable *arguments = NULL;
       
  3028 #endif
       
  3029   
       
  3030 
       
  3031   if (arguments == NULL)
       
  3032     {
       
  3033       arguments = g_hash_table_new (g_str_hash, g_str_equal);
       
  3034 
       
  3035       g_hash_table_insert (arguments, "message", "s");
       
  3036       g_hash_table_insert (arguments, "priority", "n");
       
  3037     }
       
  3038 
       
  3039   return arguments;
       
  3040 }
       
  3041 
       
  3042 /****************************************************************************
       
  3043  *                          D-BUS EXPORTED METHODS                          *
       
  3044  ****************************************************************************/
       
  3045 
       
  3046 
       
  3047 /**
       
  3048  * gabble_connection_add_status
       
  3049  *
       
  3050  * Implements D-Bus method AddStatus
       
  3051  * on interface org.freedesktop.Telepathy.Connection.Interface.Presence
       
  3052  *
       
  3053  * @error: Used to return a pointer to a GError detailing any error
       
  3054  *         that occurred, D-Bus will throw the error only if this
       
  3055  *         function returns FALSE.
       
  3056  *
       
  3057  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3058  */
       
  3059 gboolean
       
  3060 gabble_connection_add_status (GabbleConnection *self,
       
  3061                               const gchar *status,
       
  3062                               GHashTable *parms,
       
  3063                               GError **error)
       
  3064 {
       
  3065   g_assert (GABBLE_IS_CONNECTION (self));
       
  3066 
       
  3067   ERROR_IF_NOT_CONNECTED (self, error);
       
  3068 
       
  3069   g_set_error (error, TELEPATHY_ERRORS, NotImplemented,
       
  3070       "Only one status is possible at a time with this protocol");
       
  3071 
       
  3072   return FALSE;
       
  3073 }
       
  3074 
       
  3075 static void
       
  3076 _emit_capabilities_changed (GabbleConnection *conn,
       
  3077                             GabbleHandle handle,
       
  3078                             GabblePresenceCapabilities old_caps,
       
  3079                             GabblePresenceCapabilities new_caps)
       
  3080 {
       
  3081   GPtrArray *caps_arr;
       
  3082   const CapabilityConversionData *ccd;
       
  3083   guint i;
       
  3084 
       
  3085   if (old_caps == new_caps)
       
  3086     return;
       
  3087 
       
  3088   caps_arr = g_ptr_array_new ();
       
  3089 
       
  3090   for (ccd = capabilities_conversions; NULL != ccd->iface; ccd++)
       
  3091     {
       
  3092       if (ccd->c2tf_fn (old_caps | new_caps))
       
  3093         {
       
  3094           GValue caps_monster_struct = {0, };
       
  3095           guint old_tpflags = ccd->c2tf_fn (old_caps);
       
  3096           guint old_caps = old_tpflags ?
       
  3097             TP_CONN_CAPABILITY_FLAG_CREATE |
       
  3098             TP_CONN_CAPABILITY_FLAG_INVITE : 0;
       
  3099           guint new_tpflags = ccd->c2tf_fn (new_caps);
       
  3100           guint new_caps = new_tpflags ?
       
  3101             TP_CONN_CAPABILITY_FLAG_CREATE |
       
  3102             TP_CONN_CAPABILITY_FLAG_INVITE : 0;
       
  3103 
       
  3104           if (0 == (old_tpflags ^ new_tpflags))
       
  3105             continue;
       
  3106 
       
  3107           g_value_init (&caps_monster_struct,
       
  3108               TP_CAPABILITIES_CHANGED_MONSTER_TYPE);
       
  3109           g_value_take_boxed (&caps_monster_struct,
       
  3110               dbus_g_type_specialized_construct
       
  3111                 (TP_CAPABILITIES_CHANGED_MONSTER_TYPE));
       
  3112 
       
  3113           dbus_g_type_struct_set (&caps_monster_struct,
       
  3114               0, handle,
       
  3115               1, ccd->iface,
       
  3116               2, old_caps,
       
  3117               3, new_caps,
       
  3118               4, old_tpflags,
       
  3119               5, new_tpflags,
       
  3120               G_MAXUINT);
       
  3121 
       
  3122           g_ptr_array_add (caps_arr, g_value_get_boxed (&caps_monster_struct));
       
  3123         }
       
  3124     }
       
  3125 
       
  3126   if (caps_arr->len)
       
  3127     g_signal_emit (conn, signals[CAPABILITIES_CHANGED], 0, caps_arr);
       
  3128 
       
  3129   for (i = 0; i < caps_arr->len; i++)
       
  3130     {
       
  3131       g_boxed_free (TP_CAPABILITIES_CHANGED_MONSTER_TYPE,
       
  3132           g_ptr_array_index (caps_arr, i));
       
  3133     }
       
  3134   g_ptr_array_free (caps_arr, TRUE);
       
  3135 }
       
  3136 
       
  3137 static void
       
  3138 connection_capabilities_update_cb (GabblePresenceCache *cache,
       
  3139                                    GabbleHandle handle,
       
  3140                                    GabblePresenceCapabilities old_caps,
       
  3141                                    GabblePresenceCapabilities new_caps,
       
  3142                                    gpointer user_data)
       
  3143 {
       
  3144   GabbleConnection *conn = GABBLE_CONNECTION (user_data);
       
  3145 
       
  3146   _emit_capabilities_changed (conn, handle, old_caps, new_caps);
       
  3147 }
       
  3148 
       
  3149 /**
       
  3150  * gabble_connection_advertise_capabilities
       
  3151  *
       
  3152  * Implements D-Bus method AdvertiseCapabilities
       
  3153  * on interface org.freedesktop.Telepathy.Connection.Interface.Capabilities
       
  3154  *
       
  3155  * @error: Used to return a pointer to a GError detailing any error
       
  3156  *         that occurred, D-Bus will throw the error only if this
       
  3157  *         function returns FALSE.
       
  3158  *
       
  3159  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3160  */
       
  3161 gboolean
       
  3162 gabble_connection_advertise_capabilities (GabbleConnection *self,
       
  3163                                           const GPtrArray *add,
       
  3164                                           const gchar **remove,
       
  3165                                           GPtrArray **ret,
       
  3166                                           GError **error)
       
  3167 {
       
  3168   guint i;
       
  3169   GabblePresence *pres;
       
  3170   GabblePresenceCapabilities add_caps = 0, remove_caps = 0, caps, save_caps;
       
  3171   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3172   const CapabilityConversionData *ccd;
       
  3173 
       
  3174   ERROR_IF_NOT_CONNECTED (self, error);
       
  3175 
       
  3176   pres = gabble_presence_cache_get (self->presence_cache, self->self_handle);
       
  3177   gabble_debug (DEBUG_FLAG, "caps before: %x", pres->caps);
       
  3178 
       
  3179   for (i = 0; i < add->len; i++)
       
  3180     {
       
  3181       GValue iface_flags_pair = {0, };
       
  3182       gchar *iface;
       
  3183       guint flags;
       
  3184 
       
  3185       g_value_init (&iface_flags_pair, TP_CAPABILITY_PAIR_TYPE);
       
  3186       g_value_set_static_boxed (&iface_flags_pair, g_ptr_array_index (add, i));
       
  3187 
       
  3188       dbus_g_type_struct_get (&iface_flags_pair,
       
  3189                               0, &iface,
       
  3190                               1, &flags,
       
  3191                               G_MAXUINT);
       
  3192 
       
  3193       for (ccd = capabilities_conversions; NULL != ccd->iface; ccd++)
       
  3194           if (g_str_equal (iface, ccd->iface))
       
  3195             add_caps |= ccd->tf2c_fn (flags);
       
  3196     }
       
  3197 
       
  3198   for (i = 0; NULL != remove[i]; i++)
       
  3199     {
       
  3200       for (ccd = capabilities_conversions; NULL != ccd->iface; ccd++)
       
  3201           if (g_str_equal (remove[i], ccd->iface))
       
  3202             remove_caps |= ccd->tf2c_fn (~0);
       
  3203     }
       
  3204 
       
  3205   pres = gabble_presence_cache_get (self->presence_cache, self->self_handle);
       
  3206   save_caps = caps = pres->caps;
       
  3207 
       
  3208   caps |= add_caps;
       
  3209   caps ^= (caps & remove_caps);
       
  3210 
       
  3211   gabble_debug (DEBUG_FLAG, "caps to add: %x", add_caps);
       
  3212   gabble_debug (DEBUG_FLAG, "caps to remove: %x", remove_caps);
       
  3213   gabble_debug (DEBUG_FLAG, "caps after: %x", caps);
       
  3214 
       
  3215   if (caps ^ save_caps)
       
  3216     {
       
  3217       gabble_debug (DEBUG_FLAG, "before != after, changing");
       
  3218       gabble_presence_set_capabilities (pres, priv->resource, caps, priv->caps_serial++);
       
  3219       gabble_debug (DEBUG_FLAG, "set caps: %x", pres->caps);
       
  3220     }
       
  3221 
       
  3222   *ret = g_ptr_array_new ();
       
  3223 
       
  3224   for (ccd = capabilities_conversions; NULL != ccd->iface; ccd++)
       
  3225     {
       
  3226       if (ccd->c2tf_fn (pres->caps))
       
  3227         {
       
  3228           GValue iface_flags_pair = {0, };
       
  3229 
       
  3230           g_value_init (&iface_flags_pair, TP_CAPABILITY_PAIR_TYPE);
       
  3231           g_value_take_boxed (&iface_flags_pair,
       
  3232               dbus_g_type_specialized_construct (TP_CAPABILITY_PAIR_TYPE));
       
  3233 
       
  3234           dbus_g_type_struct_set (&iface_flags_pair,
       
  3235                                   0, ccd->iface,
       
  3236                                   1, ccd->c2tf_fn (pres->caps),
       
  3237                                   G_MAXUINT);
       
  3238 
       
  3239           g_ptr_array_add (*ret, g_value_get_boxed (&iface_flags_pair));
       
  3240         }
       
  3241     }
       
  3242 
       
  3243   if (caps ^ save_caps)
       
  3244     {
       
  3245       if (!signal_own_presence (self, error))
       
  3246         return FALSE;
       
  3247 
       
  3248       _emit_capabilities_changed (self, self->self_handle, save_caps, caps);
       
  3249     }
       
  3250 
       
  3251   return TRUE;
       
  3252 }
       
  3253 
       
  3254 /**
       
  3255  * gabble_connection_clear_status
       
  3256  *
       
  3257  * Implements D-Bus method ClearStatus
       
  3258  * on interface org.freedesktop.Telepathy.Connection.Interface.Presence
       
  3259  *
       
  3260  * @error: Used to return a pointer to a GError detailing any error
       
  3261  *         that occurred, D-Bus will throw the error only if this
       
  3262  *         function returns FALSE.
       
  3263  *
       
  3264  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3265  */
       
  3266 gboolean
       
  3267 gabble_connection_clear_status (GabbleConnection *self,
       
  3268                                 GError **error)
       
  3269 {
       
  3270   GabbleConnectionPrivate *priv;
       
  3271   g_assert (GABBLE_IS_CONNECTION (self));
       
  3272 
       
  3273   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3274 
       
  3275   ERROR_IF_NOT_CONNECTED (self, error);
       
  3276 
       
  3277   gabble_presence_cache_update (self->presence_cache, self->self_handle,
       
  3278       priv->resource, GABBLE_PRESENCE_AVAILABLE, NULL, priv->priority);
       
  3279   emit_one_presence_update (self, self->self_handle);
       
  3280   return signal_own_presence (self, error);
       
  3281 }
       
  3282 
       
  3283 
       
  3284 /**
       
  3285  * gabble_connection_connect
       
  3286  * Implements D-Bus method Connect
       
  3287  * on interface org.freedesktop.Telepathy.Connection
       
  3288  *
       
  3289  * @error: Used to return a pointer to a GError detailing any error
       
  3290  *         that occurred, D-Bus will throw the error only if this
       
  3291  *         function returns FALSE.
       
  3292  *
       
  3293  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3294  */
       
  3295 
       
  3296 gboolean
       
  3297 gabble_connection_connect (GabbleConnection *self,
       
  3298                            GError **error)
       
  3299 {
       
  3300   g_assert(GABBLE_IS_CONNECTION (self));
       
  3301   
       
  3302   if (self->status == TP_CONN_STATUS_NEW)
       
  3303     return _gabble_connection_connect (self, error);
       
  3304   return TRUE;
       
  3305 }
       
  3306 
       
  3307 
       
  3308 /**
       
  3309  * gabble_connection_disconnect
       
  3310  *
       
  3311  * Implements D-Bus method Disconnect
       
  3312  * on interface org.freedesktop.Telepathy.Connection
       
  3313  *
       
  3314  * @error: Used to return a pointer to a GError detailing any error
       
  3315  *         that occurred, D-Bus will throw the error only if this
       
  3316  *         function returns FALSE.
       
  3317  *
       
  3318  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3319  */
       
  3320 gboolean
       
  3321 gabble_connection_disconnect (GabbleConnection *self,
       
  3322                               GError **error)
       
  3323 {
       
  3324   GabbleConnectionPrivate *priv;
       
  3325 
       
  3326   g_assert (GABBLE_IS_CONNECTION (self));
       
  3327 
       
  3328   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3329 
       
  3330   g_message("gabble_connection_disconnect: going to change status to TP_CONN_STATUS_DISCONNECTED ")	;
       
  3331   connection_status_change (self,
       
  3332       TP_CONN_STATUS_DISCONNECTED,
       
  3333       TP_CONN_STATUS_REASON_REQUESTED);
       
  3334 
       
  3335   return TRUE;
       
  3336 }
       
  3337 
       
  3338 
       
  3339 /**
       
  3340  * gabble_connection_get_alias_flags
       
  3341  *
       
  3342  * Implements D-Bus method GetAliasFlags
       
  3343  * on interface org.freedesktop.Telepathy.Connection.Interface.Aliasing
       
  3344  *
       
  3345  * @error: Used to return a pointer to a GError detailing any error
       
  3346  *         that occurred, D-Bus will throw the error only if this
       
  3347  *         function returns FALSE.
       
  3348  *
       
  3349  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3350  */
       
  3351 gboolean
       
  3352 gabble_connection_get_alias_flags (GabbleConnection *self,
       
  3353                                    guint *ret,
       
  3354                                    GError **error)
       
  3355 {
       
  3356   GabbleConnectionPrivate *priv;
       
  3357 
       
  3358   g_assert (GABBLE_IS_CONNECTION (self));
       
  3359 
       
  3360   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3361 
       
  3362   ERROR_IF_NOT_CONNECTED (self, error)
       
  3363 
       
  3364   *ret = TP_CONN_ALIAS_FLAG_USER_SET;
       
  3365 
       
  3366   return TRUE;
       
  3367 }
       
  3368 
       
  3369 //#ifndef EMULATOR
       
  3370 static const gchar *assumed_caps[] =
       
  3371 {
       
  3372   TP_IFACE_CHANNEL_TYPE_TEXT,
       
  3373   TP_IFACE_CHANNEL_INTERFACE_GROUP,
       
  3374   NULL
       
  3375 };
       
  3376 //#endif
       
  3377 
       
  3378 
       
  3379 /**
       
  3380  * gabble_connection_get_capabilities
       
  3381  *
       
  3382  * Implements D-Bus method GetCapabilities
       
  3383  * on interface org.freedesktop.Telepathy.Connection.Interface.Capabilities
       
  3384  *
       
  3385  * @error: Used to return a pointer to a GError detailing any error
       
  3386  *         that occurred, D-Bus will throw the error only if this
       
  3387  *         function returns FALSE.
       
  3388  *
       
  3389  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3390  */
       
  3391 gboolean
       
  3392 gabble_connection_get_capabilities (GabbleConnection *self,
       
  3393                                     const GArray *handles,
       
  3394                                     GPtrArray **ret,
       
  3395                                     GError **error)
       
  3396 {
       
  3397   guint i;
       
  3398 
       
  3399   ERROR_IF_NOT_CONNECTED (self, error);
       
  3400 
       
  3401   if (!gabble_handles_are_valid (self->handles,
       
  3402                                  TP_HANDLE_TYPE_CONTACT,
       
  3403                                  handles,
       
  3404                                  TRUE,
       
  3405                                  error))
       
  3406     {
       
  3407       return FALSE;
       
  3408     }
       
  3409 
       
  3410   *ret = g_ptr_array_new ();
       
  3411 
       
  3412   for (i = 0; i < handles->len; i++)
       
  3413     {
       
  3414       GabbleHandle handle = g_array_index (handles, guint, i);
       
  3415       GabblePresence *pres;
       
  3416       const CapabilityConversionData *ccd;
       
  3417       guint typeflags;
       
  3418       //#ifndef EMULATOR
       
  3419       const gchar **assumed;
       
  3420 	  //#else
       
  3421 	  //gchar **assumed;
       
  3422 	  //#endif
       
  3423 	  
       
  3424       if (0 == handle)
       
  3425         {
       
  3426           /* FIXME report the magical channel types available on the connection itself */
       
  3427           continue;
       
  3428         }
       
  3429 
       
  3430       pres = gabble_presence_cache_get (self->presence_cache, handle);
       
  3431 
       
  3432       if (NULL != pres)
       
  3433         for (ccd = capabilities_conversions; NULL != ccd->iface; ccd++)
       
  3434           {
       
  3435             typeflags = ccd->c2tf_fn (pres->caps);
       
  3436 
       
  3437             if (typeflags)
       
  3438               {
       
  3439                 GValue monster = {0, };
       
  3440 
       
  3441                 g_value_init (&monster, TP_GET_CAPABILITIES_MONSTER_TYPE);
       
  3442                 g_value_take_boxed (&monster,
       
  3443                     dbus_g_type_specialized_construct (
       
  3444                       TP_GET_CAPABILITIES_MONSTER_TYPE));
       
  3445 
       
  3446                 dbus_g_type_struct_set (&monster,
       
  3447                     0, handle,
       
  3448                     1, ccd->iface,
       
  3449                     2, TP_CONN_CAPABILITY_FLAG_CREATE |
       
  3450                         TP_CONN_CAPABILITY_FLAG_INVITE,
       
  3451                     3, typeflags,
       
  3452                     G_MAXUINT);
       
  3453 
       
  3454                 g_ptr_array_add (*ret, g_value_get_boxed (&monster));
       
  3455               }
       
  3456           }
       
  3457 
       
  3458       for (assumed = assumed_caps; NULL != *assumed; assumed++)
       
  3459         {
       
  3460           GValue monster = {0, };
       
  3461 
       
  3462           g_value_init (&monster, TP_GET_CAPABILITIES_MONSTER_TYPE);
       
  3463           g_value_take_boxed (&monster,
       
  3464               dbus_g_type_specialized_construct (TP_GET_CAPABILITIES_MONSTER_TYPE));
       
  3465 
       
  3466           dbus_g_type_struct_set (&monster,
       
  3467               0, handle,
       
  3468               1, *assumed,
       
  3469               2, TP_CONN_CAPABILITY_FLAG_CREATE |
       
  3470                   TP_CONN_CAPABILITY_FLAG_INVITE,
       
  3471               3, 0,
       
  3472               G_MAXUINT);
       
  3473 
       
  3474           g_ptr_array_add (*ret, g_value_get_boxed (&monster));
       
  3475         }
       
  3476     }
       
  3477 
       
  3478   return TRUE;
       
  3479 }
       
  3480 
       
  3481 
       
  3482 /**
       
  3483  * gabble_connection_get_interfaces
       
  3484  *
       
  3485  * Implements D-Bus method GetInterfaces
       
  3486  * on interface org.freedesktop.Telepathy.Connection
       
  3487  *
       
  3488  * @error: Used to return a pointer to a GError detailing any error
       
  3489  *         that occurred, D-Bus will throw the error only if this
       
  3490  *         function returns FALSE.
       
  3491  *
       
  3492  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3493  */
       
  3494 gboolean
       
  3495 gabble_connection_get_interfaces (GabbleConnection *self,
       
  3496                                   gchar ***ret,
       
  3497                                   GError **error)
       
  3498 {
       
  3499   const char *interfaces[] = {
       
  3500       TP_IFACE_CONN_INTERFACE_ALIASING,
       
  3501       TP_IFACE_CONN_INTERFACE_CAPABILITIES,
       
  3502       TP_IFACE_CONN_INTERFACE_PRESENCE,
       
  3503       TP_IFACE_PROPERTIES,
       
  3504       TP_IFACE_CONN_INTERFACE_AVATAR,
       
  3505       NULL };
       
  3506   GabbleConnectionPrivate *priv;
       
  3507 
       
  3508   g_assert (GABBLE_IS_CONNECTION (self));
       
  3509 
       
  3510   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3511 
       
  3512   ERROR_IF_NOT_CONNECTED (self, error)
       
  3513 
       
  3514   *ret = g_strdupv ((gchar **) interfaces);
       
  3515 
       
  3516   return TRUE;
       
  3517 }
       
  3518 
       
  3519 
       
  3520 /**
       
  3521  * gabble_connection_get_presence
       
  3522  *
       
  3523  * Implements D-Bus method GetPresence
       
  3524  * on interface org.freedesktop.Telepathy.Connection.Interface.Presence
       
  3525  *
       
  3526  * @context: The D-Bus invocation context to use to return values
       
  3527  *           or throw an error.
       
  3528  */
       
  3529 void
       
  3530 gabble_connection_get_presence (GabbleConnection *self,
       
  3531                                 const GArray *contacts,
       
  3532                                 DBusGMethodInvocation *context)
       
  3533 {
       
  3534   GHashTable *presence_hash;
       
  3535   GError *error = NULL;
       
  3536 
       
  3537   if (!gabble_handles_are_valid (self->handles, TP_HANDLE_TYPE_CONTACT,
       
  3538         contacts, FALSE, &error))
       
  3539     {
       
  3540       dbus_g_method_return_error (context, error);
       
  3541       g_error_free (error);
       
  3542     }
       
  3543 
       
  3544   presence_hash = construct_presence_hash (self, contacts);
       
  3545   dbus_g_method_return (context, presence_hash);
       
  3546   g_hash_table_destroy (presence_hash);
       
  3547 }
       
  3548 
       
  3549 
       
  3550 /**
       
  3551  * gabble_connection_get_properties
       
  3552  *
       
  3553  * Implements D-Bus method GetProperties
       
  3554  * on interface org.freedesktop.Telepathy.Properties
       
  3555  *
       
  3556  * @error: Used to return a pointer to a GError detailing any error
       
  3557  *         that occurred, D-Bus will throw the error only if this
       
  3558  *         function returns FALSE.
       
  3559  *
       
  3560  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3561  */
       
  3562 gboolean
       
  3563 gabble_connection_get_properties (GabbleConnection *self,
       
  3564                                   const GArray *properties,
       
  3565                                   GPtrArray **ret,
       
  3566                                   GError **error)
       
  3567 {
       
  3568   return gabble_properties_mixin_get_properties (G_OBJECT (self), properties,
       
  3569       ret, error);
       
  3570 }
       
  3571 
       
  3572 
       
  3573 /**
       
  3574  * gabble_connection_get_protocol
       
  3575  *
       
  3576  * Implements D-Bus method GetProtocol
       
  3577  * on interface org.freedesktop.Telepathy.Connection
       
  3578  *
       
  3579  * @error: Used to return a pointer to a GError detailing any error
       
  3580  *         that occurred, D-Bus will throw the error only if this
       
  3581  *         function returns FALSE.
       
  3582  *
       
  3583  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3584  */
       
  3585 gboolean
       
  3586 gabble_connection_get_protocol (GabbleConnection *self,
       
  3587                                 gchar **ret,
       
  3588                                 GError **error)
       
  3589 {
       
  3590   GabbleConnectionPrivate *priv;
       
  3591 
       
  3592   g_assert (GABBLE_IS_CONNECTION (self));
       
  3593 
       
  3594   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3595 
       
  3596   ERROR_IF_NOT_CONNECTED (self, error)
       
  3597 
       
  3598   *ret = g_strdup (priv->protocol);
       
  3599 
       
  3600   return TRUE;
       
  3601 }
       
  3602 
       
  3603 
       
  3604 /**
       
  3605  * gabble_connection_get_self_handle
       
  3606  *
       
  3607  * Implements D-Bus method GetSelfHandle
       
  3608  * on interface org.freedesktop.Telepathy.Connection
       
  3609  *
       
  3610  * @error: Used to return a pointer to a GError detailing any error
       
  3611  *         that occurred, D-Bus will throw the error only if this
       
  3612  *         function returns FALSE.
       
  3613  *
       
  3614  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3615  */
       
  3616 gboolean
       
  3617 gabble_connection_get_self_handle (GabbleConnection *self,
       
  3618                                    guint *ret,
       
  3619                                    GError **error)
       
  3620 {
       
  3621   GabbleConnectionPrivate *priv;
       
  3622 
       
  3623   g_assert (GABBLE_IS_CONNECTION (self));
       
  3624 
       
  3625   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3626 
       
  3627   ERROR_IF_NOT_CONNECTED (self, error)
       
  3628 
       
  3629   *ret = self->self_handle;
       
  3630 
       
  3631   return TRUE;
       
  3632 }
       
  3633 
       
  3634 
       
  3635 /**
       
  3636  * gabble_connection_get_status
       
  3637  *
       
  3638  * Implements D-Bus method GetStatus
       
  3639  * on interface org.freedesktop.Telepathy.Connection
       
  3640  *
       
  3641  * @error: Used to return a pointer to a GError detailing any error
       
  3642  *         that occurred, D-Bus will throw the error only if this
       
  3643  *         function returns FALSE.
       
  3644  *
       
  3645  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3646  */
       
  3647 gboolean
       
  3648 gabble_connection_get_status (GabbleConnection *self,
       
  3649                               guint *ret,
       
  3650                               GError **error)
       
  3651 {
       
  3652   g_assert (GABBLE_IS_CONNECTION (self));
       
  3653 
       
  3654   if (self->status == TP_CONN_STATUS_NEW)
       
  3655     {
       
  3656       *ret = TP_CONN_STATUS_DISCONNECTED;
       
  3657     }
       
  3658   else
       
  3659     {
       
  3660       *ret = self->status;
       
  3661     }
       
  3662 
       
  3663   return TRUE;
       
  3664 }
       
  3665 
       
  3666 
       
  3667 /**
       
  3668  * gabble_connection_get_statuses
       
  3669  *
       
  3670  * Implements D-Bus method GetStatuses
       
  3671  * on interface org.freedesktop.Telepathy.Connection.Interface.Presence
       
  3672  *
       
  3673  * @error: Used to return a pointer to a GError detailing any error
       
  3674  *         that occurred, D-Bus will throw the error only if this
       
  3675  *         function returns FALSE.
       
  3676  *
       
  3677  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3678  */
       
  3679 gboolean
       
  3680 gabble_connection_get_statuses (GabbleConnection *self,
       
  3681                                 GHashTable **ret,
       
  3682                                 GError **error)
       
  3683 {
       
  3684   GabbleConnectionPrivate *priv;
       
  3685   GValueArray *status;
       
  3686   int i;
       
  3687 
       
  3688   g_assert (GABBLE_IS_CONNECTION (self));
       
  3689 
       
  3690   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3691 
       
  3692   ERROR_IF_NOT_CONNECTED (self, error)
       
  3693 
       
  3694   gabble_debug (DEBUG_FLAG, "called.");
       
  3695 
       
  3696   *ret = g_hash_table_new_full (g_str_hash, g_str_equal,
       
  3697                                 NULL, (GDestroyNotify) g_value_array_free);
       
  3698 
       
  3699   for (i=0; i < LAST_GABBLE_PRESENCE; i++)
       
  3700     {
       
  3701       /* don't report the invisible presence if the server
       
  3702        * doesn't have the presence-invisible feature */
       
  3703       if (!status_is_available (self, i))
       
  3704         continue;
       
  3705 
       
  3706       status = g_value_array_new (5);
       
  3707 
       
  3708       g_value_array_append (status, NULL);
       
  3709       g_value_init (g_value_array_get_nth (status, 0), G_TYPE_UINT);
       
  3710       g_value_set_uint (g_value_array_get_nth (status, 0),
       
  3711           gabble_statuses[i].presence_type);
       
  3712 
       
  3713       g_value_array_append (status, NULL);
       
  3714       g_value_init (g_value_array_get_nth (status, 1), G_TYPE_BOOLEAN);
       
  3715       g_value_set_boolean (g_value_array_get_nth (status, 1),
       
  3716           gabble_statuses[i].self);
       
  3717 
       
  3718       g_value_array_append (status, NULL);
       
  3719       g_value_init (g_value_array_get_nth (status, 2), G_TYPE_BOOLEAN);
       
  3720       g_value_set_boolean (g_value_array_get_nth (status, 2),
       
  3721           gabble_statuses[i].exclusive);
       
  3722 
       
  3723       g_value_array_append (status, NULL);
       
  3724       g_value_init (g_value_array_get_nth (status, 3),
       
  3725           DBUS_TYPE_G_STRING_STRING_HASHTABLE);
       
  3726       g_value_set_static_boxed (g_value_array_get_nth (status, 3),
       
  3727           get_statuses_arguments());
       
  3728 
       
  3729       g_hash_table_insert (*ret, (gchar*) gabble_statuses[i].name, status);
       
  3730     }
       
  3731 
       
  3732   return TRUE;
       
  3733 }
       
  3734 
       
  3735 
       
  3736 /**
       
  3737  * gabble_connection_hold_handles
       
  3738  *
       
  3739  * Implements D-Bus method HoldHandles
       
  3740  * on interface org.freedesktop.Telepathy.Connection
       
  3741  *
       
  3742  * @context: The D-Bus invocation context to use to return values
       
  3743  *           or throw an error.
       
  3744  */
       
  3745 void
       
  3746 gabble_connection_hold_handles (GabbleConnection *self,
       
  3747                                 guint handle_type,
       
  3748                                 const GArray *handles,
       
  3749                                 DBusGMethodInvocation *context)
       
  3750 {
       
  3751   GabbleConnectionPrivate *priv;
       
  3752   GError *error = NULL;
       
  3753   gchar *sender;
       
  3754   guint i;
       
  3755 
       
  3756   g_assert (GABBLE_IS_CONNECTION (self));
       
  3757 
       
  3758   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3759 
       
  3760   ERROR_IF_NOT_CONNECTED_ASYNC (self, error, context)
       
  3761 
       
  3762   if (!gabble_handles_are_valid (self->handles,
       
  3763                                  handle_type,
       
  3764                                  handles,
       
  3765                                  FALSE,
       
  3766                                  &error))
       
  3767     {
       
  3768       dbus_g_method_return_error (context, error);
       
  3769       g_error_free (error);
       
  3770       return;
       
  3771     }
       
  3772 
       
  3773   sender = dbus_g_method_get_sender (context);
       
  3774   for (i = 0; i < handles->len; i++)
       
  3775     {
       
  3776       GabbleHandle handle = g_array_index (handles, GabbleHandle, i);
       
  3777       if (!gabble_handle_client_hold (self->handles, sender, handle,
       
  3778             handle_type, &error))
       
  3779         {
       
  3780           dbus_g_method_return_error (context, error);
       
  3781           g_error_free (error);
       
  3782           return;
       
  3783         }
       
  3784     }
       
  3785 
       
  3786   dbus_g_method_return (context);
       
  3787 }
       
  3788 
       
  3789 
       
  3790 /**
       
  3791  * gabble_connection_inspect_handles
       
  3792  *
       
  3793  * Implements D-Bus method InspectHandles
       
  3794  * on interface org.freedesktop.Telepathy.Connection
       
  3795  *
       
  3796  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3797  */
       
  3798 void
       
  3799 gabble_connection_inspect_handles (GabbleConnection *self,
       
  3800                                    guint handle_type,
       
  3801                                    const GArray *handles,
       
  3802                                    DBusGMethodInvocation *context)
       
  3803 {
       
  3804   GabbleConnectionPrivate *priv;
       
  3805   GError *error = NULL;
       
  3806   const gchar **ret;
       
  3807   guint i;
       
  3808 
       
  3809   g_assert (GABBLE_IS_CONNECTION (self));
       
  3810 
       
  3811   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3812 
       
  3813   ERROR_IF_NOT_CONNECTED_ASYNC (self, error, context);
       
  3814 
       
  3815   if (!gabble_handles_are_valid (self->handles,
       
  3816                                  handle_type,
       
  3817                                  handles,
       
  3818                                  FALSE,
       
  3819                                  &error))
       
  3820     {
       
  3821       dbus_g_method_return_error (context, error);
       
  3822 
       
  3823       g_error_free (error);
       
  3824 
       
  3825       return;
       
  3826     }
       
  3827 
       
  3828   ret = g_new (const gchar *, handles->len + 1);
       
  3829 
       
  3830   for (i = 0; i < handles->len; i++)
       
  3831     {
       
  3832       GabbleHandle handle;
       
  3833       const gchar *tmp;
       
  3834 
       
  3835       handle = g_array_index (handles, GabbleHandle, i);
       
  3836       tmp = gabble_handle_inspect (self->handles, handle_type, handle);
       
  3837       g_assert (tmp != NULL);
       
  3838 
       
  3839       ret[i] = tmp;
       
  3840     }
       
  3841 
       
  3842   ret[i] = NULL;
       
  3843 
       
  3844   dbus_g_method_return (context, ret);
       
  3845 
       
  3846   g_free (ret);
       
  3847 }
       
  3848 
       
  3849 /**
       
  3850  * list_channel_factory_foreach_one:
       
  3851  * @key: iterated key
       
  3852  * @value: iterated value
       
  3853  * @data: data attached to this key/value pair
       
  3854  *
       
  3855  * Called by the exported ListChannels function, this should iterate over
       
  3856  * the handle/channel pairs in a channel factory, and to the GPtrArray in
       
  3857  * the data pointer, add a GValueArray containing the following:
       
  3858  *  a D-Bus object path for the channel object on this service
       
  3859  *  a D-Bus interface name representing the channel type
       
  3860  *  an integer representing the handle type this channel communicates with, or zero
       
  3861  *  an integer handle representing the contact, room or list this channel communicates with, or zero
       
  3862  */
       
  3863 static void
       
  3864 list_channel_factory_foreach_one (TpChannelIface *chan,
       
  3865                                   gpointer data)
       
  3866 {
       
  3867   GObject *channel = G_OBJECT (chan);
       
  3868   GPtrArray *channels = (GPtrArray *) data;
       
  3869   gchar *path, *type;
       
  3870   guint handle_type, handle;
       
  3871   GValue entry = { 0, };
       
  3872 
       
  3873   g_value_init (&entry, TP_CHANNEL_LIST_ENTRY_TYPE);
       
  3874   g_value_take_boxed (&entry, dbus_g_type_specialized_construct
       
  3875       (TP_CHANNEL_LIST_ENTRY_TYPE));
       
  3876 
       
  3877   g_object_get (channel,
       
  3878       "object-path", &path,
       
  3879       "channel-type", &type,
       
  3880       "handle-type", &handle_type,
       
  3881       "handle", &handle,
       
  3882       NULL);
       
  3883 
       
  3884   dbus_g_type_struct_set (&entry,
       
  3885       0, path,
       
  3886       1, type,
       
  3887       2, handle_type,
       
  3888       3, handle,
       
  3889       G_MAXUINT);
       
  3890 
       
  3891   g_ptr_array_add (channels, g_value_get_boxed (&entry));
       
  3892 
       
  3893   g_free (path);
       
  3894   g_free (type);
       
  3895 }
       
  3896 
       
  3897 /**
       
  3898  * gabble_connection_list_channels
       
  3899  *
       
  3900  * Implements D-Bus method ListChannels
       
  3901  * on interface org.freedesktop.Telepathy.Connection
       
  3902  *
       
  3903  * @error: Used to return a pointer to a GError detailing any error
       
  3904  *         that occurred, D-Bus will throw the error only if this
       
  3905  *         function returns FALSE.
       
  3906  *
       
  3907  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3908  */
       
  3909 gboolean
       
  3910 gabble_connection_list_channels (GabbleConnection *self,
       
  3911                                  GPtrArray **ret,
       
  3912                                  GError **error)
       
  3913 {
       
  3914   GabbleConnectionPrivate *priv;
       
  3915   GPtrArray *channels;
       
  3916   guint i;
       
  3917 
       
  3918   g_assert (GABBLE_IS_CONNECTION (self));
       
  3919 
       
  3920   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3921 
       
  3922   ERROR_IF_NOT_CONNECTED (self, error)
       
  3923 
       
  3924   /* I think on average, each factory will have 2 channels :D */
       
  3925   channels = g_ptr_array_sized_new (priv->channel_factories->len * 2);
       
  3926 
       
  3927   for (i = 0; i < priv->channel_factories->len; i++)
       
  3928     {
       
  3929       TpChannelFactoryIface *factory = g_ptr_array_index
       
  3930         (priv->channel_factories, i);
       
  3931       tp_channel_factory_iface_foreach (factory,
       
  3932           list_channel_factory_foreach_one, channels);
       
  3933     }
       
  3934 
       
  3935   *ret = channels;
       
  3936 
       
  3937   return TRUE;
       
  3938 }
       
  3939 
       
  3940 
       
  3941 /**
       
  3942  * gabble_connection_list_properties
       
  3943  *
       
  3944  * Implements D-Bus method ListProperties
       
  3945  * on interface org.freedesktop.Telepathy.Properties
       
  3946  *
       
  3947  * @error: Used to return a pointer to a GError detailing any error
       
  3948  *         that occurred, D-Bus will throw the error only if this
       
  3949  *         function returns false.
       
  3950  *
       
  3951  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  3952  */
       
  3953 gboolean
       
  3954 gabble_connection_list_properties (GabbleConnection *self,
       
  3955                                    GPtrArray **ret,
       
  3956                                    GError **error)
       
  3957 {
       
  3958   return gabble_properties_mixin_list_properties (G_OBJECT (self), ret, error);
       
  3959 }
       
  3960 
       
  3961 
       
  3962 /**
       
  3963  * gabble_connection_release_handles
       
  3964  *
       
  3965  * Implements D-Bus method ReleaseHandles
       
  3966  * on interface org.freedesktop.Telepathy.Connection
       
  3967  *
       
  3968  * @context: The D-Bus invocation context to use to return values
       
  3969  *           or throw an error.
       
  3970  */
       
  3971 void
       
  3972 gabble_connection_release_handles (GabbleConnection *self,
       
  3973                                    guint handle_type,
       
  3974                                    const GArray * handles,
       
  3975                                    DBusGMethodInvocation *context)
       
  3976 {
       
  3977   GabbleConnectionPrivate *priv;
       
  3978   char *sender;
       
  3979   GError *error = NULL;
       
  3980   guint i;
       
  3981 
       
  3982   g_assert (GABBLE_IS_CONNECTION (self));
       
  3983 
       
  3984   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  3985 
       
  3986   ERROR_IF_NOT_CONNECTED_ASYNC (self, error, context)
       
  3987 
       
  3988   if (!gabble_handles_are_valid (self->handles,
       
  3989                                  handle_type,
       
  3990                                  handles,
       
  3991                                  FALSE,
       
  3992                                  &error))
       
  3993     {
       
  3994       dbus_g_method_return_error (context, error);
       
  3995       g_error_free (error);
       
  3996       return;
       
  3997     }
       
  3998 
       
  3999   sender = dbus_g_method_get_sender (context);
       
  4000   for (i = 0; i < handles->len; i++)
       
  4001     {
       
  4002       GabbleHandle handle = g_array_index (handles, GabbleHandle, i);
       
  4003       if (!gabble_handle_client_release (self->handles, sender, handle,
       
  4004             handle_type, &error))
       
  4005         {
       
  4006           dbus_g_method_return_error (context, error);
       
  4007           g_error_free (error);
       
  4008           return;
       
  4009         }
       
  4010     }
       
  4011 
       
  4012   dbus_g_method_return (context);
       
  4013 }
       
  4014 
       
  4015 
       
  4016 /**
       
  4017  * gabble_connection_remove_status
       
  4018  *
       
  4019  * Implements D-Bus method RemoveStatus
       
  4020  * on interface org.freedesktop.Telepathy.Connection.Interface.Presence
       
  4021  *
       
  4022  * @error: Used to return a pointer to a GError detailing any error
       
  4023  *         that occurred, D-Bus will throw the error only if this
       
  4024  *         function returns FALSE.
       
  4025  *
       
  4026  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  4027  */
       
  4028 gboolean
       
  4029 gabble_connection_remove_status (GabbleConnection *self,
       
  4030                                  const gchar *status,
       
  4031                                  GError **error)
       
  4032 {
       
  4033   GabblePresence *presence;
       
  4034   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  4035 
       
  4036   g_assert (GABBLE_IS_CONNECTION (self));
       
  4037 
       
  4038   ERROR_IF_NOT_CONNECTED (self, error)
       
  4039 
       
  4040   presence = gabble_presence_cache_get (self->presence_cache,
       
  4041       self->self_handle);
       
  4042 
       
  4043   if (strcmp (status, gabble_statuses[presence->status].name) == 0)
       
  4044     {
       
  4045       gabble_presence_cache_update (self->presence_cache, self->self_handle,
       
  4046           priv->resource, GABBLE_PRESENCE_AVAILABLE, NULL, priv->priority);
       
  4047       emit_one_presence_update (self, self->self_handle);
       
  4048       return signal_own_presence (self, error);
       
  4049     }
       
  4050   else
       
  4051     {
       
  4052       g_set_error (error, TELEPATHY_ERRORS, InvalidArgument,
       
  4053           "Attempting to remove non-existent presence.");
       
  4054       return FALSE;
       
  4055     }
       
  4056 }
       
  4057 
       
  4058 
       
  4059 typedef struct _AliasesRequest AliasesRequest;
       
  4060 
       
  4061 struct _AliasesRequest
       
  4062 {
       
  4063   GabbleConnection *conn;
       
  4064   DBusGMethodInvocation *request_call;
       
  4065   guint pending_vcard_requests;
       
  4066   GArray *contacts;
       
  4067   GabbleVCardManagerRequest **vcard_requests;
       
  4068   gchar **aliases;
       
  4069 };
       
  4070 
       
  4071 
       
  4072 static AliasesRequest *
       
  4073 aliases_request_new (GabbleConnection *conn,
       
  4074                      DBusGMethodInvocation *request_call,
       
  4075                      const GArray *contacts)
       
  4076 {
       
  4077   AliasesRequest *request;
       
  4078 
       
  4079   request = g_slice_new0 (AliasesRequest);
       
  4080   request->conn = conn;
       
  4081   request->request_call = request_call;
       
  4082   request->contacts = g_array_new (FALSE, FALSE, sizeof (GabbleHandle));
       
  4083   g_array_insert_vals (request->contacts, 0, contacts->data, contacts->len);
       
  4084   request->vcard_requests =
       
  4085     g_new0 (GabbleVCardManagerRequest *, contacts->len);
       
  4086   request->aliases = g_new0 (gchar *, contacts->len + 1);
       
  4087   return request;
       
  4088 }
       
  4089 
       
  4090 
       
  4091 static void
       
  4092 aliases_request_free (AliasesRequest *request)
       
  4093 {
       
  4094   guint i;
       
  4095 
       
  4096   for (i = 0; i < request->contacts->len; i++)
       
  4097     {
       
  4098       if (request->vcard_requests[i] != NULL)
       
  4099         gabble_vcard_manager_cancel_request (request->conn->vcard_manager,
       
  4100             request->vcard_requests[i]);
       
  4101     }
       
  4102 
       
  4103   g_array_free (request->contacts, TRUE);
       
  4104   g_free (request->vcard_requests);
       
  4105   g_strfreev (request->aliases);
       
  4106   g_slice_free (AliasesRequest, request);
       
  4107 }
       
  4108 
       
  4109 
       
  4110 static gboolean
       
  4111 aliases_request_try_return (AliasesRequest *request)
       
  4112 {
       
  4113   if (request->pending_vcard_requests == 0)
       
  4114     {
       
  4115       dbus_g_method_return (request->request_call, request->aliases);
       
  4116       return TRUE;
       
  4117     }
       
  4118 
       
  4119   return FALSE;
       
  4120 }
       
  4121 
       
  4122 
       
  4123 static void
       
  4124 aliases_request_vcard_cb (GabbleVCardManager *manager,
       
  4125                           GabbleVCardManagerRequest *request,
       
  4126                           GabbleHandle handle,
       
  4127                           LmMessageNode *vcard,
       
  4128                           GError *error,
       
  4129                           gpointer user_data)
       
  4130 {
       
  4131   AliasesRequest *aliases_request = (AliasesRequest *) user_data;
       
  4132   GabbleConnectionAliasSource source;
       
  4133   guint i;
       
  4134   gboolean found = FALSE;
       
  4135   gchar *alias = NULL;
       
  4136 
       
  4137   g_assert (aliases_request->pending_vcard_requests > 0);
       
  4138 
       
  4139   /* The index of the vCard request in the vCard request array is the
       
  4140    * index of the contact/alias in their respective arrays. */
       
  4141 
       
  4142   for (i = 0; i < aliases_request->contacts->len; i++)
       
  4143     if (aliases_request->vcard_requests[i] == request)
       
  4144       {
       
  4145         found = TRUE;
       
  4146         break;
       
  4147       }
       
  4148 
       
  4149   g_assert (found);
       
  4150   source = _gabble_connection_get_cached_alias (aliases_request->conn,
       
  4151       g_array_index (aliases_request->contacts, GabbleHandle, i), &alias);
       
  4152   g_assert (source != GABBLE_CONNECTION_ALIAS_NONE);
       
  4153   g_assert (NULL != alias);
       
  4154 
       
  4155   aliases_request->pending_vcard_requests--;
       
  4156   aliases_request->vcard_requests[i] = NULL;
       
  4157   aliases_request->aliases[i] = alias;
       
  4158 
       
  4159   if (aliases_request_try_return (aliases_request))
       
  4160     aliases_request_free (aliases_request);
       
  4161 }
       
  4162 
       
  4163 
       
  4164 /**
       
  4165  * gabble_connection_request_aliases
       
  4166  *
       
  4167  * Implements D-Bus method RequestAliases
       
  4168  * on interface org.freedesktop.Telepathy.Connection.Interface.Aliasing
       
  4169  *
       
  4170  * @context: The D-Bus invocation context to use to return values
       
  4171  *           or throw an error.
       
  4172  */
       
  4173 void
       
  4174 gabble_connection_request_aliases (GabbleConnection *self,
       
  4175                                    const GArray *contacts,
       
  4176                                    DBusGMethodInvocation *context)
       
  4177 {
       
  4178   guint i;
       
  4179   AliasesRequest *request;
       
  4180   GError *error = NULL;
       
  4181 
       
  4182   g_assert (GABBLE_IS_CONNECTION (self));
       
  4183 
       
  4184   ERROR_IF_NOT_CONNECTED_ASYNC (self, error, context)
       
  4185 
       
  4186   if (!gabble_handles_are_valid (self->handles, TP_HANDLE_TYPE_CONTACT,
       
  4187         contacts, FALSE, &error))
       
  4188     {
       
  4189       dbus_g_method_return_error (context, error);
       
  4190       g_error_free (error);
       
  4191       return;
       
  4192     }
       
  4193 
       
  4194   request = aliases_request_new (self, context, contacts);
       
  4195 
       
  4196   for (i = 0; i < contacts->len; i++)
       
  4197     {
       
  4198       GabbleHandle handle = g_array_index (contacts, GabbleHandle, i);
       
  4199       GabbleConnectionAliasSource source;
       
  4200       GabbleVCardManagerRequest *vcard_request;
       
  4201       gchar *alias;
       
  4202 
       
  4203       source = _gabble_connection_get_cached_alias (self, handle, &alias);
       
  4204       g_assert (source != GABBLE_CONNECTION_ALIAS_NONE);
       
  4205       g_assert (NULL != alias);
       
  4206 
       
  4207       if (source >= GABBLE_CONNECTION_ALIAS_FROM_VCARD ||
       
  4208           gabble_vcard_manager_has_cached_alias (self->vcard_manager, handle))
       
  4209         {
       
  4210           /* Either the alias we got was from a vCard or better, or we already
       
  4211            * tried getting an alias from a vcard and failed, so there's no
       
  4212            * point trying again. */
       
  4213           request->aliases[i] = alias;
       
  4214         }
       
  4215       else
       
  4216         {
       
  4217           gabble_debug (DEBUG_FLAG, "requesting vCard for alias of contact %s",
       
  4218               gabble_handle_inspect (self->handles, TP_HANDLE_TYPE_CONTACT,
       
  4219                 handle));
       
  4220 
       
  4221           g_free (alias);
       
  4222           vcard_request = gabble_vcard_manager_request (self->vcard_manager,
       
  4223               handle, 0, aliases_request_vcard_cb, request, G_OBJECT (self),
       
  4224               &error);
       
  4225 
       
  4226           if (NULL != error)
       
  4227             {
       
  4228               dbus_g_method_return_error (context, error);
       
  4229               g_error_free (error);
       
  4230               aliases_request_free (request);
       
  4231               return;
       
  4232             }
       
  4233 
       
  4234           request->vcard_requests[i] = vcard_request;
       
  4235           request->pending_vcard_requests++;
       
  4236         }
       
  4237     }
       
  4238 
       
  4239   if (aliases_request_try_return (request))
       
  4240     aliases_request_free (request);
       
  4241 }
       
  4242 
       
  4243 
       
  4244 /**
       
  4245  * gabble_connection_request_channel
       
  4246  *
       
  4247  * Implements D-Bus method RequestChannel
       
  4248  * on interface org.freedesktop.Telepathy.Connection
       
  4249  *
       
  4250  * @context: The D-Bus invocation context to use to return values
       
  4251  *           or throw an error.
       
  4252  */
       
  4253 void
       
  4254 gabble_connection_request_channel (GabbleConnection *self,
       
  4255                                    const gchar *type,
       
  4256                                    guint handle_type,
       
  4257                                    guint handle,
       
  4258                                    gboolean suppress_handler,
       
  4259                                    DBusGMethodInvocation *context)
       
  4260 {
       
  4261   GabbleConnectionPrivate *priv;
       
  4262   TpChannelFactoryRequestStatus status =
       
  4263     TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_IMPLEMENTED;
       
  4264   gchar *object_path = NULL;
       
  4265   GError *error = NULL;
       
  4266   guint i;
       
  4267 
       
  4268   g_assert (GABBLE_IS_CONNECTION (self));
       
  4269 
       
  4270   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  4271 
       
  4272   ERROR_IF_NOT_CONNECTED_ASYNC (self, error, context);
       
  4273 
       
  4274   for (i = 0; i < priv->channel_factories->len; i++)
       
  4275     {
       
  4276       TpChannelFactoryIface *factory = g_ptr_array_index
       
  4277         (priv->channel_factories, i);
       
  4278       TpChannelFactoryRequestStatus cur_status;
       
  4279       TpChannelIface *chan = NULL;
       
  4280       ChannelRequest *request = NULL;
       
  4281 
       
  4282       priv->suppress_next_handler = suppress_handler;
       
  4283 
       
  4284       cur_status = tp_channel_factory_iface_request (factory, type,
       
  4285           (TpHandleType) handle_type, handle, &chan, &error);
       
  4286 
       
  4287       priv->suppress_next_handler = FALSE;
       
  4288 
       
  4289       switch (cur_status)
       
  4290         {
       
  4291         case TP_CHANNEL_FACTORY_REQUEST_STATUS_DONE:
       
  4292           g_assert (NULL != chan);
       
  4293           g_object_get (chan, "object-path", &object_path, NULL);
       
  4294           goto OUT;
       
  4295         case TP_CHANNEL_FACTORY_REQUEST_STATUS_QUEUED:
       
  4296           gabble_debug (DEBUG_FLAG, "queueing request, channel_type=%s, handle_type=%u, "
       
  4297               "handle=%u, suppress_handler=%u", type, handle_type,
       
  4298               handle, suppress_handler);
       
  4299           request = channel_request_new (context, type, handle_type, handle,
       
  4300               suppress_handler);
       
  4301           g_ptr_array_add (priv->channel_requests, request);
       
  4302           return;
       
  4303         case TP_CHANNEL_FACTORY_REQUEST_STATUS_ERROR:
       
  4304           /* pass through error */
       
  4305           goto OUT;
       
  4306         default:
       
  4307           /* always return the most specific error */
       
  4308           if (cur_status > status)
       
  4309             status = cur_status;
       
  4310         }
       
  4311     }
       
  4312 
       
  4313   switch (status)
       
  4314     {
       
  4315       case TP_CHANNEL_FACTORY_REQUEST_STATUS_INVALID_HANDLE:
       
  4316         gabble_debug (DEBUG_FLAG, "invalid handle %u", handle);
       
  4317 
       
  4318         error = g_error_new (TELEPATHY_ERRORS, InvalidHandle,
       
  4319                              "invalid handle %u", handle);
       
  4320 
       
  4321         break;
       
  4322 
       
  4323       case TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_AVAILABLE:
       
  4324         gabble_debug (DEBUG_FLAG, "requested channel is unavailable with "
       
  4325                  "handle type %u", handle_type);
       
  4326 
       
  4327         error = g_error_new (TELEPATHY_ERRORS, NotAvailable,
       
  4328                              "requested channel is not available with "
       
  4329                              "handle type %u", handle_type);
       
  4330 
       
  4331         break;
       
  4332 
       
  4333       case TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_IMPLEMENTED:
       
  4334         gabble_debug (DEBUG_FLAG, "unsupported channel type %s", type);
       
  4335 
       
  4336         error = g_error_new (TELEPATHY_ERRORS, NotImplemented,
       
  4337                              "unsupported channel type %s", type);
       
  4338 
       
  4339         break;
       
  4340 
       
  4341       default:
       
  4342         g_assert_not_reached ();
       
  4343     }
       
  4344 
       
  4345 OUT:
       
  4346   if (NULL != error)
       
  4347     {
       
  4348       g_assert (NULL == object_path);
       
  4349       dbus_g_method_return_error (context, error);
       
  4350       g_error_free (error);
       
  4351       return;
       
  4352     }
       
  4353 
       
  4354   g_assert (NULL != object_path);
       
  4355   dbus_g_method_return (context, object_path);
       
  4356   g_free (object_path);
       
  4357 }
       
  4358 
       
  4359 
       
  4360 static void
       
  4361 hold_and_return_handles (DBusGMethodInvocation *context,
       
  4362                          GabbleConnection *conn,
       
  4363                          GArray *handles,
       
  4364                          guint handle_type)
       
  4365 {
       
  4366   GError *error = NULL;
       
  4367   gchar *sender = dbus_g_method_get_sender(context);
       
  4368   guint i;
       
  4369 
       
  4370   for (i = 0; i < handles->len; i++)
       
  4371     {
       
  4372       GabbleHandle handle = (GabbleHandle) g_array_index (handles, guint, i);
       
  4373       if (!gabble_handle_client_hold (conn->handles, sender, handle, handle_type, &error))
       
  4374         {
       
  4375           dbus_g_method_return_error (context, error);
       
  4376           g_error_free (error);
       
  4377           return;
       
  4378         }
       
  4379     }
       
  4380   dbus_g_method_return (context, handles);
       
  4381 }
       
  4382 
       
  4383 
       
  4384 const char *
       
  4385 _gabble_connection_find_conference_server (GabbleConnection *conn)
       
  4386 {
       
  4387   GabbleConnectionPrivate *priv;
       
  4388 
       
  4389   g_assert (GABBLE_IS_CONNECTION (conn));
       
  4390 
       
  4391   priv = GABBLE_CONNECTION_GET_PRIVATE (conn);
       
  4392 
       
  4393   if (priv->conference_server == NULL)
       
  4394     {
       
  4395       /* Find first server that has NS_MUC feature */
       
  4396       const GabbleDiscoItem *item = gabble_disco_service_find (conn->disco,
       
  4397           NULL, NULL, NS_MUC);
       
  4398       if (item != NULL)
       
  4399         priv->conference_server = item->jid;
       
  4400     }
       
  4401 
       
  4402   if (priv->conference_server == NULL)
       
  4403     priv->conference_server = priv->fallback_conference_server;
       
  4404 
       
  4405   return priv->conference_server;
       
  4406 }
       
  4407 
       
  4408 
       
  4409 static gchar *
       
  4410 _gabble_connection_get_canonical_room_name (GabbleConnection *conn,
       
  4411                                            const gchar *name)
       
  4412 {
       
  4413   const gchar *server;
       
  4414 
       
  4415   g_assert (GABBLE_IS_CONNECTION (conn));
       
  4416 
       
  4417   if (index (name, '@'))
       
  4418     return g_strdup (name);
       
  4419 
       
  4420   server = _gabble_connection_find_conference_server (conn);
       
  4421 
       
  4422   if (server == NULL)
       
  4423     return NULL;
       
  4424 
       
  4425   return g_strdup_printf ("%s@%s", name, server);
       
  4426 }
       
  4427 
       
  4428 
       
  4429 typedef struct _RoomVerifyContext RoomVerifyContext;
       
  4430 
       
  4431 typedef struct {
       
  4432     GabbleConnection *conn;
       
  4433     DBusGMethodInvocation *invocation;
       
  4434     gboolean errored;
       
  4435     guint count;
       
  4436     GArray *handles;
       
  4437     RoomVerifyContext *contexts;
       
  4438 } RoomVerifyBatch;
       
  4439 
       
  4440 struct _RoomVerifyContext {
       
  4441     gchar *jid;
       
  4442     guint index;
       
  4443     RoomVerifyBatch *batch;
       
  4444     GabbleDiscoRequest *request;
       
  4445 };
       
  4446 
       
  4447 static void
       
  4448 room_verify_batch_free (RoomVerifyBatch *batch)
       
  4449 {
       
  4450   guint i;
       
  4451 
       
  4452   g_array_free (batch->handles, TRUE);
       
  4453   for (i = 0; i < batch->count; i++)
       
  4454     {
       
  4455       g_free(batch->contexts[i].jid);
       
  4456     }
       
  4457   g_free (batch->contexts);
       
  4458   g_free (batch);
       
  4459 }
       
  4460 
       
  4461 /* Frees the error and the batch. */
       
  4462 static void
       
  4463 room_verify_batch_raise_error (RoomVerifyBatch *batch,
       
  4464                                GError *error)
       
  4465 {
       
  4466   guint i;
       
  4467 
       
  4468   dbus_g_method_return_error (batch->invocation, error);
       
  4469   g_error_free (error);
       
  4470   batch->errored = TRUE;
       
  4471   for (i = 0; i < batch->count; i++)
       
  4472     {
       
  4473       if (batch->contexts[i].request)
       
  4474         {
       
  4475           gabble_disco_cancel_request(batch->conn->disco,
       
  4476                                       batch->contexts[i].request);
       
  4477         }
       
  4478     }
       
  4479   room_verify_batch_free (batch);
       
  4480 }
       
  4481 
       
  4482 static RoomVerifyBatch *
       
  4483 room_verify_batch_new (GabbleConnection *conn,
       
  4484                        DBusGMethodInvocation *invocation,
       
  4485                        guint count,
       
  4486                        const gchar **jids)
       
  4487 {
       
  4488   RoomVerifyBatch *batch = g_new(RoomVerifyBatch, 1);
       
  4489   guint i;
       
  4490 
       
  4491   batch->errored = FALSE;
       
  4492   batch->conn = conn;
       
  4493   batch->invocation = invocation;
       
  4494   batch->count = count;
       
  4495   batch->handles = g_array_sized_new(FALSE, FALSE, sizeof(GabbleHandle), count);
       
  4496   batch->contexts = g_new0(RoomVerifyContext, count);
       
  4497   for (i = 0; i < count; i++)
       
  4498     {
       
  4499       const gchar *name = jids[i];
       
  4500       gchar *qualified_name;
       
  4501       GabbleHandle handle;
       
  4502 
       
  4503       batch->contexts[i].index = i;
       
  4504       batch->contexts[i].batch = batch;
       
  4505 
       
  4506       qualified_name = _gabble_connection_get_canonical_room_name (conn, name);
       
  4507 
       
  4508       if (!qualified_name)
       
  4509         {
       
  4510           GError *error = NULL;
       
  4511           gabble_debug (DEBUG_FLAG, "requested handle %s contains no conference server",
       
  4512                  name);
       
  4513           error = g_error_new (TELEPATHY_ERRORS, NotAvailable, "requested "
       
  4514                   "room handle %s does not specify a server, but we have not discovered "
       
  4515                   "any local conference servers and no fallback was provided", name);
       
  4516           room_verify_batch_raise_error (batch, error);
       
  4517           return NULL;
       
  4518         }
       
  4519 
       
  4520       batch->contexts[i].jid = qualified_name;
       
  4521 
       
  4522       /* has the handle been verified before? */
       
  4523       if (gabble_handle_for_room_exists (conn->handles, qualified_name, FALSE))
       
  4524         {
       
  4525           handle = gabble_handle_for_room (conn->handles, qualified_name);
       
  4526         }
       
  4527       else
       
  4528         {
       
  4529           handle = 0;
       
  4530         }
       
  4531       g_array_append_val (batch->handles, handle);
       
  4532     }
       
  4533 
       
  4534   return batch;
       
  4535 }
       
  4536 
       
  4537 /* If all handles in the array have been disco'd or got from cache,
       
  4538 free the batch and return TRUE. Else return FALSE. */
       
  4539 static gboolean
       
  4540 room_verify_batch_try_return (RoomVerifyBatch *batch)
       
  4541 {
       
  4542   guint i;
       
  4543 
       
  4544   for (i = 0; i < batch->count; i++)
       
  4545     {
       
  4546       if (!g_array_index(batch->handles, GabbleHandle, i))
       
  4547         {
       
  4548           /* we're not ready yet */
       
  4549           return FALSE;
       
  4550         }
       
  4551     }
       
  4552 
       
  4553   hold_and_return_handles (batch->invocation, batch->conn, batch->handles, TP_HANDLE_TYPE_ROOM);
       
  4554   room_verify_batch_free (batch);
       
  4555   return TRUE;
       
  4556 }
       
  4557 
       
  4558 static void
       
  4559 room_jid_disco_cb (GabbleDisco *disco,
       
  4560                    GabbleDiscoRequest *request,
       
  4561                    const gchar *jid,
       
  4562                    const gchar *node,
       
  4563                    LmMessageNode *query_result,
       
  4564                    GError *error,
       
  4565                    gpointer user_data)
       
  4566 {
       
  4567   RoomVerifyContext *rvctx = user_data;
       
  4568   RoomVerifyBatch *batch = rvctx->batch;
       
  4569   LmMessageNode *lm_node;
       
  4570   gboolean found = FALSE;
       
  4571   GabbleHandle handle;
       
  4572 
       
  4573   /* stop the request getting cancelled after it's already finished */
       
  4574   rvctx->request = NULL;
       
  4575 
       
  4576   /* if an error is being handled already, quietly go away */
       
  4577   if (batch->errored)
       
  4578     {
       
  4579       return;
       
  4580     }
       
  4581 
       
  4582   if (error != NULL)
       
  4583     {
       
  4584       gabble_debug (DEBUG_FLAG, "disco reply error %s", error->message);
       
  4585 
       
  4586       /* disco will free the old error, _raise_error will free the new one */
       
  4587       error = g_error_new (TELEPATHY_ERRORS, NotAvailable,
       
  4588         "can't retrieve room info: %s", error->message);
       
  4589 
       
  4590       room_verify_batch_raise_error (batch, error);
       
  4591 
       
  4592       return;
       
  4593     }
       
  4594 
       
  4595   for (lm_node = query_result->children; lm_node; lm_node = lm_node->next)
       
  4596     {
       
  4597       const gchar *var;
       
  4598 
       
  4599       if (g_strdiff (lm_node->name, "feature"))
       
  4600         continue;
       
  4601 
       
  4602       var = lm_message_node_get_attribute (lm_node, "var");
       
  4603 
       
  4604       /* for servers who consider schema compliance to be an optional bonus */
       
  4605       if (var == NULL)
       
  4606         var = lm_message_node_get_attribute (lm_node, "type");
       
  4607 
       
  4608       if (!g_strdiff (var, NS_MUC))
       
  4609         {
       
  4610           found = TRUE;
       
  4611           break;
       
  4612         }
       
  4613     }
       
  4614 
       
  4615   if (!found)
       
  4616     {
       
  4617       gabble_debug (DEBUG_FLAG, "no MUC support for service name in jid %s", rvctx->jid);
       
  4618 
       
  4619       error = g_error_new (TELEPATHY_ERRORS, NotAvailable, "specified server "
       
  4620           "doesn't support MUC");
       
  4621 
       
  4622       room_verify_batch_raise_error (batch, error);
       
  4623 
       
  4624       return;
       
  4625     }
       
  4626 
       
  4627   handle = gabble_handle_for_room (batch->conn->handles, rvctx->jid);
       
  4628   g_assert (handle != 0);
       
  4629 
       
  4630   gabble_debug (DEBUG_FLAG, "disco reported MUC support for service name in jid %s", rvctx->jid);
       
  4631   g_array_index (batch->handles, GabbleHandle, rvctx->index) = handle;
       
  4632 
       
  4633   /* if this was the last callback to be run, send off the result */
       
  4634   room_verify_batch_try_return (batch);
       
  4635 }
       
  4636 
       
  4637 /**
       
  4638  * room_jid_verify:
       
  4639  *
       
  4640  * Utility function that verifies that the service name of
       
  4641  * the specified jid exists and reports MUC support.
       
  4642  */
       
  4643 static gboolean
       
  4644 room_jid_verify (RoomVerifyBatch *batch,
       
  4645                  guint index,
       
  4646                  DBusGMethodInvocation *context)
       
  4647 {
       
  4648   gchar *room, *service;
       
  4649   gboolean ret;
       
  4650   GError *error = NULL;
       
  4651 
       
  4652   room = service = NULL;
       
  4653   gabble_decode_jid (batch->contexts[index].jid, &room, &service, NULL);
       
  4654 
       
  4655   g_assert (room && service);
       
  4656 
       
  4657   ret = (gabble_disco_request (batch->conn->disco, GABBLE_DISCO_TYPE_INFO,
       
  4658                                service, NULL, room_jid_disco_cb,
       
  4659                                batch->contexts + index,
       
  4660                                G_OBJECT (batch->conn), &error) != NULL);
       
  4661   if (!ret)
       
  4662     {
       
  4663       room_verify_batch_raise_error (batch, error);
       
  4664     }
       
  4665 
       
  4666   g_free (room);
       
  4667   g_free (service);
       
  4668 
       
  4669   return ret;
       
  4670 }
       
  4671 
       
  4672 
       
  4673 /**
       
  4674  * gabble_connection_request_handles
       
  4675  *
       
  4676  * Implements D-Bus method RequestHandles
       
  4677  * on interface org.freedesktop.Telepathy.Connection
       
  4678  *
       
  4679  * @context: The D-Bus invocation context to use to return values
       
  4680  *           or throw an error.
       
  4681  */
       
  4682 void
       
  4683 gabble_connection_request_handles (GabbleConnection *self,
       
  4684                                    guint handle_type,
       
  4685                                    const gchar **names,
       
  4686                                    DBusGMethodInvocation *context)
       
  4687 {
       
  4688   guint count = 0, i;
       
  4689   const gchar **cur_name;
       
  4690   GError *error = NULL;
       
  4691   GArray *handles = NULL;
       
  4692   RoomVerifyBatch *batch = NULL;
       
  4693 
       
  4694   for (cur_name = names; *cur_name != NULL; cur_name++)
       
  4695     {
       
  4696       count++;
       
  4697     }
       
  4698 
       
  4699   g_assert (GABBLE_IS_CONNECTION (self));
       
  4700 
       
  4701   ERROR_IF_NOT_CONNECTED_ASYNC (self, error, context)
       
  4702 
       
  4703   if (!gabble_handle_type_is_valid (handle_type, &error))
       
  4704     {
       
  4705       dbus_g_method_return_error (context, error);
       
  4706       g_error_free (error);
       
  4707       return;
       
  4708     }
       
  4709 
       
  4710   switch (handle_type)
       
  4711     {
       
  4712     case TP_HANDLE_TYPE_CONTACT:
       
  4713       handles = g_array_sized_new(FALSE, FALSE, sizeof(GabbleHandle), count);
       
  4714 
       
  4715       for (i = 0; i < count; i++)
       
  4716         {
       
  4717           GabbleHandle handle;
       
  4718           const gchar *name = names[i];
       
  4719 
       
  4720           if (!gabble_handle_jid_is_valid (handle_type, name, &error))
       
  4721             {
       
  4722               dbus_g_method_return_error (context, error);
       
  4723               g_error_free (error);
       
  4724 
       
  4725               g_array_free (handles, TRUE);
       
  4726               return;
       
  4727             }
       
  4728 
       
  4729           handle = gabble_handle_for_contact (self->handles, name, FALSE);
       
  4730 
       
  4731           if (handle == 0)
       
  4732             {
       
  4733               gabble_debug (DEBUG_FLAG, "requested handle %s was invalid", name);
       
  4734 
       
  4735               error = g_error_new (TELEPATHY_ERRORS, NotAvailable,
       
  4736                                    "requested handle %s was invalid", name);
       
  4737               dbus_g_method_return_error (context, error);
       
  4738               g_error_free (error);
       
  4739 
       
  4740               g_array_free (handles, TRUE);
       
  4741               return;
       
  4742             }
       
  4743 
       
  4744           g_array_append_val(handles, handle);
       
  4745         }
       
  4746       hold_and_return_handles (context, self, handles, handle_type);
       
  4747       g_array_free(handles, TRUE);
       
  4748       break;
       
  4749 
       
  4750     case TP_HANDLE_TYPE_ROOM:
       
  4751       batch = room_verify_batch_new (self, context, count, names);
       
  4752       if (!batch)
       
  4753         {
       
  4754           /* an error occurred while setting up the batch, and we returned error
       
  4755           to dbus */
       
  4756           return;
       
  4757         }
       
  4758 
       
  4759       /* have all the handles been verified already? If so, nothing to do */
       
  4760       if (room_verify_batch_try_return (batch))
       
  4761         {
       
  4762           return;
       
  4763         }
       
  4764 
       
  4765       for (i = 0; i < count; i++)
       
  4766         {
       
  4767           if (!room_jid_verify (batch, i, context))
       
  4768             {
       
  4769               return;
       
  4770             }
       
  4771         }
       
  4772 
       
  4773       /* we've set the verification process going - the callback will handle
       
  4774       returning or raising error */
       
  4775       break;
       
  4776 
       
  4777     case TP_HANDLE_TYPE_LIST:
       
  4778       handles = g_array_sized_new(FALSE, FALSE, sizeof(GabbleHandle), count);
       
  4779 
       
  4780       for (i = 0; i < count; i++)
       
  4781         {
       
  4782           GabbleHandle handle;
       
  4783           const gchar *name = names[i];
       
  4784 
       
  4785           handle = gabble_handle_for_list (self->handles, name);
       
  4786 
       
  4787           if (handle == 0)
       
  4788             {
       
  4789               gabble_debug (DEBUG_FLAG, "requested list channel %s not available", name);
       
  4790 
       
  4791               error = g_error_new (TELEPATHY_ERRORS, NotAvailable,
       
  4792                                    "requested list channel %s not available",
       
  4793                                    name);
       
  4794               dbus_g_method_return_error (context, error);
       
  4795               g_error_free (error);
       
  4796 
       
  4797               g_array_free (handles, TRUE);
       
  4798               return;
       
  4799             }
       
  4800           g_array_append_val(handles, handle);
       
  4801         }
       
  4802       hold_and_return_handles (context, self, handles, handle_type);
       
  4803       g_array_free(handles, TRUE);
       
  4804       break;
       
  4805 
       
  4806     default:
       
  4807       gabble_debug (DEBUG_FLAG, "unimplemented handle type %u", handle_type);
       
  4808 
       
  4809       error = g_error_new (TELEPATHY_ERRORS, NotAvailable,
       
  4810                           "unimplemented handle type %u", handle_type);
       
  4811       dbus_g_method_return_error (context, error);
       
  4812       g_error_free (error);
       
  4813     }
       
  4814 }
       
  4815 
       
  4816 
       
  4817 /**
       
  4818  * gabble_connection_request_presence
       
  4819  *
       
  4820  * Implements D-Bus method RequestPresence
       
  4821  * on interface org.freedesktop.Telepathy.Connection.Interface.Presence
       
  4822  *
       
  4823  * @error: Used to return a pointer to a GError detailing any error
       
  4824  *         that occurred, D-Bus will throw the error only if this
       
  4825  *         function returns FALSE.
       
  4826  *
       
  4827  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  4828  */
       
  4829 gboolean
       
  4830 gabble_connection_request_presence (GabbleConnection *self,
       
  4831                                     const GArray *contacts,
       
  4832                                     GError **error)
       
  4833 {
       
  4834   GabbleConnectionPrivate *priv;
       
  4835 
       
  4836   g_assert (GABBLE_IS_CONNECTION (self));
       
  4837 
       
  4838   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  4839 
       
  4840   ERROR_IF_NOT_CONNECTED (self, error)
       
  4841 
       
  4842   if (!gabble_handles_are_valid (self->handles, TP_HANDLE_TYPE_CONTACT,
       
  4843         contacts, FALSE, error))
       
  4844     return FALSE;
       
  4845 
       
  4846   if (contacts->len)
       
  4847     emit_presence_update (self, contacts);
       
  4848 
       
  4849   return TRUE;
       
  4850 }
       
  4851 
       
  4852 
       
  4853 struct _i_hate_g_hash_table_foreach
       
  4854 {
       
  4855   GabbleConnection *conn;
       
  4856   GError **error;
       
  4857   gboolean retval;
       
  4858 };
       
  4859 
       
  4860 static void
       
  4861 setaliases_foreach (gpointer key, gpointer value, gpointer user_data)
       
  4862 {
       
  4863   struct _i_hate_g_hash_table_foreach *data =
       
  4864     (struct _i_hate_g_hash_table_foreach *) user_data;
       
  4865   GabbleHandle handle = GPOINTER_TO_INT (key);
       
  4866   gchar *alias = (gchar *) value;
       
  4867   GError *error = NULL;
       
  4868 
       
  4869   if (!gabble_handle_is_valid (data->conn->handles, TP_HANDLE_TYPE_CONTACT,
       
  4870         handle, &error))
       
  4871     {
       
  4872       data->retval = FALSE;
       
  4873     }
       
  4874   else if (data->conn->self_handle == handle)
       
  4875     {
       
  4876       /* only alter the roster if we're already there, e.g. because someone
       
  4877        * added us with another client
       
  4878        */
       
  4879       if (gabble_roster_handle_has_entry (data->conn->roster, handle)
       
  4880           && !gabble_roster_handle_set_name (data->conn->roster, handle,
       
  4881                                              alias, data->error))
       
  4882         {
       
  4883           data->retval = FALSE;
       
  4884         }
       
  4885     }
       
  4886   else if (!gabble_roster_handle_set_name (data->conn->roster, handle, alias,
       
  4887         data->error))
       
  4888     {
       
  4889       data->retval = FALSE;
       
  4890     }
       
  4891 
       
  4892   if (data->conn->self_handle == handle)
       
  4893     {
       
  4894       /* User has done SetAliases on themselves - patch their vCard.
       
  4895        * FIXME: because SetAliases is currently synchronous, we ignore errors
       
  4896        * here, and just let the request happen in the background
       
  4897        */
       
  4898       gabble_vcard_manager_edit (data->conn->vcard_manager,
       
  4899                                  0, NULL, NULL, G_OBJECT(data->conn), NULL,
       
  4900                                  "NICKNAME", alias, NULL);
       
  4901     }
       
  4902 
       
  4903   if (NULL != error)
       
  4904     {
       
  4905       if (NULL == *(data->error))
       
  4906         {
       
  4907           *(data->error) = error;
       
  4908         }
       
  4909       else
       
  4910         {
       
  4911           g_error_free (error);
       
  4912         }
       
  4913     }
       
  4914 }
       
  4915 
       
  4916 /**
       
  4917  * gabble_connection_set_aliases
       
  4918  *
       
  4919  * Implements D-Bus method SetAliases
       
  4920  * on interface org.freedesktop.Telepathy.Connection.Interface.Aliasing
       
  4921  *
       
  4922  * @error: Used to return a pointer to a GError detailing any error
       
  4923  *         that occurred, D-Bus will throw the error only if this
       
  4924  *         function returns false.
       
  4925  *
       
  4926  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  4927  */
       
  4928 gboolean
       
  4929 gabble_connection_set_aliases (GabbleConnection *self,
       
  4930                                GHashTable *aliases,
       
  4931                                GError **error)
       
  4932 {
       
  4933   GabbleConnectionPrivate *priv;
       
  4934   struct _i_hate_g_hash_table_foreach data = { NULL, NULL, TRUE };
       
  4935 
       
  4936   g_assert (GABBLE_IS_CONNECTION (self));
       
  4937 
       
  4938   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  4939 
       
  4940   ERROR_IF_NOT_CONNECTED (self, error)
       
  4941 
       
  4942   data.conn = self;
       
  4943   data.error = error;
       
  4944 
       
  4945   g_hash_table_foreach (aliases, setaliases_foreach, &data);
       
  4946 
       
  4947   return data.retval;
       
  4948 }
       
  4949 
       
  4950 
       
  4951 /**
       
  4952  * gabble_connection_set_last_activity_time
       
  4953  *
       
  4954  * Implements D-Bus method SetLastActivityTime
       
  4955  * on interface org.freedesktop.Telepathy.Connection.Interface.Presence
       
  4956  *
       
  4957  * @error: Used to return a pointer to a GError detailing any error
       
  4958  *         that occurred, D-Bus will throw the error only if this
       
  4959  *         function returns false.
       
  4960  *
       
  4961  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  4962  */
       
  4963 gboolean
       
  4964 gabble_connection_set_last_activity_time (GabbleConnection *self,
       
  4965                                           guint time,
       
  4966                                           GError **error)
       
  4967 {
       
  4968   GabbleConnectionPrivate *priv;
       
  4969 
       
  4970   g_assert (GABBLE_IS_CONNECTION (self));
       
  4971 
       
  4972   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  4973 
       
  4974   ERROR_IF_NOT_CONNECTED (self, error)
       
  4975 
       
  4976   return TRUE;
       
  4977 }
       
  4978 
       
  4979 
       
  4980 static void
       
  4981 setstatuses_foreach (gpointer key, gpointer value, gpointer user_data)
       
  4982 {
       
  4983   struct _i_hate_g_hash_table_foreach *data =
       
  4984     (struct _i_hate_g_hash_table_foreach*) user_data;
       
  4985   GabbleConnectionPrivate *priv = GABBLE_CONNECTION_GET_PRIVATE (data->conn);
       
  4986 
       
  4987   int i;
       
  4988 
       
  4989   for (i = 0; i < LAST_GABBLE_PRESENCE; i++)
       
  4990     {
       
  4991       if (0 == strcmp (gabble_statuses[i].name, (const gchar*) key))
       
  4992         break;
       
  4993     }
       
  4994 
       
  4995   if (i < LAST_GABBLE_PRESENCE)
       
  4996     {
       
  4997       GHashTable *args = (GHashTable *)value;
       
  4998       GValue *message = g_hash_table_lookup (args, "message");
       
  4999       GValue *priority = g_hash_table_lookup (args, "priority");
       
  5000       const gchar *status = NULL;
       
  5001       gint8 prio = priv->priority;
       
  5002 
       
  5003       if (!status_is_available (data->conn, i))
       
  5004         {
       
  5005           gabble_debug (DEBUG_FLAG, "requested status %s is not available", (const gchar *) key);
       
  5006           g_set_error (data->error, TELEPATHY_ERRORS, NotAvailable,
       
  5007               "requested status '%s' is not available on this connection",
       
  5008               (const gchar *) key);
       
  5009           data->retval = FALSE;
       
  5010           return;
       
  5011         }
       
  5012 
       
  5013       if (message)
       
  5014         {
       
  5015           if (!G_VALUE_HOLDS_STRING (message))
       
  5016             {
       
  5017               gabble_debug (DEBUG_FLAG, "got a status message which was not a string");
       
  5018               g_set_error (data->error, TELEPATHY_ERRORS, InvalidArgument,
       
  5019                   "Status argument 'message' requires a string");
       
  5020               data->retval = FALSE;
       
  5021               return;
       
  5022             }
       
  5023           status = g_value_get_string (message);
       
  5024         }
       
  5025 
       
  5026       if (priority)
       
  5027         {
       
  5028           if (!G_VALUE_HOLDS_INT (priority))
       
  5029             {
       
  5030               gabble_debug (DEBUG_FLAG, "got a priority value which was not a signed integer");
       
  5031               g_set_error (data->error, TELEPATHY_ERRORS, InvalidArgument,
       
  5032                    "Status argument 'priority' requires a signed integer");
       
  5033               data->retval = FALSE;
       
  5034               return;
       
  5035             }
       
  5036           prio = CLAMP (g_value_get_int (priority), G_MININT8, G_MAXINT8);
       
  5037         }
       
  5038 
       
  5039       gabble_presence_cache_update (data->conn->presence_cache, data->conn->self_handle, priv->resource, i, status, prio);
       
  5040       emit_one_presence_update (data->conn, data->conn->self_handle);
       
  5041       data->retval = signal_own_presence (data->conn, data->error);
       
  5042     }
       
  5043   else
       
  5044     {
       
  5045       gabble_debug (DEBUG_FLAG, "got unknown status identifier %s", (const gchar *) key);
       
  5046       g_set_error (data->error, TELEPATHY_ERRORS, InvalidArgument,
       
  5047           "unknown status identifier: %s", (const gchar *) key);
       
  5048       data->retval = FALSE;
       
  5049     }
       
  5050 }
       
  5051 
       
  5052 /**
       
  5053  * gabble_connection_set_properties
       
  5054  *
       
  5055  * Implements D-Bus method SetProperties
       
  5056  * on interface org.freedesktop.Telepathy.Properties
       
  5057  *
       
  5058  * @context: The D-Bus invocation context to use to return values
       
  5059  *           or throw an error.
       
  5060  */
       
  5061 void
       
  5062 gabble_connection_set_properties (GabbleConnection *self,
       
  5063                                   const GPtrArray *properties,
       
  5064                                   DBusGMethodInvocation *context)
       
  5065 {
       
  5066   gabble_properties_mixin_set_properties (G_OBJECT (self), properties, context);
       
  5067 }
       
  5068 
       
  5069 /**
       
  5070  * gabble_connection_set_status
       
  5071  *
       
  5072  * Implements D-Bus method SetStatus
       
  5073  * on interface org.freedesktop.Telepathy.Connection.Interface.Presence
       
  5074  *
       
  5075  * @error: Used to return a pointer to a GError detailing any error
       
  5076  *         that occurred, D-Bus will throw the error only if this
       
  5077  *         function returns FALSE.
       
  5078  *
       
  5079  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  5080  */
       
  5081 gboolean
       
  5082 gabble_connection_set_status (GabbleConnection *self,
       
  5083                               GHashTable *statuses,
       
  5084                               GError **error)
       
  5085 {
       
  5086   GabbleConnectionPrivate *priv;
       
  5087   struct _i_hate_g_hash_table_foreach data = { NULL, NULL, TRUE };
       
  5088 
       
  5089   g_assert (GABBLE_IS_CONNECTION (self));
       
  5090 
       
  5091   priv = GABBLE_CONNECTION_GET_PRIVATE (self);
       
  5092 
       
  5093   ERROR_IF_NOT_CONNECTED (self, error)
       
  5094 
       
  5095   if (g_hash_table_size (statuses) != 1)
       
  5096     {
       
  5097       gabble_debug (DEBUG_FLAG, "got more than one status");
       
  5098       g_set_error (error, TELEPATHY_ERRORS, InvalidArgument,
       
  5099           "Only one status may be set at a time in this protocol");
       
  5100       return FALSE;
       
  5101     }
       
  5102 
       
  5103   data.conn = self;
       
  5104   data.error = error;
       
  5105   g_hash_table_foreach (statuses, setstatuses_foreach, &data);
       
  5106 
       
  5107   return data.retval;
       
  5108 }
       
  5109 
       
  5110 /**
       
  5111  * gabble_connection_build_avatar
       
  5112  *
       
  5113  * Implements D-Bus method SetAvatar
       
  5114  * on interface org.freedesktop.Telepathy.Connection.Avatar
       
  5115  *
       
  5116  * @context: The D-Bus invocation context to use to return values
       
  5117  *           or throw an error.
       
  5118  */
       
  5119 
       
  5120 LmMessage* gabble_connection_build_avatar(GabbleConnection *self,  
       
  5121         const GArray* bin_image, gchar* mime )
       
  5122     {
       
  5123     int i = 0; 
       
  5124     LmMessage    *message;
       
  5125     LmMessageNode *lm_node,*photo_node;
       
  5126     LmMessageHandler* handler = NULL;
       
  5127     char* base64 = NULL;
       
  5128     GError* error = NULL;
       
  5129     //NULL values to be checked ? never returns NULL?
       
  5130     if ( bin_image )
       
  5131         {
       
  5132         if ( self->self_avatar_sha1 ) 
       
  5133             {
       
  5134             free( self->self_avatar_sha1 );
       
  5135             self->self_avatar_sha1 = NULL;
       
  5136             }
       
  5137         self->self_avatar_sha1 = sha1_hex( bin_image->data, bin_image->len );
       
  5138         base64 = base64_encode ( bin_image->len, bin_image->data );
       
  5139         }  
       
  5140 
       
  5141     message = lm_message_new_with_sub_type ( NULL,
       
  5142             LM_MESSAGE_TYPE_IQ,
       
  5143             LM_MESSAGE_SUB_TYPE_SET );
       
  5144     lm_node = lm_message_node_add_child (message->node, "vCard", NULL);
       
  5145     lm_message_node_set_attribute (lm_node, "xmlns", NS_VCARD_TEMP);
       
  5146     photo_node = lm_message_node_add_child (lm_node, "PHOTO", NULL); 
       
  5147     lm_message_node_add_child (photo_node, "TYPE", mime);
       
  5148     lm_message_node_add_child (photo_node, "BINVAL", base64);
       
  5149     g_free(base64);
       
  5150     return message;
       
  5151     }
       
  5152 
       
  5153 /**
       
  5154  * gabble_connection_set_avatar
       
  5155  *
       
  5156  * Implements D-Bus method SetAvatar
       
  5157  * on interface org.freedesktop.Telepathy.Connection
       
  5158  *
       
  5159  */
       
  5160 gboolean  
       
  5161 gabble_connection_set_avatar( GabbleConnection *self, const GArray* bin_image, gchar* mime_type, gchar**avatar_sha1,
       
  5162         GError** err )
       
  5163     {
       
  5164     
       
  5165     gboolean ret = FALSE; 
       
  5166     LmMessage *message; 
       
  5167     
       
  5168 
       
  5169     //There is no need to check bin_image and mime for NULL.. NULL is a valid value for those
       
  5170     message = gabble_connection_build_avatar( self, bin_image, mime_type );
       
  5171 
       
  5172     ret = _gabble_connection_send ( self, message, err );
       
  5173     
       
  5174     if ( *err ) 
       
  5175             {
       
  5176             *avatar_sha1 = NULL;
       
  5177             //ret is already false.. so false returned
       
  5178             }
       
  5179         else {
       
  5180             if ( self->self_avatar_sha1 )
       
  5181                 {
       
  5182                 *avatar_sha1 = g_strdup( self->self_avatar_sha1 );
       
  5183                 }
       
  5184             ret = TRUE;
       
  5185             }
       
  5186 
       
  5187     lm_message_unref( message );
       
  5188     
       
  5189     return ret;
       
  5190     }
       
  5191 
       
  5192 /**
       
  5193  * gabble_connection_clear_avatar
       
  5194  *
       
  5195  * Implements D-Bus method ClearAvatar
       
  5196  * on interface org.freedesktop.Telepathy.Connection.Interface.Avatar
       
  5197  *
       
  5198  * @error: Used to return a pointer to a GError detailing any error
       
  5199  *         that occurred, D-Bus will throw the error only if this
       
  5200  *         function returns FALSE.
       
  5201  *
       
  5202  * Returns: TRUE if successful, FALSE if an error was thrown.
       
  5203  */
       
  5204 gboolean 
       
  5205 gabble_connection_clear_avatar( GabbleConnection *self,
       
  5206                               GError **error)
       
  5207  {
       
  5208    LmMessage *message;
       
  5209    gboolean ret = TRUE;
       
  5210 
       
  5211 
       
  5212    //Build the avatar xml with NULL as image data and NULL as mimetype
       
  5213    message = gabble_connection_build_avatar( self, 
       
  5214            NULL, NULL );
       
  5215 
       
  5216    ret = _gabble_connection_send ( self, message, error );
       
  5217 
       
  5218    if ( self->self_avatar_sha1 ) 
       
  5219        {
       
  5220        free( self->self_avatar_sha1 );
       
  5221        self->self_avatar_sha1 = NULL;
       
  5222        }
       
  5223 
       
  5224    lm_message_unref( message );
       
  5225 
       
  5226    return ret;
       
  5227  }