Logo Search packages:      
Sourcecode: libtelepathy version File versions

tp-conn.c

/* tp-conn.c
 *
 * Copyright (C) 2005 Nokia Corporation.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#include <string.h>
#include "tp-conn.h"
#include "tp-helpers.h"
#include "tp-connmgr.h"
#include "tp-props-iface.h"
#include "internal.h"

static GObjectClass *parent_class = NULL;

static gboolean tp_conn_status_change_handler(DBusGProxy *proxy,
                                    guint status, guint reason,
                                    gpointer user_data);

static void tp_conn_connect_req_handler(DBusGProxy *proxy,
                                        GError *error, gpointer user_data);

static void _tp_conn_register_signal_marshallers()
{
  /* Register marshaller for NewChannel signal */
  dbus_g_object_register_marshaller(tp_conn_signals_marshal_VOID__OBJECT_STRING_UINT_UINT_BOOLEAN, G_TYPE_NONE, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN, G_TYPE_INVALID);
  /* Register marshaller for StatusChanged signal */
  dbus_g_object_register_marshaller(tp_conn_signals_marshal_VOID__UINT_UINT, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID);
}

static void _tp_conn_register_interface_signal_marshallers()
{
  /* Register marshaller for Aliasing interface signal AliasUpdate and
     ContactInfo interface signal GotContactInfo*/
  dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_STRING, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_INVALID);
  /* Register marshaller for Forwarding interface signal ForwardingChanged */
  dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_INVALID);
  /* Register marshaller for Presence interface signal PresenceUpdate */
  dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__BOXED, G_TYPE_NONE, G_TYPE_BOXED, G_TYPE_INVALID);
  /* Register marshaller for Privacy interface signal PrivacyModeChanged */
  dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__STRING, G_TYPE_NONE, G_TYPE_STRING, G_TYPE_INVALID);
  /* Register marshaller for Renaming interface signal Renamed */
  dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_UINT, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID);
}


/* We initialize the list of signatures here, so that we can use
 * it to add them for new interface instances later.
 */

/* FIXME: This should be replaced by a more automatic way of doing
 * this. The reason for using a set of function pointers is that there is no
 * apparent cleaner way of doing this, unless DBusGProxy gains a non-varargs
 * version of dbus_g_proxy_add_signal...
 */

static void _tp_conn_init_interface_signal_signatures(GData **signal_sigs)
{
  g_datalist_init(signal_sigs);

  /* Create and store aliasing iface signal signatures */
  g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_ALIASING_QUARK,
                   &tp_conn_set_aliasing_signatures);
  /* Create and store avatars iface signal signatures */
  g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_AVATARS_QUARK,
                   &tp_conn_set_avatars_signatures);
  /* Create and store capabilities iface signal signatures */
  g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_CAPABILITIES_QUARK,
                   &tp_conn_set_capabilities_signatures);
  /* Create and store contactinfo iface signal signatures */
  g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_CONTACTINFO_QUARK,
                   &tp_conn_set_contactinfo_signatures);
  /* Create and store forwarding iface signal signatures */
  g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_FORWARDING_QUARK,
                   &tp_conn_set_forwarding_signatures);
  /* Create and store presence iface signal signatures */
  g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_PRESENCE_QUARK,
                   &tp_conn_set_presence_signatures);
  /* Create and store privacy iface signal signatures */
  g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_PRIVACY_QUARK,
                   &tp_conn_set_privacy_signatures);
  /* Create and store renaming iface signal signatures */
  g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_RENAMING_QUARK,
                   &tp_conn_set_renaming_signatures);
}

static void tp_conn_init(GTypeInstance *instance, gpointer g_class)
{
  TpConn *self = TELEPATHY_CONN(instance);

  self->first_run = TRUE;
}


static void tp_conn_dispose(GObject *obj)
{
  TpConn *self = TELEPATHY_CONN(obj);
      
  if (self->first_run == TRUE)
  {
    self->first_run = FALSE;
    g_datalist_clear(&(self->interface_list));
  }
  
  /* Call parent class dispose method */
  if (G_OBJECT_CLASS(parent_class)->dispose)
  {
    G_OBJECT_CLASS(parent_class)->dispose(obj);
  }

}


static void tp_conn_finalize(GObject *obj)
{
  if (G_OBJECT_CLASS(parent_class)->finalize)
    {
      G_OBJECT_CLASS(parent_class)->finalize(obj);
    }

}


static void tp_conn_class_init(TpConnClass *klass)
{
  GObjectClass *obj = G_OBJECT_CLASS(klass);
  parent_class = g_type_class_peek_parent(klass);

  obj->set_property = parent_class->set_property;
  obj->get_property = parent_class->get_property;

  obj->dispose = tp_conn_dispose;
  obj->finalize = tp_conn_finalize;
  _tp_conn_register_signal_marshallers();
  _tp_conn_register_interface_signal_marshallers();
  _tp_conn_init_interface_signal_signatures(&(klass->iface_signal_sigs));
}


GType tp_conn_get_type(void)
{
  static GType type = 0;
  if (type == 0)
    {
      static const GTypeInfo info = 
      {
        sizeof(TpConnClass),
        NULL,
        NULL,
        (GClassInitFunc)tp_conn_class_init,
        NULL,
        NULL,
        sizeof(TpConn),
        0,
        (GInstanceInitFunc)tp_conn_init
        
      };
      type = g_type_register_static(DBUS_TYPE_G_PROXY,
                            "TpConn", &info, 0);
    }
  return type;
}

/* The interface name getters */

GQuark tp_get_conn_interface()
{
  static GQuark ret = 0;

  if (ret == 0)
  {
    /* FIXME: The naming conventions should be unified */
    ret = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE);
  }

  return ret;
}

GQuark tp_get_conn_aliasing_interface()
{
  static GQuark ret = 0;

  if (ret == 0)
  {
    ret = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_ALIASING);
  }

  return ret;
}

GQuark tp_get_conn_avatars_interface()
{
  static GQuark ret = 0;

  if (ret == 0)
  {
    ret = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_AVATARS);
  }

  return ret;
}

GQuark tp_get_conn_capabilities_interface()
{
  static GQuark ret = 0;

  if (ret == 0)
  {
    ret = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_CAPABILITIES);
  }

  return ret;
}

GQuark tp_get_conn_contactinfo_interface()
{
  static GQuark ret = 0;

  if (ret == 0)
  {
    ret = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_CONTACT_INFO);
  }

  return ret;
}

GQuark tp_get_conn_forwarding_interface()
{
  static GQuark ret = 0;

  if (ret == 0)
  {
    ret = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_FORWARDING);
  }

  return ret;
}

GQuark tp_get_conn_presence_interface()
{
  static GQuark ret = 0;

  if (ret == 0)
  {
    ret = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_PRESENCE);
  }

  return ret;
}


GQuark tp_get_conn_privacy_interface()
{
  static GQuark ret = 0;

  if (ret == 0)
  {
    ret = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_PRIVACY);
  }

  return ret;
}



GQuark tp_get_conn_renaming_interface()
{
  static GQuark ret = 0;

  if (ret == 0)
  {
    ret = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_RENAMING);
  }

  return ret;
}


TpConn *
tp_conn_new_without_connect (DBusGConnection *connection,
                             const gchar *bus_name,
                             const gchar *object_path,
                             guint *status,
                             GError **error)
{
  gchar *unique_name;
  gchar **interfaces;
  guint conn_status = TP_CONN_STATUS_DISCONNECTED;
  TpConn *obj;

  g_return_val_if_fail (connection != NULL, NULL);
  g_return_val_if_fail (bus_name != NULL, NULL);
  g_return_val_if_fail (object_path, NULL);

  /* Create the proxy object for this connection. It will be used to
     perform the actual method calls over D-BUS. */

  if (!dbus_g_proxy_call (tp_get_bus_proxy (), "GetNameOwner", error,
        G_TYPE_STRING, bus_name, G_TYPE_INVALID,
        G_TYPE_STRING, &unique_name, G_TYPE_INVALID))
    {
      return NULL;
    }

  obj = g_object_new (TELEPATHY_CONN_TYPE,
      "name", unique_name,
      "path", object_path,
      "interface", TP_IFACE_CONN_INTERFACE,
      "connection", connection,
      NULL);
  g_free (unique_name);

  g_datalist_init (&(obj->interface_list));

  dbus_g_proxy_add_signal (DBUS_G_PROXY (obj), "NewChannel",
      DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT,
      G_TYPE_BOOLEAN, G_TYPE_INVALID);
  dbus_g_proxy_add_signal(DBUS_G_PROXY (obj), "StatusChanged",
      G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID);

  /* Check if the connection is already connected. If so, we can
     already perform GetInterfaces(). */

  if (!tp_conn_get_status (DBUS_G_PROXY (obj), &conn_status, error))
    {
      g_object_unref (obj);
      return NULL;
    }

  if (conn_status == TP_CONN_STATUS_CONNECTED)
    {
      if (!tp_conn_get_interfaces (DBUS_G_PROXY (obj), &interfaces, error))
        {
          g_object_unref (obj);
          return NULL;
        }

      /* Initialize the interface objects for this TpConn object */
      tp_conn_local_set_interfaces (obj, interfaces);

      g_strfreev (interfaces);
    }
  else
    {
      /* Not connected yet, so this is really a new connection. Thus, we
         have to hook up to StatusChanged signal to perform the
         GetInterfaces when it goes Connected */

      dbus_g_proxy_connect_signal(DBUS_G_PROXY(obj), "StatusChanged",
                                  G_CALLBACK(tp_conn_status_change_handler),
                                  NULL, NULL);
    }

  if (status != NULL)
    *status = conn_status;
  return obj;
}


TpConn *
tp_conn_new (DBusGConnection *connection,
             const gchar *bus_name,
             const gchar *object_path)
{
  GError *error = NULL;
  guint status;
  TpConn *obj;

  obj = tp_conn_new_without_connect (connection, bus_name, object_path,
      &status, &error);

  if (obj == NULL)
    {
      /* either GetNameOwner, GetStatus or GetInterfaces failed */
      g_warning ("Failed to create connection for %s %s: %s", bus_name,
          object_path, error->message);
      g_error_free (error);
      return NULL;
    }

  if (status != TP_CONN_STATUS_CONNECTED)
    {
      tp_conn_connect_async (DBUS_G_PROXY(obj),
                             tp_conn_connect_req_handler, NULL);
    }

  return obj;
}


TpChan *tp_conn_new_channel(DBusGConnection *connection,
                      TpConn *tp_conn, const gchar *bus_name,
                      gchar *type, guint handle_type,
                      guint handle, gboolean supress_handler)
{
  GError *error = NULL;
  gchar *chan_object_path = NULL;
  TpChan *new_chan = NULL;

  g_return_val_if_fail(connection, NULL);
  g_return_val_if_fail(TELEPATHY_IS_CONN(tp_conn), NULL);
  g_return_val_if_fail(bus_name, NULL);
  g_return_val_if_fail(type, NULL);

  /* Request a new channel to be created by using the proxy object.
     We also retrieve the object path for it here. */

  if (!tp_conn_request_channel(DBUS_G_PROXY(tp_conn),
                               type, handle_type, handle, supress_handler,
                               &chan_object_path, &error))
  {
    _tp_warn_failure ("RequestChannel()", error);
    g_error_free(error);
    return NULL;
  }

  /* Create the object to represent the channel */

  new_chan = tp_chan_new(connection, bus_name, chan_object_path, type,
                         handle_type, handle);
  g_free(chan_object_path);



  return new_chan;
}


void tp_conn_local_set_interfaces(TpConn *self, gchar **interfaces)
{
  gchar **temp_ifaces = NULL;
  const gchar *bus_name = dbus_g_proxy_get_bus_name(DBUS_G_PROXY(self));
  const gchar *object_path = dbus_g_proxy_get_path(DBUS_G_PROXY(self));

  DBusGConnection *connection = tp_get_bus ();

  if (interfaces == NULL || connection == NULL)
  {
    return;
  }

  /* Create and store the proxy objects for the connection interfaces. */
  for (temp_ifaces = interfaces; *temp_ifaces; temp_ifaces++)
  {
    DBusGProxy *if_proxy;
    GQuark key = g_quark_from_string(*temp_ifaces);

    if (key == TELEPATHY_PROPS_IFACE_QUARK)
      {
        if_proxy = DBUS_G_PROXY (tp_props_iface_new (connection,
                                                     bus_name, object_path));
      }
    else
      {
        if_proxy = dbus_g_proxy_new_for_name(connection, bus_name, object_path,
                                             *temp_ifaces);
        if (if_proxy != NULL)
        {
          GData *sig_list = TELEPATHY_CONN_GET_CLASS(self)->iface_signal_sigs;
          void (*signature_setter_func)();

          /* Does the interface have signals? If yes, add their signatures
             for the interface instance */
          signature_setter_func =
            g_datalist_id_get_data(&sig_list, key);

          if (signature_setter_func != NULL)
          {
            signature_setter_func(if_proxy);
          }
        }
      }

   if (if_proxy != NULL)
    {
      g_datalist_id_set_data_full(&(self->interface_list),
      key, if_proxy, g_object_unref);
    }

  }
}

DBusGProxy *tp_conn_get_interface(TpConn *self, GQuark iface_quark)
{
  DBusGProxy *iface_proxy = NULL;
  
  iface_proxy = (DBusGProxy *)g_datalist_id_get_data(&(self->interface_list),
                                         iface_quark);

  return iface_proxy;
}

static void tp_conn_connect_req_handler(DBusGProxy *proxy,
                                        GError *error, gpointer user_data)
{
  /* The interfaces for the TpConn are set on the StatusChanged
     handler when we get connected. Just print errors (if any)
     here. */

  if (error)
  {
    g_warning("Could not perform Connect() for the connection, because: %s",
              error->message);
    g_error_free(error);
    return;
  }

}

static gboolean tp_conn_status_change_handler(DBusGProxy *proxy, guint status,
                                              guint reason, gpointer user_data)
{
  gchar **interfaces = NULL;
  GError *error = NULL;
  TpConn *tp_conn = (TpConn *)proxy;

  /* If the connection is up, we can get the list of interfaces */
  /* FIXME: At some point, we should switch to doing this asynchronously */

  if (status == TP_CONN_STATUS_CONNECTED)
  {
    if (!tp_conn_get_interfaces(DBUS_G_PROXY(proxy),
                                &interfaces, &error))
    {
      g_warning("GetInterfaces failed: %s\n", error->message);
      g_error_free(error);
      return TRUE;

    }

    /* Initialize the interface objects for this TpConn object */

    tp_conn_local_set_interfaces(tp_conn, interfaces);

    g_strfreev(interfaces);

    dbus_g_proxy_disconnect_signal(proxy, "StatusChanged",
                                   G_CALLBACK(tp_conn_status_change_handler),
                                   NULL);

    return TRUE;
  }

  return TRUE;
}


Generated by  Doxygen 1.6.0   Back to index