Logo Search packages:      
Sourcecode: telepathy-feed version File versions  Download package

dbus.c

/*
 * This file is part of telepathy-feed
 *
 * Copyright (C) 2006 Nokia Corporation. All rights reserved.
 *
 * Contact: Onne Gorter <onne.gorter@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <string.h>
#include <glib.h>

#define DBUS_API_SUBJECT_TO_CHANGE

#include <dbus/dbus.h>
#include <dbus/dbus-glib-bindings.h>
#include <dbus/dbus-glib-lowlevel.h>

#include <libtelepathy/tp-interfaces.h>
#include <libtelepathy/tp-conn.h>

#include "dbus.h"
#include "galago.h"
#include "shared.h"

static void
context_free (FeedContext *context)
{
  g_return_if_fail (context != NULL);

  if (context->account_hash) {
    g_hash_table_destroy (context->account_hash);
    context->account_hash = NULL;
  }

  if (context->conn) {
    g_object_unref (context->conn);
    context->conn = NULL;
  }

  g_free (context);
}

static void
connection_dead (gpointer data, GObject *object)
{
  FeedContext *context = data;

  g_assert (context);

  d(g_printerr (G_STRLOC ": connection dead\n"));
  
  /* We got here as the context died, so nullify it */
  context->conn = NULL;
  context_free (context);
}

static FeedContext *
new_context (const char *service, const char *object_path)
{
  static DBusGProxy *dbus_proxy = NULL;
  GError *error = NULL;
  FeedContext *context;
  char *real_name;
  
  g_assert (service);
  g_assert (object_path);

  if (G_UNLIKELY (dbus_proxy == NULL)) {
    dbus_proxy = dbus_g_proxy_new_for_name (gconnection, DBUS_SERVICE_DBUS,
                                            DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
    if (dbus_proxy == NULL) {
      return NULL;
    }
  }

  /* We only get destroy signals if we use the unique name... This sucks */
  if (!org_freedesktop_DBus_get_name_owner (dbus_proxy, service, &real_name, &error)) {
    g_warning ("Cannot get real owner: %s", error->message);
    g_error_free (error);
    return NULL;
  }

  context = g_new0 (FeedContext, 1);
  context->conn = tp_conn_new (gconnection, real_name, object_path);
  g_free (real_name);

  /* Handle connections closing between calling the function and now */
  if (context->conn) {
    /* Get called when the connection object disconnects from the bus */
    g_object_weak_ref (G_OBJECT (context->conn), connection_dead, context);
    /* This is a hash from integers to GalagoAccount objects */
    return context;
  } else {
    g_free (context);
    return NULL;
  }
}

/**
 * DBus message filter, listening for Telepathy NewConnection signals.
 */
static DBusHandlerResult
signal_filter (DBusConnection *connection,
               DBusMessage    *message,
               void           *user_data)
{
  DBusError error;
  char *bus_name, *object_path;
  FeedContext *context;
  
  if (!dbus_message_is_signal (message,
                               TP_IFACE_CONN_MGR_INTERFACE,
                               "NewConnection")) {
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  }
  
  dbus_error_init (&error);
  
  if (!dbus_message_get_args (message, &error,
                              DBUS_TYPE_STRING, &bus_name,
                              DBUS_TYPE_OBJECT_PATH, &object_path,
                              DBUS_TYPE_INVALID)) {
    g_warning ("Cannot parse NewConnection message: %s", error.message);
    dbus_error_free (&error);
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  }

  context = new_context (bus_name, object_path);
  if (context) {
    send_presence_for_connection (context);
  }
  
  return DBUS_HANDLER_RESULT_HANDLED;
}

/**
 * Listen for new Telepathy connections being created, so their presence can be
 * injected into Galago.
 */
void
listen_for_new (void)
{
  DBusError error;

  g_assert (connection != NULL);

  dbus_error_init (&error);

  dbus_bus_add_match (connection,
                      "type='signal',interface='"
                      TP_IFACE_CONN_MGR_INTERFACE
                      "',member='NewConnection'",
                      &error);
  
  if (dbus_error_is_set (&error)) {
    g_critical ("Error adding match: %s\n", error.message);
    dbus_error_free (&error);
    return;
  }

  if (!dbus_connection_add_filter (connection, signal_filter, NULL, NULL)) {
    g_critical ("Cannot add filter");
  }
}

/**
 * Create a GList of bus names of all Telepathy connections currently active on
 * the bus.
 */
static GList*
get_connections (void)
{
  DBusGProxy *proxy;
  GError *error = NULL;
  char **names = NULL, **n;
  GList *l = NULL;

  g_assert (gconnection);

  proxy = dbus_g_proxy_new_for_name (gconnection,
                                     DBUS_SERVICE_DBUS,
                                     DBUS_PATH_DBUS,
                                     DBUS_INTERFACE_DBUS);

  if (!org_freedesktop_DBus_list_names (proxy, &names, &error)) {
    g_critical ("Cannot get names: %s", error->message);
    g_error_free (error);
    return NULL;
  }
  g_object_unref (proxy);

  n = names;
  while (*n) {
    if (g_str_has_prefix (*n, "org.freedesktop.Telepathy.Connection.")) {
      l = g_list_prepend (l, *n); /* Take ownership of the string */
    } else {
      g_free (*n);
    }
    n++;
  }
  g_free (names);

  return l;
}

/**
 * Connect to all existing Telepathy connections and inject their presence into
 * Galago.
 */
void
connect_to_existing (void)
{
  GList *names;

  g_assert (gconnection != NULL);

  names = get_connections ();

  while (names) {
    char *service, *path;
    FeedContext *context;

    service = names->data;
    
    /* Transform the service name into an object path (per the Telepathy
       specification) */
    path = g_strdup_printf ("/%s", service);
    g_strdelimit (path, ".", '/');

    d(g_printerr (G_STRLOC": connecting to %s\n", service));

    context = new_context (service, path);
    if (context) {
      /* We need to create the hash now as it's lazy created normally */
      context->account_hash = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
     send_presence_for_connection (context);
    }

    g_free (service);
    g_free (path);
    names = g_list_delete_link (names, names);
  }
}

Generated by  Doxygen 1.6.0   Back to index