summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTravis Reitter <treitter@gmail.com>2010-02-25 14:36:08 -0800
committerTravis Reitter <treitter@gmail.com>2010-02-25 14:36:09 -0800
commit6f5caa40473feea9c9c7526affab43d173b34636 (patch)
tree05ea18a2154d7482547031a8c1357e5f08a9a9db
parent9c5151d2622f1ef04ce0d7a59c70cc355df3af28 (diff)
downloadtelepathy-logger-6f5caa40473feea9c9c7526affab43d173b34636.tar.gz
Add favourite contacts support.
This adds a simple D-Bus API and implementation for storing and manipulating a set of favourite Telepathy contacts.
-rw-r--r--extensions/Logger.xml83
-rw-r--r--telepathy-logger/Makefile.am2
-rw-r--r--telepathy-logger/dbus-service.c660
-rw-r--r--telepathy-logger/dbus-service.h6
4 files changed, 749 insertions, 2 deletions
diff --git a/extensions/Logger.xml b/extensions/Logger.xml
index 1695690..a377829 100644
--- a/extensions/Logger.xml
+++ b/extensions/Logger.xml
@@ -91,6 +91,89 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
</tp:docstring>
</method>
+ <method name="GetFavouriteContacts"
+ tp:name-for-bindings="Get_Favourite_Contacts">
+ <arg direction="out" name="Favourite_Contacts" type="a(oas)">
+ <tp:docstring>
+ The favourite contacts, as an array of TpAccounts and their contact
+ identifiers.
+ </tp:docstring>
+ </arg>
+
+ <tp:docstring>
+ Returns the favourite contacts.
+ </tp:docstring>
+ </method>
+
+ <method name="AddFavouriteContact"
+ tp:name-for-bindings="Add_Favourite_Contact">
+ <arg direction="in" name="Account" type="o" tp:type="Account">
+ <tp:docstring>
+ The object path for the TpAccount to which the contact belongs
+ </tp:docstring>
+ </arg>
+
+ <arg direction="in" name="Identifier" type="s">
+ <tp:docstring>
+ The favourite contact's identifier
+ </tp:docstring>
+ </arg>
+
+ <tp:docstring>
+ Add a contact's designation as a favourite. This method may not be
+ called until the service is ready. See the <tp:dbus-ref
+ namespace="org.freedesktop.Telepathy.Logger.DRAFT">FavouriteContactsReady</tp:dbus-ref> signal and <tp:dbus-ref
+ namespace="org.freedesktop.Telepathy.Logger.DRAFT">FavouriteContactsIsReady</tp:dbus-ref> property.
+ </tp:docstring>
+ </method>
+
+ <method name="RemoveFavouriteContact"
+ tp:name-for-bindings="Remove_Favourite_Contact">
+ <arg direction="in" name="Account" type="o" tp:type="Account">
+ <tp:docstring>
+ The object path for the TpAccount to which the contact belongs
+ </tp:docstring>
+ </arg>
+
+ <arg direction="in" name="Identifier" type="s">
+ <tp:docstring>
+ The favourite contact's identifier
+ </tp:docstring>
+ </arg>
+
+ <tp:docstring>
+ Remove a contact's designation as a favourite. This method may not be
+ called until the service is ready. See the <tp:dbus-ref
+ namespace="org.freedesktop.Telepathy.Logger.DRAFT">FavouriteContactsReady</tp:dbus-ref> signal and <tp:dbus-ref
+ namespace="org.freedesktop.Telepathy.Logger.DRAFT">FavouriteContactsIsReady</tp:dbus-ref> property.
+ </tp:docstring>
+ </method>
+
+ <signal name="FavouriteContactsChanged"
+ tp:name-for-bindings="Favourite_Contacts_Changed">
+ <tp:docstring>
+ The set of favourite contacts has changed.
+ </tp:docstring>
+
+ <arg name="Account" type="o" tp:type="Account">
+ <tp:docstring>
+ An account associated with the contact.
+ </tp:docstring>
+ </arg>
+
+ <arg name="Added" type="as">
+ <tp:docstring>
+ List of contact identifiers of contacts which are now favourites.
+ </tp:docstring>
+ </arg>
+
+ <arg name="Removed" type="as">
+ <tp:docstring>
+ List of contact identifiers of contacts which are no longer favourites.
+ </tp:docstring>
+ </arg>
+ </signal>
+
</interface>
</node>
<!-- vim:set sw=2 sts=2 et ft=xml: -->
diff --git a/telepathy-logger/Makefile.am b/telepathy-logger/Makefile.am
index 3f2021c..3892482 100644
--- a/telepathy-logger/Makefile.am
+++ b/telepathy-logger/Makefile.am
@@ -6,6 +6,7 @@ AM_CPPFLAGS = \
-I$(top_srcdir) \
$(ERROR_CFLAGS) \
-DG_LOG_DOMAIN=\"tp-logger\" \
+ -DTPL_DATA_DIR=\"$(PACKAGE_NAME)\" \
$(LIBTPL_CFLAGS) \
$(DISABLE_DEPRECATED) \
$(WARN_CFLAGS)
@@ -38,7 +39,6 @@ LIBTPL_HEADERS = \
observer.h \
util.h
-
libtelepathy_logger_la_SOURCES = \
action-chain.c \
channel.c \
diff --git a/telepathy-logger/dbus-service.c b/telepathy-logger/dbus-service.c
index 6f00c44..26a358b 100644
--- a/telepathy-logger/dbus-service.c
+++ b/telepathy-logger/dbus-service.c
@@ -22,11 +22,16 @@
#include "config.h"
#include "dbus-service.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/action-chain.h>
#include <telepathy-logger/log-entry-text.h>
#include <telepathy-logger/log-manager.h>
#include <telepathy-logger/util.h>
@@ -36,22 +41,306 @@
#define DEBUG_FLAG TPL_DEBUG_DBUS_SERVICE
#include <telepathy-logger/debug.h>
+#define FAVOURITE_CONTACTS_FILENAME "favourite-contacts.txt"
+
static void tpl_logger_iface_init (gpointer iface, gpointer iface_data);
#define GET_PRIV(obj) TPL_GET_PRIV (obj, TplDBusService)
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 = GET_PRIV (self);
+
+ 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_actionchain_get_object (action_chain);
+ TplDBusServicePriv *priv;
+ gchar *line;
+ GError *error = NULL;
+
+ priv = GET_PRIV (self);
+
+ 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_actionchain_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_actionchain_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_actionchain_continue (action_chain);
+ }
+ else
+ {
+ DEBUG ("Failed to open the favourite contacts file: %s", error->message);
+ g_clear_error (&error);
+ tpl_actionchain_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 = GET_PRIV (obj);
+
+ 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 = GET_PRIV (self);
+
+ if (!tpl_actionchain_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 = GET_PRIV (object);
+
+ priv->favourite_contacts_actions = tpl_actionchain_new (object,
+ favourite_contacts_file_parsed_cb, object);
+
+ tpl_actionchain_append (priv->favourite_contacts_actions,
+ pendingproc_favourite_contacts_file_open, NULL);
+ tpl_actionchain_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));
}
@@ -66,6 +355,9 @@ tpl_dbus_service_init (TplDBusService *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;
}
@@ -209,6 +501,371 @@ out:
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 = GET_PRIV (closure->service);
+
+ 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_actionchain_continue (action_chain);
+}
+
+
+static void
+tpl_dbus_service_get_favourite_contacts (TplSvcLogger *self,
+ DBusGMethodInvocation *context)
+{
+ TplDBusServicePriv *priv;
+ FavouriteContactClosure *closure;
+
+ g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
+ g_return_if_fail (context != NULL);
+
+ priv = GET_PRIV (self);
+
+ closure = favourite_contact_closure_new (TPL_DBUS_SERVICE (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_actionchain_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 = GET_PRIV (self);
+ 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 = GET_PRIV (closure->service);
+ 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_actionchain_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 = GET_PRIV (closure->service);
+
+ 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_actionchain_terminate (action_chain);
+}
+
+
+static void
+tpl_dbus_service_add_favourite_contact (TplSvcLogger *self,
+ const gchar *account,
+ const gchar *contact_id,
+ DBusGMethodInvocation *context)
+{
+ TplDBusServicePriv *priv;
+ FavouriteContactClosure *closure;
+
+ g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
+ g_return_if_fail (context != NULL);
+
+ priv = GET_PRIV (self);
+
+ closure = favourite_contact_closure_new (TPL_DBUS_SERVICE (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_actionchain_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 = GET_PRIV (closure->service);
+ 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_actionchain_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 = GET_PRIV (closure->service);
+
+ 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_actionchain_terminate (action_chain);
+}
+
+static void
+tpl_dbus_service_remove_favourite_contact (TplSvcLogger *self,
+ const gchar *account,
+ const gchar *contact_id,
+ DBusGMethodInvocation *context)
+{
+ TplDBusServicePriv *priv;
+ FavouriteContactClosure *closure;
+
+ g_return_if_fail (TPL_IS_DBUS_SERVICE (self));
+ g_return_if_fail (context != NULL);
+
+ priv = GET_PRIV (self);
+
+ closure = favourite_contact_closure_new (TPL_DBUS_SERVICE (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_actionchain_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)
{
@@ -216,5 +873,8 @@ tpl_logger_iface_init (gpointer 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
}
diff --git a/telepathy-logger/dbus-service.h b/telepathy-logger/dbus-service.h
index d0424a2..600c826 100644
--- a/telepathy-logger/dbus-service.h
+++ b/telepathy-logger/dbus-service.h
@@ -23,6 +23,7 @@
#define __TPL_DBUS_SERVICE_H__
#include <glib-object.h>
+#include <telepathy-glib/dbus-properties-mixin.h>
#include <telepathy-logger/log-manager.h>
@@ -44,7 +45,10 @@ G_BEGIN_DECLS
"tpl-dbus-service-error-quark")
typedef enum
{
- TPL_DBUS_SERVICE_ERROR_FAILED
+ TPL_DBUS_SERVICE_ERROR_FAILED,
+ /* >= 1 argument(s) is/are invalid */
+ TPL_DBUS_SERVICE_ERROR_INVALID_ARGS,
+ TPL_DBUS_SERVICE_ERROR_NOT_READY,
} TplDBusServiceError;
typedef struct _TplDBusServicePriv TplDBusServicePriv;