tracker r2794 - in trunk: . data/db src src/libtracker-data src/plugins src/plugins/evolution src/tracker-indexer src/tracker-indexer/modules src/trackerd



Author: pvanhoof
Date: Thu Jan 15 12:58:15 2009
New Revision: 2794
URL: http://svn.gnome.org/viewvc/tracker?rev=2794&view=rev

Log:
2009-01-15  Philip Van Hoof  <philip codeminded be>

        * src/tracker-indexer/modules/Makefile.am
        * src/tracker-indexer/modules/evolution.c:

        Selecting between the old and the new Evolution support, depending on
        availability of the right version of EDS

        * data/services/email.metadata: 
        * data/db/sqlite-tracker.sql:
        * configure.ac
        * src/tracker-indexer/Makefile.am
        * src/trackerd/Makefile.am
        * src/Makefile.am
        * src/tracker-evolution-plugin/tracker-evolution-plugin.h
        * src/tracker-evolution-plugin/tracker-evolution-indexer.h
        * src/tracker-evolution-plugin/tracker-evolution.h
        * src/tracker-evolution-plugin/tracker-evolution-registrar.h
        * src/tracker-evolution-plugin/tracker-evolution-plugin.xml
        * src/tracker-evolution-plugin/org-freedesktop-Tracker-evolution-plugin.eplug.xml
        * src/tracker-evolution-plugin/tracker-evolution-common.h
        * src/tracker-evolution-plugin/Makefile.am
        * src/tracker-evolution-plugin/tracker-evolution-plugin.c
        * src/tracker-evolution-plugin/tracker-evolution-indexer.c
        * src/tracker-evolution-plugin/tracker-evolution-registrar.xml
        * src/tracker-evolution-plugin/tracker-evolution.c
        * src/tracker-evolution-plugin/tracker-evolution-registrar.c: 

        Implementation of the new Evolution support

        * src/trackerd/tracker-main.c



Added:
   trunk/src/plugins/
   trunk/src/plugins/Makefile.am
   trunk/src/plugins/evolution/
   trunk/src/plugins/evolution/Makefile.am
   trunk/src/plugins/evolution/org-freedesktop-Tracker-evolution-plugin.eplug.xml
   trunk/src/plugins/evolution/tracker-evolution-common.h
   trunk/src/plugins/evolution/tracker-evolution-indexer.c
   trunk/src/plugins/evolution/tracker-evolution-indexer.h
   trunk/src/plugins/evolution/tracker-evolution-plugin.c
   trunk/src/plugins/evolution/tracker-evolution-plugin.h
   trunk/src/plugins/evolution/tracker-evolution-plugin.xml
   trunk/src/plugins/evolution/tracker-evolution-registrar.c
   trunk/src/plugins/evolution/tracker-evolution-registrar.h
   trunk/src/plugins/evolution/tracker-evolution-registrar.xml
   trunk/src/plugins/evolution/tracker-evolution.c
   trunk/src/plugins/evolution/tracker-evolution.h
Modified:
   trunk/ChangeLog
   trunk/configure.ac
   trunk/data/db/sqlite-stored-procs.sql
   trunk/data/db/sqlite-tracker.sql
   trunk/src/Makefile.am
   trunk/src/libtracker-data/tracker-data-update.c
   trunk/src/libtracker-data/tracker-data-update.h
   trunk/src/tracker-indexer/Makefile.am
   trunk/src/tracker-indexer/modules/evolution.c
   trunk/src/tracker-indexer/tracker-main.c
   trunk/src/trackerd/Makefile.am
   trunk/src/trackerd/tracker-main.c

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Thu Jan 15 12:58:15 2009
@@ -120,6 +120,8 @@
 LIBGSF_REQUIRED=1.13
 EXEMPI_REQUIRED=1.99.2
 HILDON_THUMBNAIL_REQUIRED=3.0.10
+EVO_REQUIRED=2.25.5
+EDS_REQUIRED=2.25.5
 
 # Library Checks
 PKG_CHECK_MODULES(GLIB2, [glib-2.0 >= $GLIB_REQUIRED])
@@ -181,6 +183,28 @@
   AC_DEFINE(HAVE_RAPTOR, 1, [Raptor RDF parsers])
 fi
 
+# Check for Evolution's plugin system
+PKG_CHECK_MODULES(EVOPLUG, [
+	evolution-plugin >= $EVO_REQUIRED
+	evolution-data-server-1.2 >= $EDS_REQUIRED], 
+	have_evoplug=yes, have_evoplug=no)
+AC_SUBST(EVOPLUG_CFLAGS)
+AC_SUBST(EVOPLUG_LIBS)
+
+if test x$have_evoplug == "xyes"; then
+EVOLUTION_PLUGIN_INSTALL_DIR=`$PKG_CONFIG evolution-plugin --variable=plugindir`
+else
+EVOLUTION_PLUGIN_INSTALL_DIR=/dev/null
+fi
+
+AC_SUBST(EVOLUTION_PLUGIN_INSTALL_DIR)
+
+if test x$have_evoplug == "xyes"; then
+  AC_DEFINE(HAVE_EVOLUTION_PLUGIN, 1, [Evolution plugin])
+fi
+
+AM_CONDITIONAL(HAVE_EVOLUTION_PLUGIN, test "$have_evoplug" = "yes")
+
 # Check we have the DBUS binding tool we need
 AC_PATH_PROG(DBUSBINDINGTOOL, dbus-binding-tool)
 if test -z $DBUSBINDINGTOOL; then
@@ -1199,6 +1223,8 @@
 	src/tracker-search-tool/Makefile
 	src/tracker-search-tool/tracker-search-tool.desktop.in
 	src/tracker-utils/Makefile
+	src/plugins/Makefile
+	src/plugins/evolution/Makefile
 	tests/common/Makefile
 	tests/libtracker-common/Makefile
 	tests/libtracker-db/Makefile
@@ -1256,6 +1282,11 @@
 	Support MP3 album art (w/ GdkPixbuf):	$have_gdkpixbuf
 	Support Playlists (w/ Totem):           $have_playlist
 
+Plugins:
+
+	Evolution support (old):	yes
+	Evolution plugin:			$have_evoplug
+
 Warning:
 
         You must make sure SQLite is compiled with --enable-threadsafe

Modified: trunk/data/db/sqlite-stored-procs.sql
==============================================================================
--- trunk/data/db/sqlite-stored-procs.sql	(original)
+++ trunk/data/db/sqlite-stored-procs.sql	Thu Jan 15 12:58:15 2009
@@ -171,6 +171,11 @@
 GetXesamMimePrefixForServiceId SELECT MimePrefix FROM XesamFileMimePrefixes WHERE ServiceTypeId = ?;
 
 /*
+ * Turtle importing
+ */
+DeleteServiceAll               DELETE FROM Services WHERE ServiceTypeID = ?;
+
+/*
  * Deprecated
  */
 GetNewID                       SELECT OptionValue FROM Options WHERE OptionKey = 'Sequence';

Modified: trunk/data/db/sqlite-tracker.sql
==============================================================================
--- trunk/data/db/sqlite-tracker.sql	(original)
+++ trunk/data/db/sqlite-tracker.sql	Thu Jan 15 12:58:15 2009
@@ -8,6 +8,7 @@
 insert Into Options (OptionKey, OptionValue) values ('Sequence', '1');
 insert Into Options (OptionKey, OptionValue) values ('EventSequence', '1');
 insert Into Options (OptionKey, OptionValue) values ('UpdateCount', '0');
+insert Into Options (OptionKey, OptionValue) values ('EvolutionLastCheckout', '0');
 
 
 /* store volume and HAL info here for files */

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Thu Jan 15 12:58:15 2009
@@ -37,6 +37,7 @@
 	libtracker-data				\
 	libtracker				\
 	$(build_sqlite_fts)			\
+	plugins					\
 	trackerd				\
 	tracker-utils				\
 	tracker-extract				\
@@ -62,4 +63,5 @@
 	libtracker-gtk				\
 	tracker-applet	 			\
 	tracker-search-tool			\
-	tracker-preferences
+	tracker-preferences			\
+	plugins

Modified: trunk/src/libtracker-data/tracker-data-update.c
==============================================================================
--- trunk/src/libtracker-data/tracker-data-update.c	(original)
+++ trunk/src/libtracker-data/tracker-data-update.c	Thu Jan 15 12:58:15 2009
@@ -607,6 +607,35 @@
 	}
 }
 
+
+void
+tracker_data_update_delete_service_all (const gchar *rdf_type)
+{
+	TrackerService     *service;
+	gchar              *service_type_id; 
+	TrackerDBInterface *iface;
+
+	if (!rdf_type)
+		return;
+
+	service = tracker_ontology_get_service_by_name (rdf_type);
+
+	g_return_if_fail (TRACKER_IS_SERVICE (service));
+
+	service_type_id = tracker_gint_to_string (tracker_service_get_id (service));
+
+	iface = tracker_db_manager_get_db_interface_by_type (tracker_service_get_name (service),
+							     TRACKER_DB_CONTENT_TYPE_METADATA);
+
+	tracker_db_interface_execute_procedure (iface,
+						NULL,
+						"DeleteServiceAll",
+						service_type_id,
+						NULL);
+
+	g_free (service_type_id);
+}
+
 static void
 set_metadata (TrackerField *field, 
 	      gpointer value, 

Modified: trunk/src/libtracker-data/tracker-data-update.h
==============================================================================
--- trunk/src/libtracker-data/tracker-data-update.h	(original)
+++ trunk/src/libtracker-data/tracker-data-update.h	Thu Jan 15 12:58:15 2009
@@ -58,6 +58,8 @@
 							 GHashTable          *metadata);
 void     tracker_data_update_delete_service_by_path     (const gchar         *path,
 							 const gchar         *rdf_type);
+void     tracker_data_update_delete_service_all         (const gchar *rdf_type);
+
 
 /* Metadata */
 void     tracker_data_update_set_metadata               (TrackerService      *service,

Added: trunk/src/plugins/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/plugins/Makefile.am	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,6 @@
+SUBDIRS = .
+
+if HAVE_EVOLUTION_PLUGIN
+SUBDIRS += evolution
+endif
+

Added: trunk/src/plugins/evolution/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/Makefile.am	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,89 @@
+INCLUDES =						\
+	-I$(top_srcdir)/src				\
+	-DGETTEXT_PACKAGE="\"$(GETTEXT_PACKAGE)\""	\
+	-DLOCALEDIR="\"$(LOCALEDIR)\""			\
+	-DTRACKER_COMPILATION				\
+	$(DBUS_CFLAGS)					\
+	$(GMIME_CFLAGS)					\
+	$(EVOPLUG_CFLAGS)
+
+%.eplug.in: %.eplug.xml
+	LC_ALL=C $(INTLTOOL_MERGE) -x -u /tmp $< $@
+
+%.eplug: %.eplug.in
+	sed -e "s%+PLUGIN_INSTALL_DIR+%$(EVOPLUG_INSTALL_DIR)%" \
+	-e "s%+GETTEXT_PACKAGE+%$(GETTEXT_PACKAGE)%" \
+	-e "s%+LOCALEDIR+%$(LOCALEDIR)%" \
+	$< > $@
+
+eplugindir = $(EVOLUTION_PLUGIN_INSTALL_DIR)
+
+eplugin_DATA = org-freedesktop-Tracker-evolution-plugin.eplug
+
+eplugin_LTLIBRARIES = liborg-freedesktop-Tracker-evolution-plugin.la
+
+noinst_LTLIBRARIES = libtracker-evolution.la libtracker-evolution-indexer.la
+
+libtracker_evolution_indexer_la_SOURCES =				\
+	tracker-evolution-indexer.c					\
+	tracker-evolution-indexer.h					\
+	tracker-evolution-registrar-glue.h				\
+	tracker-evolution-common.h
+
+libtracker_evolution_la_SOURCES =	 				\
+	tracker-evolution.c						\
+	tracker-evolution.h						\
+	tracker-evolution-registrar.c					\
+	tracker-evolution-registrar.h					\
+	tracker-evolution-common.h					\
+	tracker-evolution-registrar-glue.h
+
+libtracker_evolution_la_LIBADD = 					\
+	$(top_builddir)/src/libtracker-data/libtracker-data.la          \
+	$(top_builddir)/src/libtracker-db/libtracker-db.la              \
+	$(top_builddir)/src/libtracker-common/libtracker-common.la      \
+	$(DBUS_LIBS)                                                    \
+	$(GTHREAD_LIBS)                                                 \
+	$(GIO_LIBS)                                                     \
+	$(GLIB2_LIBS)                                                   \
+	$(RAPTOR_LIBS)
+
+libtracker_evolution_indexer_la_LIBADD = 				\
+	$(top_builddir)/src/libtracker-data/libtracker-data.la          \
+	$(top_builddir)/src/libtracker-db/libtracker-db.la              \
+	$(top_builddir)/src/libtracker-common/libtracker-common.la      \
+	$(DBUS_LIBS)                                                    \
+	$(GTHREAD_LIBS)                                                 \
+	$(GIO_LIBS)                                                     \
+	$(GLIB2_LIBS)                                                   \
+	$(RAPTOR_LIBS)							\
+	$(GMIME_LIBS)
+
+liborg_freedesktop_Tracker_evolution_plugin_la_SOURCES = 		\
+	tracker-evolution-plugin.c 			 		\
+	tracker-evolution-plugin.h					\
+	tracker-evolution-common.h					\
+	tracker-evolution-plugin-glue.h
+
+liborg_freedesktop_Tracker_evolution_plugin_la_LDFLAGS = -module -avoid-version
+liborg_freedesktop_Tracker_evolution_plugin_la_LDLIBS = 		\
+	$(EVOPLUG_LIBS)							\
+	$(DBUS_LIBS)
+
+dbus_sources = 								\
+	tracker-evolution-plugin-glue.h					\
+	tracker-evolution-registrar-glue.h
+
+%-glue.h: %.xml
+	$(DBUSBINDINGTOOL) --mode=glib-server --output=$@ --prefix=$(subst -,_,$*) $^
+
+BUILT_SOURCES = 							\
+	$(dbus_sources)							\
+	$(eplugin_DATA)
+
+CLEANFILES = $(BUILT_SOURCES) \
+	org-freedesktop-Tracker-evolution-plugin.eplug
+
+EXTRA_DIST = 								\
+	$(BUILT_SOURCES)						\
+	org-freedesktop-Tracker-evolution-plugin.eplug.xml

Added: trunk/src/plugins/evolution/org-freedesktop-Tracker-evolution-plugin.eplug.xml
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/org-freedesktop-Tracker-evolution-plugin.eplug.xml	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<e-plugin-list>
+	<e-plugin id="org.freedesktop.Tracker.evolution_plugin" 
+		type="shlib"
+		location="+PLUGIN_INSTALL_DIR+/liborg-freedesktop-Tracker-evolution-plugin.so"
+		domain="+GETTEXT_PACKAGE+"
+		localedir="+LOCALEDIR+"
+		_name="TrackerEvolutionPlugin"
+		load-on-startup="after-ui">
+
+		<_description>Support for Tracker.</_description>
+
+		<author name="Philip Van Hoof" email="philip codeminded be"/>
+	</e-plugin>
+</e-plugin-list>

Added: trunk/src/plugins/evolution/tracker-evolution-common.h
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/tracker-evolution-common.h	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#ifndef __TRACKER_EVOLUTION_COMMON_H__
+#define __TRACKER_EVOLUTION_COMMON_H__
+
+#define TRACKER_EVOLUTION_INDEXER_PATH		"/org/freedesktop/Tracker/Indexer/Evolution/Registrar"
+
+#define TRACKER_EVOLUTION_REGISTRAR_SERVICE	"org.freedesktop.Tracker"
+#define TRACKER_EVOLUTION_REGISTRAR_PATH	"/org/freedesktop/Tracker/Evolution/Registrar"
+#define TRACKER_EVOLUTION_REGISTRAR_INTERFACE	"org.gnome.evolution.metadata.Registrar"
+
+#define TRACKER_EVOLUTION_MANAGER_SERVICE	"org.gnome.evolution"
+#define TRACKER_EVOLUTION_MANAGER_PATH		"/org/gnome/evolution/metadata/Manager"
+#define TRACKER_EVOLUTION_MANAGER_INTERFACE	"org.gnome.evolution.metadata.Manager"
+
+#define DBUS_ERROR_DOMAIN			"TrackerEvolution"
+#define DBUS_ERROR				g_quark_from_static_string (DBUS_ERROR_DOMAIN)
+
+#define TRACKER_EVOLUTION_PREDICATE_SUBJECT	"Evolution:MessageSubject"
+#define TRACKER_EVOLUTION_PREDICATE_SENT	"Evolution:MessageSent"
+#define TRACKER_EVOLUTION_PREDICATE_FROM	"Evolution:MessageFrom"
+#define TRACKER_EVOLUTION_PREDICATE_TO		"Evolution:MessageTo"
+#define TRACKER_EVOLUTION_PREDICATE_FILE	"Evolution:MessageFile"
+#define TRACKER_EVOLUTION_PREDICATE_CC		"Evolution:MessageCc"
+#define TRACKER_EVOLUTION_PREDICATE_UID		"Evolution:MessageUid"
+#define TRACKER_EVOLUTION_PREDICATE_SEEN	"Evolution:MessageSeen"
+#define TRACKER_EVOLUTION_PREDICATE_JUNK	"Evolution:MessageJunk"
+#define TRACKER_EVOLUTION_PREDICATE_ANSWERED	"Evolution:MessageAnswered"
+#define TRACKER_EVOLUTION_PREDICATE_FLAGGED	"Evolution:MessageFlagged"
+#define TRACKER_EVOLUTION_PREDICATE_TAG		"Evolution:MessageTag"
+#define TRACKER_EVOLUTION_PREDICATE_FORWARDED	"Evolution:MessageForwarded"
+#define TRACKER_EVOLUTION_PREDICATE_DELETED	"Evolution:MessageDeleted"
+#define TRACKER_EVOLUTION_PREDICATE_SIZE	"Evolution:MessageSize"
+
+#define TRACKER_TYPE_G_STRV_ARRAY		(dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRV))
+
+#define dbus_async_return_if_fail(expr,context)				\
+	G_STMT_START {							\
+		if G_LIKELY(expr) { } else {				\
+			GError *error = NULL;				\
+									\
+			g_set_error (&error,				\
+				     DBUS_ERROR,			\
+				     0,					\
+				     "Assertion `%s' failed",		\
+				     #expr);				\
+									\
+			dbus_g_method_return_error (context, error);	\
+			g_error_free (error);				\
+									\
+			return;						\
+		};							\
+	} G_STMT_END
+
+#endif /* __TRACKER_EVOLUTION_COMMON_H__ */

Added: trunk/src/plugins/evolution/tracker-evolution-indexer.c
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/tracker-evolution-indexer.c	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,606 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib/gstdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <gmime/gmime.h>
+
+#include <libtracker-data/tracker-data-update.h>
+
+/* This is okay, we run in-process of the indexer: we can access its symbols */
+#include <tracker-indexer/tracker-module.h>
+#include <tracker-indexer/tracker-module-metadata-private.h>
+
+#include "tracker-evolution-indexer.h"
+
+/* These defines/renames are necessary for -glue.h */
+#define tracker_evolution_registrar_set tracker_evolution_indexer_set
+#define tracker_evolution_registrar_set_many tracker_evolution_indexer_set_many
+#define tracker_evolution_registrar_unset_many tracker_evolution_indexer_unset_many
+#define tracker_evolution_registrar_unset tracker_evolution_indexer_unset
+#define tracker_evolution_registrar_cleanup tracker_evolution_indexer_cleanup
+#define dbus_glib_tracker_evolution_indexer_object_info dbus_glib_tracker_evolution_registrar_object_info
+
+#include "tracker-evolution-registrar-glue.h"
+
+/* Based on data/services/email.metadata */
+
+#define METADATA_EMAIL_RECIPIENT     "Email:Recipient"
+#define METADATA_EMAIL_DATE	     "Email:Date"
+#define METADATA_EMAIL_SENDER	     "Email:Sender"
+#define METADATA_EMAIL_SUBJECT	     "Email:Subject"
+#define METADATA_EMAIL_SENT_TO	     "Email:SentTo"
+#define METADATA_EMAIL_CC	     "Email:CC"
+#define METADATA_EMAIL_TEXT	     "Email:Body"
+#define METADATA_EMAIL_TAG	     "User:Keywords"
+
+#define TRACKER_EVOLUTION_INDEXER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TRACKER_TYPE_EVOLUTION_INDEXER, TrackerEvolutionIndexerPrivate))
+
+G_DEFINE_TYPE (TrackerEvolutionIndexer, tracker_evolution_indexer, G_TYPE_OBJECT)
+
+/* This runs in-process of tracker-indexer */
+
+static GObject *idx_indexer = NULL;
+
+typedef struct {
+	TrackerIndexer *indexer;
+} TrackerEvolutionIndexerPrivate;
+
+enum {
+	PROP_0,
+	PROP_INDEXER
+};
+
+static void
+tracker_evolution_indexer_finalize (GObject *object)
+{
+	TrackerEvolutionIndexerPrivate *priv = TRACKER_EVOLUTION_INDEXER_GET_PRIVATE (object);
+
+	if (priv->indexer)
+		g_object_unref (priv->indexer);
+
+	G_OBJECT_CLASS (tracker_evolution_indexer_parent_class)->finalize (object);
+}
+
+static void
+tracker_evolution_indexer_set_property (GObject      *object,
+					guint         prop_id,
+					const GValue *value,
+					GParamSpec   *pspec)
+{
+	TrackerEvolutionIndexerPrivate *priv = TRACKER_EVOLUTION_INDEXER_GET_PRIVATE (object);
+
+	switch (prop_id) {
+
+	case PROP_INDEXER:
+
+		if (priv->indexer)
+			g_object_unref (priv->indexer);
+
+		priv->indexer = g_value_dup_object (value);
+		break;
+
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+tracker_evolution_indexer_get_property (GObject    *object,
+					guint       prop_id,
+					GValue     *value,
+					GParamSpec *pspec)
+{
+	TrackerEvolutionIndexerPrivate *priv;
+
+	priv = TRACKER_EVOLUTION_INDEXER_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_INDEXER:
+		g_value_set_object (value, priv->indexer);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+tracker_evolution_indexer_class_init (TrackerEvolutionIndexerClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = tracker_evolution_indexer_finalize;
+	object_class->set_property = tracker_evolution_indexer_set_property;
+	object_class->get_property = tracker_evolution_indexer_get_property;
+
+	g_object_class_install_property (object_class,
+					 PROP_INDEXER,
+					 g_param_spec_object ("indexer",
+							      "Indexer",
+							      "Indexer",
+							      tracker_indexer_get_type (),
+							      G_PARAM_READWRITE |
+							      G_PARAM_CONSTRUCT));
+
+	g_type_class_add_private (object_class, sizeof (TrackerEvolutionIndexerPrivate));
+}
+
+static void
+tracker_evolution_indexer_init (TrackerEvolutionIndexer *object)
+{
+	TrackerEvolutionIndexerPrivate *priv = TRACKER_EVOLUTION_INDEXER_GET_PRIVATE (object);
+	priv->indexer = NULL;
+}
+
+
+#if 0
+static void
+extract_mime_parts (GMimeObject *object,
+		    gpointer     user_data)
+{
+	const gchar *message_subject = user_data;
+	gchar *subject = NULL;
+	const gchar *disposition, *filename;
+	GMimePart *part;
+
+	if (GMIME_IS_MESSAGE_PART (object)) {
+		GMimeMessage *message;
+
+		message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (object));
+
+		if (message) {
+			g_mime_message_foreach_part (message, extract_mime_parts, user_data);
+			g_object_unref (message);
+		}
+
+		return;
+	} else if (GMIME_IS_MULTIPART (object)) {
+		g_mime_multipart_foreach (GMIME_MULTIPART (object), extract_mime_parts, user_data);
+		return;
+	}
+
+	part = GMIME_PART (object);
+	disposition = g_mime_part_get_content_disposition (part);
+
+	if (!disposition ||
+	    (g_strcmp0 (disposition, GMIME_DISPOSITION_ATTACHMENT) != 0 &&
+	     g_strcmp0 (disposition, GMIME_DISPOSITION_INLINE) != 0)) {
+		return;
+	}
+
+	filename = g_mime_part_get_filename (GMIME_PART (object));
+
+	if (!filename ||
+	    g_strcmp0 (filename, "signature.asc") == 0 ||
+	    g_strcmp0 (filename, "signature.pgp") == 0) {
+		return;
+	}
+
+	if (filename) {
+		GHashTable *data;
+		TrackerModuleMetadata *metadata;
+		gchar *subject;
+
+		/* This is not a path but a URI: don't use the OS's dir separator
+		 * here, use the '/'. Another option is to use '#' instead of '/'
+		 * here. This depends on how we want to format the URI and what
+		 * Evolution can cope with as URI for an attachment (I don't 
+		 * think it can cope with any attachment URI, btw). */
+
+		subject = g_strdup_printf ("%s/%s", message_subject, 
+					   filename);
+
+		metadata = tracker_module_metadata_new ();
+
+		tracker_module_metadata_add_string (metadata, 
+						    "File:Path", 
+						    subject);
+
+		tracker_module_metadata_add_string (metadata, 
+						    "File:Name", 
+						    filename);
+
+		data = tracker_module_metadata_get_hash_table (metadata);
+
+		tracker_data_update_replace_service (subject, "EvolutionEmails", data);
+
+		g_hash_table_destroy (data);
+		g_object_unref (metadata);
+		g_free (subject);
+	}
+}
+
+static gchar *
+get_object_encoding (GMimeObject *object)
+{
+	const gchar *start_encoding, *end_encoding;
+	const gchar *content_type = NULL;
+
+	if (GMIME_IS_MESSAGE (object)) {
+		content_type = g_mime_message_get_header (GMIME_MESSAGE (object), "Content-Type");
+	} else if (GMIME_IS_PART (object)) {
+		content_type = g_mime_part_get_content_header (GMIME_PART (object), "Content-Type");
+	}
+
+	if (!content_type) {
+		return NULL;
+	}
+
+	start_encoding = strstr (content_type, "charset=");
+
+	if (!start_encoding) {
+		return NULL;
+	}
+
+	start_encoding += strlen ("charset=");
+
+	if (start_encoding[0] == '"') {
+		/* encoding is quoted */
+		start_encoding++;
+		end_encoding = strstr (start_encoding, "\"");
+	} else {
+		end_encoding = strstr (start_encoding, ";");
+	}
+
+	if (end_encoding) {
+		return g_strndup (start_encoding, end_encoding - start_encoding);
+	} else {
+		return g_strdup (start_encoding);
+	}
+}
+#endif
+
+static void
+perform_set (TrackerEvolutionIndexer *object, 
+	     const gchar *subject, 
+	     const GStrv predicates, 
+	     const GStrv values)
+{
+	guint i = 0;
+	TrackerModuleMetadata *metadata;
+	GHashTable *data;
+
+	metadata = tracker_module_metadata_new ();
+
+	while (predicates [i] != NULL && values[i] != NULL) {
+
+		/* TODO: TRACKER_EVOLUTION_PREDICATE_SEEN (!)
+		 *       TRACKER_EVOLUTION_PREDICATE_JUNK (!)
+		 *       TRACKER_EVOLUTION_PREDICATE_ANSWERED
+		 *       TRACKER_EVOLUTION_PREDICATE_FLAGGED
+		 *       TRACKER_EVOLUTION_PREDICATE_FORWARDED
+		 *       TRACKER_EVOLUTION_PREDICATE_DELETED (!)
+		 *       TRACKER_EVOLUTION_PREDICATE_SIZE (!) :
+		 *
+		 * I don't have predicates in Tracker's ontology for these. In
+		 * JÃrg's vstore branch we are working with Nepomuk as ontology-
+		 * set. Perhaps when we merge this to that branch that we can 
+		 * improve this situation. */
+
+
+#if 0
+
+		/* Disabling this as I can't find any version of GMime-2.0 that
+		 * wont crash on any of my test E-mails. Going to ask Garnacho
+		 * to migrate to GMime-2.4 with his old Evolution support. */
+
+		if (g_strcmp0 (predicates[i], TRACKER_EVOLUTION_PREDICATE_FILE) == 0) {
+			GMimeStream *stream;
+			GMimeParser *parser;
+			GMimeMessage *message;
+			gint fd;
+			gchar *text, *orig_text, *ptr, *encoding;
+			gchar *path = g_strdup (values[i]);
+			off_t offset = 0;
+			gboolean is_html;
+
+			ptr = strstr (path, "/!");
+			if (ptr) {
+				offset = (off_t) atol (ptr+2);
+				*ptr = '\0';
+			}
+
+			fd = tracker_file_open (path, FALSE);
+
+			g_free (path);
+
+			if (fd == -1) 
+				goto cont;
+
+			stream = g_mime_stream_fs_new_with_bounds (fd, offset, -1);
+
+			if (!stream) {
+				close (fd);
+				goto cont;
+			}
+
+			parser = g_mime_parser_new_with_stream (stream);
+
+			if (!parser) {
+				g_object_unref (stream);
+				goto cont;
+			}
+
+			g_mime_parser_set_scan_from (parser, FALSE);
+
+			message = g_mime_parser_construct_message (parser);
+
+			if (!message) {
+				g_object_unref (parser);
+				g_object_unref (stream);
+				goto cont;
+			}
+
+			g_mime_message_foreach_part (message,
+						     extract_mime_parts,
+						     subject);
+
+			orig_text = g_mime_message_get_body (message, TRUE, &is_html);
+
+			if (orig_text) {
+
+				encoding = get_object_encoding (GMIME_OBJECT (message));
+
+				if (encoding) {
+					text = g_convert (text, -1, "utf8", encoding, NULL, NULL, NULL);
+					g_free (orig_text);
+				} else
+					text = orig_text;
+
+				tracker_module_metadata_add_string (metadata, 
+								    METADATA_EMAIL_TEXT, 
+								    text);
+
+				g_free (text);
+				g_free (encoding);
+			}
+
+			g_object_unref (message);
+			g_object_unref (parser);
+			g_object_unref (stream);
+		}
+#endif
+
+		if (g_strcmp0 (predicates[i], TRACKER_EVOLUTION_PREDICATE_TAG) == 0) {
+			gchar *key, *value;
+
+			if (!values[i] || strlen (values[i]) < 1)
+				goto cont;
+
+			key = g_strdup (values[i]);
+
+			value = strchr (key, '=');
+
+			if (value) {
+				*value = '\0';
+				value++;
+			}
+
+			/* TODO: what about value? The format of Evolution is
+			 * key=value, so we can store a value too here. Is this 
+			 * something Nepomuk can someday save us with? */
+
+			tracker_module_metadata_add_string (metadata, 
+							    METADATA_EMAIL_TAG, 
+							    key);
+
+			g_free (key);
+		}
+
+		if (g_strcmp0 (predicates[i], TRACKER_EVOLUTION_PREDICATE_SUBJECT) == 0) {
+			tracker_module_metadata_add_string (metadata, 
+							    METADATA_EMAIL_SUBJECT, 
+							    values[i]);
+		}
+
+		if (g_strcmp0 (predicates[i], TRACKER_EVOLUTION_PREDICATE_SENT) == 0) {
+			tracker_module_metadata_add_string (metadata, 
+							    METADATA_EMAIL_DATE, 
+							    values[i]);
+		}
+
+		if (g_strcmp0 (predicates[i], METADATA_EMAIL_SENDER) == 0) {
+			tracker_module_metadata_add_string (metadata, 
+							    METADATA_EMAIL_SENDER, 
+							    values[i]);
+		}
+
+		if (g_strcmp0 (predicates[i], TRACKER_EVOLUTION_PREDICATE_TO) == 0) {
+			tracker_module_metadata_add_string (metadata, 
+							    METADATA_EMAIL_SENT_TO, 
+							    values[i]);
+		}
+
+		if (g_strcmp0 (predicates[i], TRACKER_EVOLUTION_PREDICATE_CC) == 0) {
+			tracker_module_metadata_add_string (metadata, 
+							    METADATA_EMAIL_CC, 
+							    values[i]);
+		}
+
+		cont:
+
+		i++;
+	}
+
+	data = tracker_module_metadata_get_hash_table (metadata);
+
+	tracker_data_update_replace_service (subject, "EvolutionEmails", data);
+
+	g_hash_table_destroy (data);
+	g_object_unref (metadata);
+}
+
+static void 
+perform_unset (TrackerEvolutionIndexer *object, 
+	       const gchar *subject)
+{
+	tracker_data_update_delete_service_by_path (subject, "EvolutionEmails"); 
+}
+
+static void
+perform_cleanup (TrackerEvolutionIndexer *object)
+{
+	tracker_data_update_delete_service_all ("EvolutionEmails");
+}
+
+void
+tracker_evolution_indexer_set (TrackerEvolutionIndexer *object, 
+			       const gchar *subject, 
+			       const GStrv predicates,
+			       const GStrv values,
+			       DBusGMethodInvocation *context,
+			       GError *derror)
+{
+	dbus_async_return_if_fail (subject != NULL, context);
+
+	if (predicates && values) {
+
+		dbus_async_return_if_fail (g_strv_length (predicates) == 
+					   g_strv_length (values), context);
+
+		perform_set (object, subject, predicates, values);
+	}
+
+	dbus_g_method_return (context);
+}
+
+void
+tracker_evolution_indexer_set_many (TrackerEvolutionIndexer *object, 
+				    const GStrv subjects, 
+				    const GPtrArray *predicates,
+				    const GPtrArray *values,
+				    DBusGMethodInvocation *context,
+				    GError *derror)
+{
+	guint len;
+	guint i = 0;
+
+	dbus_async_return_if_fail (subjects != NULL, context);
+	dbus_async_return_if_fail (predicates != NULL, context);
+	dbus_async_return_if_fail (values != NULL, context);
+
+	len = g_strv_length (subjects);
+
+	dbus_async_return_if_fail (len == predicates->len, context);
+	dbus_async_return_if_fail (len == values->len, context);
+
+	while (subjects[i] != NULL) {
+		GStrv preds = g_ptr_array_index (predicates, i);
+		GStrv vals = g_ptr_array_index (values, i);
+
+		perform_set (object, subjects[i], preds, vals);
+
+		i++;
+	}
+
+	dbus_g_method_return (context);
+}
+
+void
+tracker_evolution_indexer_unset_many (TrackerEvolutionIndexer *object, 
+				      const GStrv subjects, 
+				      DBusGMethodInvocation *context,
+				      GError *derror)
+{
+	guint i = 0;
+
+	dbus_async_return_if_fail (subjects != NULL, context);
+
+	while (subjects[i] != NULL) {
+
+		perform_unset (object, subjects[i]);
+
+		i++;
+	}
+
+	dbus_g_method_return (context);
+}
+
+void
+tracker_evolution_indexer_unset (TrackerEvolutionIndexer *object, 
+				 const gchar *subject, 
+				 DBusGMethodInvocation *context,
+				 GError *derror)
+{
+	dbus_async_return_if_fail (subject != NULL, context);
+
+	perform_unset (object, subject);
+
+	dbus_g_method_return (context);
+}
+
+void
+tracker_evolution_indexer_cleanup (TrackerEvolutionIndexer *object, 
+				   DBusGMethodInvocation *context,
+				   GError *derror)
+{
+	perform_cleanup (object);
+
+	dbus_g_method_return (context);
+}
+
+void
+tracker_evolution_storer_init (TrackerConfig *config, 
+			       TrackerIndexer *indexer)
+{
+	GError *error = NULL;
+	DBusGConnection *connection;
+
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+
+	if (!error) {
+		idx_indexer = g_object_new (TRACKER_TYPE_EVOLUTION_INDEXER, 
+					    "indexer", indexer, NULL);
+
+		dbus_g_object_type_install_info (G_OBJECT_TYPE (idx_indexer), 
+						 &dbus_glib_tracker_evolution_indexer_object_info);
+
+		dbus_g_connection_register_g_object (connection, 
+						     TRACKER_EVOLUTION_INDEXER_PATH, 
+						     idx_indexer);
+	}
+
+	if (error) {
+		g_critical ("Can't init DBus for Evolution support: %s", error->message);
+		g_error_free (error);
+	}
+}
+
+void
+tracker_evolution_storer_shutdown (void)
+{
+	if (idx_indexer)
+		g_object_unref (idx_indexer);
+}

Added: trunk/src/plugins/evolution/tracker-evolution-indexer.h
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/tracker-evolution-indexer.h	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,100 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#ifndef __LIBTRACKER_EVOLUTION_H__
+#define __LIBTRACKER_EVOLUTION_H__
+
+#if !defined (TRACKER_ENABLE_INTERNALS) && !defined (TRACKER_COMPILATION)
+#error "TRACKER_ENABLE_INTERNALS not defined, this must be defined to use tracker's internal functions"
+#endif
+
+#include <glib.h>
+
+#include <libtracker-common/tracker-common.h>
+
+G_BEGIN_DECLS
+
+#if !defined (TRACKER_ENABLE_INTERNALS) && !defined (TRACKER_COMPILATION)
+#error "TRACKER_ENABLE_INTERNALS not defined, this must be defined to use tracker's internal functions"
+#endif
+
+#include <glib.h>
+#include <dbus/dbus-glib-bindings.h>
+
+#include <tracker-indexer/tracker-indexer.h>
+
+#include "tracker-evolution-common.h"
+
+G_BEGIN_DECLS
+
+#define TRACKER_TYPE_EVOLUTION_INDEXER          (tracker_evolution_indexer_get_type())
+#define TRACKER_EVOLUTION_INDEXER(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_EVOLUTION_INDEXER, TrackerEvolutionIndexer))
+#define TRACKER_EVOLUTION_INDEXER_CLASS(c)      (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_EVOLUTION_INDEXER, TrackerEvolutionIndexerClass))
+#define TRACKER_EVOLUTION_INDEXER_GET_CLASS(o)  (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_EVOLUTION_INDEXER, TrackerEvolutionIndexerClass))
+
+G_BEGIN_DECLS
+
+typedef struct TrackerEvolutionIndexer TrackerEvolutionIndexer;
+typedef struct TrackerEvolutionIndexerClass TrackerEvolutionIndexerClass;
+
+struct TrackerEvolutionIndexer {
+	GObject parent;
+};
+
+struct TrackerEvolutionIndexerClass {
+	GObjectClass parent;
+};
+
+GType  tracker_evolution_indexer_get_type   (void);
+
+void  tracker_evolution_indexer_set         (TrackerEvolutionIndexer *object, 
+					     const gchar *subject, 
+					     const GStrv predicates,
+					     const GStrv values,
+					     DBusGMethodInvocation *context,
+					     GError *derror);
+void  tracker_evolution_indexer_set_many    (TrackerEvolutionIndexer *object, 
+					     const GStrv subjects, 
+					     const GPtrArray *predicates,
+					     const GPtrArray *values,
+					     DBusGMethodInvocation *context,
+					     GError *derror);
+void  tracker_evolution_indexer_unset_many  (TrackerEvolutionIndexer *object, 
+					     const GStrv subjects, 
+					     DBusGMethodInvocation *context,
+					     GError *derror);
+void  tracker_evolution_indexer_unset       (TrackerEvolutionIndexer *object, 
+					     const gchar *subject, 
+					     DBusGMethodInvocation *context,
+					     GError *derror);
+void  tracker_evolution_indexer_cleanup     (TrackerEvolutionIndexer *object, 
+					     DBusGMethodInvocation *context,
+					     GError *derror);
+
+void  tracker_evolution_storer_init        (TrackerConfig *config, 
+					    TrackerIndexer *indexer);
+void  tracker_evolution_storer_shutdown    (void);
+
+G_END_DECLS
+
+#endif /* __LIBTRACKER_EVOLUTION_H__ */

Added: trunk/src/plugins/evolution/tracker-evolution-plugin.c
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/tracker-evolution-plugin.c	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,1738 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <pthread.h>
+#include <signal.h>
+#include <time.h>
+#include <inttypes.h>
+
+#include <sqlite3.h>
+
+#include <camel/camel-mime-message.h>
+#include <camel/camel-i18n.h>
+#include <camel/camel-store.h>
+#include <camel/camel-folder.h>
+#include <camel/camel-db.h>
+#include <camel/camel-offline-store.h>
+#include <camel/camel-session.h>
+
+#include <mail/mail-config.h>
+#include <mail/mail-session.h>
+#include <mail/em-utils.h>
+#include <mail/mail-ops.h>
+
+#include <e-util/e-config.h>
+
+#include <libedataserver/e-account.h>
+#include <libedataserver/e-account-list.h>
+
+#include "tracker-evolution-plugin.h"
+#include "tracker-evolution-plugin-glue.h"
+
+/* This runs in-process of evolution (in the mailer, as a EPlugin). It has 
+ * access to the CamelSession using the external variable 'session'. The header
+ * mail/mail-session.h makes this variable public */
+
+#define MAX_BEFORE_SEND 2000
+
+G_DEFINE_TYPE (TrackerEvolutionPlugin, tracker_evolution_plugin, G_TYPE_OBJECT)
+
+#define TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TRACKER_TYPE_EVOLUTION_PLUGIN, TrackerEvolutionPluginPrivate))
+
+/* Some helper-defines */
+#define CAMEL_CALLBACK(func) ((CamelObjectEventHookFunc) func)
+#define EXTRACT_STRING(val) if (*part) part++; len=strtoul (part, &part, 10); if (*part) part++; val=g_strndup (part, len); part+=len;
+#define EXTRACT_FIRST_DIGIT(val) val=strtoul (part, &part, 10);
+
+/* About the locks being used: Camel's API must be used in a multi-threaded
+ * fashion. Therefore it's necessary to guard against concurrent access of
+ * memory. Especially given that both the mainloop and the Camel-threads will
+ * be accessing the memory (mainloop for DBus calls, and Camel-threads mostly
+ * during registration of accounts and folders) */
+
+typedef struct {
+	guint64 last_checkout;
+	DBusGProxy *registrar;
+	guint signal;
+} ClientRegistry;
+
+typedef struct {
+	TrackerEvolutionPlugin *self;
+	gchar *account_uri;
+	guint hook_id;
+} OnSummaryChangedInfo;
+
+typedef struct {
+	OnSummaryChangedInfo *hook_info;
+	CamelFolder *folder;
+} FolderRegistry;
+
+typedef struct {
+	EAccount *account;
+	TrackerEvolutionPlugin *self;
+	guint hook_id;
+	CamelStore *store;
+} StoreRegistry;
+
+typedef struct {
+	TrackerEvolutionPlugin *self;
+	gchar *account_uri;
+	ClientRegistry *info;
+} IntroductionInfo;
+
+typedef struct {
+	TrackerEvolutionPlugin *self;
+	gchar *uri;
+	gboolean old_state;
+	EAccount *account;
+} RegisterInfo;
+
+typedef struct {
+	DBusGConnection *connection;
+	GHashTable *registrars;
+	GStaticRecMutex *mutex;
+	GHashTable *registered_folders;
+	GHashTable *cached_folders;
+	GHashTable *registered_stores;
+	GList *registered_clients;
+	EAccountList *accounts;
+} TrackerEvolutionPluginPrivate;
+
+enum {
+	PROP_0,
+	PROP_CONNECTION
+};
+
+static DBusGProxy *dbus_proxy = NULL;
+static TrackerEvolutionPlugin *manager = NULL;
+static GStaticRecMutex glock = G_STATIC_REC_MUTEX_INIT;
+
+/* Prototype declarations */
+static void register_account (TrackerEvolutionPlugin *self, EAccount *account);
+static void unregister_account (TrackerEvolutionPlugin *self, EAccount *account);
+int e_plugin_lib_enable (EPluginLib *ep, int enable);
+static void metadata_set_many (TrackerEvolutionPlugin *self, GStrv subjects, GPtrArray *predicates, GPtrArray *values);
+static void metadata_unset_many (TrackerEvolutionPlugin *self, GStrv subjects);
+
+static GList *
+get_recipient_list (const gchar *str)
+{
+	GList *list = NULL;
+	gchar **arr;
+	gint i;
+
+	if (!str) {
+		return NULL;
+	}
+
+	arr = g_strsplit (str, ",", -1);
+
+	for (i = 0; arr[i]; i++) {
+		g_strstrip (arr[i]);
+		list = g_list_prepend (list, g_strdup (arr[i]));
+	}
+
+	g_strfreev (arr);
+
+	return g_list_reverse (list);
+}
+
+static void
+folder_registry_free (FolderRegistry *registry)
+{
+	camel_object_remove_event (registry->folder, registry->hook_info->hook_id);
+	camel_object_unref (registry->folder);
+	g_free (registry->hook_info->account_uri);
+	g_slice_free (OnSummaryChangedInfo, registry->hook_info);
+	g_slice_free (FolderRegistry, registry);
+}
+
+static FolderRegistry*
+folder_registry_new (const gchar *account_uri, 
+		     CamelFolder *folder, 
+		     TrackerEvolutionPlugin *self)
+{
+	FolderRegistry *registry = g_slice_new (FolderRegistry);
+
+	registry->hook_info = g_slice_new (OnSummaryChangedInfo);
+	registry->hook_info->account_uri = g_strdup (account_uri);
+	registry->hook_info->self = self; /* weak */
+	registry->hook_info->hook_id = 0;
+	camel_object_ref (folder);
+	registry->folder = folder;
+
+	return registry;
+}
+
+static void
+process_fields (GPtrArray *predicates_temp, 
+		GPtrArray *values_temp, 
+		gchar *uid, 
+		guint flags, 
+		gchar *sent, 
+		gchar *subject,
+		gchar *from, 
+		gchar *to, 
+		gchar *cc, 
+		gchar *size,
+		CamelFolder *folder)
+{
+	GList *list, *l;
+
+	g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_UID));
+	g_ptr_array_add (values_temp, g_strdup (uid));
+
+	g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_SEEN));
+	g_ptr_array_add (values_temp, g_strdup ((flags & CAMEL_MESSAGE_SEEN) ? "True" : "False"));
+
+	g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_JUNK));
+	g_ptr_array_add (values_temp, g_strdup ((flags & CAMEL_MESSAGE_JUNK) ? "True" : "False"));
+
+	g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_DELETED));
+	g_ptr_array_add (values_temp, g_strdup ((flags & CAMEL_MESSAGE_DELETED) ? "True" : "False"));
+
+	g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_ANSWERED));
+	g_ptr_array_add (values_temp, g_strdup ((flags & CAMEL_MESSAGE_ANSWERED) ? "True" : "False"));
+
+	g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_FLAGGED));
+	g_ptr_array_add (values_temp, g_strdup ((flags & CAMEL_MESSAGE_FLAGGED) ? "True" : "False"));
+
+	g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_FORWARDED));
+	g_ptr_array_add (values_temp, g_strdup ((flags & CAMEL_MESSAGE_FORWARDED) ? "True" : "False"));
+
+
+	if (subject && g_utf8_validate (subject, -1, NULL)) {
+		g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_SUBJECT));
+		g_ptr_array_add (values_temp, g_strdup (subject));
+	}
+
+	list = get_recipient_list (to);
+	for (l = list; l; l = l->next) {
+		if (l->data && g_utf8_validate (l->data, -1, NULL)) {
+			g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_TO));
+			g_ptr_array_add (values_temp, l->data);
+		} else
+			g_free (l->data);
+	}
+	g_list_free (list);
+
+	if (from && g_utf8_validate (from, -1, NULL)) {
+		g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_FROM));
+		g_ptr_array_add (values_temp, g_strdup (from));
+	}
+
+	if (size && g_utf8_validate (size, -1, NULL)) {
+		g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_SIZE));
+		g_ptr_array_add (values_temp, g_strdup (size));
+	}
+
+	list = get_recipient_list (cc);
+	for (l = list; l; l = l->next) {
+		if (l->data && g_utf8_validate (l->data, -1, NULL)) {
+			g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_CC));
+			g_ptr_array_add (values_temp, l->data);
+		} else
+			g_free (l->data);
+	}
+	g_list_free (list);
+
+	if (sent && g_utf8_validate (sent, -1, NULL)) {
+		g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_SENT));
+		g_ptr_array_add (values_temp, g_strdup (sent));
+	}
+
+	if (folder) {
+		gchar *filen = camel_folder_get_filename (folder, uid, NULL);
+		if (filen) {
+			if (g_file_test (filen, G_FILE_TEST_EXISTS)) {
+				g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_FILE));
+				g_ptr_array_add (values_temp, filen);
+			} else
+				g_free (filen);
+		}
+	}
+}
+
+/* When new messages arrive to- or got deleted from the summary, called in
+ * mainloop or by a thread (unknown, depends on Camel and Evolution code that 
+ * executes the reason why this signal gets emitted) */
+
+static void
+on_folder_summary_changed (CamelFolder *folder, 
+			   CamelFolderChangeInfo *changes, 
+			   gpointer user_data)
+{
+	OnSummaryChangedInfo *info = user_data;
+	TrackerEvolutionPlugin *self  = info->self;
+	CamelFolderSummary *summary;
+	gchar *account_uri = info->account_uri;
+	GPtrArray *merged;
+	guint i;
+	gchar *em_uri;
+
+	if (!folder)
+		return;
+
+	summary = folder->summary;
+	em_uri = em_uri_from_camel (account_uri);
+
+	merged = g_ptr_array_new ();
+
+	/* the uid_added member contains the added-to-the-summary items */
+
+	if (changes->uid_added && changes->uid_added->len > 0) {
+		for (i = 0; i < changes->uid_added->len; i++)
+			g_ptr_array_add (merged, changes->uid_added->pdata[i]);
+	}
+
+	/* the uid_changed member contains the changed-in-the-summary items */
+
+	if (changes->uid_changed && changes->uid_changed->len > 0) {
+		gboolean found = FALSE;
+		guint y;
+
+		for (i = 0; i < changes->uid_changed->len; i++) {
+			for (y = 0; y < merged->len; y++) {
+				if (strcmp (merged->pdata[y], changes->uid_changed->pdata[i]) == 0) {
+					found = TRUE;
+					break;
+				}
+			}
+
+			if (!found)
+				g_ptr_array_add (merged, changes->uid_changed->pdata[i]);
+		}
+	}
+
+	if (merged->len > 0) {
+		GPtrArray *predicates_array = g_ptr_array_new ();
+		GPtrArray *values_array = g_ptr_array_new ();
+		gchar **subjects = (gchar **) g_malloc0 (sizeof (gchar *) * merged->len + 1);
+		guint y;
+
+		y = 0;
+
+		for (i = 0; i< merged->len; i++) {
+			gchar *subject, *to, *from, *cc, *uid = NULL, *sent, *size;
+			guint flags;
+			gchar **values, **predicates;
+			CamelMessageInfo *linfo;
+			GPtrArray *values_temp = g_ptr_array_new ();
+			GPtrArray *predicates_temp = g_ptr_array_new ();
+			const CamelTag *ctags;
+			const CamelFlag *cflags;
+
+			linfo = camel_folder_summary_uid (summary, merged->pdata[i]);
+
+			if (linfo)
+				uid = (gchar *) camel_message_info_uid (linfo);
+
+			if (linfo && uid) {
+				guint j, max;
+
+				subject = (gchar *) camel_message_info_subject (linfo);
+				to =      (gchar *) camel_message_info_to (linfo);
+				from =    (gchar *) camel_message_info_from (linfo);
+				cc =      (gchar *) camel_message_info_cc (linfo);
+				flags =   (guint)   camel_message_info_flags (linfo);
+
+				/* Camel returns a time_t, I think a uint64 is the best fit here */
+				sent = g_strdup_printf ("%"PRIu64, (unsigned long long) camel_message_info_date_sent (linfo));
+
+				/* Camel returns a uint32, so %u */
+				size = g_strdup_printf ("%u", camel_message_info_size (linfo));
+
+				process_fields (predicates_temp, values_temp, uid,
+						flags, sent, subject, from, to, cc, 
+						size, folder);
+
+				cflags = camel_message_info_user_flags (linfo);
+				while (cflags) {
+					g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_TAG));
+					g_ptr_array_add (values_temp, g_strdup_printf ("%s=True", cflags->name));
+					cflags = cflags->next;
+				}
+
+				ctags = camel_message_info_user_tags (linfo);
+				while (ctags) {
+					g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_TAG));
+					g_ptr_array_add (values_temp, g_strdup_printf ("%s=%s", ctags->name, ctags->value));
+					ctags = ctags->next;
+				}
+
+				if (values_temp->len != predicates_temp->len)
+					g_critical ("values_temp->len != predicates_temp->len");
+
+				max = MIN (values_temp->len, predicates_temp->len);
+
+				values = (gchar **) g_malloc0 (sizeof (gchar*) * max + 1);
+				predicates = (gchar **) g_malloc0 (sizeof (gchar*) * max + 1);
+
+				for (j = 0; j < max; j++) {
+					predicates[j] = predicates_temp->pdata[j];
+					values[j] = values_temp->pdata[j];
+				}
+
+				predicates[j] = NULL;
+				values[j] = NULL;
+
+				g_ptr_array_add (values_array, values);
+				g_ptr_array_add (predicates_array, predicates);
+
+				/* This is not a path but a URI, don't use the 
+				 * OS's directory separator here */
+
+				subjects[y] = g_strdup_printf ("%s%s/%s", 
+							       em_uri, 
+							       camel_folder_get_full_name (folder),
+							       uid);
+
+				g_ptr_array_free (predicates_temp, TRUE);
+				g_ptr_array_free (values_temp, TRUE);
+
+				y++;
+			}
+
+			if (linfo)
+				camel_message_info_free (linfo);
+		}
+
+		subjects[y] = NULL;
+
+		/* This goes to all currently registered registrars */
+
+		metadata_set_many (self, subjects, predicates_array, values_array);
+
+		g_strfreev (subjects);
+		for (i = 0; i < values_array->len; i++)
+			g_strfreev (values_array->pdata[i]);
+		g_ptr_array_free (values_array, TRUE);
+		for (i = 0; i < predicates_array->len; i++)
+			g_strfreev (predicates_array->pdata[i]);
+		g_ptr_array_free (predicates_array, TRUE);
+	}
+
+	g_ptr_array_free (merged, TRUE);
+
+	/* the uid_removed member contains the removed-from-the-summary items */
+
+	if (changes->uid_removed && changes->uid_removed->len > 0) {
+		gchar **subjects = (gchar **) g_malloc0 (sizeof (gchar *) * changes->uid_removed->len + 1);
+
+		for (i = 0; i< changes->uid_removed->len; i++) {
+
+			/* This is not a path but a URI, don't use the OS's 
+			 * directory separator here */
+
+			subjects[i] = g_strdup_printf ("%s%s/%s", em_uri, 
+						       camel_folder_get_full_name (folder),
+						       (char*) changes->uid_removed->pdata[i]);
+		}
+
+		subjects[i] = NULL;
+
+		/* This goes to all currently registered registrars */
+
+		metadata_unset_many (self, subjects);
+
+		g_strfreev (subjects);
+	}
+	g_free (em_uri);
+}
+
+/* Initial upload of more recent than last_checkout items, called in the mainloop */
+static void
+introduce_walk_folders_in_folder (TrackerEvolutionPlugin *self, 
+				  CamelFolderInfo *iter, 
+				  CamelStore *store, 
+				  gchar *account_uri, 
+				  ClientRegistry *info)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (self);
+	gchar *em_uri = em_uri_from_camel (account_uri);
+
+	while (iter) {
+		guint i, ret = SQLITE_OK;
+		CamelDB *cdb_r = store->cdb_r;
+		gchar *query;
+		sqlite3_stmt *stmt = NULL;
+		gboolean more = TRUE;
+
+		query = sqlite3_mprintf ("SELECT uid, flags, read, deleted, "            /* 0  - 3  */
+					        "replied, important, junk, attachment, " /* 4  - 7  */
+					        "size, dsent, dreceived, subject, "      /* 8  - 11 */
+					        "mail_from, mail_to, mail_cc, mlist, "   /* 12 - 15 */
+					        "labels, usertags "                      /* 16 - 17 */
+					 "FROM %Q "
+					 "WHERE modified > %"PRIu64, 
+
+					 iter->full_name, 
+					 info->last_checkout);
+
+		g_mutex_lock (cdb_r->lock);
+
+		ret = sqlite3_prepare_v2 (cdb_r->db, query, -1, &stmt, NULL);
+
+		while (more) {
+			GPtrArray *subjects_a = g_ptr_array_new ();
+			GPtrArray *predicates_array = g_ptr_array_new ();
+			GPtrArray *values_array = g_ptr_array_new ();
+			guint count = 0;
+
+			more = FALSE;
+
+			while (ret == SQLITE_OK || ret == SQLITE_BUSY || ret == SQLITE_ROW) {
+				gchar **values, **predicates;
+				gchar *subject, *to, *from, *cc, *sent, *uid, *size;
+				gchar *part, *label, *p;
+				guint flags;
+
+				ret = sqlite3_step (stmt);
+
+				if (ret == SQLITE_BUSY) {
+					usleep (10);
+					continue;
+				}
+
+				if ((ret != SQLITE_OK && ret != SQLITE_ROW) || ret == SQLITE_DONE) {
+					more = FALSE;
+					break;
+				}
+
+				uid = (gchar *) sqlite3_column_text (stmt, 0);
+
+				if (uid) {
+					GPtrArray *predicates_temp = g_ptr_array_new ();
+					GPtrArray *values_temp = g_ptr_array_new ();
+					CamelFolder *folder;
+					guint max = 0, j;
+
+					flags =   (guint  ) sqlite3_column_int  (stmt, 1);
+					size =    (gchar *) sqlite3_column_text (stmt, 8);
+					sent =    (gchar *) sqlite3_column_text (stmt, 9);
+					subject = (gchar *) sqlite3_column_text (stmt, 11);
+					from =    (gchar *) sqlite3_column_text (stmt, 12);
+					to =      (gchar *) sqlite3_column_text (stmt, 13);
+					cc =      (gchar *) sqlite3_column_text (stmt, 14);
+
+					g_static_rec_mutex_lock (priv->mutex);
+
+					folder = g_hash_table_lookup (priv->cached_folders, iter->full_name);
+
+					process_fields (predicates_temp, values_temp, uid, flags, sent, 
+							subject, from, to, cc, size, folder);
+
+					g_static_rec_mutex_unlock (priv->mutex);
+
+					/* Extract User flags/labels */
+					p = part = g_strdup ((const gchar *) sqlite3_column_text (stmt, 16));
+					if (part) {
+						label = part;
+						for (j=0; part[j]; j++) {
+
+							if (part[j] == ' ') {
+								part[j] = 0;
+								g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_TAG));
+								g_ptr_array_add (values_temp, g_strdup_printf ("%s=True", label));
+								label = &(part[j+1]);
+							}
+						}
+						g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_TAG));
+						g_ptr_array_add (values_temp, g_strdup (label));
+					}
+					g_free (p);
+
+					/* Extract User tags */
+					p = part = g_strdup ((const gchar *) sqlite3_column_text (stmt, 17));
+					EXTRACT_FIRST_DIGIT (max)
+					for (j = 0; j < max; j++) {
+						int len;
+						char *name, *value;
+						EXTRACT_STRING (name)
+						EXTRACT_STRING (value)
+						if (name && g_utf8_validate (name, -1, NULL) &&
+						    value && g_utf8_validate (value, -1, NULL)) {
+							g_ptr_array_add (predicates_temp, g_strdup (TRACKER_EVOLUTION_PREDICATE_TAG));
+							g_ptr_array_add (values_temp, g_strdup_printf ("%s=%s", name, value));
+						}
+						g_free(name);
+						g_free(value);
+					}
+					g_free (p);
+
+					if (values_temp->len != predicates_temp->len)
+						g_critical ("values_temp->len != predicates_temp->len");
+
+					max = MIN (values_temp->len, predicates_temp->len);
+
+					values = (gchar **) g_malloc0 (sizeof (gchar*) * max + 1);
+					predicates = (gchar **) g_malloc0 (sizeof (gchar*) * max + 1);
+
+					for (j = 0; j < max; j++) {
+						predicates[j] = predicates_temp->pdata[j];
+						values[j] = values_temp->pdata[j];
+					}
+
+					predicates[j] = NULL;
+					values[j] = NULL;
+
+					/* This is not a path but a URI, don't use the 
+					 * OS's directory separator here */
+
+					g_ptr_array_add (subjects_a, g_strdup_printf ("%s%s/%s", em_uri, 
+										      iter->full_name, uid));
+
+					g_ptr_array_add (predicates_array, predicates);
+					g_ptr_array_add (values_array, values);
+
+					g_ptr_array_free (predicates_temp, TRUE);
+					g_ptr_array_free (values_temp, TRUE);
+
+					count++;
+				}
+
+				if (count > MAX_BEFORE_SEND) {
+
+					/* Yield per MAX_BEFORE_SEND. This function is 
+					 * called as a result of a DBus call, so it runs
+					 * in the mainloop. Therefore, yield he mainloop
+					 * sometimes, indeed */
+
+					g_main_context_iteration (NULL, TRUE);
+
+					more = TRUE;
+					break;
+				}
+
+				more = FALSE;
+			}
+
+
+			if (count > 0) {
+				gchar **subjects;
+
+				subjects = (gchar **) g_malloc0 (sizeof (gchar *) * subjects_a->len + 1);
+				for (i = 0; i < subjects_a->len; i++)
+					subjects[i] = g_ptr_array_index (subjects_a, i);
+				subjects[i] = NULL;
+
+				dbus_g_proxy_call_no_reply (info->registrar,
+							    "SetMany",
+							    G_TYPE_STRV, subjects,
+							    TRACKER_TYPE_G_STRV_ARRAY, predicates_array,
+							    TRACKER_TYPE_G_STRV_ARRAY, values_array,
+							    G_TYPE_INVALID, 
+							    G_TYPE_INVALID);
+
+				g_strfreev (subjects);
+			}
+
+			g_ptr_array_free (subjects_a, TRUE);
+
+			for (i = 0; i < values_array->len; i++)
+				g_strfreev (values_array->pdata[i]); 
+			g_ptr_array_free (values_array, TRUE);
+
+			for (i = 0; i < predicates_array->len; i++)
+				g_strfreev (predicates_array->pdata[i]); 
+			g_ptr_array_free (predicates_array, TRUE);
+		}
+
+		sqlite3_finalize (stmt);
+		sqlite3_free (query);
+
+		g_mutex_unlock (cdb_r->lock);
+
+		if (iter->child) {
+			introduce_walk_folders_in_folder (self, iter->child, store, account_uri, info);
+		}
+
+		iter = iter->next;
+	}
+
+	g_free (em_uri);
+}
+
+/* Initial notify of deletes that are more recent than last_checkout, called in 
+ * the mainloop */
+
+static void
+introduce_store_deal_with_deleted (TrackerEvolutionPlugin *self, 
+				   CamelStore *store, 
+				   char *account_uri, 
+				   gpointer user_data)
+{
+	ClientRegistry *info = user_data;
+	gboolean more = TRUE;
+	gchar *query;
+	sqlite3_stmt *stmt = NULL;
+	CamelDB *cdb_r;
+	guint i, ret;
+	gchar *em_uri = em_uri_from_camel (account_uri);
+
+	query = sqlite3_mprintf ("SELECT uid, mailbox FROM Deletes WHERE modified > %" PRIu64, 
+				 info->last_checkout);
+
+	cdb_r = store->cdb_r;
+
+	g_mutex_lock (cdb_r->lock);
+
+	sqlite3_prepare_v2 (cdb_r->db, query, -1, &stmt, NULL);
+
+	ret = SQLITE_OK;
+
+	while (more) {
+		GPtrArray *subjects_a = g_ptr_array_new ();
+		guint count = 0;
+
+		more = FALSE;
+
+		while (ret == SQLITE_OK || ret == SQLITE_BUSY || ret == SQLITE_ROW) {
+			const gchar *uid;
+			const gchar *mailbox;
+
+			ret = sqlite3_step (stmt);
+
+			if (ret == SQLITE_BUSY) {
+				usleep (10);
+				continue;
+			}
+
+			if ((ret != SQLITE_OK && ret != SQLITE_ROW) || ret == SQLITE_DONE) {
+				more = FALSE;
+				break;
+			}
+
+			uid     = (const gchar *) sqlite3_column_text (stmt, 0);
+			mailbox = (const gchar *) sqlite3_column_text (stmt, 1);
+
+			/* This is not a path but a URI, don't use the OS's 
+			 * directory separator here */
+
+			g_ptr_array_add (subjects_a, g_strdup_printf ("%s%s/%s", em_uri, 
+								      mailbox, uid));
+
+			if (count > MAX_BEFORE_SEND) {
+
+				/* Yield per MAX_BEFORE_SEND. This function is 
+				 * called as a result of a DBus call, so it runs
+				 * in the mainloop. Therefore, yield he mainloop
+				 * sometimes, indeed */
+
+				g_main_context_iteration (NULL, TRUE);
+
+				more = TRUE;
+				break;
+			}
+
+			count++;
+
+			more = FALSE;
+		}
+
+		if (count > 0) {
+			gchar **subjects;
+
+			subjects = (gchar **) g_malloc0 (sizeof (gchar *) * subjects_a->len + 1);
+			for (i = 0; i < subjects_a->len; i++)
+				subjects[i] = g_ptr_array_index (subjects_a, i);
+			subjects[i] = NULL;
+
+			dbus_g_proxy_call_no_reply (info->registrar,
+						    "UnsetMany",
+						    G_TYPE_STRV, subjects,
+						    G_TYPE_INVALID,
+						    G_TYPE_INVALID);
+
+			g_strfreev (subjects);
+		}
+
+		g_ptr_array_free (subjects_a, TRUE);
+
+	}
+
+	sqlite3_finalize (stmt);
+	sqlite3_free (query);
+
+	g_mutex_unlock (cdb_r->lock);
+
+	g_free (em_uri);
+}
+
+/* Get the oldest date in all of the deleted-tables, called in the mainloop */
+
+static guint64
+get_last_deleted_time (TrackerEvolutionPlugin *self)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (self);
+	guint64 smallest = (guint64) time (NULL);
+
+	if (priv->accounts) {
+		EIterator *it;
+
+		for (it = e_list_get_iterator (E_LIST (priv->accounts)); e_iterator_is_valid (it); e_iterator_next (it)) {
+			EAccount *account = (EAccount *) e_iterator_get (it);
+			CamelProvider *provider;
+			CamelStore *store;
+			CamelException ex;
+			char *uri;
+			CamelDB *cdb_r;
+			sqlite3_stmt *stmt = NULL;
+			gchar *query;
+			guint ret = SQLITE_OK;
+			guint64 latest = smallest;
+
+			camel_exception_init (&ex);
+
+			if (!account->enabled || !(uri = account->source->url))
+				continue;
+
+			if (!(provider = camel_provider_get(uri, NULL))) {
+				camel_exception_clear (&ex);
+				continue;
+			}
+
+			if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
+				continue;
+
+			if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
+				camel_exception_clear (&ex);
+				continue;
+			}
+
+			cdb_r = store->cdb_r;
+
+			query = sqlite3_mprintf ("SELECT time FROM Deletes ORDER BY time LIMIT 1");
+
+			g_mutex_lock (cdb_r->lock);
+
+			ret = sqlite3_prepare_v2 (cdb_r->db, query, -1, &stmt, NULL);
+
+			ret = sqlite3_step (stmt);
+			if (ret == SQLITE_OK || ret == SQLITE_ROW)
+				latest = sqlite3_column_int64 (stmt, 0);
+
+			if (latest < smallest)
+				smallest = latest;
+
+			sqlite3_finalize (stmt);
+			sqlite3_free (query);
+
+			g_mutex_unlock (cdb_r->lock);
+
+		}
+
+		g_object_unref (it);
+	}
+
+	return smallest;
+}
+
+
+static void
+register_walk_folders_in_folder (TrackerEvolutionPlugin *self, 
+				 CamelFolderInfo *iter, 
+				 CamelStore *store, 
+				 gchar *account_uri)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (self);
+
+	while (iter) {
+		CamelFolder *folder;
+
+		folder = camel_store_get_folder (store, iter->full_name, 0, NULL);
+
+		if (folder) {
+			guint hook_id;
+			FolderRegistry *registry;
+
+			registry = folder_registry_new (account_uri, folder, self);
+
+			g_static_rec_mutex_lock (priv->mutex);
+
+			if (!priv->registered_folders) {
+				priv->registered_folders = g_hash_table_new_full (g_int_hash, g_int_equal,
+										  (GDestroyNotify) NULL,
+										  (GDestroyNotify) folder_registry_free);
+				priv->cached_folders = g_hash_table_new_full (g_str_hash, g_str_equal,
+									      (GDestroyNotify) g_free,
+									      (GDestroyNotify) NULL);
+			}
+
+			hook_id = camel_object_hook_event (folder, "folder_changed", 
+							   CAMEL_CALLBACK (on_folder_summary_changed), 
+							   registry->hook_info);
+			registry->hook_info->hook_id = hook_id;
+
+			g_hash_table_replace (priv->registered_folders, &hook_id, 
+					      registry);
+			g_hash_table_replace (priv->cached_folders, g_strdup (iter->full_name), 
+					      folder);
+
+			g_static_rec_mutex_unlock (priv->mutex);
+
+			camel_object_unref (folder);
+		}
+
+		if (iter->child) {
+			register_walk_folders_in_folder (self, iter->child, store, 
+							 account_uri);
+		}
+
+		iter = iter->next;
+	}
+}
+
+
+static void
+unregister_walk_folders_in_folder (TrackerEvolutionPlugin *self, 
+				   CamelFolderInfo *titer, 
+				   CamelStore *store, 
+				   gchar *account_uri)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (self);
+
+	while (titer) {
+		CamelFolder *folder;
+		GHashTableIter iter;
+		gpointer key, value;
+
+		folder = camel_store_get_folder (store, titer->full_name, 0, NULL);
+
+		if (folder) {
+			g_static_rec_mutex_lock (priv->mutex);
+
+			g_hash_table_iter_init (&iter, priv->registered_folders);
+			while (g_hash_table_iter_next (&iter, &key, &value)) {
+				FolderRegistry *registry = value;
+
+				if (folder == registry->folder) {
+					g_hash_table_remove (priv->cached_folders, titer->full_name);
+					g_hash_table_iter_remove (&iter);
+					break;
+				}
+			}
+
+			camel_object_unref (folder);
+
+			g_static_rec_mutex_unlock (priv->mutex);
+		}
+
+		if (titer->child) {
+			unregister_walk_folders_in_folder (self, titer->child, store, 
+							   account_uri);
+		}
+
+		titer = titer->next;
+	}
+}
+
+static void
+client_registry_info_free (ClientRegistry *info)
+{
+	if (info->signal != 0) /* known (see below) */
+		g_signal_handler_disconnect (info->registrar, info->signal);
+	g_object_unref (info->registrar);
+	g_slice_free (ClientRegistry, info);
+}
+
+static ClientRegistry*
+client_registry_info_copy (ClientRegistry *info)
+{
+	ClientRegistry *ninfo = g_slice_new0 (ClientRegistry);
+
+	ninfo->signal = 0; /* known */
+	ninfo->last_checkout = info->last_checkout;
+	ninfo->registrar = g_object_ref (info->registrar);
+
+	return ninfo;
+}
+
+static gboolean
+on_got_folderinfo_introduce (CamelStore *store, 
+			     CamelFolderInfo *iter, 
+			     void *data)
+{
+	IntroductionInfo *intro_info = data;
+
+	introduce_walk_folders_in_folder (intro_info->self, iter, store, 
+					  intro_info->account_uri, 
+					  intro_info->info);
+
+	client_registry_info_free (intro_info->info);
+	g_free (intro_info->account_uri);
+	g_object_unref (intro_info->self);
+	g_free (intro_info);
+
+	return TRUE;
+}
+
+static void
+introduce_account_to (TrackerEvolutionPlugin *self, 
+		      EAccount *account, 
+		      ClientRegistry *info)
+{
+	CamelProvider *provider;
+	CamelStore *store;
+	CamelException ex;
+	char *uri, *account_uri, *ptr;
+	IntroductionInfo *intro_info;
+
+	if (!account->enabled || !(uri = account->source->url))
+		return;
+
+	camel_exception_init (&ex);
+	if (!(provider = camel_provider_get(uri, &ex))) {
+		camel_exception_clear (&ex);
+		return;
+	}
+
+	if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
+		return;
+
+	if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
+		camel_exception_clear (&ex);
+		return;
+	}
+
+	account_uri = g_strdup (uri);
+
+	ptr = strchr (account_uri, ';');
+
+	if (ptr)
+		*ptr = '\0';
+
+	introduce_store_deal_with_deleted (self, store, account_uri, info);
+
+	intro_info = g_new0 (IntroductionInfo, 1);
+
+	intro_info->self = g_object_ref (self);
+	intro_info->info = client_registry_info_copy (info);
+	intro_info->account_uri = account_uri; /* is freed in on_got above */
+
+	mail_get_folderinfo (store, NULL, on_got_folderinfo_introduce, intro_info);
+
+	camel_object_unref (store);
+
+}
+
+
+static void
+introduce_account_to_all (TrackerEvolutionPlugin *self, 
+			  EAccount *account)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (self);
+	GList *copy = priv->registered_clients;
+
+	while (copy) {
+		ClientRegistry *info = copy->data;
+		introduce_account_to (self, account, info);
+		copy = g_list_next (copy);
+	}
+
+}
+
+static void
+introduce_accounts_to (TrackerEvolutionPlugin *self, 
+		       ClientRegistry *info)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (self);
+	EIterator *it;
+
+	for (it = e_list_get_iterator (E_LIST (priv->accounts)); e_iterator_is_valid (it); e_iterator_next (it))
+		introduce_account_to (self, (EAccount *) e_iterator_get (it), info);
+
+	g_object_unref (it);
+}
+
+
+static void
+register_client (TrackerEvolutionPlugin *self, 
+		 guint64 last_checkout, 
+		 DBusGProxy *registrar, 
+		 guint dsignal)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (self);
+	guint64 too_old = get_last_deleted_time (self);
+	ClientRegistry *info = g_slice_new (ClientRegistry);
+
+	info->signal = dsignal;
+	info->registrar = g_object_ref (registrar);
+
+	if (last_checkout < too_old) {
+		dbus_g_proxy_call_no_reply (registrar,
+					    "Cleanup",
+					    G_TYPE_INVALID,
+					    G_TYPE_INVALID);
+		info->last_checkout = 0;
+	} else
+		info->last_checkout = last_checkout;
+
+	introduce_accounts_to (self, info);
+
+	priv->registered_clients = 
+		g_list_prepend (priv->registered_clients, info);
+
+}
+
+
+static void
+metadata_set_many (TrackerEvolutionPlugin *self, 
+		   GStrv subjects, 
+		   GPtrArray *predicates, 
+		   GPtrArray *values)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (self);
+	GHashTableIter iter;
+	gpointer key, value;
+
+	g_static_rec_mutex_lock (priv->mutex);
+
+	g_hash_table_iter_init (&iter, priv->registrars);
+
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		DBusGProxy *registrar = value;
+
+		dbus_g_proxy_call_no_reply (registrar,
+					    "SetMany",
+					    G_TYPE_STRV, subjects,
+					    TRACKER_TYPE_G_STRV_ARRAY, predicates,
+					    TRACKER_TYPE_G_STRV_ARRAY, values,
+					    G_TYPE_INVALID, 
+					    G_TYPE_INVALID);
+	}
+
+	g_static_rec_mutex_unlock (priv->mutex);
+}
+
+static void
+metadata_unset_many (TrackerEvolutionPlugin *self, 
+		     GStrv subjects)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (self);
+	GHashTableIter iter;
+	gpointer key, value;
+
+	g_static_rec_mutex_lock (priv->mutex);
+
+	g_hash_table_iter_init (&iter, priv->registrars);
+
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		DBusGProxy *registrar = value;
+
+		dbus_g_proxy_call_no_reply (registrar,
+					    "UnsetMany",
+					    G_TYPE_STRV, subjects,
+					    G_TYPE_INVALID, 
+					    G_TYPE_INVALID);
+	}
+
+	g_static_rec_mutex_unlock (priv->mutex);
+
+}
+
+static void
+on_folder_created (CamelStore *store, void *event_data, 
+		   StoreRegistry *registry)
+{
+	unregister_account (registry->self, registry->account);
+	register_account (registry->self, registry->account);
+	introduce_account_to_all (registry->self, registry->account);
+}
+
+static void
+on_folder_deleted (CamelStore *store, 
+		   void *event_data, 
+		   StoreRegistry *registry)
+{
+	unregister_account (registry->self, registry->account);
+	register_account (registry->self, registry->account);
+	introduce_account_to_all (registry->self, registry->account);
+}
+
+static void
+on_folder_renamed (CamelStore *store, 
+		   CamelRenameInfo *info, 
+		   StoreRegistry *registry)
+{
+	unregister_account (registry->self, registry->account);
+	register_account (registry->self, registry->account);
+	introduce_account_to_all (registry->self, registry->account);
+}
+
+static StoreRegistry*
+store_registry_new (gpointer co, 
+		    EAccount *account, 
+		    TrackerEvolutionPlugin *self)
+{
+	StoreRegistry *registry = g_slice_new (StoreRegistry);
+
+	registry->store = co;
+	registry->account = account; /* weak */
+	registry->self = self; /* weak */
+	camel_object_ref (co);
+
+	return registry;
+}
+
+static void
+store_registry_free (StoreRegistry *registry) 
+{
+	camel_object_remove_event (registry->store, registry->hook_id);
+	camel_object_unref (registry->store);
+	g_slice_free (StoreRegistry, registry);
+}
+
+
+static gboolean
+on_got_folderinfo_register (CamelStore *store, 
+			    CamelFolderInfo *iter, 
+			    void *data)
+{
+	RegisterInfo *reg_info = data;
+	TrackerEvolutionPlugin *self = reg_info->self;
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (self);
+	EAccount *account = reg_info->account;
+	StoreRegistry *registry;
+	gchar *uri = reg_info->uri;
+	guint hook_id;
+
+	g_static_rec_mutex_lock (priv->mutex);
+
+	if (!priv->registered_stores)
+		priv->registered_stores = g_hash_table_new_full (g_int_hash, g_int_equal,
+								 (GDestroyNotify) NULL,
+								 (GDestroyNotify) store_registry_free);
+
+	/* Hook up catching folder changes in the store */
+	registry = store_registry_new (store, account, self);
+	hook_id = camel_object_hook_event (store, "folder_created", 
+					   CAMEL_CALLBACK (on_folder_created), 
+					   registry);
+	registry->hook_id = hook_id;
+	g_hash_table_replace (priv->registered_stores, &hook_id, registry);
+
+	registry = store_registry_new (store, account, self);
+	hook_id = camel_object_hook_event (store, "folder_renamed", 
+					   CAMEL_CALLBACK (on_folder_renamed), 
+					   registry);
+	registry->hook_id = hook_id;
+	g_hash_table_replace (priv->registered_stores, &hook_id, registry);
+
+	registry = store_registry_new (store, account, self);
+	hook_id = camel_object_hook_event (store, "folder_deleted", 
+					   CAMEL_CALLBACK (on_folder_deleted), 
+					   registry);
+	registry->hook_id = hook_id;
+	g_hash_table_replace (priv->registered_stores, &hook_id, registry);
+
+	g_static_rec_mutex_unlock (priv->mutex);
+
+	/* Register each folder to hook folder_changed everywhere */
+	register_walk_folders_in_folder (self, iter, store, uri);
+
+	g_object_unref (reg_info->account);
+	g_object_unref (reg_info->self);
+	g_free (reg_info->uri);
+	g_free (reg_info);
+
+	return TRUE;
+}
+
+static void
+register_account (TrackerEvolutionPlugin *self,
+		  EAccount *account)
+{
+	CamelProvider *provider;
+	CamelStore *store;
+	CamelException ex;
+	char *uri;
+	RegisterInfo *reg_info;
+
+	if (!account->enabled || !(uri = account->source->url))
+		return;
+
+	camel_exception_init (&ex);
+	if (!(provider = camel_provider_get(uri, &ex))) {
+		camel_exception_clear (&ex);
+		return;
+	}
+
+	if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
+		return;
+
+	if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
+		camel_exception_clear (&ex);
+		return;
+	}
+
+	reg_info = g_new0 (RegisterInfo, 1);
+
+	reg_info->self = g_object_ref (self);
+	reg_info->uri = g_strdup (uri);
+	reg_info->account = g_object_ref (account);
+
+	/* Get the account's folder-info and register it asynchronously */
+	mail_get_folderinfo (store, NULL, on_got_folderinfo_register, reg_info);
+
+	camel_object_unref (store);
+}
+
+static gboolean
+on_got_folderinfo_unregister (CamelStore *store, 
+			      CamelFolderInfo *titer,
+			      void *data)
+{
+	RegisterInfo *reg_info = data;
+	TrackerEvolutionPlugin *self = reg_info->self;
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (self);
+	gchar *uri = reg_info->uri;
+	GHashTableIter iter;
+	gpointer key, value;
+
+	unregister_walk_folders_in_folder (self, titer, store, uri);
+
+	g_static_rec_mutex_lock (priv->mutex);
+
+	if (priv->registered_stores) {
+		g_hash_table_iter_init (&iter, priv->registered_stores);
+
+		while (g_hash_table_iter_next (&iter, &key, &value)) {
+			if (value == store) 
+				g_hash_table_iter_remove (&iter);
+		}
+	}
+
+	g_static_rec_mutex_unlock (priv->mutex);
+
+	g_object_unref (reg_info->self);
+	g_free (reg_info->uri);
+	g_free (reg_info);
+
+	return TRUE;
+}
+
+static void
+unregister_account (TrackerEvolutionPlugin *self,
+		    EAccount *account)
+{
+	CamelProvider *provider;
+	CamelStore *store;
+	CamelException ex;
+	char *uri;
+	RegisterInfo *reg_info;
+
+
+	camel_exception_init (&ex);
+	if (!(provider = camel_provider_get(uri, &ex))) {
+		camel_exception_clear (&ex);
+		return;
+	}
+
+	if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
+		return;
+
+	if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
+		camel_exception_clear (&ex);
+		return;
+	}
+
+	reg_info = g_new0 (RegisterInfo, 1);
+
+	reg_info->self = g_object_ref (self);
+	reg_info->uri = g_strdup (uri);
+	reg_info->account = NULL;
+
+	/* Get the account's folder-info and unregister asynchronously */
+	mail_get_folderinfo (store, NULL, on_got_folderinfo_unregister, reg_info);
+
+	camel_object_unref (store);
+}
+
+static void
+on_account_added (EAccountList *list, 
+		  EAccount *account, 
+		  TrackerEvolutionPlugin *self)
+{
+	register_account (self, account);
+	introduce_account_to_all (self, account);
+}
+
+static void
+on_account_removed (EAccountList *list,
+		    EAccount *account,
+		    TrackerEvolutionPlugin *self)
+{
+	unregister_account (self, account);
+}
+
+static void
+on_account_changed (EAccountList *list, 
+		    EAccount *account,
+		    TrackerEvolutionPlugin *self)
+{
+	unregister_account (self, account);
+	register_account (self, account);
+	introduce_account_to_all (self, account);
+}
+
+static void
+disable_plugin (void) 
+{
+	GError *error = NULL;
+	guint result;
+
+	org_freedesktop_DBus_release_name (dbus_proxy, TRACKER_EVOLUTION_MANAGER_SERVICE, 
+					   &result, &error);
+
+	if (!error) {
+		if (manager) {
+			g_object_unref (manager);
+			manager = NULL;
+		}
+
+		if (dbus_proxy) {
+			g_object_unref (dbus_proxy);
+			dbus_proxy = NULL;
+		}
+	} else {
+		g_warning ("Could not setup DBus, ReleaseName of %s: %s\n", 
+			   TRACKER_EVOLUTION_MANAGER_SERVICE, error->message);
+
+		g_error_free (error);
+	}
+}
+
+static void
+enable_plugin (void)
+{
+	DBusGConnection *connection;
+	GError *error = NULL;
+	guint result;
+
+	if (dbus_proxy && manager)
+		return;
+
+	if ((dbus_proxy && !manager) || (!dbus_proxy && manager))
+		disable_plugin ();
+
+	if ((dbus_proxy && !manager) || (!dbus_proxy && manager))
+		return;
+
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+
+	if (error)
+		goto error_handler;
+
+	dbus_proxy = dbus_g_proxy_new_for_name (connection, 
+						DBUS_SERVICE_DBUS,
+						DBUS_PATH_DBUS,
+						DBUS_INTERFACE_DBUS);
+
+	if (!org_freedesktop_DBus_request_name (dbus_proxy, TRACKER_EVOLUTION_MANAGER_SERVICE,
+						DBUS_NAME_FLAG_DO_NOT_QUEUE,
+						&result, &error)) {
+
+		g_warning ("Could not setup DBus, failed at RequestName for %s\n", 
+			   TRACKER_EVOLUTION_MANAGER_SERVICE);
+
+		goto error_handler;
+	}
+
+	if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+
+		g_warning ("Could not setup DBus, can't become primary owner of %s\n", 
+			   TRACKER_EVOLUTION_MANAGER_SERVICE);
+
+		goto error_handler;
+	}
+
+	if (error)
+		goto error_handler;
+
+	manager = g_object_new (TRACKER_TYPE_EVOLUTION_PLUGIN, 
+				"connection", connection, NULL);
+
+	dbus_g_object_type_install_info (G_OBJECT_TYPE (manager), 
+					 &dbus_glib_tracker_evolution_plugin_object_info);
+
+	dbus_g_connection_register_g_object (connection, 
+					     TRACKER_EVOLUTION_MANAGER_PATH, 
+					     G_OBJECT (manager));
+
+	error_handler:
+
+	if (error) {
+		g_warning ("Could not setup DBus, %s\n", error->message);
+		disable_plugin();
+		g_error_free (error);
+	}
+}
+
+static gboolean 
+do_remove_or_not (gpointer key, gpointer value, gpointer user_data)
+{
+	if (user_data == value)
+		return TRUE;
+
+	return FALSE;
+}
+
+static void
+service_gone (DBusGProxy *lproxy, TrackerEvolutionPlugin *plugin)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (plugin);
+	GList *copy = priv->registered_clients;
+	GList *to_delete = NULL;
+
+	g_static_rec_mutex_lock (priv->mutex);
+
+	g_hash_table_foreach_remove (priv->registrars, 
+				     do_remove_or_not,
+				     lproxy);
+
+	while (copy) {
+		ClientRegistry *creg = copy->data;
+		if (creg->registrar == lproxy)
+			to_delete = g_list_prepend (to_delete, copy);
+		copy = g_list_next (copy);
+	}
+
+	copy = to_delete;
+	while (copy) {
+		GList *node = copy->data;
+		ClientRegistry *creg = node->data;
+		priv->registered_clients = g_list_delete_link (priv->registered_clients, node);
+		client_registry_info_free (creg);
+		copy = g_list_next (copy);
+	}
+
+	g_list_free (to_delete);
+
+	g_static_rec_mutex_unlock (priv->mutex);
+}
+
+void 
+tracker_evolution_plugin_register  (TrackerEvolutionPlugin *plugin, 
+				    gchar *registrar_path,
+				    guint last_checkout, 
+				    DBusGMethodInvocation *context,
+				    GError *derror)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (plugin);
+	gchar *sender;
+	DBusGProxy *registrar;
+	guint dsignal;
+
+	g_static_rec_mutex_lock (priv->mutex);
+
+	sender = dbus_g_method_get_sender (context);
+
+	registrar = dbus_g_proxy_new_for_name (priv->connection, sender, 
+					       registrar_path,
+					       TRACKER_EVOLUTION_REGISTRAR_INTERFACE);
+
+	g_hash_table_replace (priv->registrars, g_strdup (sender), 
+			      registrar);
+
+	dsignal = g_signal_connect (registrar, "destroy",
+				    G_CALLBACK (service_gone),
+				    plugin);
+
+	g_static_rec_mutex_unlock (priv->mutex);
+
+	/* Passing uint64 over DBus ain't working :-\ */
+	register_client (plugin, (guint64) last_checkout, registrar, dsignal);
+
+	dbus_g_method_return (context);
+}
+
+
+int
+e_plugin_lib_enable (EPluginLib *ep, int enabled)
+{
+	g_static_rec_mutex_lock (&glock);
+
+	if (enabled)
+		enable_plugin ();
+	else
+		disable_plugin ();
+
+	g_static_rec_mutex_unlock (&glock);
+
+	return 0;
+}
+
+
+static void
+tracker_evolution_plugin_finalize (GObject *plugin)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (plugin);
+
+	g_static_rec_mutex_lock (priv->mutex);
+
+	g_list_foreach (priv->registered_clients,
+			(GFunc) client_registry_info_free,
+			NULL);
+
+	g_list_free (priv->registered_clients);
+
+	if (priv->registered_folders) {
+		g_hash_table_destroy (priv->registered_folders);
+		g_hash_table_destroy (priv->cached_folders);
+		priv->cached_folders = NULL;
+		priv->registered_folders = NULL;
+	}
+
+	if (priv->registered_stores) {
+		g_hash_table_destroy (priv->registered_stores);
+		priv->registered_stores = NULL;
+	}
+
+	g_object_unref (priv->accounts);
+
+	g_hash_table_destroy (priv->registrars);
+
+	if (priv->connection)
+		dbus_g_connection_unref (priv->connection);
+
+	g_static_rec_mutex_unlock (priv->mutex);
+
+	g_slice_free (GStaticRecMutex, priv->mutex);
+
+	G_OBJECT_CLASS (tracker_evolution_plugin_parent_class)->finalize (plugin);
+}
+
+static void 
+tracker_evolution_plugin_set_connection (TrackerEvolutionPlugin *plugin, 
+					 DBusGConnection *connection)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (plugin);
+
+	if (priv->connection)
+		dbus_g_connection_unref (priv->connection);
+
+	priv->connection = dbus_g_connection_ref (connection);
+}
+
+static void
+tracker_evolution_plugin_set_property (GObject     *plugin,
+				      guint         prop_id,
+				      const GValue *value,
+				      GParamSpec   *pspec)
+{
+	switch (prop_id) {
+	case PROP_CONNECTION:
+		tracker_evolution_plugin_set_connection (TRACKER_EVOLUTION_PLUGIN (plugin),
+							 g_value_get_pointer (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (plugin, prop_id, pspec);
+	}
+}
+
+static void
+tracker_evolution_plugin_get_property (GObject   *plugin,
+				      guint       prop_id,
+				      GValue     *value,
+				      GParamSpec *pspec)
+{
+	TrackerEvolutionPluginPrivate *priv;
+
+	priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (plugin);
+
+	switch (prop_id) {
+	case PROP_CONNECTION:
+		g_value_set_pointer (value, priv->connection);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (plugin, prop_id, pspec);
+	}
+}
+
+static void
+tracker_evolution_plugin_class_init (TrackerEvolutionPluginClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = tracker_evolution_plugin_finalize;
+	object_class->set_property = tracker_evolution_plugin_set_property;
+	object_class->get_property = tracker_evolution_plugin_get_property;
+
+	g_object_class_install_property (object_class,
+					 PROP_CONNECTION,
+					 g_param_spec_pointer ("connection",
+							       "DBus connection",
+							       "DBus connection",
+							       G_PARAM_READWRITE |
+							       G_PARAM_CONSTRUCT));
+
+	g_type_class_add_private (object_class, sizeof (TrackerEvolutionPluginPrivate));
+}
+
+static void
+tracker_evolution_plugin_init (TrackerEvolutionPlugin *plugin)
+{
+	TrackerEvolutionPluginPrivate *priv = TRACKER_EVOLUTION_PLUGIN_GET_PRIVATE (plugin);
+	EIterator *it;
+
+	priv->mutex = g_slice_new0 (GStaticRecMutex);
+	g_static_rec_mutex_init (priv->mutex);
+
+	g_static_rec_mutex_lock (priv->mutex);
+
+	priv->registrars = g_hash_table_new_full (g_str_hash, g_str_equal,
+						  (GDestroyNotify) g_free, 
+						  (GDestroyNotify) g_object_unref);
+
+
+	priv->cached_folders = NULL;
+	priv->registered_folders = NULL;
+	priv->registered_stores = NULL;
+	priv->registered_clients = NULL;
+
+	g_static_rec_mutex_unlock (priv->mutex);
+
+	priv->accounts = g_object_ref (mail_config_get_accounts ());
+
+	for (it = e_list_get_iterator (E_LIST (priv->accounts)); e_iterator_is_valid (it); e_iterator_next (it))
+		register_account (plugin, (EAccount *) e_iterator_get (it));
+
+	g_object_unref (it);
+
+	g_signal_connect (priv->accounts, "account-added", 
+			  G_CALLBACK (on_account_added), plugin);
+	g_signal_connect (priv->accounts, "account-removed", 
+			  G_CALLBACK (on_account_removed), plugin);
+	g_signal_connect (priv->accounts, "account-changed", 
+			  G_CALLBACK (on_account_changed), plugin);
+}

Added: trunk/src/plugins/evolution/tracker-evolution-plugin.h
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/tracker-evolution-plugin.h	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#ifndef __TRACKER_EVOLUTION_PLUGIN_H__
+#define __TRACKER_EVOLUTION_PLUGIN_H__
+
+#include <dbus/dbus-glib-bindings.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "tracker-evolution-common.h"
+
+#define TRACKER_TYPE_EVOLUTION_PLUGIN          (tracker_evolution_plugin_get_type())
+#define TRACKER_EVOLUTION_PLUGIN(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_EVOLUTION_PLUGIN, TrackerEvolutionPlugin))
+#define TRACKER_EVOLUTION_PLUGIN_CLASS(c)      (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_EVOLUTION_PLUGIN, TrackerEvolutionPluginClass))
+#define TRACKER_EVOLUTION_PLUGIN_GET_CLASS(o)  (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_EVOLUTION_PLUGIN, TrackerEvolutionPluginClass))
+
+G_BEGIN_DECLS
+
+typedef struct TrackerEvolutionPlugin TrackerEvolutionPlugin;
+typedef struct TrackerEvolutionPluginClass TrackerEvolutionPluginClass;
+
+struct TrackerEvolutionPlugin {
+	GObject parent;
+};
+
+struct TrackerEvolutionPluginClass {
+	GObjectClass parent;
+};
+
+GType tracker_evolution_plugin_get_type (void);
+
+void tracker_evolution_plugin_register  (TrackerEvolutionPlugin *object, 
+					 gchar *registrar_path,
+					 guint last_checkout, 
+					 DBusGMethodInvocation *context,
+					 GError *derror);
+
+G_END_DECLS
+
+#endif /* __TRACKER_EVOLUTION_PLUGIN_H__ */

Added: trunk/src/plugins/evolution/tracker-evolution-plugin.xml
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/tracker-evolution-plugin.xml	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<node name="/">
+  <interface name="org.gnome.evolution.metadata.Manager">  
+    <method name="Register">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="o" name="registrar_path" direction="in" />
+      <arg type="u" name="last_checkout" direction="in" />
+    </method>
+  </interface>
+</node>
+

Added: trunk/src/plugins/evolution/tracker-evolution-registrar.c
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/tracker-evolution-registrar.c	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,245 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#include "config.h"
+
+#include <libtracker-data/tracker-data-update.h>
+#define __TRACKER_EVOLUTION_REGISTRAR_C__
+#include "tracker-evolution-registrar.h"
+#include "tracker-evolution-registrar-glue.h"
+
+const DBusGMethodInfo *registrar_methods = dbus_glib_tracker_evolution_registrar_methods;
+
+#define TRACKER_EVOLUTION_REGISTRAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TRACKER_TYPE_EVOLUTION_REGISTRAR, TrackerEvolutionRegistrarPrivate))
+
+G_DEFINE_TYPE (TrackerEvolutionRegistrar, tracker_evolution_registrar, G_TYPE_OBJECT)
+
+/* This runs in-process of trackerd. It simply proxies everything to the indexer
+ * who wont always be running. Which is why this is needed (trackerd is always
+ * running, so it's more suitable to respond to Evolution's requests). */
+
+typedef struct {
+	DBusGProxy *idx_proxy;
+	DBusGConnection *connection;
+} TrackerEvolutionRegistrarPrivate;
+
+enum {
+	PROP_0,
+	PROP_CONNECTION
+};
+
+static void
+tracker_evolution_registrar_finalize (GObject *object)
+{
+	TrackerEvolutionRegistrarPrivate *priv = TRACKER_EVOLUTION_REGISTRAR_GET_PRIVATE (object);
+
+	if (priv->idx_proxy)
+		g_object_unref (priv->idx_proxy);
+
+	G_OBJECT_CLASS (tracker_evolution_registrar_parent_class)->finalize (object);
+}
+
+static void 
+tracker_evolution_registrar_set_connection (TrackerEvolutionRegistrar *object, 
+					    DBusGConnection *connection)
+{
+	TrackerEvolutionRegistrarPrivate *priv = TRACKER_EVOLUTION_REGISTRAR_GET_PRIVATE (object);
+
+	priv->connection = connection; /* weak */
+
+	priv->idx_proxy = dbus_g_proxy_new_for_name (priv->connection, 
+						     "org.freedesktop.Tracker.Indexer",
+						     TRACKER_EVOLUTION_INDEXER_PATH,
+						     TRACKER_EVOLUTION_REGISTRAR_INTERFACE);
+}
+
+static void
+tracker_evolution_registrar_set_property (GObject      *object,
+					  guint         prop_id,
+					  const GValue *value,
+					  GParamSpec   *pspec)
+{
+	switch (prop_id) {
+	case PROP_CONNECTION:
+		tracker_evolution_registrar_set_connection (TRACKER_EVOLUTION_REGISTRAR (object),
+							    g_value_get_pointer (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static void
+tracker_evolution_registrar_get_property (GObject    *object,
+					  guint       prop_id,
+					  GValue     *value,
+					  GParamSpec *pspec)
+{
+	TrackerEvolutionRegistrarPrivate *priv = TRACKER_EVOLUTION_REGISTRAR_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_CONNECTION:
+		g_value_set_pointer (value, priv->connection);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static void
+tracker_evolution_registrar_class_init (TrackerEvolutionRegistrarClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = tracker_evolution_registrar_finalize;
+	object_class->set_property = tracker_evolution_registrar_set_property;
+	object_class->get_property = tracker_evolution_registrar_get_property;
+
+	g_object_class_install_property (object_class,
+					 PROP_CONNECTION,
+					 g_param_spec_pointer ("connection",
+							       "DBus connection",
+							       "DBus connection",
+							       G_PARAM_READWRITE |
+							       G_PARAM_CONSTRUCT));
+
+	g_type_class_add_private (object_class, sizeof (TrackerEvolutionRegistrarPrivate));
+}
+
+static void
+tracker_evolution_registrar_init (TrackerEvolutionRegistrar *object)
+{
+}
+
+void
+tracker_evolution_registrar_set (TrackerEvolutionRegistrar *object, 
+				 const gchar *subject, 
+				 const GStrv predicates,
+				 const GStrv values,
+				 DBusGMethodInvocation *context,
+				 GError *derror)
+{
+	TrackerEvolutionRegistrarPrivate *priv = TRACKER_EVOLUTION_REGISTRAR_GET_PRIVATE (object);
+
+	dbus_async_return_if_fail (subject != NULL, context);
+
+	if (predicates && values) {
+
+		dbus_async_return_if_fail (g_strv_length (predicates) == 
+					   g_strv_length (values), context);
+
+		dbus_g_proxy_call_no_reply (priv->idx_proxy,
+					    "Set",
+					    G_TYPE_STRING, subject,
+					    G_TYPE_STRV, predicates,
+					    G_TYPE_STRV, values,
+					    G_TYPE_INVALID, 
+					    G_TYPE_INVALID);
+	}
+
+	dbus_g_method_return (context);
+}
+
+void
+tracker_evolution_registrar_set_many (TrackerEvolutionRegistrar *object, 
+				      const GStrv subjects, 
+				      const GPtrArray *predicates,
+				      const GPtrArray *values,
+				      DBusGMethodInvocation *context,
+				      GError *derror)
+{
+	TrackerEvolutionRegistrarPrivate *priv = TRACKER_EVOLUTION_REGISTRAR_GET_PRIVATE (object);
+	guint len;
+
+	dbus_async_return_if_fail (subjects != NULL, context);
+	dbus_async_return_if_fail (predicates != NULL, context);
+	dbus_async_return_if_fail (values != NULL, context);
+
+	len = g_strv_length (subjects);
+
+	dbus_async_return_if_fail (len == predicates->len, context);
+	dbus_async_return_if_fail (len == values->len, context);
+
+	dbus_g_proxy_call_no_reply (priv->idx_proxy,
+				    "SetMany",
+				    G_TYPE_STRV, subjects,
+				    TRACKER_TYPE_G_STRV_ARRAY, predicates,
+				    TRACKER_TYPE_G_STRV_ARRAY, values,
+				    G_TYPE_INVALID, 
+				    G_TYPE_INVALID);
+
+	dbus_g_method_return (context);
+}
+
+void
+tracker_evolution_registrar_unset_many (TrackerEvolutionRegistrar *object, 
+					const GStrv subjects, 
+					DBusGMethodInvocation *context,
+					GError *derror)
+{
+	TrackerEvolutionRegistrarPrivate *priv = TRACKER_EVOLUTION_REGISTRAR_GET_PRIVATE (object);
+
+	dbus_async_return_if_fail (subjects != NULL, context);
+
+	dbus_g_proxy_call_no_reply (priv->idx_proxy,
+				    "UnsetMany",
+				    G_TYPE_STRV, subjects,
+				    G_TYPE_INVALID, 
+				    G_TYPE_INVALID);
+
+	dbus_g_method_return (context);
+}
+
+void
+tracker_evolution_registrar_unset (TrackerEvolutionRegistrar *object, 
+				   const gchar *subject, 
+				   DBusGMethodInvocation *context,
+				   GError *derror)
+{
+	TrackerEvolutionRegistrarPrivate *priv = TRACKER_EVOLUTION_REGISTRAR_GET_PRIVATE (object);
+
+	dbus_async_return_if_fail (subject != NULL, context);
+
+	dbus_g_proxy_call_no_reply (priv->idx_proxy,
+				    "Unset",
+				    G_TYPE_STRING, subject,
+				    G_TYPE_INVALID, 
+				    G_TYPE_INVALID);
+
+	dbus_g_method_return (context);
+}
+
+void
+tracker_evolution_registrar_cleanup (TrackerEvolutionRegistrar *object, 
+				     DBusGMethodInvocation *context,
+				     GError *derror)
+{
+	TrackerEvolutionRegistrarPrivate *priv = TRACKER_EVOLUTION_REGISTRAR_GET_PRIVATE (object);
+
+	dbus_g_proxy_call_no_reply (priv->idx_proxy,
+				    "Cleanup",
+				    G_TYPE_INVALID, 
+				    G_TYPE_INVALID);
+
+	dbus_g_method_return (context);
+}

Added: trunk/src/plugins/evolution/tracker-evolution-registrar.h
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/tracker-evolution-registrar.h	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,88 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#ifndef __LIBTRACKER_EVOLUTION_REGISTRAR_H__
+#define __LIBTRACKER_EVOLUTION_REGISTRAR_H__
+
+#if !defined (TRACKER_ENABLE_INTERNALS) && !defined (TRACKER_COMPILATION)
+#error "TRACKER_ENABLE_INTERNALS not defined, this must be defined to use tracker's internal functions"
+#endif
+
+#include <dbus/dbus-glib-bindings.h>
+
+#include "tracker-evolution-common.h"
+
+G_BEGIN_DECLS
+
+#define TRACKER_TYPE_EVOLUTION_REGISTRAR          (tracker_evolution_registrar_get_type())
+#define TRACKER_EVOLUTION_REGISTRAR(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_EVOLUTION_REGISTRAR, TrackerEvolutionRegistrar))
+#define TRACKER_EVOLUTION_REGISTRAR_CLASS(c)      (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_EVOLUTION_REGISTRAR, TrackerEvolutionRegistrarClass))
+#define TRACKER_EVOLUTION_REGISTRAR_GET_CLASS(o)  (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_EVOLUTION_REGISTRAR, TrackerEvolutionRegistrarClass))
+
+G_BEGIN_DECLS
+
+#ifndef __TRACKER_EVOLUTION_REGISTRAR_C__
+extern const DBusGMethodInfo *registrar_methods;
+#endif
+
+typedef struct TrackerEvolutionRegistrar TrackerEvolutionRegistrar;
+typedef struct TrackerEvolutionRegistrarClass TrackerEvolutionRegistrarClass;
+
+struct TrackerEvolutionRegistrar {
+	GObject parent;
+};
+
+struct TrackerEvolutionRegistrarClass {
+	GObjectClass parent;
+};
+
+GType  tracker_evolution_registrar_get_type   (void);
+
+void  tracker_evolution_registrar_set         (TrackerEvolutionRegistrar *object, 
+					       const gchar *subject, 
+					       const GStrv predicates,
+					       const GStrv values,
+					       DBusGMethodInvocation *context,
+					       GError *derror);
+void  tracker_evolution_registrar_set_many    (TrackerEvolutionRegistrar *object, 
+					       const GStrv subjects, 
+					       const GPtrArray *predicates,
+					       const GPtrArray *values,
+					       DBusGMethodInvocation *context,
+					       GError *derror);
+void  tracker_evolution_registrar_unset_many  (TrackerEvolutionRegistrar *object, 
+					       const GStrv subjects, 
+					       DBusGMethodInvocation *context,
+					       GError *derror);
+void  tracker_evolution_registrar_unset       (TrackerEvolutionRegistrar *object, 
+					       const gchar *subject, 
+					       DBusGMethodInvocation *context,
+					       GError *derror);
+void  tracker_evolution_registrar_cleanup     (TrackerEvolutionRegistrar *object, 
+					       DBusGMethodInvocation *context,
+					       GError *derror);
+
+
+G_END_DECLS
+
+#endif /* __LIBTRACKER_EVOLUTION_REGISTRAR_H__ */

Added: trunk/src/plugins/evolution/tracker-evolution-registrar.xml
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/tracker-evolution-registrar.xml	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<node name="/">
+  <interface name="org.gnome.evolution.metadata.Registrar">
+
+  <method name="Set">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="s" name="subject" direction="in" />
+      <arg type="as" name="predicates" direction="in" />
+      <arg type="as" name="values" direction="in" />
+    </method>
+
+    <method name="SetMany">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="as" name="subjects" direction="in" />
+      <arg type="aas" name="predicates" direction="in" />
+      <arg type="aas" name="values" direction="in" />
+    </method>
+
+    <method name="Unset">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="s" name="subject" direction="in" />
+    </method>
+
+    <method name="UnsetMany">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="as" name="subjects" direction="in" />
+    </method>
+
+    <method name="Cleanup">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+    </method>
+
+  </interface>
+</node>

Added: trunk/src/plugins/evolution/tracker-evolution.c
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/tracker-evolution.c	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,358 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <time.h>
+
+#include <libtracker-data/tracker-data-manager.h>
+
+#include "tracker-evolution.h"
+#include "tracker-evolution-registrar.h"
+
+typedef struct {
+	TrackerConfig *config;
+	DBusGConnection *connection;
+	gboolean is_enabled;
+	DBusGProxy *dbus_proxy;
+	DBusGProxy *manager_proxy;
+	GObject *object;
+	gboolean deactivating;
+} EvolutionSupportPrivate;
+
+static GStaticPrivate private_key = G_STATIC_PRIVATE_INIT;
+
+static guint
+get_stored_last_checkout (void)
+{
+	return (guint) tracker_data_manager_get_db_option_int ("EvolutionLastCheckout");
+}
+
+static void
+set_stored_last_checkout (guint last_checkout)
+{
+	tracker_data_manager_set_db_option_int ("EvolutionLastCheckout", (gint) last_checkout);
+}
+
+static void
+deactivate_registrar (void)
+{
+	EvolutionSupportPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	set_stored_last_checkout (time(NULL));
+
+	if (private->object) {
+		g_object_unref (private->object);
+		private->object = NULL;
+	}
+
+	if (private->manager_proxy && !private->deactivating)
+		g_object_unref (private->manager_proxy);
+
+	private->manager_proxy = NULL;
+}
+
+static void
+deactivate_dbus_client (void)
+{
+	EvolutionSupportPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	deactivate_registrar ();
+
+	if (private->dbus_proxy) {
+		g_object_unref (private->dbus_proxy);
+		private->dbus_proxy = NULL;
+	}
+}
+
+static void
+on_manager_destroy (DBusGProxy *proxy, gpointer user_data)
+{
+	EvolutionSupportPrivate *private;
+	gboolean old_setting;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	old_setting = private->deactivating;
+
+	private->deactivating = TRUE;
+	deactivate_registrar ();
+	private->deactivating = old_setting;
+}
+
+
+static void
+activate_registrar (void)
+{
+	EvolutionSupportPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	if (private->object)
+		return;
+
+	private->manager_proxy = 
+		dbus_g_proxy_new_for_name (private->connection,
+					   TRACKER_EVOLUTION_MANAGER_SERVICE,
+					   TRACKER_EVOLUTION_MANAGER_PATH,
+					   TRACKER_EVOLUTION_MANAGER_INTERFACE);
+
+	/* If while we had a proxy for the manager the manager shut itself down,
+	 * then we'll get rid of our registrar too, in on_manager_destroy */
+
+	g_signal_connect (private->manager_proxy, "destroy",
+			  G_CALLBACK (on_manager_destroy), NULL);
+
+	if (private->manager_proxy) {
+		GError *error = NULL;
+		guint result;
+
+		/* Creation of the registrar */
+		if (!org_freedesktop_DBus_request_name (private->dbus_proxy, 
+							   TRACKER_EVOLUTION_REGISTRAR_SERVICE,
+							   DBUS_NAME_FLAG_DO_NOT_QUEUE,
+							   &result, &error)) {
+			g_critical ("Could not setup DBus, %s in use\n", TRACKER_EVOLUTION_REGISTRAR_SERVICE);
+			goto error_handler;
+		}
+
+		if (error)
+			goto error_handler;
+
+		private->object = g_object_new (TRACKER_TYPE_EVOLUTION_REGISTRAR, 
+						"connection", private->connection, 
+						NULL);
+
+		dbus_g_object_type_install_info (G_OBJECT_TYPE (private->object), 
+						 &registrar_methods);
+		dbus_g_connection_register_g_object (private->connection, 
+						     TRACKER_EVOLUTION_REGISTRAR_PATH, 
+						     private->object);
+
+		/* Registration of the registrar to the manager */
+		dbus_g_proxy_call_no_reply (private->manager_proxy, "Register",
+					    G_TYPE_OBJECT, private->object, /* TRACKER_EVOLUTION_REGISTRAR_PATH, */
+					    G_TYPE_UINT, get_stored_last_checkout (),
+					    G_TYPE_INVALID,
+					    G_TYPE_INVALID);
+
+		error_handler:
+
+		if (error) {
+			g_critical ("Could not setup DBus, %s\n", error->message);
+			g_error_free (error);
+		}
+	}
+}
+
+static void
+name_owner_changed_cb (DBusGProxy *proxy, 
+		       gchar *name, 
+		       gchar *old_owner, 
+		       gchar *new_owner, 
+		       gpointer user_data)
+{
+
+	/* If we receive a NameOwnerChanged about the manager's service */
+
+	if (g_strcmp0 (name, TRACKER_EVOLUTION_MANAGER_SERVICE) == 0) {
+		if (tracker_is_empty_string (new_owner) && !tracker_is_empty_string (old_owner))
+			deactivate_registrar ();
+		if (tracker_is_empty_string (old_owner) && !tracker_is_empty_string (new_owner))
+			activate_registrar ();
+	}
+}
+
+static void
+list_names_reply_cb (DBusGProxy     *proxy,
+		     DBusGProxyCall *call,
+		     gpointer        user_data)
+{
+	GError *error = NULL;
+	GStrv names = NULL;
+	guint i = 0;
+
+	dbus_g_proxy_end_call (proxy, call, &error,
+			       G_TYPE_STRV, &names,
+			       G_TYPE_INVALID);
+
+	if (error) {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+		if (names)
+			g_strfreev (names); 
+		return;
+	}
+
+	while (names[i] != NULL) {
+		/* If the manager's service is found, start the registrar */
+		if (g_strcmp0 (names[i], TRACKER_EVOLUTION_MANAGER_SERVICE) == 0) {
+			activate_registrar ();
+			break;
+		}
+		i++;
+	}
+
+	g_strfreev (names); 
+}
+
+static void
+activate_dbus_client (void)
+{
+	EvolutionSupportPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	private->dbus_proxy = dbus_g_proxy_new_for_name (private->connection, 
+							 DBUS_SERVICE_DBUS,
+							 DBUS_PATH_DBUS,
+							 DBUS_INTERFACE_DBUS);
+
+	/* We listen for NameOwnerChanged to know when the manager's service 
+	 * comes up and to know when it goes down */
+
+	dbus_g_proxy_add_signal (private->dbus_proxy, "NameOwnerChanged",
+				 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+				 G_TYPE_INVALID);
+
+	dbus_g_proxy_connect_signal (private->dbus_proxy, "NameOwnerChanged",
+				     G_CALLBACK (name_owner_changed_cb),
+				     NULL, NULL);
+
+	/* If the manager service is up and running, then list_names_reply_cb
+	 * will execute activate_registrar, as it'll appear in the results of
+	 * the ListNames DBus function. If not then we will just wait for the
+	 * NameOwnerChanged to emit that the manager's service has came up. */
+
+	dbus_g_proxy_begin_call (private->dbus_proxy, "ListNames",
+				 list_names_reply_cb, NULL, NULL,
+				 G_TYPE_INVALID,
+				 G_TYPE_INVALID);
+}
+
+static gboolean 
+is_enabled (TrackerConfig *config)
+{
+	/* If none of the disabled modules include the Evolution module,
+	 * we assume we are enabled in the configuration. */
+
+	return (g_slist_find_custom (tracker_config_get_disabled_modules (config),
+				    "Evolution",
+				    (GCompareFunc) g_strcmp0) != NULL);
+}
+
+static void 
+disabled_notify (GObject    *pspec,
+		 GParamSpec *gobject,
+		 gpointer    user_data)
+{
+	EvolutionSupportPrivate *private;
+	gboolean new_value;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	new_value = is_enabled (private->config);
+
+	if (private->is_enabled != new_value) {
+		if (private->is_enabled) {
+			/* If we were enabled, disable */
+			deactivate_dbus_client ();
+		} else {
+			/* If we were disabled, enable */
+			activate_dbus_client ();
+		}
+		private->is_enabled = new_value;
+	}
+
+	g_message ("Evolution support service %s", 
+		   private->is_enabled ? "enabled" : "disabled");
+}
+
+static void
+free_private (EvolutionSupportPrivate *private)
+{
+	dbus_g_connection_unref (private->connection);
+	g_object_unref (private->config);
+	g_free (private);
+}
+
+void
+tracker_evolution_init (TrackerConfig *config)
+{
+	DBusGConnection *connection;
+	GError *error = NULL;
+
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+
+	if (!error) {
+		EvolutionSupportPrivate *private;
+
+		private = g_new0 (EvolutionSupportPrivate, 1);
+
+		private->deactivating = FALSE;
+		private->config = g_object_ref (config);
+		private->is_enabled = is_enabled (config);
+		private->connection = dbus_g_connection_ref (connection);
+
+		g_static_private_set (&private_key,
+				      private,
+				      (GDestroyNotify) free_private);
+
+		/* Hook configuration changes */
+		g_signal_connect (private->config, "notify::disabled-modules",
+				  G_CALLBACK (disabled_notify), 
+				  NULL);
+
+		/* If in configuration we are enabled now */
+		if (private->is_enabled)
+			activate_dbus_client ();
+	} else {
+		g_critical ("Could not setup DBus, %s\n", error->message);
+		g_error_free (error);
+	}
+}
+
+void
+tracker_evolution_shutdown ()
+{
+	EvolutionSupportPrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	if (private->is_enabled)
+		deactivate_dbus_client ();
+
+	g_static_private_set (&private_key, NULL, NULL);
+}

Added: trunk/src/plugins/evolution/tracker-evolution.h
==============================================================================
--- (empty file)
+++ trunk/src/plugins/evolution/tracker-evolution.h	Thu Jan 15 12:58:15 2009
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Authors:
+ *  Philip Van Hoof <philip codeminded be>
+ */
+
+#ifndef __LIBTRACKER_EVOLUTION_H__
+#define __LIBTRACKER_EVOLUTION_H__
+
+#if !defined (TRACKER_ENABLE_INTERNALS) && !defined (TRACKER_COMPILATION)
+#error "TRACKER_ENABLE_INTERNALS not defined, this must be defined to use tracker's internal functions"
+#endif
+
+#include <glib.h>
+
+#include <libtracker-common/tracker-common.h>
+
+G_BEGIN_DECLS
+
+void  tracker_evolution_init     (TrackerConfig *config);
+void  tracker_evolution_shutdown (void);
+
+G_END_DECLS
+
+#endif /* __LIBTRACKER_EVOLUTION_H__ */

Modified: trunk/src/tracker-indexer/Makefile.am
==============================================================================
--- trunk/src/tracker-indexer/Makefile.am	(original)
+++ trunk/src/tracker-indexer/Makefile.am	Thu Jan 15 12:58:15 2009
@@ -17,6 +17,7 @@
 	$(RAPTOR_CFLAGS)						\
 	$(GMODULE_CFLAGS)
 
+
 libtracker_moduledir = $(libdir)/tracker
 libtracker_moduleincludedir=$(includedir)/tracker-1.0/libtracker-module/
 libtracker_module_LTLIBRARIES = libtracker-module.la
@@ -55,6 +56,7 @@
 	$(top_builddir)/src/libtracker-db/libtracker-db.la 		\
 	$(top_builddir)/src/libtracker-common/libtracker-common.la 	\
 	$(top_builddir)/src/libstemmer/libstemmer.la	 		\
+	$(top_builddir)/src/plugins/evolution/libtracker-evolution-indexer.la \
 	$(trackerd_win_libs)						\
 	$(DBUS_LIBS)							\
 	$(GMODULE_LIBS)							\

Modified: trunk/src/tracker-indexer/modules/evolution.c
==============================================================================
--- trunk/src/tracker-indexer/modules/evolution.c	(original)
+++ trunk/src/tracker-indexer/modules/evolution.c	Thu Jan 15 12:58:15 2009
@@ -26,7 +26,10 @@
 
 #include "evolution-pop.h"
 #include "evolution-imap.h"
+
+#ifndef HAVE_EVOLUTION_PLUGIN
 #include "evolution-imap-db.h"
+#endif
 
 typedef enum MailStorageType MailStorageType;
 
@@ -34,7 +37,9 @@
 	MAIL_STORAGE_NONE,
 	MAIL_STORAGE_LOCAL,
 	MAIL_STORAGE_IMAP,
+#ifndef HAVE_EVOLUTION_PLUGIN
 	MAIL_STORAGE_IMAP_DB
+#endif
 };
 
 static gchar *local_dir = NULL;
@@ -76,9 +81,12 @@
 	} else if (g_str_has_prefix (path, imap_dir)) {
 		if (strcmp (basenam, "summary") == 0) {
 			type = MAIL_STORAGE_IMAP;
-		} else if (strcmp (basenam, "folders.db") == 0) {
+		}
+#ifndef HAVE_EVOLUTION_PLUGIN
+		else if (strcmp (basenam, "folders.db") == 0) {
 			type = MAIL_STORAGE_IMAP_DB;
 		}
+#endif
 	}
 
 	/* Exclude non wanted folders */
@@ -110,9 +118,12 @@
                 return tracker_evolution_pop_file_new (file);
         } else if (type == MAIL_STORAGE_IMAP) {
                 return tracker_evolution_imap_file_new (file);
-        } else if (type == MAIL_STORAGE_IMAP_DB) {
+        }
+#ifndef HAVE_EVOLUTION_PLUGIN
+	else if (type == MAIL_STORAGE_IMAP_DB) {
 		return tracker_evolution_imap_db_file_new (file);
 	}
+#endif
 
         return NULL;
 }

Modified: trunk/src/tracker-indexer/tracker-main.c
==============================================================================
--- trunk/src/tracker-indexer/tracker-main.c	(original)
+++ trunk/src/tracker-indexer/tracker-main.c	Thu Jan 15 12:58:15 2009
@@ -44,6 +44,9 @@
 
 #include <libtracker-data/tracker-data-update.h>
 #include <libtracker-data/tracker-turtle.h>
+#include <libtracker-data/tracker-data-manager.h>
+
+#include <plugins/evolution/tracker-evolution-indexer.h>
 
 #include "tracker-dbus.h"
 #include "tracker-indexer.h"
@@ -254,11 +257,14 @@
 main (gint argc, gchar *argv[])
 {
 	TrackerConfig *config;
+	TrackerLanguage *language;
 	TrackerIndexer *indexer;
 	TrackerDBManagerFlags flags = 0;
 	GOptionContext *context;
 	GError *error = NULL;
 	gchar *filename;
+	TrackerDBIndex *file_index;
+	TrackerDBIndex *email_index;
 
 	g_type_init ();
 
@@ -296,6 +302,7 @@
 
 	/* Initialize logging */
 	config = tracker_config_new ();
+	language = tracker_language_new (config);
 
 	if (verbosity > -1) {
 		tracker_config_set_verbosity (config, verbosity);
@@ -371,6 +378,15 @@
                 tracker_indexer_process_modules (indexer, modules);
         }
 
+	file_index = tracker_db_index_manager_get_index (TRACKER_DB_INDEX_FILE);
+	email_index = tracker_db_index_manager_get_index (TRACKER_DB_INDEX_EMAIL);
+
+	tracker_data_manager_init (config, language, file_index, email_index);
+
+#ifdef HAVE_EVOLUTION_PLUGIN
+	tracker_evolution_storer_init (config, indexer);
+#endif
+
 	tracker_turtle_init ();
 
 	g_message ("Starting...");
@@ -383,15 +399,24 @@
 
 	tracker_turtle_shutdown ();
 
+
 	if (quit_timeout_id) {
 		g_source_remove (quit_timeout_id);
 	}
 
 	g_main_loop_unref (main_loop);
 	g_object_unref (indexer);
+
 	g_object_unref (config);
+	g_object_unref (language);
+
+	tracker_data_manager_shutdown ();
+
+#ifdef HAVE_EVOLUTION_PLUGIN
+	tracker_evolution_storer_shutdown ();
+#endif
 
-        tracker_thumbnailer_shutdown ();
+	tracker_thumbnailer_shutdown ();
 	tracker_dbus_shutdown ();
 	tracker_db_index_manager_shutdown ();
 	tracker_db_manager_shutdown ();

Modified: trunk/src/trackerd/Makefile.am
==============================================================================
--- trunk/src/trackerd/Makefile.am	(original)
+++ trunk/src/trackerd/Makefile.am	Thu Jan 15 12:58:15 2009
@@ -77,6 +77,7 @@
 	$(top_builddir)/src/libtracker-db/libtracker-db.la 		\
 	$(top_builddir)/src/libtracker-common/libtracker-common.la 	\
 	$(top_builddir)/src/libstemmer/libstemmer.la	 		\
+	$(top_builddir)/src/plugins/evolution/libtracker-evolution.la	\
 	$(inotify_libs)							\
 	$(GMIME_LIBS)							\
 	$(FAM_LIBS)							\

Modified: trunk/src/trackerd/tracker-main.c
==============================================================================
--- trunk/src/trackerd/tracker-main.c	(original)
+++ trunk/src/trackerd/tracker-main.c	Thu Jan 15 12:58:15 2009
@@ -53,8 +53,11 @@
 #include <libtracker-db/tracker-db-index.h>
 #include <libtracker-db/tracker-db-index-manager.h>
 
+#include <libtracker-data/tracker-data-manager.h>
 #include <libtracker-data/tracker-turtle.h>
 
+#include <plugins/evolution/tracker-evolution.h>
+
 #include "tracker-crawler.h"
 #include "tracker-dbus.h"
 #include "tracker-indexer-client.h"
@@ -1030,11 +1033,11 @@
 		return EXIT_FAILURE;
 	}
 
+	tracker_module_config_init ();
+
 	tracker_turtle_init ();
 	tracker_thumbnailer_init (config);
 
-	tracker_module_config_init ();
-
 	flags |= TRACKER_DB_MANAGER_REMOVE_CACHE;
 	index_flags |= TRACKER_DB_INDEX_MANAGER_READONLY;
 
@@ -1132,6 +1135,10 @@
 		return EXIT_FAILURE;
 	}
 
+#ifdef HAVE_EVOLUTION_PLUGIN
+	tracker_evolution_init (config);
+#endif
+
 	g_message ("Waiting for DBus requests...");
 
 	/* Set our status as running, if this is FALSE, threads stop
@@ -1202,6 +1209,11 @@
 	shutdown_directories ();
 
 	/* Shutdown major subsystems */
+	
+#ifdef HAVE_EVOLUTION_PLUGIN
+	tracker_evolution_shutdown ();
+#endif
+
 	tracker_cleanup_shutdown ();
 	tracker_xesam_manager_shutdown ();
 	tracker_dbus_shutdown ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]