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

dbus-service.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Copyright (C) 2009 Collabora Ltd.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
 */

#include "config.h"
#include "dbus-service-internal.h"

#include <string.h>
#include <sys/stat.h>

#include <glib.h>
#include <telepathy-glib/dbus.h>
#include <telepathy-glib/account.h>
#include <telepathy-glib/util.h>
#include <telepathy-glib/svc-generic.h>

#include <telepathy-logger/entry-internal.h>
#include <telepathy-logger/entry-text.h>
#include <telepathy-logger/log-manager.h>

#include <extensions/extensions.h>

#define DEBUG_FLAG TPL_DEBUG_DBUS_SERVICE
#include <telepathy-logger/action-chain-internal.h>
#include <telepathy-logger/debug-internal.h>
#include <telepathy-logger/util-internal.h>

#define FAVOURITE_CONTACTS_FILENAME "favourite-contacts.txt"

static void tpl_logger_iface_init (gpointer iface, gpointer iface_data);

struct _TplDBusServicePriv
{
  TplLogManager *manager;
  /* map of (string) account name -> (string set) contact ID */
  /* (the set is implemented as a hash table) */
  GHashTable *accounts_contacts_map;
  TplActionChain *favourite_contacts_actions;
};

G_DEFINE_TYPE_WITH_CODE (TplDBusService, _tpl_dbus_service, G_TYPE_OBJECT,
    G_IMPLEMENT_INTERFACE (TPL_TYPE_SVC_LOGGER, tpl_logger_iface_init));

typedef struct _FavouriteContactClosure FavouriteContactClosure;
typedef void (*FavouriteContactCallback) (gboolean success,
    FavouriteContactClosure *closure);


struct _FavouriteContactClosure {
  TplDBusService *service;
  gchar *account;
  gchar *contact_id;
  gchar *file_contents;
  DBusGMethodInvocation *context;
  FavouriteContactCallback cb;
};


static void
favourite_contact_closure_free (FavouriteContactClosure *closure)
{
  if (closure == NULL)
    return;

  if (closure->service != NULL)
    g_object_unref (closure->service);

  g_free (closure->account);
  g_free (closure->contact_id);
  g_free (closure->file_contents);
  g_slice_free (FavouriteContactClosure, closure);
}


static FavouriteContactClosure *
favourite_contact_closure_new (TplDBusService *self,
    const gchar *account,
    const gchar *contact_id,
    DBusGMethodInvocation *context)
{
  FavouriteContactClosure *closure;

  closure = g_slice_new0 (FavouriteContactClosure);
  closure->service = g_object_ref (G_OBJECT (self));
  closure->account = g_strdup (account);
  closure->contact_id = g_strdup (contact_id);
  /* XXX: ideally we'd up the ref count or duplicate this */
  closure->context = context;

  return closure;
}


static gboolean
favourite_contacts_add_entry (TplDBusService *self,
    const gchar *account,
    const gchar *contact_id)
{
  GHashTable *contacts;
  gboolean new_entry = FALSE;
  TplDBusServicePriv *priv;

  g_return_val_if_fail (TPL_IS_DBUS_SERVICE (self), FALSE);
  g_return_val_if_fail (account != NULL, FALSE);
  g_return_val_if_fail (contact_id != NULL, FALSE);

  priv = self->priv;

  DEBUG ("adding favourite contact: account '%s', ID '%s'",
      account, contact_id);

  contacts = g_hash_table_lookup (priv->accounts_contacts_map, account);
  if (contacts == NULL)
    {
      contacts = g_hash_table_new_full (g_str_hash, g_str_equal,
          (GDestroyNotify) g_free, NULL);
      g_hash_table_insert (priv->accounts_contacts_map, g_strdup (account),
          contacts);
      new_entry = TRUE;
    }
  else if (g_hash_table_lookup (contacts, contact_id) == NULL)
    {
      new_entry = TRUE;
    }

  if (new_entry)
    {
      /* add dummy string for the value just for the convenience of looking up
       * whether the key already exists */
      g_hash_table_insert (contacts, g_strdup (contact_id),
          GINT_TO_POINTER (TRUE));
    }

  return new_entry;
}


static const gchar *
favourite_contacts_get_filename (void)
{
  static gchar *filename = NULL;

  if (filename == NULL)
    {
      filename = g_build_filename (g_get_user_data_dir (), TPL_DATA_DIR,
          FAVOURITE_CONTACTS_FILENAME, NULL);
    }

  return filename;
}


static gboolean
favourite_contacts_parse_line (TplDBusService *self,
    const gchar *line)
{
  gboolean success = TRUE;
  gchar **elements;

  if (line == NULL || line[0] == '\0')
    return TRUE;

  /* this works on the assumption that account names can't have spaces in them
   */
  elements = g_strsplit (line, " ", 2);
  if (g_strv_length (elements) < 2)
    {
      DEBUG ("invalid number of elements on favourite contacts file line:\n"
          "%s\n", line);
      success = FALSE;
    }
  else
    favourite_contacts_add_entry (self, elements[0], elements[1]);

  g_strfreev (elements);

  return success;
}


static void
favourite_contacts_file_read_line_cb (GObject *object,
    GAsyncResult *result,
    gpointer user_data)
{
  GDataInputStream *data_stream = G_DATA_INPUT_STREAM (object);
  TplActionChain *action_chain = (TplActionChain *) (user_data);
  TplDBusService *self = _tpl_action_chain_get_object (action_chain);
  TplDBusServicePriv *priv;
  gchar *line;
  GError *error = NULL;

  priv = self->priv;

  line = g_data_input_stream_read_line_finish (data_stream, result, NULL, &error);

  if (error != NULL)
    {
      DEBUG ("failed to open favourite contacts file: %s", error->message);
      g_clear_error (&error);
      _tpl_action_chain_terminate (action_chain);
    }
  else if (line != NULL)
    {
      favourite_contacts_parse_line (self, line);

      g_data_input_stream_read_line_async (data_stream, G_PRIORITY_DEFAULT,
          NULL, favourite_contacts_file_read_line_cb, action_chain);
    }
  else
    _tpl_action_chain_continue (action_chain);
}


static void
favourite_contacts_file_open_cb (GObject *object,
    GAsyncResult *result,
    gpointer user_data)
{
  GFile *file = G_FILE (object);
  TplActionChain *action_chain = (TplActionChain *) user_data;
  GFileInputStream *stream;
  GError *error = NULL;

  if ((stream = g_file_read_finish (file, result, &error)))
    {
      GDataInputStream *data_stream = g_data_input_stream_new (
          G_INPUT_STREAM (stream));

      g_data_input_stream_read_line_async (data_stream, G_PRIORITY_DEFAULT,
          NULL, favourite_contacts_file_read_line_cb, action_chain);

      g_object_unref (stream);
    }
  else if (error->code == G_IO_ERROR_NOT_FOUND)
    {
      DEBUG ("Favourite contacts file doesn't exist yet. Will create as "
          "necessary.");

      g_clear_error (&error);
      _tpl_action_chain_continue (action_chain);
    }
  else
    {
      DEBUG ("Failed to open the favourite contacts file: %s", error->message);
      g_clear_error (&error);
      _tpl_action_chain_terminate (action_chain);
    }
}


static void
pendingproc_favourite_contacts_file_open (TplActionChain *action_chain,
    gpointer user_data)
{
  const gchar *filename;
  GFile *file;

  filename = favourite_contacts_get_filename ();
  file = g_file_new_for_path (filename);

  g_file_read_async (file, G_PRIORITY_DEFAULT, NULL,
      favourite_contacts_file_open_cb, action_chain);

  g_object_unref (G_OBJECT (file));
}


static void
tpl_dbus_service_dispose (GObject *obj)
{
  TplDBusServicePriv *priv = TPL_DBUS_SERVICE (obj)->priv;

  if (priv->accounts_contacts_map != NULL)
    {
      g_hash_table_destroy (priv->accounts_contacts_map);
      priv->accounts_contacts_map = NULL;
    }

  if (priv->favourite_contacts_actions != NULL)
    priv->favourite_contacts_actions = NULL;

  G_OBJECT_CLASS (_tpl_dbus_service_parent_class)->dispose (obj);
}


static void
favourite_contacts_file_parsed_cb (GObject *object,
    GAsyncResult *result,
    gpointer user_data)
{
  TplDBusService *self = TPL_DBUS_SERVICE (object);
  TplDBusServicePriv *priv = self->priv;

  if (!_tpl_action_chain_new_finish (result))
    {
      DEBUG ("Failed to parse the favourite contacts file and/or execute "
          "subsequent queued method calls");
    }

  priv->favourite_contacts_actions = NULL;
}


static void
tpl_dbus_service_constructed (GObject *object)
{
  TplDBusServicePriv *priv = TPL_DBUS_SERVICE (object)->priv;

  priv->favourite_contacts_actions = _tpl_action_chain_new_async (object,
      favourite_contacts_file_parsed_cb, object);

  _tpl_action_chain_append (priv->favourite_contacts_actions,
      pendingproc_favourite_contacts_file_open, NULL);
  _tpl_action_chain_continue (priv->favourite_contacts_actions);
}


static void
_tpl_dbus_service_class_init (TplDBusServiceClass *klass)
{
  GObjectClass* object_class = G_OBJECT_CLASS (klass);

  object_class->constructed = tpl_dbus_service_constructed;
  object_class->dispose = tpl_dbus_service_dispose;

  g_type_class_add_private (object_class, sizeof (TplDBusServicePriv));
}


static void
_tpl_dbus_service_init (TplDBusService *self)
{
  TplDBusServicePriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
      TPL_TYPE_DBUS_SERVICE, TplDBusServicePriv);

  g_return_if_fail (TPL_IS_DBUS_SERVICE (self));

  self->priv = priv;
  priv->manager = tpl_log_manager_dup_singleton ();
  priv->accounts_contacts_map = g_hash_table_new_full (g_str_hash, g_str_equal,
      (GDestroyNotify) g_free, (GDestroyNotify) g_hash_table_destroy);
  priv->favourite_contacts_actions = NULL;
}


TplDBusService *
_tpl_dbus_service_new (void)
{
  return g_object_new (TPL_TYPE_DBUS_SERVICE, NULL);
}


typedef struct
{
  TplDBusService *self;
  TpAccount *account;
  char *identifier;
  gboolean is_chatroom;
  guint lines;
  DBusGMethodInvocation *context;
  GPtrArray *packed;
  GList *dates, *ptr;
} RecentMessagesContext;

static void _lookup_next_date (RecentMessagesContext *ctx);

static void
_get_messages_return (GObject *manager,
    GAsyncResult *res,
    gpointer user_data)
{
  RecentMessagesContext *ctx = user_data;
  GList *messages, *ptr;
  GError *error = NULL;

  if (!tpl_log_manager_get_messages_for_date_finish (
      TPL_LOG_MANAGER (manager), res, &messages, &error))
    {
      DEBUG ("Failed to get messages: %s", error->message);

      g_clear_error (&error);
      messages = NULL; /* just to be sure */
    }

  /* from the most recent message, backward */
  for (ptr = g_list_last (messages);
       ptr != NULL && ctx->lines > 0;
       ptr = g_list_previous (ptr))
    {
      TplEntry *log = ptr->data;
      const char *message = tpl_entry_text_get_message (
          TPL_ENTRY_TEXT (log));
      const char *sender = tpl_entity_get_identifier (
          tpl_entry_get_sender (log));
      gint64 timestamp = tpl_entry_get_timestamp (log);

      DEBUG ("Message: %" G_GINT64_FORMAT " <%s> %s",
          timestamp, sender, message);

      g_ptr_array_add (ctx->packed, tp_value_array_build (3,
          G_TYPE_STRING, sender,
          G_TYPE_STRING, message,
          G_TYPE_INT64, timestamp,
          G_TYPE_INVALID));

      ctx->lines--;
    }

  g_list_foreach (messages, (GFunc) g_object_unref, NULL);
  g_list_free (messages);

  _lookup_next_date (ctx);
}


static void
_lookup_next_date (RecentMessagesContext *ctx)
{
  TplDBusServicePriv *priv = ctx->self->priv;

  if (ctx->ptr != NULL && ctx->lines > 0)
    {
      GDate *date = ctx->ptr->data;

      DEBUG ("Looking up date %04u-%02u-%02u", g_date_get_year (date),
          g_date_get_month (date), g_date_get_day (date));

      tpl_log_manager_get_messages_for_date_async (priv->manager,
          ctx->account, ctx->identifier, ctx->is_chatroom, date,
          _get_messages_return, ctx);

      ctx->ptr = g_list_previous (ctx->ptr);
    }
  else
    {
      /* return and release */
      DEBUG ("complete, returning");

      g_list_foreach (ctx->dates, (GFunc) g_date_free, NULL);
      g_list_free (ctx->dates);

      tpl_svc_logger_return_from_get_recent_messages (ctx->context,
          ctx->packed);

      g_ptr_array_free (ctx->packed, TRUE);
      g_free (ctx->identifier);
      g_object_unref (ctx->account);
      g_slice_free (RecentMessagesContext, ctx);
    }
}


static void
_get_dates_return (GObject *manager,
    GAsyncResult *res,
    gpointer user_data)
{
  RecentMessagesContext *ctx = user_data;
  GError *error = NULL;

  if (!tpl_log_manager_get_dates_finish (TPL_LOG_MANAGER (manager), res,
      &ctx->dates, &error))
    {
      DEBUG ("Failed to get dates: %s", error->message);

      dbus_g_method_return_error (ctx->context, error);

      g_clear_error (&error);

      g_free (ctx->identifier);
      g_object_unref (ctx->account);
      g_slice_free (RecentMessagesContext, ctx);

      return;
    }

  ctx->ptr = g_list_last (ctx->dates);
  ctx->packed = g_ptr_array_new_with_free_func (
      (GDestroyNotify) g_value_array_free);

  _lookup_next_date (ctx);
}


static void
tpl_dbus_service_get_recent_messages (TplSvcLogger *self,
    const gchar *account_path,
    const gchar *identifier,
    gboolean is_chatroom,
    guint lines,
    DBusGMethodInvocation *context)
{
  TplDBusServicePriv *priv = TPL_DBUS_SERVICE (self)->priv;
  TpDBusDaemon *tp_dbus;
  TpAccount *account;
  RecentMessagesContext *ctx;
  GError *error = NULL;

  g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
  g_return_if_fail (context != NULL);

  tp_dbus = tp_dbus_daemon_dup (&error);
  if (tp_dbus == NULL)
    {
      DEBUG ("Unable to acquire the bus daemon: %s", error->message);
      dbus_g_method_return_error (context, error);
      goto out;
    }

  account = tp_account_new (tp_dbus, account_path, &error);
  if (account == NULL)
    {
      DEBUG ("Unable to acquire the account for %s: %s", account_path,
          error->message);
      dbus_g_method_return_error (context, error);
      goto out;
    }

  ctx = g_slice_new (RecentMessagesContext);
  ctx->self = TPL_DBUS_SERVICE (self);
  ctx->account = account;
  ctx->identifier = g_strdup (identifier);
  ctx->is_chatroom = is_chatroom;
  ctx->lines = lines;
  ctx->context = context;

  tpl_log_manager_get_dates_async (priv->manager,
      account, identifier, is_chatroom,
      _get_dates_return, ctx);

out:

  if (tp_dbus != NULL)
    g_object_unref (tp_dbus);

  g_clear_error (&error);
}


static void
append_favourite_contacts_account_and_contacts (const gchar *account,
    GHashTable *contacts,
    GPtrArray *packed)
{
  GList *l;
  gchar **contact_ids;
  gint i;

  /* this case shouldn't happen, but this is just some basic sanity checking */
  if (g_hash_table_size (contacts) < 1)
    return;

  /* includes room for the terminal NULL */
  contact_ids = g_new0 (gchar *, g_hash_table_size (contacts)+1);

  for (i = 0, l = g_hash_table_get_keys (contacts);
      l;
      i++, l = g_list_delete_link (l, l))
    {
      contact_ids[i] = l->data;
    }

  g_ptr_array_add (packed, tp_value_array_build (2,
      DBUS_TYPE_G_OBJECT_PATH, account,
      G_TYPE_STRV, contact_ids,
      G_TYPE_INVALID));

  g_free (contact_ids);
}


static void
pendingproc_get_favourite_contacts (TplActionChain *action_chain,
    gpointer user_data)
{
  FavouriteContactClosure *closure = user_data;
  TplDBusServicePriv *priv;
  GPtrArray *packed;

  g_return_if_fail (closure);
  g_return_if_fail (TPL_IS_DBUS_SERVICE (closure->service));
  g_return_if_fail (closure->context != NULL);

  priv = closure->service->priv;

  packed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);

  g_hash_table_foreach (priv->accounts_contacts_map,
      (GHFunc) append_favourite_contacts_account_and_contacts, packed);

  tpl_svc_logger_return_from_get_favourite_contacts (closure->context, packed);

  g_ptr_array_free (packed, TRUE);
  favourite_contact_closure_free (closure);

  if (action_chain != NULL)
    _tpl_action_chain_continue (action_chain);
}


static void
tpl_dbus_service_get_favourite_contacts (TplSvcLogger *logger,
    DBusGMethodInvocation *context)
{
  TplDBusService *self;
  TplDBusServicePriv *priv;
  FavouriteContactClosure *closure;

  g_return_if_fail (TPL_IS_DBUS_SERVICE (logger));
  g_return_if_fail (context != NULL);

  self = TPL_DBUS_SERVICE (logger);
  priv = self->priv;

  closure = favourite_contact_closure_new (self, NULL, NULL, context);

  /* If we're still waiting on the contacts to finish being parsed from disk,
   * queue this action */
  if (priv->favourite_contacts_actions != NULL)
    {
      _tpl_action_chain_append (priv->favourite_contacts_actions,
          pendingproc_get_favourite_contacts, closure);
    }
  else
    pendingproc_get_favourite_contacts (NULL, closure);
}


static void
append_favourite_contacts_file_entries (const gchar *account,
    GHashTable *contacts,
    GString *string)
{
  GList *l;

  for (l = g_hash_table_get_keys (contacts); l; l = g_list_delete_link (l, l))
    g_string_append_printf (string, "%s %s\n", account, (const gchar*) l->data);
}


static gchar *
favourite_contacts_to_string (TplDBusService *self)
{
  TplDBusServicePriv *priv = self->priv;
  GString *string;

  string = g_string_new ("");

  g_hash_table_foreach (priv->accounts_contacts_map,
      (GHFunc) append_favourite_contacts_file_entries, string);

  return g_string_free (string, FALSE);
}


static void
favourite_contacts_file_replace_contents_cb (GObject *object,
    GAsyncResult *result,
    gpointer user_data)
{
  GFile *file = G_FILE (object);
  GError *error = NULL;
  FavouriteContactClosure *closure = user_data;
  gboolean success;

  if (g_file_replace_contents_finish (file, result, NULL, &error))
    {
      success = TRUE;
    }
  else
    {
      DEBUG ("Failed to save favourite contacts file: %s", error->message);
      success = FALSE;
      g_clear_error (&error);
    }

  ((FavouriteContactCallback) closure->cb) (success, closure);
}


static void
favourite_contacts_file_save_async (TplDBusService *self,
    FavouriteContactClosure *closure)
{
  gchar *dir;
  const gchar *filename;
  GFile *file;
  gchar *file_contents;

  g_return_if_fail (closure != NULL);

  filename = favourite_contacts_get_filename ();
  dir = g_path_get_dirname (filename);
  g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR);
  g_free (dir);

  file = g_file_new_for_path (filename);

  file_contents = favourite_contacts_to_string (self);

  closure->file_contents = file_contents;

  g_file_replace_contents_async (file,
      file_contents, strlen (file_contents), NULL, FALSE,
      G_FILE_CREATE_REPLACE_DESTINATION, NULL,
      favourite_contacts_file_replace_contents_cb, closure);

  g_object_unref (file);
}


static void
add_favourite_contact_file_save_cb (gboolean added_favourite,
    FavouriteContactClosure *closure)
{
  TplDBusServicePriv *priv = closure->service->priv;
  TplActionChain *action_chain = priv->favourite_contacts_actions;

  if (added_favourite)
    {
      const gchar *added[] = { NULL, NULL };
      const gchar *removed[] = { NULL };

      added[0] = closure->contact_id;

      tpl_svc_logger_emit_favourite_contacts_changed (closure->service,
          closure->account, added, removed);
    }

  tpl_svc_logger_return_from_add_favourite_contact (closure->context);

  favourite_contact_closure_free (closure);
  if (action_chain != NULL)
    _tpl_action_chain_continue (action_chain);
}


static void
pendingproc_add_favourite_contact (TplActionChain *action_chain,
    gpointer user_data)
{
  FavouriteContactClosure *closure = user_data;
  gboolean should_add = FALSE;
  TplDBusServicePriv *priv;
  GError *error = NULL;

  g_return_if_fail (closure);
  g_return_if_fail (TPL_IS_DBUS_SERVICE (closure->service));
  g_return_if_fail (closure->context != NULL);

  priv = closure->service->priv;

  if (!tp_dbus_check_valid_object_path (closure->account, &error))
    {
      dbus_g_method_return_error (closure->context, error);

      goto pendingproc_add_favourite_contact_ERROR;
    }

  should_add = favourite_contacts_add_entry (closure->service, closure->account,
      closure->contact_id);

  closure->cb = add_favourite_contact_file_save_cb;

  if (should_add)
    favourite_contacts_file_save_async (closure->service, closure);
  else
    add_favourite_contact_file_save_cb (FALSE, closure);

  return;

pendingproc_add_favourite_contact_ERROR:
  g_clear_error (&error);
  if (action_chain != NULL)
    _tpl_action_chain_terminate (action_chain);
}


static void
tpl_dbus_service_add_favourite_contact (TplSvcLogger *logger,
    const gchar *account,
    const gchar *contact_id,
    DBusGMethodInvocation *context)
{
  TplDBusService *self = TPL_DBUS_SERVICE (logger);
  TplDBusServicePriv *priv;
  FavouriteContactClosure *closure;

  g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
  g_return_if_fail (context != NULL);

  priv = self->priv;

  closure = favourite_contact_closure_new (self, account, contact_id, context);

  /* If we're still waiting on the contacts to finish being parsed from disk,
   * queue this action */
  if (priv->favourite_contacts_actions != NULL)
    {
      _tpl_action_chain_append (priv->favourite_contacts_actions,
          pendingproc_add_favourite_contact, closure);
    }
  else
    pendingproc_add_favourite_contact (NULL, closure);
}

static void
remove_favourite_contact_file_save_cb (gboolean removed_favourite,
    FavouriteContactClosure *closure)
{
  TplDBusServicePriv *priv = closure->service->priv;
  TplActionChain *action_chain = priv->favourite_contacts_actions;

  if (removed_favourite)
    {
      const gchar *added[] = { NULL };
      const gchar *removed[] = { NULL, NULL };

      removed[0] = closure->contact_id;

      tpl_svc_logger_emit_favourite_contacts_changed (closure->service,
          closure->account, added, removed);
    }

  tpl_svc_logger_return_from_remove_favourite_contact (closure->context);

  favourite_contact_closure_free (closure);
  if (action_chain != NULL)
    _tpl_action_chain_continue (action_chain);
}


static void
pendingproc_remove_favourite_contact (TplActionChain *action_chain,
    gpointer user_data)
{
  FavouriteContactClosure *closure = user_data;
  GHashTable *contacts;
  gboolean removed = FALSE;
  GError *error = NULL;

  g_return_if_fail (closure != NULL);
  g_return_if_fail (TPL_IS_DBUS_SERVICE (closure->service));
  g_return_if_fail (closure->context != NULL);

  TplDBusServicePriv *priv = closure->service->priv;

  if (!tp_dbus_check_valid_object_path (closure->account, &error))
    {
      dbus_g_method_return_error (closure->context, error);

      goto pendingproc_remove_favourite_contact_ERROR;
    }

  DEBUG ("removing favourite contact: account '%s', ID '%s'",
      closure->account, closure->contact_id);

  contacts = g_hash_table_lookup (priv->accounts_contacts_map,
      closure->account);
  if (contacts != NULL && g_hash_table_remove (contacts, closure->contact_id))
      removed = TRUE;

  closure->cb = remove_favourite_contact_file_save_cb;

  if (removed)
    favourite_contacts_file_save_async (closure->service, closure);
  else
    remove_favourite_contact_file_save_cb (FALSE, closure);

  return;

pendingproc_remove_favourite_contact_ERROR:
  g_clear_error (&error);
  if (action_chain != NULL)
    _tpl_action_chain_terminate (action_chain);
}

static void
tpl_dbus_service_remove_favourite_contact (TplSvcLogger *logger,
    const gchar *account,
    const gchar *contact_id,
    DBusGMethodInvocation *context)
{
  TplDBusService *self = TPL_DBUS_SERVICE (logger);
  TplDBusServicePriv *priv;
  FavouriteContactClosure *closure;

  g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
  g_return_if_fail (context != NULL);

  priv = self->priv;

  closure = favourite_contact_closure_new (self, account, contact_id, context);

  /* If we're still waiting on the contacts to finish being parsed from disk,
   * queue this action */
  if (priv->favourite_contacts_actions != NULL)
    {
      _tpl_action_chain_append (priv->favourite_contacts_actions,
          pendingproc_remove_favourite_contact, closure);
    }
  else
    pendingproc_remove_favourite_contact (NULL, closure);
}

static void
tpl_logger_iface_init (gpointer iface,
    gpointer iface_data)
{
  TplSvcLoggerClass *klass = (TplSvcLoggerClass *) iface;

#define IMPLEMENT(x) tpl_svc_logger_implement_##x (klass, tpl_dbus_service_##x)
  IMPLEMENT (get_recent_messages);
  IMPLEMENT (get_favourite_contacts);
  IMPLEMENT (add_favourite_contact);
  IMPLEMENT (remove_favourite_contact);
#undef IMPLEMENT
}

Generated by  Doxygen 1.6.0   Back to index