[evolution-data-server/account-mgmt: 4/28] Add new ESource classes.



commit be162028f24c5f54c0b491d30c8edcc1341e5f58
Author: Matthew Barnes <mbarnes redhat com>
Date:   Fri Nov 12 10:19:34 2010 -0500

    Add new ESource classes.
    
    ESource
    ESourceExtension
    ESourceRegistry

 addressbook/libebook/Makefile.am                   |    4 +-
 addressbook/libebook/e-book.c                      |    4 +
 addressbook/libebook/e-source-address-book.c       |   65 +
 addressbook/libebook/e-source-address-book.h       |   67 +
 calendar/libecal/Makefile.am                       |    6 +-
 calendar/libecal/e-cal.c                           |    6 +
 calendar/libecal/e-source-calendar.c               |  111 ++
 calendar/libecal/e-source-calendar.h               |  135 ++
 configure.ac                                       |    2 +-
 .../addressbook/libebook/libebook-docs.sgml        |    1 +
 .../addressbook/libebook/libebook-sections.txt     |   19 +
 docs/reference/addressbook/libebook/libebook.types |    2 +
 .../addressbook/libebook/tmpl/e-book.sgml          |   10 -
 .../libebook/tmpl/e-source-address-book.sgml       |   35 +
 .../addressbook/libebook/tmpl/libebook-unused.sgml |    9 +
 docs/reference/calendar/libecal/libecal-docs.sgml  |    3 +
 .../calendar/libecal/libecal-sections.txt          |   55 +-
 docs/reference/calendar/libecal/libecal.types      |    4 +
 docs/reference/calendar/libecal/tmpl/e-cal.sgml    |   11 -
 .../calendar/libecal/tmpl/e-source-calendar.sgml   |   35 +
 .../calendar/libecal/tmpl/e-source-memo-list.sgml  |   35 +
 .../calendar/libecal/tmpl/e-source-memo_list.sgml  |   35 +
 .../calendar/libecal/tmpl/e-source-task-list.sgml  |   35 +
 .../calendar/libecal/tmpl/e-source-task_list.sgml  |   35 +
 .../calendar/libecal/tmpl/libecal-unused.sgml      |   64 +-
 docs/reference/libedataserver/Makefile.am          |    1 +
 .../libedataserver/libedataserver-docs.sgml        |   15 +
 .../libedataserver/libedataserver-sections.txt     |  301 ++++-
 docs/reference/libedataserver/libedataserver.types |   14 +
 .../libedataserver/tmpl/e-source-alarms.sgml       |   71 +
 .../tmpl/e-source-authentication.sgml              |  182 +++
 .../libedataserver/tmpl/e-source-autocomplete.sgml |   53 +
 .../libedataserver/tmpl/e-source-extension.sgml    |   49 +
 .../libedataserver/tmpl/e-source-offline.sgml      |   58 +
 .../libedataserver/tmpl/e-source-password.sgml     |  145 ++
 .../libedataserver/tmpl/e-source-refresh.sgml      |   58 +
 .../libedataserver/tmpl/e-source-registry.sgml     |  263 +++
 .../libedataserver/tmpl/e-source-security.sgml     |   81 +
 .../libedataserver/tmpl/e-source-selectable.sgml   |   97 ++
 .../libedataserver/tmpl/e-source-webdav.sgml       |   89 +
 docs/reference/libedataserver/tmpl/e-source.sgml   |  160 +--
 .../libedataserverui/libedataserverui-sections.txt |    4 +-
 libedataserver/Makefile.am                         |   32 +-
 libedataserver/e-marshal.list                      |    1 +
 libedataserver/e-source-alarms.c                   |  174 ++
 libedataserver/e-source-alarms.h                   |   72 +
 libedataserver/e-source-authentication.c           |  408 +++++
 libedataserver/e-source-authentication.h           |   96 ++
 libedataserver/e-source-autocomplete.c             |  126 ++
 libedataserver/e-source-autocomplete.h             |   69 +
 libedataserver/e-source-extension.c                |  167 ++
 libedataserver/e-source-extension.h                |   65 +
 libedataserver/e-source-offline.c                  |  126 ++
 libedataserver/e-source-offline.h                  |   69 +
 libedataserver/e-source-password.c                 |  412 +++++
 libedataserver/e-source-password.h                 |   72 +
 libedataserver/e-source-refresh.c                  |  126 ++
 libedataserver/e-source-refresh.h                  |   69 +
 libedataserver/e-source-registry.c                 | 1319 +++++++++++++++
 libedataserver/e-source-registry.h                 |  127 ++
 libedataserver/e-source-security.c                 |  203 +++
 libedataserver/e-source-security.h                 |   70 +
 libedataserver/e-source-selectable.c               |  235 +++
 libedataserver/e-source-selectable.h               |   73 +
 libedataserver/e-source-webdav.c                   |  552 +++++++
 libedataserver/e-source-webdav.h                   |   95 ++
 libedataserver/e-source.c                          | 1698 ++++++++++++--------
 libedataserver/e-source.h                          |  164 +-
 libedataserver/e-system-source.c                   |  117 ++
 libedataserver/e-system-source.h                   |   63 +
 libedataserver/libedataserver.pc.in                |    2 +-
 71 files changed, 8280 insertions(+), 951 deletions(-)
---
diff --git a/addressbook/libebook/Makefile.am b/addressbook/libebook/Makefile.am
index 07b3475..6e8d9a3 100644
--- a/addressbook/libebook/Makefile.am
+++ b/addressbook/libebook/Makefile.am
@@ -28,7 +28,8 @@ libebook_1_2_la_SOURCES =				\
 	e-contact.c					\
 	e-destination.c					\
 	e-name-western.c				\
-	e-name-western-tables.h                         \
+	e-name-western-tables.h				\
+	e-source-address-book.c				\
 	e-vcard.c					\
 	e-error.h
 
@@ -53,6 +54,7 @@ libebookinclude_HEADERS =				\
 	e-contact.h					\
 	e-destination.h					\
 	e-name-western.h				\
+	e-source-address-book.h				\
 	e-vcard.h
 
 %-$(API_VERSION).pc: %.pc
diff --git a/addressbook/libebook/e-book.c b/addressbook/libebook/e-book.c
index e63cce8..60eaf36 100644
--- a/addressbook/libebook/e-book.c
+++ b/addressbook/libebook/e-book.c
@@ -40,6 +40,7 @@
 #include "e-error.h"
 #include "e-contact.h"
 #include "e-name-western.h"
+#include "e-source-address-book.h"
 #include "e-book-view-private.h"
 #include "e-book-marshal.h"
 
@@ -244,6 +245,9 @@ e_book_class_init (EBookClass *e_book_class)
 	gobject_class->finalize = e_book_finalize;
 
 	g_type_class_add_private (e_book_class, sizeof (EBookPrivate));
+
+	/* Register relevant ESource extensions. */
+	E_TYPE_SOURCE_ADDRESS_BOOK;
 }
 
 static void
diff --git a/addressbook/libebook/e-source-address-book.c b/addressbook/libebook/e-source-address-book.c
new file mode 100644
index 0000000..dcd3e11
--- /dev/null
+++ b/addressbook/libebook/e-source-address-book.c
@@ -0,0 +1,65 @@
+/*
+ * e-source-address-book.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-address-book.h"
+
+#include <libedataserver/e-data-server-util.h>
+
+G_DEFINE_TYPE (
+	ESourceAddressBook,
+	e_source_address_book,
+	E_TYPE_SOURCE_SELECTABLE)
+
+static void
+source_address_book_constructed (GObject *object)
+{
+	ESource *source;
+	ESourceExtension *extension;
+	GFile *user_data_dir;
+	GFile *user_sources_dir;
+
+	extension = E_SOURCE_EXTENSION (object);
+	source = e_source_extension_get_source (extension);
+
+	/* Redirect changes to the user's sources directory.
+	 * That way built-in address books like "system" can
+	 * be renamed or tweaked. */
+	user_data_dir = g_file_new_for_path (e_get_user_data_dir ());
+	user_sources_dir = g_file_get_child (user_data_dir, "sources");
+	e_source_redirect (source, user_sources_dir);
+	g_object_unref (user_sources_dir);
+	g_object_unref (user_data_dir);
+}
+
+static void
+e_source_address_book_class_init (ESourceAddressBookClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->constructed = source_address_book_constructed;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+}
+
+static void
+e_source_address_book_init (ESourceAddressBook *extension)
+{
+}
diff --git a/addressbook/libebook/e-source-address-book.h b/addressbook/libebook/e-source-address-book.h
new file mode 100644
index 0000000..eb7a45a
--- /dev/null
+++ b/addressbook/libebook/e-source-address-book.h
@@ -0,0 +1,67 @@
+/*
+ * e-source-address-book.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_ADDRESS_BOOK_H
+#define E_SOURCE_ADDRESS_BOOK_H
+
+/* This is a trivial but important ESourceSelectable subclass.
+ * It identifies an ESource as an address book. */
+
+#include <libedataserver/e-source-selectable.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_ADDRESS_BOOK \
+	(e_source_address_book_get_type ())
+#define E_SOURCE_ADDRESS_BOOK(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_ADDRESS_BOOK, ESourceAddressBook))
+#define E_SOURCE_ADDRESS_BOOK_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_ADDRESS_BOOK, ESourceAddressBookClass))
+#define E_IS_SOURCE_ADDRESS_BOOK(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_ADDRESS_BOOK))
+#define E_IS_SOURCE_ADDRESS_BOOK_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_ADDRESS_BOOK))
+#define E_SOURCE_ADDRESS_BOOK_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_ADDRESS_BOOK, ESourceAddressBookClass))
+
+#define E_SOURCE_EXTENSION_ADDRESS_BOOK "Address Book"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceAddressBook ESourceAddressBook;
+typedef struct _ESourceAddressBookClass ESourceAddressBookClass;
+typedef struct _ESourceAddressBookPrivate ESourceAddressBookPrivate;
+
+struct _ESourceAddressBook {
+	ESourceSelectable parent;
+	ESourceAddressBookPrivate *priv;
+};
+
+struct _ESourceAddressBookClass {
+	ESourceSelectableClass parent_class;
+};
+
+GType		e_source_address_book_get_type	(void);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_ADDRESS_BOOK_H */
diff --git a/calendar/libecal/Makefile.am b/calendar/libecal/Makefile.am
index 215c4bf..1d58ba9 100644
--- a/calendar/libecal/Makefile.am
+++ b/calendar/libecal/Makefile.am
@@ -31,7 +31,8 @@ libecal_1_2_la_SOURCES =			\
 	e-cal-system-timezone.h			\
 	e-cal-util.c				\
 	e-cal-view.c				\
-	e-cal-view-private.h
+	e-cal-view-private.h			\
+	e-source-calendar.c
 
 libecal_1_2_la_LIBADD = 					\
 	$(top_builddir)/libedataserver/libedataserver-1.2.la 	\
@@ -53,7 +54,8 @@ libecalinclude_HEADERS =	\
 	e-cal-system-timezone.h	\
 	e-cal-types.h		\
 	e-cal-util.h		\
-	e-cal-view.h
+	e-cal-view.h		\
+	e-source-calendar.h
 
 %-$(API_VERSION).pc: %.pc
 	 cp $< $@
diff --git a/calendar/libecal/e-cal.c b/calendar/libecal/e-cal.c
index d5e87e4..f1efd8c 100644
--- a/calendar/libecal/e-cal.c
+++ b/calendar/libecal/e-cal.c
@@ -51,6 +51,7 @@
 #include "e-cal-time-util.h"
 #include "e-cal-view-private.h"
 #include "e-cal.h"
+#include "e-source-calendar.h"
 
 #include "e-gdbus-egdbuscalfactory.h"
 #include "e-gdbus-egdbuscal.h"
@@ -644,6 +645,11 @@ e_cal_class_init (ECalClass *klass)
 	object_class->finalize = e_cal_finalize;
 
 	g_type_class_add_private (klass, sizeof (ECalPrivate));
+
+	/* Register relevant ESource extensions. */
+	E_TYPE_SOURCE_CALENDAR;
+	E_TYPE_SOURCE_MEMO_LIST;
+	E_TYPE_SOURCE_TASK_LIST;
 }
 
 static void
diff --git a/calendar/libecal/e-source-calendar.c b/calendar/libecal/e-source-calendar.c
new file mode 100644
index 0000000..7f9472d
--- /dev/null
+++ b/calendar/libecal/e-source-calendar.c
@@ -0,0 +1,111 @@
+/*
+ * e-source-calendar.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-calendar.h"
+
+#include <libedataserver/e-data-server-util.h>
+
+G_DEFINE_TYPE (
+	ESourceCalendar,
+	e_source_calendar,
+	E_TYPE_SOURCE_SELECTABLE)
+
+G_DEFINE_TYPE (
+	ESourceMemoList,
+	e_source_memo_list,
+	E_TYPE_SOURCE_SELECTABLE)
+
+G_DEFINE_TYPE (
+	ESourceTaskList,
+	e_source_task_list,
+	E_TYPE_SOURCE_SELECTABLE)
+
+static void
+source_common_constructed (GObject *object)
+{
+	ESource *source;
+	ESourceExtension *extension;
+	GFile *user_data_dir;
+	GFile *user_sources_dir;
+
+	extension = E_SOURCE_EXTENSION (object);
+	source = e_source_extension_get_source (extension);
+
+	/* Redirect changes to the user's sources directory.
+	 * That way built-in calendars, task lists and memo
+	 * lists like "system" can be renamed or tweaked. */
+	user_data_dir = g_file_new_for_path (e_get_user_data_dir ());
+	user_sources_dir = g_file_get_child (user_data_dir, "sources");
+	e_source_redirect (source, user_sources_dir);
+	g_object_unref (user_sources_dir);
+	g_object_unref (user_data_dir);
+}
+
+static void
+e_source_calendar_class_init (ESourceCalendarClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->constructed = source_common_constructed;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_CALENDAR;
+}
+
+static void
+e_source_calendar_init (ESourceCalendar *extension)
+{
+}
+
+static void
+e_source_memo_list_class_init (ESourceMemoListClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->constructed = source_common_constructed;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_MEMO_LIST;
+}
+
+static void
+e_source_memo_list_init (ESourceMemoList *extension)
+{
+}
+
+static void
+e_source_task_list_class_init (ESourceTaskListClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->constructed = source_common_constructed;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_TASK_LIST;
+}
+
+static void
+e_source_task_list_init (ESourceTaskList *extension)
+{
+}
diff --git a/calendar/libecal/e-source-calendar.h b/calendar/libecal/e-source-calendar.h
new file mode 100644
index 0000000..a7fabea
--- /dev/null
+++ b/calendar/libecal/e-source-calendar.h
@@ -0,0 +1,135 @@
+/*
+ * e-source-calendar.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_CALENDAR_H
+#define E_SOURCE_CALENDAR_H
+
+/* These are trivial but important ESourceSelectable subclasses.
+ * They identify an ESource as a calendar, memo list or task list. */
+
+#include <libedataserver/e-source-selectable.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_CALENDAR \
+	(e_source_calendar_get_type ())
+#define E_SOURCE_CALENDAR(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_CALENDAR, ESourceCalendar))
+#define E_SOURCE_CALENDAR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_CALENDAR, ESourceCalendarClass))
+#define E_IS_SOURCE_CALENDAR(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_CALENDAR))
+#define E_IS_SOURCE_CALENDAR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_CALENDAR))
+#define E_SOURCE_CALENDAR_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_CALENDAR, ESourceCalendarClass))
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_MEMO_LIST \
+	(e_source_memo_list_get_type ())
+#define E_SOURCE_MEMO_LIST(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_MEMO_LIST, ESourceMemoList))
+#define E_SOURCE_MEMO_LIST_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_MEMO_LIST, ESourceMemoListClass))
+#define E_IS_SOURCE_MEMO_LIST(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_MEMO_LIST))
+#define E_IS_SOURCE_MEMO_LIST_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_MEMO_LIST))
+#define E_SOURCE_MEMO_LIST_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_MEMO_LIST, ESourceMemoListClass))
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_TASK_LIST \
+	(e_source_task_list_get_type ())
+#define E_SOURCE_TASK_LIST(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_TASK_LIST, ESourceTaskList))
+#define E_SOURCE_TASK_LIST_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_TASK_LIST, ESourceTaskListClass))
+#define E_IS_SOURCE_TASK_LIST(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_TASK_LIST))
+#define E_IS_SOURCE_TASK_LIST_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_TASK_LIST))
+#define E_SOURCE_TASK_LIST_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_TASK_LIST, ESourceTaskListClass))
+
+#define E_SOURCE_EXTENSION_CALENDAR  "Calendar"
+#define E_SOURCE_EXTENSION_MEMO_LIST "Memo List"
+#define E_SOURCE_EXTENSION_TASK_LIST "Task List"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceCalendar ESourceCalendar;
+typedef struct _ESourceCalendarClass ESourceCalendarClass;
+typedef struct _ESourceCalendarPrivate ESourceCalendarPrivate;
+
+typedef struct _ESourceMemoList ESourceMemoList;
+typedef struct _ESourceMemoListClass ESourceMemoListClass;
+typedef struct _ESourceMemoListPrivate ESourceMemoListPrivate;
+
+typedef struct _ESourceTaskList ESourceTaskList;
+typedef struct _ESourceTaskListClass ESourceTaskListClass;
+typedef struct _ESourceTaskListPrivate ESourceTaskListPrivate;
+
+struct _ESourceCalendar {
+	ESourceSelectable parent;
+	ESourceCalendarPrivate *priv;
+};
+
+struct _ESourceCalendarClass {
+	ESourceSelectableClass parent_class;
+};
+
+struct _ESourceMemoList {
+	ESourceSelectable parent;
+	ESourceMemoListPrivate *priv;
+};
+
+struct _ESourceMemoListClass {
+	ESourceSelectableClass parent_class;
+};
+
+struct _ESourceTaskList {
+	ESourceSelectable parent;
+	ESourceTaskListPrivate *priv;
+};
+
+struct _ESourceTaskListClass {
+	ESourceSelectableClass parent_class;
+};
+
+GType		e_source_calendar_get_type	(void);
+GType		e_source_memo_list_get_type	(void);
+GType		e_source_task_list_get_type	(void);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_CALENDAR_H */
diff --git a/configure.ac b/configure.ac
index 368834c..2dca9da 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1179,7 +1179,7 @@ AC_DEFUN([EVO_SET_COMPILE_FLAGS], [
 dnl ******************************
 dnl libedataserver flags
 dnl ******************************
-E_DATA_SERVER_DEPS="gio-2.0 libxml-2.0 libsoup-2.4 gconf-2.0 $mozilla_nspr"
+E_DATA_SERVER_DEPS="gio-2.0 gnome-keyring-1 libxml-2.0 libsoup-2.4 gconf-2.0 $mozilla_nspr"
 
 EVO_SET_COMPILE_FLAGS(E_DATA_SERVER, $E_DATA_SERVER_DEPS, $MANUAL_NSPR_CFLAGS, $MANUAL_NSPR_LIBS)
 AC_SUBST(E_DATA_SERVER_CFLAGS)
diff --git a/docs/reference/addressbook/libebook/libebook-docs.sgml b/docs/reference/addressbook/libebook/libebook-docs.sgml
index aef65b4..7bfcd83 100644
--- a/docs/reference/addressbook/libebook/libebook-docs.sgml
+++ b/docs/reference/addressbook/libebook/libebook-docs.sgml
@@ -19,6 +19,7 @@
     <xi:include href="xml/e-destination.xml"/>
     <xi:include href="xml/e-address-western.xml"/>
     <xi:include href="xml/e-name-western.xml"/>
+    <xi:include href="xml/e-source-address-book.xml"/>
   </chapter>
 
   <index id="api-index-full">
diff --git a/docs/reference/addressbook/libebook/libebook-sections.txt b/docs/reference/addressbook/libebook/libebook-sections.txt
index c13e406..7352302 100644
--- a/docs/reference/addressbook/libebook/libebook-sections.txt
+++ b/docs/reference/addressbook/libebook/libebook-sections.txt
@@ -409,3 +409,22 @@ E_DESTINATION_GET_CLASS
 E_IS_DESTINATION
 E_IS_DESTINATION_CLASS
 </SECTION>
+
+<SECTION>
+<FILE>e-source-address-book</FILE>
+<TITLE>ESourceAddressBook</TITLE>
+ESourceAddressBook
+E_SOURCE_EXTENSION_ADDRESS_BOOK
+<SUBSECTION Standard>
+E_SOURCE_ADDRESS_BOOK
+E_IS_SOURCE_ADDRESS_BOOK
+E_TYPE_SOURCE_ADDRESS_BOOK
+E_SOURCE_ADDRESS_BOOK_CLASS
+E_IS_SOURCE_ADDRESS_BOOK_CLASS
+E_SOURCE_ADDRESS_BOOK_GET_CLASS
+ESourceAddressBookClass
+<SUBSECTION Private>
+ESourceAddressBookPrivate
+e_source_address_book_get_type
+</SECTION>
+
diff --git a/docs/reference/addressbook/libebook/libebook.types b/docs/reference/addressbook/libebook/libebook.types
index 4dd5f9f..c331ec8 100644
--- a/docs/reference/addressbook/libebook/libebook.types
+++ b/docs/reference/addressbook/libebook/libebook.types
@@ -3,9 +3,11 @@
 #include <libebook/e-contact.h>
 #include <libebook/e-destination.h>
 #include <libebook/e-vcard.h>
+#include <libebook/e-source-address-book.h>
 
 e_book_get_type
 e_book_view_get_type
 e_contact_get_type
 e_destination_get_type
 e_vcard_get_type
+e_source_address_book_get_type
diff --git a/docs/reference/addressbook/libebook/tmpl/e-book.sgml b/docs/reference/addressbook/libebook/tmpl/e-book.sgml
index 2d7a8fe..7b34c99 100644
--- a/docs/reference/addressbook/libebook/tmpl/e-book.sgml
+++ b/docs/reference/addressbook/libebook/tmpl/e-book.sgml
@@ -401,16 +401,6 @@ The writable status for this book is being reported.
 @Returns: 
 
 
-<!-- ##### FUNCTION e_book_get_addressbooks ##### -->
-<para>
-
-</para>
-
- addressbook_sources: 
- error: 
- Returns: 
-
-
 <!-- ##### MACRO e_return_error_if_fail ##### -->
 <para>
 
diff --git a/docs/reference/addressbook/libebook/tmpl/e-source-address-book.sgml b/docs/reference/addressbook/libebook/tmpl/e-source-address-book.sgml
new file mode 100644
index 0000000..8384390
--- /dev/null
+++ b/docs/reference/addressbook/libebook/tmpl/e-source-address-book.sgml
@@ -0,0 +1,35 @@
+<!-- ##### SECTION Title ##### -->
+ESourceAddressBook
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceAddressBook ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_ADDRESS_BOOK ##### -->
+<para>
+
+</para>
+
+
+
diff --git a/docs/reference/addressbook/libebook/tmpl/libebook-unused.sgml b/docs/reference/addressbook/libebook/tmpl/libebook-unused.sgml
index 416a567..e8fe0b8 100644
--- a/docs/reference/addressbook/libebook/tmpl/libebook-unused.sgml
+++ b/docs/reference/addressbook/libebook/tmpl/libebook-unused.sgml
@@ -493,6 +493,15 @@ Data sent back to the e-book object.
 
 @book: 
 
+<!-- ##### FUNCTION e_book_get_addressbooks ##### -->
+<para>
+
+</para>
+
+ addressbook_sources: 
+ error: 
+ Returns: 
+
 <!-- ##### FUNCTION e_book_get_default_addressbook ##### -->
 <para>
 
diff --git a/docs/reference/calendar/libecal/libecal-docs.sgml b/docs/reference/calendar/libecal/libecal-docs.sgml
index c3dd228..09f45fc 100644
--- a/docs/reference/calendar/libecal/libecal-docs.sgml
+++ b/docs/reference/calendar/libecal/libecal-docs.sgml
@@ -19,6 +19,9 @@
     <xi:include href="xml/e-cal-util.xml"/>
     <xi:include href="xml/e-cal-system-timezone.xml"/>
     <xi:include href="xml/e-cal-check-timezones.xml"/>
+    <xi:include href="xml/e-source-calendar.xml"/>
+    <xi:include href="xml/e-source-memo-list.xml"/>
+    <xi:include href="xml/e-source-task-list.xml"/>
   </chapter>
 
   <index id="api-index-full">
diff --git a/docs/reference/calendar/libecal/libecal-sections.txt b/docs/reference/calendar/libecal/libecal-sections.txt
index 77f88b4..54d645f 100644
--- a/docs/reference/calendar/libecal/libecal-sections.txt
+++ b/docs/reference/calendar/libecal/libecal-sections.txt
@@ -232,7 +232,6 @@ e_cal_get_error_message
 e_cal_open_default
 e_cal_set_default
 e_cal_set_default_source
-e_cal_get_sources
 e_cal_get_local_attachment_store
 e_cal_get_recurrences_no_master
 e_cal_get_attachments_for_comp
@@ -391,3 +390,57 @@ e_cal_tzlookup_ecal
 e_cal_tzlookup_icomp
 e_cal_match_tzid
 </SECTION>
+
+<SECTION>
+<FILE>e-source-calendar</FILE>
+<TITLE>ESourceCalendar</TITLE>
+ESourceCalendar
+E_SOURCE_EXTENSION_CALENDAR
+<SUBSECTION Standard>
+E_SOURCE_CALENDAR
+E_IS_SOURCE_CALENDAR
+E_TYPE_SOURCE_CALENDAR
+E_SOURCE_CALENDAR_CLASS
+E_IS_SOURCE_CALENDAR_CLASS
+E_SOURCE_CALENDAR_GET_CLASS
+ESourceCalendarClass
+<SUBSECTION Private>
+ESourceCalendarPrivate
+e_source_calendar_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-memo-list</FILE>
+<TITLE>ESourceMemoList</TITLE>
+ESourceMemoList
+E_SOURCE_EXTENSION_MEMO_LIST
+<SUBSECTION Standard>
+E_SOURCE_MEMO_LIST
+E_IS_SOURCE_MEMO_LIST
+E_TYPE_SOURCE_MEMO_LIST
+E_SOURCE_MEMO_LIST_CLASS
+E_IS_SOURCE_MEMO_LIST_CLASS
+E_SOURCE_MEMO_LIST_GET_CLASS
+ESourceMemoListClass
+<SUBSECTION Private>
+ESourceMemoListPrivate
+e_source_memo_list_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-task-list</FILE>
+<TITLE>ESourceTaskList</TITLE>
+ESourceTaskList
+E_SOURCE_EXTENSION_TASK_LIST
+<SUBSECTION Standard>
+E_SOURCE_TASK_LIST
+E_IS_SOURCE_TASK_LIST
+E_TYPE_SOURCE_TASK_LIST
+E_SOURCE_TASK_LIST_CLASS
+E_IS_SOURCE_TASK_LIST_CLASS
+E_SOURCE_TASK_LIST_GET_CLASS
+ESourceTaskListClass
+<SUBSECTION Private>
+ESourceTaskListPrivate
+e_source_task_list_get_type
+</SECTION>
diff --git a/docs/reference/calendar/libecal/libecal.types b/docs/reference/calendar/libecal/libecal.types
index 1286092..c32c6bb 100644
--- a/docs/reference/calendar/libecal/libecal.types
+++ b/docs/reference/calendar/libecal/libecal.types
@@ -1,7 +1,11 @@
 #include <libecal/e-cal.h>
 #include <libecal/e-cal-component.h>
 #include <libecal/e-cal-view.h>
+#include <libecal/e-source-calendar.h>
 
 e_cal_get_type
 e_cal_component_get_type
 e_cal_view_get_type
+e_source_calendar_get_type
+e_source_memo_list_get_type
+e_source_task_list_get_type
diff --git a/docs/reference/calendar/libecal/tmpl/e-cal.sgml b/docs/reference/calendar/libecal/tmpl/e-cal.sgml
index 231c89c..f360005 100644
--- a/docs/reference/calendar/libecal/tmpl/e-cal.sgml
+++ b/docs/reference/calendar/libecal/tmpl/e-cal.sgml
@@ -711,17 +711,6 @@ Represents an entire calendar or task list, not individual items within them.2
 @Returns: 
 
 
-<!-- ##### FUNCTION e_cal_get_sources ##### -->
-<para>
-
-</para>
-
- sources: 
- type: 
- error: 
- Returns: 
-
-
 <!-- ##### FUNCTION e_cal_get_local_attachment_store ##### -->
 <para>
 
diff --git a/docs/reference/calendar/libecal/tmpl/e-source-calendar.sgml b/docs/reference/calendar/libecal/tmpl/e-source-calendar.sgml
new file mode 100644
index 0000000..b1aa2fc
--- /dev/null
+++ b/docs/reference/calendar/libecal/tmpl/e-source-calendar.sgml
@@ -0,0 +1,35 @@
+<!-- ##### SECTION Title ##### -->
+ESourceCalendar
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceCalendar ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_CALENDAR ##### -->
+<para>
+
+</para>
+
+
+
diff --git a/docs/reference/calendar/libecal/tmpl/e-source-memo-list.sgml b/docs/reference/calendar/libecal/tmpl/e-source-memo-list.sgml
new file mode 100644
index 0000000..a582fa7
--- /dev/null
+++ b/docs/reference/calendar/libecal/tmpl/e-source-memo-list.sgml
@@ -0,0 +1,35 @@
+<!-- ##### SECTION Title ##### -->
+ESourceMemoList
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceMemoList ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_MEMO_LIST ##### -->
+<para>
+
+</para>
+
+
+
diff --git a/docs/reference/calendar/libecal/tmpl/e-source-memo_list.sgml b/docs/reference/calendar/libecal/tmpl/e-source-memo_list.sgml
new file mode 100644
index 0000000..a582fa7
--- /dev/null
+++ b/docs/reference/calendar/libecal/tmpl/e-source-memo_list.sgml
@@ -0,0 +1,35 @@
+<!-- ##### SECTION Title ##### -->
+ESourceMemoList
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceMemoList ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_MEMO_LIST ##### -->
+<para>
+
+</para>
+
+
+
diff --git a/docs/reference/calendar/libecal/tmpl/e-source-task-list.sgml b/docs/reference/calendar/libecal/tmpl/e-source-task-list.sgml
new file mode 100644
index 0000000..9cb620b
--- /dev/null
+++ b/docs/reference/calendar/libecal/tmpl/e-source-task-list.sgml
@@ -0,0 +1,35 @@
+<!-- ##### SECTION Title ##### -->
+ESourceTaskList
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceTaskList ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_TASK_LIST ##### -->
+<para>
+
+</para>
+
+
+
diff --git a/docs/reference/calendar/libecal/tmpl/e-source-task_list.sgml b/docs/reference/calendar/libecal/tmpl/e-source-task_list.sgml
new file mode 100644
index 0000000..9cb620b
--- /dev/null
+++ b/docs/reference/calendar/libecal/tmpl/e-source-task_list.sgml
@@ -0,0 +1,35 @@
+<!-- ##### SECTION Title ##### -->
+ESourceTaskList
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceTaskList ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_TASK_LIST ##### -->
+<para>
+
+</para>
+
+
+
diff --git a/docs/reference/calendar/libecal/tmpl/libecal-unused.sgml b/docs/reference/calendar/libecal/tmpl/libecal-unused.sgml
index df0f1a7..b77d556 100644
--- a/docs/reference/calendar/libecal/tmpl/libecal-unused.sgml
+++ b/docs/reference/calendar/libecal/tmpl/libecal-unused.sgml
@@ -46,6 +46,62 @@ Listens for responses and event notifications sent by #e-cal-view.
 ECalViewListener
 
 
+<!-- ##### SECTION ./tmpl/e-source-memo_list.sgml:Image ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/e-source-memo_list.sgml:Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/e-source-memo_list.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/e-source-memo_list.sgml:Short_Description ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/e-source-memo_list.sgml:Stability_Level ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/e-source-memo_list.sgml:Title ##### -->
+ESourceMemoList
+
+
+<!-- ##### SECTION ./tmpl/e-source-task_list.sgml:Image ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/e-source-task_list.sgml:Long_Description ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/e-source-task_list.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/e-source-task_list.sgml:Short_Description ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/e-source-task_list.sgml:Stability_Level ##### -->
+
+
+
+<!-- ##### SECTION ./tmpl/e-source-task_list.sgml:Title ##### -->
+ESourceTaskList
+
+
 <!-- ##### SECTION ./tmpl/libecal-unused.sgml:Stability_Level ##### -->
 
 
@@ -516,14 +572,6 @@ ECalViewListener
 @error: 
 @Returns: 
 
-<!-- ##### FUNCTION e_cal_get_uri ##### -->
-<para>
-
-</para>
-
- ecal: 
- Returns: 
-
 <!-- ##### FUNCTION e_cal_listener_construct ##### -->
 <para>
 
diff --git a/docs/reference/libedataserver/Makefile.am b/docs/reference/libedataserver/Makefile.am
index 176a76c..2f5b531 100644
--- a/docs/reference/libedataserver/Makefile.am
+++ b/docs/reference/libedataserver/Makefile.am
@@ -14,6 +14,7 @@ DOC_SOURCE_DIR = $(top_srcdir)/libedataserver
 HFILE_GLOB = $(top_srcdir)/libedataserver/*.h
 CFILE_GLOB = $(top_srcdir)/libedataserver/*.c
 IGNORE_HFILES = 			\
+	e-marshal.h			\
 	libedataserver-private.h
 
 GTKDOC_CFLAGS  =					\
diff --git a/docs/reference/libedataserver/libedataserver-docs.sgml b/docs/reference/libedataserver/libedataserver-docs.sgml
index 11e8df0..61e45e7 100644
--- a/docs/reference/libedataserver/libedataserver-docs.sgml
+++ b/docs/reference/libedataserver/libedataserver-docs.sgml
@@ -23,6 +23,17 @@
     <xi:include href="xml/e-sexp.xml"/>
     <xi:include href="xml/e-soap-message.xml"/>
     <xi:include href="xml/e-source.xml"/>
+    <xi:include href="xml/e-source-password.xml"/>
+    <xi:include href="xml/e-source-registry.xml"/>
+    <xi:include href="xml/e-source-extension.xml"/>
+    <xi:include href="xml/e-source-alarms.xml"/>
+    <xi:include href="xml/e-source-authentication.xml"/>
+    <xi:include href="xml/e-source-autocomplete.xml"/>
+    <xi:include href="xml/e-source-offline.xml"/>
+    <xi:include href="xml/e-source-refresh.xml"/>
+    <xi:include href="xml/e-source-security.xml"/>
+    <xi:include href="xml/e-source-selectable.xml"/>
+    <xi:include href="xml/e-source-webdav.xml"/>
     <xi:include href="xml/e-time-utils.xml"/>
     <xi:include href="xml/e-uid.xml"/>
     <xi:include href="xml/e-util.xml"/>
@@ -39,6 +50,10 @@
     <title>Index of deprecated symbols</title>
     <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
   </index>
+  <index id="api-index-2.92" role="2.92">
+    <title>Index of new symbols in 2.92</title>
+    <xi:include href="xml/api-index-2.92.xml"><xi:fallback /></xi:include>
+  </index>
   <index id="api-index-2.32" role="2.32">
     <title>Index of new symbols in 2.32</title>
     <xi:include href="xml/api-index-2.32.xml"><xi:fallback /></xi:include>
diff --git a/docs/reference/libedataserver/libedataserver-sections.txt b/docs/reference/libedataserver/libedataserver-sections.txt
index 4cf7f11..486b095 100644
--- a/docs/reference/libedataserver/libedataserver-sections.txt
+++ b/docs/reference/libedataserver/libedataserver-sections.txt
@@ -189,41 +189,31 @@ e_proxy_get_type
 <TITLE>ESource</TITLE>
 ESource
 e_source_new
-e_source_new_with_absolute_uri
-e_source_new_from_xml_node
-e_source_new_from_standalone_xml
-e_source_copy
-e_source_update_from_xml_node
-e_source_uid_from_xml_node
-e_source_set_group
-e_source_set_name
-e_source_set_relative_uri
-e_source_set_absolute_uri
-e_source_set_color_spec
-e_source_set_readonly
-e_source_peek_group
-e_source_peek_uid
-e_source_peek_name
-e_source_peek_relative_uri
-e_source_peek_absolute_uri
-e_source_peek_color_spec
-e_source_get_readonly
-e_source_get_uri
-e_source_dump_to_xml_node
-e_source_to_standalone_xml
-e_source_get_property
-e_source_set_property
-e_source_foreach_property
-e_source_get_duped_property
-e_source_build_absolute_uri
+e_source_hash
 e_source_equal
-e_source_xmlstr_equal
+e_source_sync
+e_source_reload
+e_source_changed
+e_source_redirect
+e_source_get_uid
+e_source_get_file
+e_source_get_node
+e_source_get_parent
+e_source_set_parent
+e_source_get_extension
+e_source_has_extension
+e_source_get_backend_name
+e_source_set_backend_name
+e_source_get_display_name
+e_source_set_display_name
+e_source_compare_by_display_name
 <SUBSECTION Standard>
 E_SOURCE
 E_IS_SOURCE
 E_TYPE_SOURCE
 E_SOURCE_CLASS
 E_IS_SOURCE_CLASS
+E_SOURCE_GET_CLASS
 ESourceClass
 <SUBSECTION Private>
 ESourcePrivate
@@ -231,6 +221,261 @@ e_source_get_type
 </SECTION>
 
 <SECTION>
+<FILE>e-source-alarms</FILE>
+<TITLE>ESourceAlarms</TITLE>
+ESourceAlarms
+E_SOURCE_EXTENSION_ALARMS
+e_source_alarms_get_include_me
+e_source_alarms_set_include_me
+e_source_alarms_get_last_notified
+e_source_alarms_set_last_notified
+<SUBSECTION Standard>
+E_SOURCE_ALARMS
+E_IS_SOURCE_ALARMS
+E_TYPE_SOURCE_ALARMS
+E_SOURCE_ALARMS_CLASS
+E_IS_SOURCE_ALARMS_CLASS
+E_SOURCE_ALARMS_GET_CLASS
+ESourceAlarmsClass
+<SUBSECTION Private>
+ESourceAlarmsPrivate
+e_source_alarms_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-authentication</FILE>
+<TITLE>ESourceAuthentication</TITLE>
+ESourceAuthentication
+E_SOURCE_EXTENSION_AUTHENTICATION
+e_source_authentication_required
+e_source_authentication_get_domain
+e_source_authentication_set_domain
+e_source_authentication_get_host
+e_source_authentication_set_host
+e_source_authentication_get_method
+e_source_authentication_set_method
+e_source_authentication_get_port
+e_source_authentication_set_port
+e_source_authentication_get_remember_password
+e_source_authentication_set_remember_password
+e_source_authentication_get_user
+e_source_authentication_set_user
+<SUBSECTION Standard>
+E_SOURCE_AUTHENTICATION
+E_IS_SOURCE_AUTHENTICATION
+E_TYPE_SOURCE_AUTHENTICATION
+E_SOURCE_AUTHENTICATION_CLASS
+E_IS_SOURCE_AUTHENTICATION_CLASS
+E_SOURCE_AUTHENTICATION_GET_CLASS
+ESourceAuthenticationClass
+<SUBSECTION Private>
+ESourceAuthenticationPrivate
+e_source_authentication_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-autocomplete</FILE>
+<TITLE>ESourceAutocomplete</TITLE>
+ESourceAutocomplete
+E_SOURCE_EXTENSION_AUTOCOMPLETE
+e_source_autocomplete_get_include_me
+e_source_autocomplete_set_include_me
+<SUBSECTION Standard>
+E_SOURCE_AUTOCOMPLETE
+E_IS_SOURCE_AUTOCOMPLETE
+E_TYPE_SOURCE_AUTOCOMPLETE
+E_SOURCE_AUTOCOMPLETE_CLASS
+E_IS_SOURCE_AUTOCOMPLETE_CLASS
+E_SOURCE_AUTOCOMPLETE_GET_CLASS
+ESourceAutocompleteClass
+<SUBSECTION Private>
+ESourceAutocompletePrivate
+e_source_autocomplete_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-extension</FILE>
+<TITLE>ESourceExtension</TITLE>
+ESourceExtension
+E_SOURCE_PARAM_SETTING
+e_source_extension_get_source
+<SUBSECTION Standard>
+E_SOURCE_EXTENSION
+E_IS_SOURCE_EXTENSION
+E_TYPE_SOURCE_EXTENSION
+E_SOURCE_EXTENSION_CLASS
+E_IS_SOURCE_EXTENSION_CLASS
+E_SOURCE_EXTENSION_GET_CLASS
+ESourceExtensionClass
+<SUBSECTION Private>
+ESourceExtensionPrivate
+e_source_extension_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-offline</FILE>
+<TITLE>ESourceOffline</TITLE>
+ESourceOffline
+E_SOURCE_EXTENSION_OFFLINE
+e_source_offline_get_stay_synchronized
+e_source_offline_set_stay_synchronized
+<SUBSECTION Standard>
+E_SOURCE_OFFLINE
+E_IS_SOURCE_OFFLINE
+E_TYPE_SOURCE_OFFLINE
+E_SOURCE_OFFLINE_CLASS
+E_IS_SOURCE_OFFLINE_CLASS
+E_SOURCE_OFFLINE_GET_CLASS
+ESourceOfflineClass
+<SUBSECTION Private>
+ESourceOfflinePrivate
+e_source_offline_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-password</FILE>
+<TITLE>ESource Passwords</TITLE>
+E_SOURCE_PASSWORD_ERROR
+e_source_password_store
+e_source_password_store_finish
+e_source_password_store_sync
+e_source_password_lookup
+e_source_password_lookup_finish
+e_source_password_lookup_sync
+e_source_password_delete
+e_source_password_delete_finish
+e_source_password_delete_sync
+e_source_password_free
+<SUBSECTION Private>
+e_source_password_error_quark
+</SECTION>
+
+<SECTION>
+<FILE>e-source-refresh</FILE>
+<TITLE>ESourceRefresh</TITLE>
+ESourceRefresh
+E_SOURCE_EXTENSION_REFRESH
+e_source_refresh_get_interval_minutes
+e_source_refresh_set_interval_minutes
+<SUBSECTION Standard>
+E_SOURCE_REFRESH
+E_IS_SOURCE_REFRESH
+E_TYPE_SOURCE_REFRESH
+E_SOURCE_REFRESH_CLASS
+E_IS_SOURCE_REFRESH_CLASS
+E_SOURCE_REFRESH_GET_CLASS
+ESourceRefreshClass
+<SUBSECTION Private>
+ESourceRefreshPrivate
+e_source_refresh_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-registry</FILE>
+<TITLE>ESourceRegistry</TITLE>
+ESourceRegistry
+e_source_registry_get_default
+e_source_registry_add_source
+e_source_registry_remove_source
+e_source_registry_load_sources
+e_source_registry_load_directory
+e_source_registry_load_file
+e_source_registry_load_error
+e_source_registry_lookup_by_file
+e_source_registry_lookup_by_uid
+e_source_registry_list_sources
+e_source_registry_build_display_tree
+e_source_registry_get_default_address_book
+e_source_registry_set_default_address_book
+e_source_registry_get_default_calendar
+e_source_registry_set_default_calendar
+e_source_registry_get_default_memo_list
+e_source_registry_set_default_memo_list
+e_source_registry_get_default_task_list
+e_source_registry_set_default_task_list
+<SUBSECTION Standard>
+E_SOURCE_REGISTRY
+E_IS_SOURCE_REGISTRY
+E_TYPE_SOURCE_REGISTRY
+E_SOURCE_REGISTRY_CLASS
+E_IS_SOURCE_REGISTRY_CLASS
+E_SOURCE_REGISTRY_GET_CLASS
+ESourceRegistryClass
+<SUBSECTION Private>
+ESourceRegistryPrivate
+e_source_registry_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-security</FILE>
+<TITLE>ESourceSecurity</TITLE>
+ESourceSecurity
+E_SOURCE_EXTENSION_SECURITY
+e_source_security_get_method
+e_source_security_set_method
+e_source_security_get_secure
+e_source_security_set_secure
+<SUBSECTION Standard>
+E_SOURCE_SECURITY
+E_IS_SOURCE_SECURITY
+E_TYPE_SOURCE_SECURITY
+E_SOURCE_SECURITY_CLASS
+E_IS_SOURCE_SECURITY_CLASS
+E_SOURCE_SECURITY_GET_CLASS
+ESourceSecurityClass
+<SUBSECTION Private>
+ESourceSecurityPrivate
+e_source_security_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-selectable</FILE>
+<TITLE>ESourceSelectable</TITLE>
+ESourceSelectable
+e_source_selectable_get_color
+e_source_selectable_set_color
+e_source_selectable_get_enabled
+e_source_selectable_set_enabled
+e_source_selectable_get_writable_hint
+e_source_selectable_set_writable_hint
+<SUBSECTION Standard>
+E_SOURCE_SELECTABLE
+E_IS_SOURCE_SELECTABLE
+E_TYPE_SOURCE_SELECTABLE
+E_SOURCE_SELECTABLE_CLASS
+E_IS_SOURCE_SELECTABLE_CLASS
+E_SOURCE_SELECTABLE_GET_CLASS
+ESourceSelectableClass
+<SUBSECTION Private>
+ESourceSelectablePrivate
+e_source_selectable_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-webdav</FILE>
+<TITLE>ESourceWebdav</TITLE>
+ESourceWebdav
+E_SOURCE_EXTENSION_WEBDAV_BACKEND
+e_source_webdav_get_display_name
+e_source_webdav_set_display_name
+e_source_webdav_get_soup_uri
+e_source_webdav_set_soup_uri
+e_source_webdav_get_avoid_ifmatch
+e_source_webdav_set_avoid_ifmatch
+<SUBSECTION Standard>
+E_SOURCE_WEBDAV
+E_IS_SOURCE_WEBDAV
+E_TYPE_SOURCE_WEBDAV
+E_SOURCE_WEBDAV_CLASS
+E_IS_SOURCE_WEBDAV_CLASS
+E_SOURCE_WEBDAV_GET_CLASS
+ESourceWebdavClass
+<SUBSECTION Private>
+ESourceWebdavPrivate
+e_source_webdav_get_type
+</SECTION>
+
+<SECTION>
 <FILE>e-categories</FILE>
 e_categories_get_list
 e_categories_add
diff --git a/docs/reference/libedataserver/libedataserver.types b/docs/reference/libedataserver/libedataserver.types
index 89ce70f..b07e098 100644
--- a/docs/reference/libedataserver/libedataserver.types
+++ b/docs/reference/libedataserver/libedataserver.types
@@ -4,6 +4,13 @@
 #include <libedataserver/e-list.h>
 #include <libedataserver/e-list-iterator.h>
 #include <libedataserver/e-source.h>
+#include <libedataserver/e-source-authentication.h>
+#include <libedataserver/e-source-extension.h>
+#include <libedataserver/e-source-offline.h>
+#include <libedataserver/e-source-refresh.h>
+#include <libedataserver/e-source-registry.h>
+#include <libedataserver/e-source-security.h>
+#include <libedataserver/e-source-selectable.h>
 
 e_account_get_type
 e_account_list_get_type
@@ -11,3 +18,10 @@ e_iterator_get_type
 e_list_get_type
 e_list_iterator_get_type
 e_source_get_type
+e_source_authentication_get_type
+e_source_extension_get_type
+e_source_offline_get_type
+e_source_refresh_get_type
+e_source_registry_get_type
+e_source_security_get_type
+e_source_selectable_get_type
diff --git a/docs/reference/libedataserver/tmpl/e-source-alarms.sgml b/docs/reference/libedataserver/tmpl/e-source-alarms.sgml
new file mode 100644
index 0000000..4e519fd
--- /dev/null
+++ b/docs/reference/libedataserver/tmpl/e-source-alarms.sgml
@@ -0,0 +1,71 @@
+<!-- ##### SECTION Title ##### -->
+ESourceAlarm
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceAlarms ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_ALARMS ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION e_source_alarms_get_include_me ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_alarms_set_include_me ##### -->
+<para>
+
+</para>
+
+ extension: 
+ include_me: 
+
+
+<!-- ##### FUNCTION e_source_alarms_get_last_notified ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_alarms_set_last_notified ##### -->
+<para>
+
+</para>
+
+ extension: 
+ last_notified: 
+
+
diff --git a/docs/reference/libedataserver/tmpl/e-source-authentication.sgml b/docs/reference/libedataserver/tmpl/e-source-authentication.sgml
new file mode 100644
index 0000000..4b66f0c
--- /dev/null
+++ b/docs/reference/libedataserver/tmpl/e-source-authentication.sgml
@@ -0,0 +1,182 @@
+<!-- ##### SECTION Title ##### -->
+ESourceAuthentication
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceAuthentication ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ARG ESourceAuthentication:domain ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ESourceAuthentication:host ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ESourceAuthentication:method ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ESourceAuthentication:port ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ESourceAuthentication:remember-password ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ESourceAuthentication:user ##### -->
+<para>
+
+</para>
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_AUTHENTICATION ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION e_source_authentication_required ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_authentication_get_domain ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_authentication_set_domain ##### -->
+<para>
+
+</para>
+
+ extension: 
+ domain: 
+
+
+<!-- ##### FUNCTION e_source_authentication_get_host ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_authentication_set_host ##### -->
+<para>
+
+</para>
+
+ extension: 
+ host: 
+
+
+<!-- ##### FUNCTION e_source_authentication_get_method ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_authentication_set_method ##### -->
+<para>
+
+</para>
+
+ extension: 
+ method: 
+
+
+<!-- ##### FUNCTION e_source_authentication_get_port ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_authentication_set_port ##### -->
+<para>
+
+</para>
+
+ extension: 
+ port: 
+
+
+<!-- ##### FUNCTION e_source_authentication_get_remember_password ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_authentication_set_remember_password ##### -->
+<para>
+
+</para>
+
+ extension: 
+ remember_password: 
+
+
+<!-- ##### FUNCTION e_source_authentication_get_user ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_authentication_set_user ##### -->
+<para>
+
+</para>
+
+ extension: 
+ user: 
+
+
diff --git a/docs/reference/libedataserver/tmpl/e-source-autocomplete.sgml b/docs/reference/libedataserver/tmpl/e-source-autocomplete.sgml
new file mode 100644
index 0000000..6f2ecbf
--- /dev/null
+++ b/docs/reference/libedataserver/tmpl/e-source-autocomplete.sgml
@@ -0,0 +1,53 @@
+<!-- ##### SECTION Title ##### -->
+ESourceAutocomplete
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceAutocomplete ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_AUTOCOMPLETE ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION e_source_autocomplete_get_include_me ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_autocomplete_set_include_me ##### -->
+<para>
+
+</para>
+
+ extension: 
+ include_me: 
+
+
diff --git a/docs/reference/libedataserver/tmpl/e-source-extension.sgml b/docs/reference/libedataserver/tmpl/e-source-extension.sgml
new file mode 100644
index 0000000..61ac733
--- /dev/null
+++ b/docs/reference/libedataserver/tmpl/e-source-extension.sgml
@@ -0,0 +1,49 @@
+<!-- ##### SECTION Title ##### -->
+ESourceExtension
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceExtension ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ARG ESourceExtension:source ##### -->
+<para>
+
+</para>
+
+<!-- ##### MACRO E_SOURCE_PARAM_SETTING ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION e_source_extension_get_source ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
diff --git a/docs/reference/libedataserver/tmpl/e-source-offline.sgml b/docs/reference/libedataserver/tmpl/e-source-offline.sgml
new file mode 100644
index 0000000..ce1a005
--- /dev/null
+++ b/docs/reference/libedataserver/tmpl/e-source-offline.sgml
@@ -0,0 +1,58 @@
+<!-- ##### SECTION Title ##### -->
+ESourceOffline
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceOffline ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ARG ESourceOffline:stay-synchronized ##### -->
+<para>
+
+</para>
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_OFFLINE ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION e_source_offline_get_stay_synchronized ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_offline_set_stay_synchronized ##### -->
+<para>
+
+</para>
+
+ extension: 
+ stay_synchronized: 
+
+
diff --git a/docs/reference/libedataserver/tmpl/e-source-password.sgml b/docs/reference/libedataserver/tmpl/e-source-password.sgml
new file mode 100644
index 0000000..485bd71
--- /dev/null
+++ b/docs/reference/libedataserver/tmpl/e-source-password.sgml
@@ -0,0 +1,145 @@
+<!-- ##### SECTION Title ##### -->
+ESource Passwords
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### MACRO E_SOURCE_PASSWORD_ERROR ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION e_source_password_store ##### -->
+<para>
+
+</para>
+
+ source: 
+ password: 
+ permanently: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION e_source_password_store_finish ##### -->
+<para>
+
+</para>
+
+ source: 
+ result: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_password_store_sync ##### -->
+<para>
+
+</para>
+
+ source: 
+ password: 
+ permanently: 
+ cancellable: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_password_lookup ##### -->
+<para>
+
+</para>
+
+ source: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION e_source_password_lookup_finish ##### -->
+<para>
+
+</para>
+
+ source: 
+ result: 
+ password: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_password_lookup_sync ##### -->
+<para>
+
+</para>
+
+ source: 
+ cancellable: 
+ password: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_password_delete ##### -->
+<para>
+
+</para>
+
+ source: 
+ io_priority: 
+ cancellable: 
+ callback: 
+ user_data: 
+
+
+<!-- ##### FUNCTION e_source_password_delete_finish ##### -->
+<para>
+
+</para>
+
+ source: 
+ result: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_password_delete_sync ##### -->
+<para>
+
+</para>
+
+ source: 
+ cancellable: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_password_free ##### -->
+<para>
+
+</para>
+
+ password: 
+
+
diff --git a/docs/reference/libedataserver/tmpl/e-source-refresh.sgml b/docs/reference/libedataserver/tmpl/e-source-refresh.sgml
new file mode 100644
index 0000000..5b3201b
--- /dev/null
+++ b/docs/reference/libedataserver/tmpl/e-source-refresh.sgml
@@ -0,0 +1,58 @@
+<!-- ##### SECTION Title ##### -->
+ESourceRefresh
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceRefresh ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ARG ESourceRefresh:interval-minutes ##### -->
+<para>
+
+</para>
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_REFRESH ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION e_source_refresh_get_interval_minutes ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_refresh_set_interval_minutes ##### -->
+<para>
+
+</para>
+
+ extension: 
+ interval_in_minutes: 
+
+
diff --git a/docs/reference/libedataserver/tmpl/e-source-registry.sgml b/docs/reference/libedataserver/tmpl/e-source-registry.sgml
new file mode 100644
index 0000000..8ebda9c
--- /dev/null
+++ b/docs/reference/libedataserver/tmpl/e-source-registry.sgml
@@ -0,0 +1,263 @@
+<!-- ##### SECTION Title ##### -->
+ESourceRegistry
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceRegistry ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SIGNAL ESourceRegistry::load-error ##### -->
+<para>
+
+</para>
+
+ esourceregistry: the object which received the signal.
+ arg1: 
+ arg2: 
+
+<!-- ##### SIGNAL ESourceRegistry::source-added ##### -->
+<para>
+
+</para>
+
+ esourceregistry: the object which received the signal.
+ arg1: 
+
+<!-- ##### SIGNAL ESourceRegistry::source-changed ##### -->
+<para>
+
+</para>
+
+ esourceregistry: the object which received the signal.
+ arg1: 
+
+<!-- ##### SIGNAL ESourceRegistry::source-removed ##### -->
+<para>
+
+</para>
+
+ esourceregistry: the object which received the signal.
+ arg1: 
+
+<!-- ##### ARG ESourceRegistry:default-address-book ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ESourceRegistry:default-calendar ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ESourceRegistry:default-memo-list ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ESourceRegistry:default-task-list ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION e_source_registry_get_default ##### -->
+<para>
+
+</para>
+
+ void: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_add_source ##### -->
+<para>
+
+</para>
+
+ registry: 
+ source: 
+
+
+<!-- ##### FUNCTION e_source_registry_remove_source ##### -->
+<para>
+
+</para>
+
+ registry: 
+ source: 
+
+
+<!-- ##### FUNCTION e_source_registry_load_sources ##### -->
+<para>
+
+</para>
+
+ registry: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_load_directory ##### -->
+<para>
+
+</para>
+
+ registry: 
+ path: 
+ monitor_for_changes: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_load_file ##### -->
+<para>
+
+</para>
+
+ registry: 
+ file: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_load_error ##### -->
+<para>
+
+</para>
+
+ registry: 
+ file: 
+ error: 
+
+
+<!-- ##### FUNCTION e_source_registry_lookup_by_file ##### -->
+<para>
+
+</para>
+
+ registry: 
+ file: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_lookup_by_uid ##### -->
+<para>
+
+</para>
+
+ registry: 
+ uid: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_list_sources ##### -->
+<para>
+
+</para>
+
+ registry: 
+ extension_name: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_build_display_tree ##### -->
+<para>
+
+</para>
+
+ registry: 
+ extension_name: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_get_default_address_book ##### -->
+<para>
+
+</para>
+
+ registry: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_set_default_address_book ##### -->
+<para>
+
+</para>
+
+ registry: 
+ default_source: 
+
+
+<!-- ##### FUNCTION e_source_registry_get_default_calendar ##### -->
+<para>
+
+</para>
+
+ registry: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_set_default_calendar ##### -->
+<para>
+
+</para>
+
+ registry: 
+ default_source: 
+
+
+<!-- ##### FUNCTION e_source_registry_get_default_memo_list ##### -->
+<para>
+
+</para>
+
+ registry: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_set_default_memo_list ##### -->
+<para>
+
+</para>
+
+ registry: 
+ default_source: 
+
+
+<!-- ##### FUNCTION e_source_registry_get_default_task_list ##### -->
+<para>
+
+</para>
+
+ registry: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_registry_set_default_task_list ##### -->
+<para>
+
+</para>
+
+ registry: 
+ default_source: 
+
+
diff --git a/docs/reference/libedataserver/tmpl/e-source-security.sgml b/docs/reference/libedataserver/tmpl/e-source-security.sgml
new file mode 100644
index 0000000..87aca15
--- /dev/null
+++ b/docs/reference/libedataserver/tmpl/e-source-security.sgml
@@ -0,0 +1,81 @@
+<!-- ##### SECTION Title ##### -->
+ESourceSecurity
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceSecurity ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ARG ESourceSecurity:method ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ESourceSecurity:secure ##### -->
+<para>
+
+</para>
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_SECURITY ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION e_source_security_get_method ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_security_set_method ##### -->
+<para>
+
+</para>
+
+ extension: 
+ method: 
+
+
+<!-- ##### FUNCTION e_source_security_get_secure ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_security_set_secure ##### -->
+<para>
+
+</para>
+
+ extension: 
+ secure: 
+
+
diff --git a/docs/reference/libedataserver/tmpl/e-source-selectable.sgml b/docs/reference/libedataserver/tmpl/e-source-selectable.sgml
new file mode 100644
index 0000000..bbcce4a
--- /dev/null
+++ b/docs/reference/libedataserver/tmpl/e-source-selectable.sgml
@@ -0,0 +1,97 @@
+<!-- ##### SECTION Title ##### -->
+ESourceSelectable
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceSelectable ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### ARG ESourceSelectable:color ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ESourceSelectable:enabled ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ESourceSelectable:writable-hint ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION e_source_selectable_get_color ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_selectable_set_color ##### -->
+<para>
+
+</para>
+
+ extension: 
+ color: 
+
+
+<!-- ##### FUNCTION e_source_selectable_get_enabled ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_selectable_set_enabled ##### -->
+<para>
+
+</para>
+
+ extension: 
+ enabled: 
+
+
+<!-- ##### FUNCTION e_source_selectable_get_writable_hint ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_selectable_set_writable_hint ##### -->
+<para>
+
+</para>
+
+ extension: 
+ writable_hint: 
+
+
diff --git a/docs/reference/libedataserver/tmpl/e-source-webdav.sgml b/docs/reference/libedataserver/tmpl/e-source-webdav.sgml
new file mode 100644
index 0000000..aa3dce9
--- /dev/null
+++ b/docs/reference/libedataserver/tmpl/e-source-webdav.sgml
@@ -0,0 +1,89 @@
+<!-- ##### SECTION Title ##### -->
+ESourceWebdav
+
+<!-- ##### SECTION Short_Description ##### -->
+
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT ESourceWebdav ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### MACRO E_SOURCE_EXTENSION_WEBDAV_BACKEND ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION e_source_webdav_get_display_name ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_webdav_set_display_name ##### -->
+<para>
+
+</para>
+
+ extension: 
+ display_name: 
+
+
+<!-- ##### FUNCTION e_source_webdav_get_soup_uri ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_webdav_set_soup_uri ##### -->
+<para>
+
+</para>
+
+ extension: 
+ uri: 
+
+
+<!-- ##### FUNCTION e_source_webdav_get_avoid_ifmatch ##### -->
+<para>
+
+</para>
+
+ extension: 
+ Returns: 
+
+
+<!-- ##### FUNCTION e_source_webdav_set_avoid_ifmatch ##### -->
+<para>
+
+</para>
+
+ extension: 
+ avoid_ifmatch: 
+
+
diff --git a/docs/reference/libedataserver/tmpl/e-source.sgml b/docs/reference/libedataserver/tmpl/e-source.sgml
index ec60c8f..504ce9e 100644
--- a/docs/reference/libedataserver/tmpl/e-source.sgml
+++ b/docs/reference/libedataserver/tmpl/e-source.sgml
@@ -33,164 +33,98 @@ ESource
 
 @esource: the object which received the signal.
 
-<!-- ##### FUNCTION e_source_new ##### -->
+<!-- ##### ARG ESource:backend-name ##### -->
 <para>
 
 </para>
 
- name: 
- relative_uri: 
- Returns: 
-
-
-<!-- ##### FUNCTION e_source_new_with_absolute_uri ##### -->
+<!-- ##### ARG ESource:display-name ##### -->
 <para>
 
 </para>
 
- name: 
- absolute_uri: 
- Returns: 
-
-
-<!-- ##### FUNCTION e_source_new_from_xml_node ##### -->
+<!-- ##### ARG ESource:file ##### -->
 <para>
 
 </para>
 
- node: 
- Returns: 
-
-
-<!-- ##### FUNCTION e_source_new_from_standalone_xml ##### -->
+<!-- ##### ARG ESource:parent ##### -->
 <para>
 
 </para>
 
- xml: 
- Returns: 
-
-
-<!-- ##### FUNCTION e_source_copy ##### -->
+<!-- ##### ARG ESource:uid ##### -->
 <para>
 
 </para>
 
- source: 
- Returns: 
-
-
-<!-- ##### FUNCTION e_source_update_from_xml_node ##### -->
-<para>
-
-</para>
-
- source: 
- node: 
- changed_return: 
- Returns: 
-
-
-<!-- ##### FUNCTION e_source_uid_from_xml_node ##### -->
+<!-- ##### FUNCTION e_source_new ##### -->
 <para>
 
 </para>
 
- node: 
+ file: 
+ error: 
 @Returns: 
 
 
-<!-- ##### FUNCTION e_source_set_group ##### -->
-<para>
-
-</para>
-
- source: 
- group: 
-
-
-<!-- ##### FUNCTION e_source_set_name ##### -->
-<para>
-
-</para>
-
- source: 
- name: 
-
-
-<!-- ##### FUNCTION e_source_set_relative_uri ##### -->
-<para>
-
-</para>
-
- source: 
- relative_uri: 
-
-
-<!-- ##### FUNCTION e_source_set_absolute_uri ##### -->
+<!-- ##### FUNCTION e_source_hash ##### -->
 <para>
 
 </para>
 
 @source: 
- absolute_uri: 
-
-
-<!-- ##### FUNCTION e_source_set_color_spec ##### -->
-<para>
-
-</para>
-
- source: 
- color_spec: 
+ Returns: 
 
 
-<!-- ##### FUNCTION e_source_set_readonly ##### -->
+<!-- ##### FUNCTION e_source_equal ##### -->
 <para>
 
 </para>
 
- source: 
- readonly: 
+ source1: 
+ source2: 
+ Returns: 
 
 
-<!-- ##### FUNCTION e_source_peek_group ##### -->
+<!-- ##### FUNCTION e_source_sync ##### -->
 <para>
 
 </para>
 
 @source: 
+ error: 
 @Returns: 
 
 
-<!-- ##### FUNCTION e_source_peek_uid ##### -->
+<!-- ##### FUNCTION e_source_reload ##### -->
 <para>
 
 </para>
 
 @source: 
+ error: 
 @Returns: 
 
 
-<!-- ##### FUNCTION e_source_peek_name ##### -->
+<!-- ##### FUNCTION e_source_changed ##### -->
 <para>
 
 </para>
 
 @source: 
- Returns: 
 
 
-<!-- ##### FUNCTION e_source_peek_relative_uri ##### -->
+<!-- ##### FUNCTION e_source_redirect ##### -->
 <para>
 
 </para>
 
 @source: 
- Returns: 
+ directory: 
 
 
-<!-- ##### FUNCTION e_source_peek_absolute_uri ##### -->
+<!-- ##### FUNCTION e_source_get_uid ##### -->
 <para>
 
 </para>
@@ -199,7 +133,7 @@ ESource
 @Returns: 
 
 
-<!-- ##### FUNCTION e_source_peek_color_spec ##### -->
+<!-- ##### FUNCTION e_source_get_file ##### -->
 <para>
 
 </para>
@@ -208,7 +142,7 @@ ESource
 @Returns: 
 
 
-<!-- ##### FUNCTION e_source_get_readonly ##### -->
+<!-- ##### FUNCTION e_source_get_node ##### -->
 <para>
 
 </para>
@@ -217,7 +151,7 @@ ESource
 @Returns: 
 
 
-<!-- ##### FUNCTION e_source_get_uri ##### -->
+<!-- ##### FUNCTION e_source_get_parent ##### -->
 <para>
 
 </para>
@@ -226,90 +160,78 @@ ESource
 @Returns: 
 
 
-<!-- ##### FUNCTION e_source_dump_to_xml_node ##### -->
+<!-- ##### FUNCTION e_source_set_parent ##### -->
 <para>
 
 </para>
 
 @source: 
- parent_node: 
+ parent: 
 
 
-<!-- ##### FUNCTION e_source_to_standalone_xml ##### -->
+<!-- ##### FUNCTION e_source_get_extension ##### -->
 <para>
 
 </para>
 
 @source: 
+ extension_name: 
 @Returns: 
 
 
-<!-- ##### FUNCTION e_source_get_property ##### -->
+<!-- ##### FUNCTION e_source_has_extension ##### -->
 <para>
 
 </para>
 
 @source: 
- property: 
+ extension_name: 
 @Returns: 
 
 
-<!-- ##### FUNCTION e_source_set_property ##### -->
+<!-- ##### FUNCTION e_source_get_backend_name ##### -->
 <para>
 
 </para>
 
 @source: 
- property: 
- value: 
+ Returns: 
 
 
-<!-- ##### FUNCTION e_source_foreach_property ##### -->
+<!-- ##### FUNCTION e_source_set_backend_name ##### -->
 <para>
 
 </para>
 
 @source: 
- func: 
- data: 
+ backend_name: 
 
 
-<!-- ##### FUNCTION e_source_get_duped_property ##### -->
+<!-- ##### FUNCTION e_source_get_display_name ##### -->
 <para>
 
 </para>
 
 @source: 
- property: 
 @Returns: 
 
 
-<!-- ##### FUNCTION e_source_build_absolute_uri ##### -->
+<!-- ##### FUNCTION e_source_set_display_name ##### -->
 <para>
 
 </para>
 
 @source: 
- Returns: 
-
-
-<!-- ##### FUNCTION e_source_equal ##### -->
-<para>
-
-</para>
-
- a: 
- b: 
- Returns: 
+ display_name: 
 
 
-<!-- ##### FUNCTION e_source_xmlstr_equal ##### -->
+<!-- ##### FUNCTION e_source_compare_by_display_name ##### -->
 <para>
 
 </para>
 
- a: 
- b: 
+ source1: 
+ source2: 
 @Returns: 
 
 
diff --git a/docs/reference/libedataserverui/libedataserverui-sections.txt b/docs/reference/libedataserverui/libedataserverui-sections.txt
index 6165102..4acca16 100644
--- a/docs/reference/libedataserverui/libedataserverui-sections.txt
+++ b/docs/reference/libedataserverui/libedataserverui-sections.txt
@@ -306,7 +306,8 @@ e_tree_model_generator_get_type
 <TITLE>ESourceSelector</TITLE>
 ESourceSelector
 e_source_selector_new
-e_source_selector_get_source_list
+e_source_selector_get_registry
+e_source_selector_get_extension_name
 e_source_selector_select_source
 e_source_selector_unselect_source
 e_source_selector_select_exclusive
@@ -319,7 +320,6 @@ e_source_selector_set_select_new
 e_source_selector_edit_primary_selection
 e_source_selector_get_primary_selection
 e_source_selector_set_primary_selection
-e_source_selector_get_primary_source_group
 e_source_selector_peek_primary_selection
 e_source_selector_get_source_by_path
 <SUBSECTION Standard>
diff --git a/libedataserver/Makefile.am b/libedataserver/Makefile.am
index cfbee47..2d04207 100644
--- a/libedataserver/Makefile.am
+++ b/libedataserver/Makefile.am
@@ -1,5 +1,8 @@
 lib_LTLIBRARIES = libedataserver-1.2.la
 
+MARSHAL_GENERATED = e-marshal.c e-marshal.h
+ EVO_MARSHAL_RULE@
+
 libedataserver_1_2_la_CPPFLAGS = \
 	$(AM_CPPFLAGS)							\
 	-I$(top_srcdir)							\
@@ -8,12 +11,14 @@ libedataserver_1_2_la_CPPFLAGS = \
 	-DE_DATA_SERVER_LOCALEDIR=\""$(localedir)"\"			\
 	-DE_DATA_SERVER_EXTENSIONDIR=\"$(extensiondir)\"		\
 	-DE_DATA_SERVER_IMAGESDIR=\"$(imagesdir)\"			\
+	-DE_DATA_SERVER_PRIVDATADIR=\"$(privdatadir)\"			\
 	-DE_DATA_SERVER_UI_UIDIR=\""$(uidir)"\"				\
 	-DDEFAULT_EDS_DBUS_TIMEOUT=$(DEFAULT_EDS_DBUS_TIMEOUT)		\
 	$(E_DATA_SERVER_CFLAGS)						\
 	$(SOUP_CFLAGS)
 
 libedataserver_1_2_la_SOURCES =		\
+	$(MARSHAL_GENERATED)		\
 	e-account-list.c		\
 	e-account.c			\
 	e-categories.c			\
@@ -27,6 +32,17 @@ libedataserver_1_2_la_SOURCES =		\
 	e-soap-response.c		\
 	e-sexp.c			\
 	e-source.c			\
+	e-source-extension.c		\
+	e-source-alarms.c		\
+	e-source-authentication.c	\
+	e-source-autocomplete.c		\
+	e-source-offline.c		\
+	e-source-password.c		\
+	e-source-refresh.c		\
+	e-source-registry.c		\
+	e-source-security.c		\
+	e-source-selectable.c		\
+	e-source-webdav.c		\
 	e-debug-log.c			\
 	e-time-utils.c			\
 	e-uid.c				\
@@ -62,6 +78,17 @@ libedataserverinclude_HEADERS =		\
 	e-soap-response.h		\
 	e-sexp.h			\
 	e-source.h			\
+	e-source-alarms.h		\
+	e-source-authentication.h	\
+	e-source-autocomplete.h		\
+	e-source-extension.h		\
+	e-source-offline.h		\
+	e-source-password.h		\
+	e-source-refresh.h		\
+	e-source-registry.h		\
+	e-source-security.h		\
+	e-source-selectable.h		\
+	e-source-webdav.h		\
 	e-debug-log.h			\
 	e-time-utils.h			\
 	e-uid.h				\
@@ -77,9 +104,12 @@ libedataserverinclude_HEADERS =		\
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libedataserver-$(API_VERSION).pc
 
+BUILT_SOURCES = $(MARSHAL_GENERATED)
+
 EXTRA_DIST = 						\
 	$(pkgconfig_DATA:-$(API_VERSION).pc=.pc.in)	\
-	eds-version.h.in
+	eds-version.h.in				\
+	e-marshal.list
 
 CLEANFILES =
 DISTCLEANFILES = eds-version.h $(pkgconfig_DATA)
diff --git a/libedataserver/e-marshal.list b/libedataserver/e-marshal.list
new file mode 100644
index 0000000..4abc0be
--- /dev/null
+++ b/libedataserver/e-marshal.list
@@ -0,0 +1 @@
+NONE:OBJECT,BOXED
diff --git a/libedataserver/e-source-alarms.c b/libedataserver/e-source-alarms.c
new file mode 100644
index 0000000..5068454
--- /dev/null
+++ b/libedataserver/e-source-alarms.c
@@ -0,0 +1,174 @@
+/*
+ * e-source-alarms.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-alarms.h"
+
+#define E_SOURCE_ALARMS_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_ALARMS, ESourceAlarmsPrivate))
+
+struct _ESourceAlarmsPrivate {
+	gboolean include_me;
+	gchar *last_notified;
+};
+
+enum {
+	PROP_0,
+	PROP_INCLUDE_ME,
+	PROP_LAST_NOTIFIED
+};
+
+G_DEFINE_TYPE (
+	ESourceAlarms,
+	e_source_alarms,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_alarms_set_property (GObject *object,
+                            guint property_id,
+                            const GValue *value,
+                            GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_INCLUDE_ME:
+			e_source_alarms_set_include_me (
+				E_SOURCE_ALARMS (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_LAST_NOTIFIED:
+			e_source_alarms_set_last_notified (
+				E_SOURCE_ALARMS (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_alarms_get_property (GObject *object,
+                            guint property_id,
+                            GValue *value,
+                            GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_INCLUDE_ME:
+			g_value_set_boolean (
+				value,
+				e_source_alarms_get_include_me (
+				E_SOURCE_ALARMS (object)));
+			return;
+
+		case PROP_LAST_NOTIFIED:
+			g_value_set_string (
+				value,
+				e_source_alarms_get_last_notified (
+				E_SOURCE_ALARMS (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_source_alarms_class_init (ESourceAlarmsClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceAlarmsPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_alarms_set_property;
+	object_class->get_property = source_alarms_get_property;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_ALARMS;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_INCLUDE_ME,
+		g_param_spec_boolean (
+			"include-me",
+			"IncludeMe",
+			"Include this source in alarm notifications",
+			TRUE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_LAST_NOTIFIED,
+		g_param_spec_string (
+			"last-notified",
+			"LastNotified",
+			"Last alarm notification (in ISO 8601 format)",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_alarms_init (ESourceAlarms *extension)
+{
+	extension->priv = E_SOURCE_ALARMS_GET_PRIVATE (extension);
+}
+
+gboolean
+e_source_alarms_get_include_me (ESourceAlarms *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_ALARMS (extension), FALSE);
+
+	return extension->priv->include_me;
+}
+
+void
+e_source_alarms_set_include_me (ESourceAlarms *extension,
+                                gboolean include_me)
+{
+	g_return_if_fail (E_IS_SOURCE_ALARMS (extension));
+
+	extension->priv->include_me = include_me;
+
+	g_object_notify (G_OBJECT (extension), "include-me");
+}
+
+const gchar *
+e_source_alarms_get_last_notified (ESourceAlarms *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_ALARMS (extension), FALSE);
+
+	return extension->priv->last_notified;
+}
+
+void
+e_source_alarms_set_last_notified (ESourceAlarms *extension,
+                                   const gchar *last_notified)
+{
+	g_return_if_fail (E_IS_SOURCE_ALARMS (extension));
+
+	g_free (extension->priv->last_notified);
+	extension->priv->last_notified = g_strdup (last_notified);
+
+	g_object_notify (G_OBJECT (extension), "last-notified");
+}
diff --git a/libedataserver/e-source-alarms.h b/libedataserver/e-source-alarms.h
new file mode 100644
index 0000000..39ee006
--- /dev/null
+++ b/libedataserver/e-source-alarms.h
@@ -0,0 +1,72 @@
+/*
+ * e-source-alarms.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_ALARMS_H
+#define E_SOURCE_ALARMS_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_ALARMS \
+	(e_source_alarms_get_type ())
+#define E_SOURCE_ALARMS(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_ALARMS, ESourceAlarms))
+#define E_SOURCE_ALARMS_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_ALARMS, ESourceAlarmsClass))
+#define E_IS_SOURCE_ALARMS(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_ALARMS))
+#define E_IS_SOURCE_ALARMS_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_ALARMS))
+#define E_SOURCE_ALARMS_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_ALARMS, ESourceAlarmsClass))
+
+#define E_SOURCE_EXTENSION_ALARMS "Alarms"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceAlarms ESourceAlarms;
+typedef struct _ESourceAlarmsClass ESourceAlarmsClass;
+typedef struct _ESourceAlarmsPrivate ESourceAlarmsPrivate;
+
+struct _ESourceAlarms {
+	ESourceExtension parent;
+	ESourceAlarmsPrivate *priv;
+};
+
+struct _ESourceAlarmsClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_alarms_get_type (void);
+gboolean	e_source_alarms_get_include_me	(ESourceAlarms *extension);
+void		e_source_alarms_set_include_me	(ESourceAlarms *extension,
+						 gboolean include_me);
+const gchar *	e_source_alarms_get_last_notified
+						(ESourceAlarms *extension);
+void		e_source_alarms_set_last_notified
+						(ESourceAlarms *extension,
+						 const gchar *last_notified);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_ALARMS_H */
diff --git a/libedataserver/e-source-authentication.c b/libedataserver/e-source-authentication.c
new file mode 100644
index 0000000..0d39af6
--- /dev/null
+++ b/libedataserver/e-source-authentication.c
@@ -0,0 +1,408 @@
+/*
+ * e-source-authentication.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-authentication.h"
+
+#define E_SOURCE_AUTHENTICATION_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_AUTHENTICATION, ESourceAuthenticationPrivate))
+
+struct _ESourceAuthenticationPrivate {
+	gchar *domain;
+	gchar *host;
+	gchar *method;
+	guint16 port;
+	gboolean remember_password;
+	gchar *user;
+};
+
+enum {
+	PROP_0,
+	PROP_DOMAIN,
+	PROP_HOST,
+	PROP_METHOD,
+	PROP_PORT,
+	PROP_REMEMBER_PASSWORD,
+	PROP_USER
+};
+
+G_DEFINE_TYPE (
+	ESourceAuthentication,
+	e_source_authentication,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_authentication_set_property (GObject *object,
+                                    guint property_id,
+                                    const GValue *value,
+                                    GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_DOMAIN:
+			e_source_authentication_set_domain (
+				E_SOURCE_AUTHENTICATION (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_HOST:
+			e_source_authentication_set_host (
+				E_SOURCE_AUTHENTICATION (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_METHOD:
+			e_source_authentication_set_method (
+				E_SOURCE_AUTHENTICATION (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_PORT:
+			e_source_authentication_set_port (
+				E_SOURCE_AUTHENTICATION (object),
+				g_value_get_uint (value));
+			return;
+
+		case PROP_REMEMBER_PASSWORD:
+			e_source_authentication_set_remember_password (
+				E_SOURCE_AUTHENTICATION (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_USER:
+			e_source_authentication_set_user (
+				E_SOURCE_AUTHENTICATION (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_authentication_get_property (GObject *object,
+                                    guint property_id,
+                                    GValue *value,
+                                    GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_DOMAIN:
+			g_value_set_string (
+				value,
+				e_source_authentication_get_domain (
+				E_SOURCE_AUTHENTICATION (object)));
+			return;
+
+		case PROP_HOST:
+			g_value_set_string (
+				value,
+				e_source_authentication_get_host (
+				E_SOURCE_AUTHENTICATION (object)));
+			return;
+
+		case PROP_METHOD:
+			g_value_set_string (
+				value,
+				e_source_authentication_get_method (
+				E_SOURCE_AUTHENTICATION (object)));
+			return;
+
+		case PROP_PORT:
+			g_value_set_uint (
+				value,
+				e_source_authentication_get_port (
+				E_SOURCE_AUTHENTICATION (object)));
+			return;
+
+		case PROP_REMEMBER_PASSWORD:
+			g_value_set_boolean (
+				value,
+				e_source_authentication_get_remember_password (
+				E_SOURCE_AUTHENTICATION (object)));
+			return;
+
+		case PROP_USER:
+			g_value_set_string (
+				value,
+				e_source_authentication_get_user (
+				E_SOURCE_AUTHENTICATION (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_authentication_finalize (GObject *object)
+{
+	ESourceAuthenticationPrivate *priv;
+
+	priv = E_SOURCE_AUTHENTICATION_GET_PRIVATE (object);
+
+	g_free (priv->domain);
+	g_free (priv->host);
+	g_free (priv->method);
+	g_free (priv->user);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_authentication_parent_class)->finalize (object);
+}
+
+static void
+e_source_authentication_class_init (ESourceAuthenticationClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceAuthenticationPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_authentication_set_property;
+	object_class->get_property = source_authentication_get_property;
+	object_class->finalize = source_authentication_finalize;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_AUTHENTICATION;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DOMAIN,
+		g_param_spec_string (
+			"domain",
+			"Domain",
+			"Authentication domain",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_HOST,
+		g_param_spec_string (
+			"host",
+			"Host",
+			"Host name for the remote account",
+			"",
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_METHOD,
+		g_param_spec_string (
+			"method",
+			"Method",
+			"Authentication method",
+			"none",
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_PORT,
+		g_param_spec_uint (
+			"port",
+			"Port",
+			"Port number for the remote account",
+			0, G_MAXUINT16, 0,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_REMEMBER_PASSWORD,
+		g_param_spec_boolean (
+			"remember-password",
+			"RememberPassword",
+			"Remember the user's password",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_USER,
+		g_param_spec_string (
+			"user",
+			"User",
+			"User name for the remote account",
+			g_get_user_name (),
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_authentication_init (ESourceAuthentication *extension)
+{
+	extension->priv = E_SOURCE_AUTHENTICATION_GET_PRIVATE (extension);
+}
+
+gboolean
+e_source_authentication_required (ESourceAuthentication *extension)
+{
+	const gchar *method;
+
+	/* This is a convenience function for when we just want to
+	 * know if a remote data source requires us to authenticate.
+	 * Our convention is to set the method name to "none" when
+	 * authentication is not required. */
+
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), FALSE);
+
+	method = e_source_authentication_get_method (extension);
+	g_return_val_if_fail (method != NULL && *method != '\0', FALSE);
+
+	return (g_strcmp0 (method, "none") != 0);
+}
+
+const gchar *
+e_source_authentication_get_domain (ESourceAuthentication *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
+
+	return extension->priv->domain;
+}
+
+void
+e_source_authentication_set_domain (ESourceAuthentication *extension,
+                                    const gchar *domain)
+{
+	g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
+
+	g_free (extension->priv->domain);
+	extension->priv->domain = g_strdup (domain);
+
+	g_object_notify (G_OBJECT (extension), "domain");
+}
+
+const gchar *
+e_source_authentication_get_host (ESourceAuthentication *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
+
+	return extension->priv->host;
+}
+
+void
+e_source_authentication_set_host (ESourceAuthentication *extension,
+                                  const gchar *host)
+{
+	g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
+
+	g_free (extension->priv->host);
+	extension->priv->host = g_strdup (host);
+
+	g_object_notify (G_OBJECT (extension), "host");
+}
+
+const gchar *
+e_source_authentication_get_method (ESourceAuthentication *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
+
+	return extension->priv->method;
+}
+
+void
+e_source_authentication_set_method (ESourceAuthentication *extension,
+                                    const gchar *method)
+{
+	g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
+
+	/* Convert empty strings to "none". */
+	if (method == NULL || *method == '\0')
+		method = "none";
+
+	g_free (extension->priv->method);
+	extension->priv->method = g_strdup (method);
+
+	g_object_notify (G_OBJECT (extension), "method");
+}
+
+guint16
+e_source_authentication_get_port (ESourceAuthentication *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), 0);
+
+	return extension->priv->port;
+}
+
+void
+e_source_authentication_set_port (ESourceAuthentication *extension,
+                                  guint16 port)
+{
+	g_return_if_fail (E_SOURCE_AUTHENTICATION (extension));
+
+	extension->priv->port = port;
+
+	g_object_notify (G_OBJECT (extension), "port");
+}
+
+gboolean
+e_source_authentication_get_remember_password (ESourceAuthentication *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), FALSE);
+
+	return extension->priv->remember_password;
+}
+
+void
+e_source_authentication_set_remember_password (ESourceAuthentication *extension,
+                                               gboolean remember_password)
+{
+	g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
+
+	extension->priv->remember_password = remember_password;
+
+	g_object_notify (G_OBJECT (extension), "remember-password");
+}
+
+const gchar *
+e_source_authentication_get_user (ESourceAuthentication *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
+
+	return extension->priv->user;
+}
+
+void
+e_source_authentication_set_user (ESourceAuthentication *extension,
+                                  const gchar *user)
+{
+	g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
+
+	g_free (extension->priv->user);
+	extension->priv->user = g_strdup (user);
+
+	/* Strip leading and trailing whitespace. */
+	if (extension->priv->user != NULL)
+		g_strstrip (extension->priv->user);
+
+	g_object_notify (G_OBJECT (extension), "user");
+}
diff --git a/libedataserver/e-source-authentication.h b/libedataserver/e-source-authentication.h
new file mode 100644
index 0000000..86b3c9e
--- /dev/null
+++ b/libedataserver/e-source-authentication.h
@@ -0,0 +1,96 @@
+/*
+ * e-source-authentication.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_AUTHENTICATION_H
+#define E_SOURCE_AUTHENTICATION_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_AUTHENTICATION \
+	(e_source_authentication_get_type ())
+#define E_SOURCE_AUTHENTICATION(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_AUTHENTICATION, ESourceAuthentication))
+#define E_SOURCE_AUTHENTICATION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_AUTHENTICATION, ESourceAuthenticationClass))
+#define E_IS_SOURCE_AUTHENTICATION(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_AUTHENTICATION))
+#define E_IS_SOURCE_AUTHENTICATION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_AUTHENTICATION))
+#define E_SOURCE_AUTHENTICATION_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_AUTHENTICATION, ESourceAuthenticationClass))
+
+#define E_SOURCE_EXTENSION_AUTHENTICATION "Authentication"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceAuthentication ESourceAuthentication;
+typedef struct _ESourceAuthenticationClass ESourceAuthenticationClass;
+typedef struct _ESourceAuthenticationPrivate ESourceAuthenticationPrivate;
+
+struct _ESourceAuthentication {
+	ESourceExtension parent;
+	ESourceAuthenticationPrivate *priv;
+};
+
+struct _ESourceAuthenticationClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_authentication_get_type (void);
+gboolean	e_source_authentication_required
+					(ESourceAuthentication *extension);
+const gchar *	e_source_authentication_get_domain
+					(ESourceAuthentication *extension);
+void		e_source_authentication_set_domain
+					(ESourceAuthentication *extension,
+					 const gchar *domain);
+const gchar *	e_source_authentication_get_host
+					(ESourceAuthentication *extension);
+void		e_source_authentication_set_host
+					(ESourceAuthentication *extension,
+					 const gchar *host);
+const gchar *	e_source_authentication_get_method
+					(ESourceAuthentication *extension);
+void		e_source_authentication_set_method
+					(ESourceAuthentication *extension,
+					 const gchar *method);
+guint16		e_source_authentication_get_port
+					(ESourceAuthentication *extension);
+void		e_source_authentication_set_port
+					(ESourceAuthentication *extension,
+					 guint16 port);
+gboolean	e_source_authentication_get_remember_password
+					(ESourceAuthentication *extension);
+void		e_source_authentication_set_remember_password
+					(ESourceAuthentication *extension,
+					 gboolean remember_password);
+const gchar *	e_source_authentication_get_user
+					(ESourceAuthentication *extension);
+void		e_source_authentication_set_user
+					(ESourceAuthentication *extension,
+					 const gchar *user);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_AUTHENTICATION_H */
diff --git a/libedataserver/e-source-autocomplete.c b/libedataserver/e-source-autocomplete.c
new file mode 100644
index 0000000..958e631
--- /dev/null
+++ b/libedataserver/e-source-autocomplete.c
@@ -0,0 +1,126 @@
+/*
+ * e-source-autocomplete.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-autocomplete.h"
+
+#define E_SOURCE_AUTOCOMPLETE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_AUTOCOMPLETE, ESourceAutocompletePrivate))
+
+struct _ESourceAutocompletePrivate {
+	gboolean include_me;
+};
+
+enum {
+	PROP_0,
+	PROP_INCLUDE_ME
+};
+
+G_DEFINE_TYPE (
+	ESourceAutocomplete,
+	e_source_autocomplete,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_autocomplete_set_property (GObject *object,
+                                    guint property_id,
+                                    const GValue *value,
+                                    GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_INCLUDE_ME:
+			e_source_autocomplete_set_include_me (
+				E_SOURCE_AUTOCOMPLETE (object),
+				g_value_get_boolean (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_autocomplete_get_property (GObject *object,
+                                    guint property_id,
+                                    GValue *value,
+                                    GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_INCLUDE_ME:
+			g_value_set_boolean (
+				value,
+				e_source_autocomplete_get_include_me (
+				E_SOURCE_AUTOCOMPLETE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_source_autocomplete_class_init (ESourceAutocompleteClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceAutocompletePrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_autocomplete_set_property;
+	object_class->get_property = source_autocomplete_get_property;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_AUTOCOMPLETE;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_INCLUDE_ME,
+		g_param_spec_boolean (
+			"include-me",
+			"IncludeMe",
+			"Include this source when autocompleting",
+			TRUE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_autocomplete_init (ESourceAutocomplete *extension)
+{
+	extension->priv = E_SOURCE_AUTOCOMPLETE_GET_PRIVATE (extension);
+}
+
+gboolean
+e_source_autocomplete_get_include_me (ESourceAutocomplete *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTOCOMPLETE (extension), FALSE);
+
+	return extension->priv->include_me;
+}
+
+void
+e_source_autocomplete_set_include_me (ESourceAutocomplete *extension,
+                                      gboolean include_me)
+{
+	g_return_if_fail (E_IS_SOURCE_AUTOCOMPLETE (extension));
+
+	extension->priv->include_me = include_me;
+
+	g_object_notify (G_OBJECT (extension), "include-me");
+}
diff --git a/libedataserver/e-source-autocomplete.h b/libedataserver/e-source-autocomplete.h
new file mode 100644
index 0000000..b91725b
--- /dev/null
+++ b/libedataserver/e-source-autocomplete.h
@@ -0,0 +1,69 @@
+/*
+ * e-source-autocomplete.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_AUTOCOMPLETE_H
+#define E_SOURCE_AUTOCOMPLETE_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_AUTOCOMPLETE \
+	(e_source_autocomplete_get_type ())
+#define E_SOURCE_AUTOCOMPLETE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_AUTOCOMPLETE, ESourceAutocomplete))
+#define E_SOURCE_AUTOCOMPLETE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_AUTOCOMPLETE, ESourceAutocompleteClass))
+#define E_IS_SOURCE_AUTOCOMPLETE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_AUTOCOMPLETE))
+#define E_IS_SOURCE_AUTOCOMPLETE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_AUTOCOMPLETE))
+#define E_SOURCE_AUTOCOMPLETE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_AUTOCOMPLETE, ESourceAutocompleteClass))
+
+#define E_SOURCE_EXTENSION_AUTOCOMPLETE "Autocomplete"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceAutocomplete ESourceAutocomplete;
+typedef struct _ESourceAutocompleteClass ESourceAutocompleteClass;
+typedef struct _ESourceAutocompletePrivate ESourceAutocompletePrivate;
+
+struct _ESourceAutocomplete {
+	ESourceExtension parent;
+	ESourceAutocompletePrivate *priv;
+};
+
+struct _ESourceAutocompleteClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_autocomplete_get_type (void);
+gboolean	e_source_autocomplete_get_include_me
+					(ESourceAutocomplete *extension);
+void		e_source_autocomplete_set_include_me
+					(ESourceAutocomplete *extension,
+					 gboolean include_me);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_AUTOCOMPLETE_H */
diff --git a/libedataserver/e-source-extension.c b/libedataserver/e-source-extension.c
new file mode 100644
index 0000000..bab3409
--- /dev/null
+++ b/libedataserver/e-source-extension.c
@@ -0,0 +1,167 @@
+/*
+ * e-source-extension.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-extension.h"
+
+#define E_SOURCE_EXTENSION_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_EXTENSION, ESourceExtensionPrivate))
+
+struct _ESourceExtensionPrivate {
+	gpointer source;  /* weak pointer */
+};
+
+enum {
+	PROP_0,
+	PROP_SOURCE
+};
+
+G_DEFINE_ABSTRACT_TYPE (
+	ESourceExtension,
+	e_source_extension,
+	G_TYPE_OBJECT)
+
+static void
+source_extension_set_source (ESourceExtension *extension,
+                             ESource *source)
+{
+	g_return_if_fail (E_IS_SOURCE (source));
+	g_return_if_fail (extension->priv->source == NULL);
+
+	extension->priv->source = source;
+
+	g_object_add_weak_pointer (
+		G_OBJECT (source), &extension->priv->source);
+}
+
+static void
+source_extension_set_property (GObject *object,
+                               guint property_id,
+                               const GValue *value,
+                               GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SOURCE:
+			source_extension_set_source (
+				E_SOURCE_EXTENSION (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_extension_get_property (GObject *object,
+                               guint property_id,
+                               GValue *value,
+                               GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SOURCE:
+			g_value_set_object (
+				value, e_source_extension_get_source (
+				E_SOURCE_EXTENSION (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_extension_dispose (GObject *object)
+{
+	ESourceExtensionPrivate *priv;
+
+	priv = E_SOURCE_EXTENSION_GET_PRIVATE (object);
+
+	if (priv->source != NULL) {
+		g_object_remove_weak_pointer (
+			G_OBJECT (priv->source), &priv->source);
+		priv->source = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (e_source_extension_parent_class)->dispose (object);
+}
+
+static void
+source_extension_notify (GObject *object,
+                         GParamSpec *pspec)
+{
+	ESource *source;
+	ESourceExtension *extension;
+
+	extension = E_SOURCE_EXTENSION (object);
+	source = e_source_extension_get_source (extension);
+
+	if (source != NULL)
+		e_source_changed (source);
+}
+
+static void
+source_extension_constructed (GObject *object)
+{
+	/* This allows subclasses to chain up safely since GObject
+	 * does not implement this method, and we might want to do
+	 * something here in the future. */
+}
+
+static void
+e_source_extension_class_init (ESourceExtensionClass *class)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (class, sizeof (ESourceExtensionPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_extension_set_property;
+	object_class->get_property = source_extension_get_property;
+	object_class->dispose = source_extension_dispose;
+	object_class->notify = source_extension_notify;
+	object_class->constructed = source_extension_constructed;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SOURCE,
+		g_param_spec_object (
+			"source",
+			"Source",
+			"The ESource being extended",
+			E_TYPE_SOURCE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY |
+			G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_source_extension_init (ESourceExtension *extension)
+{
+	extension->priv = E_SOURCE_EXTENSION_GET_PRIVATE (extension);
+}
+
+ESource *
+e_source_extension_get_source (ESourceExtension *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_EXTENSION (extension), NULL);
+
+	/* If the ESource was finalized and our weak pointer set this
+	 * to NULL, then the type cast macro will fail and we'll get a
+	 * runtime warning about it, which is what we want. */
+	return E_SOURCE (extension->priv->source);
+}
diff --git a/libedataserver/e-source-extension.h b/libedataserver/e-source-extension.h
new file mode 100644
index 0000000..d4db376
--- /dev/null
+++ b/libedataserver/e-source-extension.h
@@ -0,0 +1,65 @@
+/*
+ * e-source-extension.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_EXTENSION_H
+#define E_SOURCE_EXTENSION_H
+
+#include <libedataserver/e-source.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_EXTENSION \
+	(e_source_extension_get_type ())
+#define E_SOURCE_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_EXTENSION, ESourceExtension))
+#define E_SOURCE_EXTENSION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_EXTENSION, ESourceExtensionClass))
+#define E_IS_SOURCE_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_EXTENSION))
+#define E_IS_SOURCE_EXTENSION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_EXTENSION))
+#define E_SOURCE_EXTENSION_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_EXTENSION, ESourceExtensionClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceExtension ESourceExtension;
+typedef struct _ESourceExtensionClass ESourceExtensionClass;
+typedef struct _ESourceExtensionPrivate ESourceExtensionPrivate;
+
+struct _ESourceExtension {
+	GObject parent;
+	ESourceExtensionPrivate *priv;
+};
+
+struct _ESourceExtensionClass {
+	GObjectClass parent_class;
+
+	const gchar *name;
+};
+
+GType		e_source_extension_get_type	(void) G_GNUC_CONST;
+ESource *	e_source_extension_get_source	(ESourceExtension *extension);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_EXTENSION_H */
diff --git a/libedataserver/e-source-offline.c b/libedataserver/e-source-offline.c
new file mode 100644
index 0000000..2319d17
--- /dev/null
+++ b/libedataserver/e-source-offline.c
@@ -0,0 +1,126 @@
+/*
+ * e-source-offline.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-offline.h"
+
+#define E_SOURCE_OFFLINE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_OFFLINE, ESourceOfflinePrivate))
+
+struct _ESourceOfflinePrivate {
+	gboolean stay_synchronized;
+};
+
+enum {
+	PROP_0,
+	PROP_STAY_SYNCHRONIZED
+};
+
+G_DEFINE_TYPE (
+	ESourceOffline,
+	e_source_offline,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_offline_set_property (GObject *object,
+                             guint property_id,
+                             const GValue *value,
+                             GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_STAY_SYNCHRONIZED:
+			e_source_offline_set_stay_synchronized (
+				E_SOURCE_OFFLINE (object),
+				g_value_get_boolean (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_offline_get_property (GObject *object,
+                             guint property_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_STAY_SYNCHRONIZED:
+			g_value_set_boolean (
+				value,
+				e_source_offline_get_stay_synchronized (
+				E_SOURCE_OFFLINE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_source_offline_class_init (ESourceOfflineClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceOfflinePrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_offline_set_property;
+	object_class->get_property = source_offline_get_property;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_OFFLINE;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_STAY_SYNCHRONIZED,
+		g_param_spec_boolean (
+			"stay-synchronized",
+			"StaySynchronized",
+			"Keep remote content synchronized locally",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_offline_init (ESourceOffline *extension)
+{
+	extension->priv = E_SOURCE_OFFLINE_GET_PRIVATE (extension);
+}
+
+gboolean
+e_source_offline_get_stay_synchronized (ESourceOffline *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_OFFLINE (extension), FALSE);
+
+	return extension->priv->stay_synchronized;
+}
+
+void
+e_source_offline_set_stay_synchronized (ESourceOffline *extension,
+                                        gboolean stay_synchronized)
+{
+	g_return_if_fail (E_IS_SOURCE_OFFLINE (extension));
+
+	extension->priv->stay_synchronized = stay_synchronized;
+
+	g_object_notify (G_OBJECT (extension), "stay-synchronized");
+}
diff --git a/libedataserver/e-source-offline.h b/libedataserver/e-source-offline.h
new file mode 100644
index 0000000..d31092e
--- /dev/null
+++ b/libedataserver/e-source-offline.h
@@ -0,0 +1,69 @@
+/*
+ * e-source-offline.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_OFFLINE_H
+#define E_SOURCE_OFFLINE_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_OFFLINE \
+	(e_source_offline_get_type ())
+#define E_SOURCE_OFFLINE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_OFFLINE, ESourceOffline))
+#define E_SOURCE_OFFLINE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_OFFLINE, ESourceOfflineClass))
+#define E_IS_SOURCE_OFFLINE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_OFFLINE))
+#define E_IS_SOURCE_OFFLINE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_OFFLINE))
+#define E_SOURCE_OFFLINE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_OFFLINE, ESourceOfflineClass))
+
+#define E_SOURCE_EXTENSION_OFFLINE "Offline"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceOffline ESourceOffline;
+typedef struct _ESourceOfflineClass ESourceOfflineClass;
+typedef struct _ESourceOfflinePrivate ESourceOfflinePrivate;
+
+struct _ESourceOffline {
+	ESourceExtension parent;
+	ESourceOfflinePrivate *priv;
+};
+
+struct _ESourceOfflineClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_offline_get_type	(void);
+gboolean	e_source_offline_get_stay_synchronized
+						(ESourceOffline *extension);
+void		e_source_offline_set_stay_synchronized
+						(ESourceOffline *extension,
+						 gboolean stay_synchronized);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_OFFLINE_H */
diff --git a/libedataserver/e-source-password.c b/libedataserver/e-source-password.c
new file mode 100644
index 0000000..6d9c0ce
--- /dev/null
+++ b/libedataserver/e-source-password.c
@@ -0,0 +1,412 @@
+/*
+ * e-source-password.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-password.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+#include <gnome-keyring.h>
+
+#define KEYRING_ITEM_ATTRIBUTE_NAME	"e-source-uid"
+#define KEYRING_ITEM_DISPLAY_FORMAT	"Evolution Data Source %s"
+
+typedef struct _Context Context;
+
+struct _Context {
+	gchar *password;
+	gboolean permanently;
+};
+
+static GnomeKeyringPasswordSchema schema = {
+	GNOME_KEYRING_ITEM_GENERIC_SECRET,
+	{
+		{ KEYRING_ITEM_ATTRIBUTE_NAME,
+		  GNOME_KEYRING_ATTRIBUTE_TYPE_STRING },
+		{ NULL, 0 }
+	}
+};
+
+static void
+context_free (Context *context)
+{
+	g_free (context->password);
+	g_slice_free (Context, context);
+}
+
+GQuark
+e_source_password_error_quark (void)
+{
+	static GQuark quark = 0;
+
+	if (G_UNLIKELY (quark == 0)) {
+		const gchar *string = "e-source-password-error-quark";
+		quark = g_quark_from_static_string (string);
+	}
+
+	return quark;
+}
+
+static void
+source_password_store_thread (GSimpleAsyncResult *simple,
+                              GObject *object,
+                              GCancellable *cancellable)
+{
+	Context *context;
+	GError *error = NULL;
+
+	context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	e_source_password_store_sync (
+		E_SOURCE (object), context->password,
+		context->permanently, cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+void
+e_source_password_store (ESource *source,
+                         const gchar *password,
+                         gboolean permanently,
+                         gint io_priority,
+                         GCancellable *cancellable,
+                         GAsyncReadyCallback callback,
+                         gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	Context *context;
+
+	g_return_if_fail (E_IS_SOURCE (source));
+	g_return_if_fail (password != NULL);
+
+	context = g_slice_new0 (Context);
+	context->password = g_strdup (password);
+	context->permanently = permanently;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (source), callback,
+		user_data, e_source_password_store);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, context, (GDestroyNotify) context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, source_password_store_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+gboolean
+e_source_password_store_finish (ESource *source,
+                                GAsyncResult *result,
+                                GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (source), e_source_password_store), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+gboolean
+e_source_password_store_sync (ESource *source,
+                              const gchar *password,
+                              gboolean permanently,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+	GnomeKeyringResult result;
+	const gchar *keyring;
+	const gchar *uid;
+	gchar *display_name;
+
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+	g_return_val_if_fail (password != NULL, FALSE);
+
+	/* XXX Syncrhonous gnome-keyring functions are not cancellable.
+	 *     Maybe they will be someday, but in the meantime check for
+	 *     cancellation ourselves before doing this. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error))
+		return FALSE;
+
+	if (permanently)
+		keyring = GNOME_KEYRING_DEFAULT;
+	else
+		keyring = GNOME_KEYRING_SESSION;
+
+	uid = e_source_get_uid (source);
+	display_name = g_strdup_printf (KEYRING_ITEM_DISPLAY_FORMAT, uid);
+
+	result = gnome_keyring_store_password_sync (
+		&schema, keyring, display_name, password,
+		KEYRING_ITEM_ATTRIBUTE_NAME, uid, NULL);
+
+	if (result == GNOME_KEYRING_RESULT_CANCELLED) {
+		g_cancellable_cancel (cancellable);
+		g_set_error_literal (
+			error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+			_("Keyring operation was cancelled"));
+
+	} else if (result != GNOME_KEYRING_RESULT_OK) {
+		g_set_error_literal (
+			error, E_SOURCE_PASSWORD_ERROR, result,
+			gnome_keyring_result_to_message (result));
+	}
+
+	g_free (display_name);
+
+	return (result == GNOME_KEYRING_RESULT_OK);
+}
+
+static void
+source_password_lookup_thread (GSimpleAsyncResult *simple,
+                               GObject *object,
+                               GCancellable *cancellable)
+{
+	Context *context;
+	GError *error = NULL;
+
+	context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	e_source_password_lookup_sync (
+		E_SOURCE (object), cancellable,
+		&context->password, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+void
+e_source_password_lookup (ESource *source,
+                          gint io_priority,
+                          GCancellable *cancellable,
+                          GAsyncReadyCallback callback,
+                          gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	Context *context;
+
+	g_return_if_fail (E_IS_SOURCE (source));
+
+	context = g_slice_new0 (Context);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (source), callback,
+		user_data, e_source_password_lookup);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, context, (GDestroyNotify) context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, source_password_lookup_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+gboolean
+e_source_password_lookup_finish (ESource *source,
+                                 GAsyncResult *result,
+                                 gchar **password,
+                                 GError **error)
+{
+	GSimpleAsyncResult *simple;
+	Context *context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (source), e_source_password_lookup), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+
+	if (password != NULL)
+		*password = context->password;
+	else
+		e_source_password_free (context->password);
+
+	context->password = NULL;
+
+	return TRUE;
+}
+
+gboolean
+e_source_password_lookup_sync (ESource *source,
+                               GCancellable *cancellable,
+                               gchar **password,
+                               GError **error)
+{
+	GnomeKeyringResult result;
+	const gchar *uid;
+	gchar *temp = NULL;
+
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+	/* XXX Synchronous gnome-keyring functions are not cancellable.
+	 *     Maybe they will be someday, but in the meantime check for
+	 *     cancellation ourselves before doing this. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error))
+		return FALSE;
+
+	uid = e_source_get_uid (source);
+
+	result = gnome_keyring_find_password_sync (
+		&schema, &temp, KEYRING_ITEM_ATTRIBUTE_NAME, uid, NULL);
+
+	/* Not finding an ESource password is not an error. */
+	if (result == GNOME_KEYRING_RESULT_NO_MATCH) {
+		result = GNOME_KEYRING_RESULT_OK;
+		e_source_password_free (temp);
+		temp = NULL;
+
+	} else if (result == GNOME_KEYRING_RESULT_CANCELLED) {
+		g_cancellable_cancel (cancellable);
+		g_set_error_literal (
+			error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+			_("Keyring operation was cancelled"));
+		g_warn_if_fail (temp == NULL);
+
+	} else if (result != GNOME_KEYRING_RESULT_OK) {
+		g_set_error_literal (
+			error, E_SOURCE_PASSWORD_ERROR, result,
+			gnome_keyring_result_to_message (result));
+		g_warn_if_fail (temp == NULL);
+	}
+
+	if (password != NULL)
+		*password = temp;
+	else
+		e_source_password_free (temp);
+
+	return (result == GNOME_KEYRING_RESULT_OK);
+}
+
+static void
+source_password_delete_thread (GSimpleAsyncResult *simple,
+                               GObject *object,
+                               GCancellable *cancellable)
+{
+	GError *error = NULL;
+
+	e_source_password_delete_sync (
+		E_SOURCE (object), cancellable, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+}
+
+void
+e_source_password_delete (ESource *source,
+                          gint io_priority,
+                          GCancellable *cancellable,
+                          GAsyncReadyCallback callback,
+                          gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail (E_IS_SOURCE (source));
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (source), callback,
+		user_data, e_source_password_delete);
+
+	g_simple_async_result_run_in_thread (
+		simple, source_password_delete_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+gboolean
+e_source_password_delete_finish (ESource *source,
+                                 GAsyncResult *result,
+                                 GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (source), e_source_password_delete), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+gboolean
+e_source_password_delete_sync (ESource *source,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+	GnomeKeyringResult result;
+	const gchar *uid;
+
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+	/* XXX Synchronous gnome-keyring functions are not cancellable.
+	 *     Maybe they will be someday, but in the meantime check for
+	 *     cancellation ourselves before doing this. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, error))
+		return FALSE;
+
+	uid = e_source_get_uid (source);
+
+	result = gnome_keyring_delete_password_sync (
+		&schema, KEYRING_ITEM_ATTRIBUTE_NAME, uid, NULL);
+
+	/* Not finding an ESource password is not an error. */
+	if (result == GNOME_KEYRING_RESULT_NO_MATCH) {
+		result = GNOME_KEYRING_RESULT_OK;
+
+	} else if (result == GNOME_KEYRING_RESULT_CANCELLED) {
+		g_cancellable_cancel (cancellable);
+		g_set_error_literal (
+			error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+			_("Keyring operation was cancelled"));
+
+	} else if (result != GNOME_KEYRING_RESULT_OK) {
+		g_set_error_literal (
+			error, E_SOURCE_PASSWORD_ERROR, result,
+			gnome_keyring_result_to_message (result));
+	}
+
+	return (result == GNOME_KEYRING_RESULT_OK);
+}
+
+void
+e_source_password_free (gchar *password)
+{
+	if (password != NULL)
+		gnome_keyring_free_password (password);
+}
diff --git a/libedataserver/e-source-password.h b/libedataserver/e-source-password.h
new file mode 100644
index 0000000..e1f8473
--- /dev/null
+++ b/libedataserver/e-source-password.h
@@ -0,0 +1,72 @@
+/*
+ * e-source-password.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_PASSWORD_H
+#define E_SOURCE_PASSWORD_H
+
+#include <libedataserver/e-source.h>
+
+#define E_SOURCE_PASSWORD_ERROR (e_source_password_error_quark ())
+
+G_BEGIN_DECLS
+
+GQuark		e_source_password_error_quark	(void) G_GNUC_CONST;
+void		e_source_password_store		(ESource *source,
+						 const gchar *password,
+						 gboolean permanently,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_source_password_store_finish	(ESource *source,
+						 GAsyncResult *result,
+						 GError **error);
+gboolean	e_source_password_store_sync	(ESource *source,
+						 const gchar *password,
+						 gboolean permanently,
+						 GCancellable *cancellable,
+						 GError **error);
+void		e_source_password_lookup	(ESource *source,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_source_password_lookup_finish	(ESource *source,
+						 GAsyncResult *result,
+						 gchar **password,
+						 GError **error);
+gboolean	e_source_password_lookup_sync	(ESource *source,
+						 GCancellable *cancellable,
+						 gchar **password,
+						 GError **error);
+void		e_source_password_delete	(ESource *source,
+						 gint io_priority,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_source_password_delete_finish	(ESource *source,
+						 GAsyncResult *result,
+						 GError **error);
+gboolean	e_source_password_delete_sync	(ESource *source,
+						 GCancellable *cancellable,
+						 GError **error);
+void		e_source_password_free		(gchar *password);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_PASSWORD_H */
diff --git a/libedataserver/e-source-refresh.c b/libedataserver/e-source-refresh.c
new file mode 100644
index 0000000..705c079
--- /dev/null
+++ b/libedataserver/e-source-refresh.c
@@ -0,0 +1,126 @@
+/*
+ * e-source-refresh.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-refresh.h"
+
+#define E_SOURCE_REFRESH_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_REFRESH, ESourceRefreshPrivate))
+
+struct _ESourceRefreshPrivate {
+	guint interval_minutes;
+};
+
+enum {
+	PROP_0,
+	PROP_INTERVAL_MINUTES
+};
+
+G_DEFINE_TYPE (
+	ESourceRefresh,
+	e_source_refresh,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_refresh_set_property (GObject *object,
+                             guint property_id,
+                             const GValue *value,
+                             GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_INTERVAL_MINUTES:
+			e_source_refresh_set_interval_minutes (
+				E_SOURCE_REFRESH (object),
+				g_value_get_uint (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_refresh_get_property (GObject *object,
+                             guint property_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_INTERVAL_MINUTES:
+			g_value_set_uint (
+				value,
+				e_source_refresh_get_interval_minutes (
+				E_SOURCE_REFRESH (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_source_refresh_class_init (ESourceRefreshClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceRefreshPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_refresh_set_property;
+	object_class->get_property = source_refresh_get_property;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_REFRESH;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_INTERVAL_MINUTES,
+		g_param_spec_uint (
+			"interval-minutes",
+			"Interval in Minutes",
+			"Refresh interval in minutes",
+			0, G_MAXUINT, 60,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_refresh_init (ESourceRefresh *extension)
+{
+	extension->priv = E_SOURCE_REFRESH_GET_PRIVATE (extension);
+}
+
+guint
+e_source_refresh_get_interval_minutes (ESourceRefresh *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_REFRESH (extension), FALSE);
+
+	return extension->priv->interval_minutes;
+}
+
+void
+e_source_refresh_set_interval_minutes (ESourceRefresh *extension,
+                                       guint interval_minutes)
+{
+	g_return_if_fail (E_IS_SOURCE_REFRESH (extension));
+
+	extension->priv->interval_minutes = interval_minutes;
+
+	g_object_notify (G_OBJECT (extension), "interval-minutes");
+}
diff --git a/libedataserver/e-source-refresh.h b/libedataserver/e-source-refresh.h
new file mode 100644
index 0000000..36fbe8f
--- /dev/null
+++ b/libedataserver/e-source-refresh.h
@@ -0,0 +1,69 @@
+/*
+ * e-source-refresh.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_REFRESH_H
+#define E_SOURCE_REFRESH_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_REFRESH \
+	(e_source_refresh_get_type ())
+#define E_SOURCE_REFRESH(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_REFRESH, ESourceRefresh))
+#define E_SOURCE_REFRESH_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_REFRESH, ESourceRefreshClass))
+#define E_IS_SOURCE_REFRESH(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_REFRESH))
+#define E_IS_SOURCE_REFRESH_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_REFRESH))
+#define E_SOURCE_REFRESH_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_REFRESH, ESourceRefreshClass))
+
+#define E_SOURCE_EXTENSION_REFRESH "Refresh"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceRefresh ESourceRefresh;
+typedef struct _ESourceRefreshClass ESourceRefreshClass;
+typedef struct _ESourceRefreshPrivate ESourceRefreshPrivate;
+
+struct _ESourceRefresh {
+	ESourceExtension parent;
+	ESourceRefreshPrivate *priv;
+};
+
+struct _ESourceRefreshClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_refresh_get_type	(void);
+guint		e_source_refresh_get_interval_minutes
+						(ESourceRefresh *extension);
+void		e_source_refresh_set_interval_minutes
+						(ESourceRefresh *extension,
+						 guint interval_in_minutes);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_REFRESH_H */
diff --git a/libedataserver/e-source-registry.c b/libedataserver/e-source-registry.c
new file mode 100644
index 0000000..557149b
--- /dev/null
+++ b/libedataserver/e-source-registry.c
@@ -0,0 +1,1319 @@
+/*
+ * e-source-registry.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-registry.h"
+
+#include <config.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+
+#include "e-data-server-util.h"
+#include "e-marshal.h"
+
+/* built-in extension types */
+#include "e-source-alarms.h"
+#include "e-source-authentication.h"
+#include "e-source-autocomplete.h"
+#include "e-source-offline.h"
+#include "e-source-refresh.h"
+#include "e-source-security.h"
+#include "e-source-selectable.h"
+#include "e-source-webdav.h"
+
+#define E_SOURCE_REGISTRY_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_REGISTRY, ESourceRegistryPrivate))
+
+#define SETTINGS_SCHEMA "org.gnome.Evolution.DefaultSources"
+
+struct _ESourceRegistryPrivate {
+	GHashTable *sources;
+	GHashTable *orphans;
+	GHashTable *monitors;
+	GSettings *settings;
+};
+
+enum {
+	PROP_0,
+	PROP_DEFAULT_ADDRESS_BOOK,
+	PROP_DEFAULT_CALENDAR,
+	PROP_DEFAULT_MEMO_LIST,
+	PROP_DEFAULT_TASK_LIST
+};
+
+enum {
+	LOAD_ERROR,
+	SOURCE_ADDED,
+	SOURCE_CHANGED,
+	SOURCE_REMOVED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+static ESourceRegistry *source_registry_singleton = NULL;
+
+G_DEFINE_TYPE (
+	ESourceRegistry,
+	e_source_registry,
+	G_TYPE_OBJECT)
+
+static void
+source_registry_settings_changed_cb (GSettings *settings,
+                                     const gchar *key,
+                                     ESourceRegistry *registry)
+{
+	/* We define a property name that matches every key in
+	 * the "org.gnome.Evolution.DefaultSources" schema. */
+	g_object_notify (G_OBJECT (registry), key);
+}
+
+static void
+source_registry_source_changed_cb (ESource *source,
+                                   ESourceRegistry *registry)
+{
+	g_signal_emit (registry, signals[SOURCE_CHANGED], 0, source);
+}
+
+static void
+source_registry_unref_source (ESource *source)
+{
+	g_signal_handlers_disconnect_matched (
+		source, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+		source_registry_source_changed_cb, NULL);
+
+	g_object_unref (source);
+}
+
+static gboolean
+source_registry_find_parent (ESourceRegistry *registry,
+                             ESource *source)
+{
+	GHashTable *orphans;
+	GPtrArray *array;
+	ESource *parent;
+	const gchar *uid;
+
+	/* If an ESource references a parent ESource and the parent
+	 * ESource is not present in the registry, the child ESource
+	 * is added to an orphan list until the referenced parent is
+	 * added to the registry. */
+
+	uid = e_source_get_parent (source);
+
+	if (uid == NULL || *uid == '\0')
+		return TRUE;
+
+	parent = e_source_registry_lookup_by_uid (registry, uid);
+
+	if (parent != NULL) {
+		GNode *parent_node;
+		GNode *source_node;
+
+		parent_node = e_source_get_node (parent);
+		source_node = e_source_get_node (source);
+		g_node_append (parent_node, source_node);
+
+		return TRUE;
+	}
+
+	orphans = registry->priv->orphans;
+	array = g_hash_table_lookup (orphans, uid);
+
+	if (array == NULL) {
+		array = g_ptr_array_new_with_free_func (
+			(GDestroyNotify) g_object_unref);
+		g_hash_table_insert (orphans, g_strdup (uid), array);
+	}
+
+	g_ptr_array_add (array, g_object_ref (source));
+
+	return FALSE;
+}
+
+static void
+source_registry_adopt_orphans (ESourceRegistry *registry,
+                               ESource *source)
+{
+	GHashTable *orphans;
+	GPtrArray *array;
+	const gchar *uid;
+	guint ii;
+
+	/* Check if a newly-added ESource has any orphan ESources
+	 * that are waiting for it.  The orphans can now be added
+	 * to the registry as children of the newly-added ESource. */
+
+	uid = e_source_get_uid (source);
+
+	orphans = registry->priv->orphans;
+	array = g_hash_table_lookup (orphans, uid);
+
+	if (array == NULL)
+		return;
+
+	for (ii = 0; ii < array->len; ii++) {
+		ESource *orphan = g_ptr_array_index (array, ii);
+		e_source_registry_add_source (registry, orphan);
+	}
+
+	g_ptr_array_set_size (array, 0);
+}
+
+static void
+source_registry_monitor_changed (GFileMonitor *monitor,
+                                 GFile *file,
+                                 GFile *other_file,
+                                 GFileMonitorEvent event_type,
+                                 ESourceRegistry *registry)
+{
+	gchar *basename;
+	gboolean hidden;
+
+	basename = g_file_get_basename (file);
+	hidden = g_str_has_prefix (basename, ".");
+	g_free (basename);
+
+	/* XXX Ignore hidden files so we don't try
+	 *     to load .goutputstream-XXXXXX files. */
+	if (hidden)
+		return;
+
+	if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
+		GError *error = NULL;
+
+		e_source_registry_load_file (registry, file, &error);
+		if (error != NULL) {
+			e_source_registry_load_error (registry, file, error);
+			g_error_free (error);
+		}
+	}
+
+	if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
+		ESource *source;
+
+		source = e_source_registry_lookup_by_file (registry, file);
+		if (source != NULL)
+			e_source_registry_remove_source (registry, source);
+	}
+}
+
+static gboolean
+source_registry_remove_cb (GNode *node,
+                           ESourceRegistry *registry)
+{
+	ESource *source = E_SOURCE (node->data);
+	const gchar *uid;
+
+	source = E_SOURCE (node->data);
+	uid = e_source_get_uid (source);
+
+	g_object_ref (source);
+
+	if (g_hash_table_remove (registry->priv->sources, uid)) {
+		g_node_unlink (e_source_get_node (source));
+		g_signal_emit (registry, signals[SOURCE_REMOVED], 0, source);
+	}
+
+	g_object_unref (source);
+
+	return FALSE;
+}
+
+static void
+source_registry_set_property (GObject *object,
+                              guint property_id,
+                              const GValue *value,
+                              GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_DEFAULT_ADDRESS_BOOK:
+			e_source_registry_set_default_address_book (
+				E_SOURCE_REGISTRY (object),
+				g_value_get_object (value));
+			return;
+
+		case PROP_DEFAULT_CALENDAR:
+			e_source_registry_set_default_calendar (
+				E_SOURCE_REGISTRY (object),
+				g_value_get_object (value));
+			return;
+
+		case PROP_DEFAULT_MEMO_LIST:
+			e_source_registry_set_default_memo_list (
+				E_SOURCE_REGISTRY (object),
+				g_value_get_object (value));
+			return;
+
+		case PROP_DEFAULT_TASK_LIST:
+			e_source_registry_set_default_task_list (
+				E_SOURCE_REGISTRY (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_registry_get_property (GObject *object,
+                              guint property_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_DEFAULT_ADDRESS_BOOK:
+			g_value_set_object (
+				value,
+				e_source_registry_get_default_address_book (
+				E_SOURCE_REGISTRY (object)));
+			return;
+
+		case PROP_DEFAULT_CALENDAR:
+			g_value_set_object (
+				value,
+				e_source_registry_get_default_calendar (
+				E_SOURCE_REGISTRY (object)));
+			return;
+
+		case PROP_DEFAULT_MEMO_LIST:
+			g_value_set_object (
+				value,
+				e_source_registry_get_default_memo_list (
+				E_SOURCE_REGISTRY (object)));
+			return;
+
+		case PROP_DEFAULT_TASK_LIST:
+			g_value_set_object (
+				value,
+				e_source_registry_get_default_task_list (
+				E_SOURCE_REGISTRY (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_registry_dispose (GObject *object)
+{
+	ESourceRegistryPrivate *priv;
+
+	priv = E_SOURCE_REGISTRY_GET_PRIVATE (object);
+
+	g_hash_table_remove_all (priv->sources);
+	g_hash_table_remove_all (priv->orphans);
+	g_hash_table_remove_all (priv->monitors);
+
+	if (priv->settings != NULL) {
+		g_object_unref (priv->settings);
+		priv->settings = NULL;
+	}
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_registry_parent_class)->dispose (object);
+}
+
+static void
+source_registry_finalize (GObject *object)
+{
+	ESourceRegistryPrivate *priv;
+
+	priv = E_SOURCE_REGISTRY_GET_PRIVATE (object);
+
+	g_hash_table_destroy (priv->sources);
+	g_hash_table_destroy (priv->orphans);
+	g_hash_table_destroy (priv->monitors);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_registry_parent_class)->finalize (object);
+}
+
+static void
+e_source_registry_class_init (ESourceRegistryClass *class)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (class, sizeof (ESourceRegistryPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_registry_set_property;
+	object_class->get_property = source_registry_get_property;
+	object_class->dispose = source_registry_dispose;
+	object_class->finalize = source_registry_finalize;
+
+	/* The property names correspond to the key names in the
+	 * "org.gnome.Evolution.DefaultSources" GSettings schema. */
+
+	/**
+	 * ESourceRegistry:default-address-book
+	 *
+	 * The default address book #ESource.
+	 **/
+	g_object_class_install_property (
+		object_class,
+		PROP_DEFAULT_ADDRESS_BOOK,
+		g_param_spec_object (
+			"default-address-book",
+			"Default Address Book",
+			"The default address book ESource",
+			E_TYPE_SOURCE,
+			G_PARAM_READWRITE |
+			G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * ESourceRegistry:default-calendar
+	 *
+	 * The default calendar #ESource.
+	 **/
+	g_object_class_install_property (
+		object_class,
+		PROP_DEFAULT_CALENDAR,
+		g_param_spec_object (
+			"default-calendar",
+			"Default Calendar",
+			"The default calendar ESource",
+			E_TYPE_SOURCE,
+			G_PARAM_READWRITE |
+			G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * ESourceRegistry:default-memo-list
+	 *
+	 * The default memo list #ESource.
+	 **/
+	g_object_class_install_property (
+		object_class,
+		PROP_DEFAULT_MEMO_LIST,
+		g_param_spec_object (
+			"default-memo-list",
+			"Default Memo List",
+			"The default memo list ESource",
+			E_TYPE_SOURCE,
+			G_PARAM_READWRITE |
+			G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * ESourceRegistry:default-task-list
+	 *
+	 * The default task list #ESource.
+	 **/
+	g_object_class_install_property (
+		object_class,
+		PROP_DEFAULT_TASK_LIST,
+		g_param_spec_object (
+			"default-task-list",
+			"Default Task List",
+			"The default task list ESource",
+			E_TYPE_SOURCE,
+			G_PARAM_READWRITE |
+			G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * ESourceRegistry::load-error:
+	 * @registry: the #DataSourceRegistry which emitted the signal
+	 * @file: the #GFile being loaded
+	 * @error: a #GError describing the error
+	 *
+	 * Emitted when an error occurs while loading or parsing a
+	 * data source key file.
+	 **/
+	signals[LOAD_ERROR] = g_signal_new (
+		"load-error",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (ESourceRegistryClass, load_error),
+		NULL, NULL,
+		e_marshal_VOID__OBJECT_BOXED,
+		G_TYPE_NONE, 2,
+		G_TYPE_FILE,
+		G_TYPE_ERROR | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+	/**
+	 * ESourceRegistry::source-added:
+	 * @registry: the #ESourceRegistry which emitted the signal
+	 * @source: the newly-added #ESource
+	 *
+	 * Emitted when an #ESource is added to @registry.
+	 **/
+	signals[SOURCE_ADDED] = g_signal_new (
+		"source-added",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (ESourceRegistryClass, source_added),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__OBJECT,
+		G_TYPE_NONE, 1,
+		E_TYPE_SOURCE);
+
+	/**
+	 * ESourceRegistry::source-changed
+	 * @registry: the #ESourceRegistry which emitted the signal
+	 * @source: the #ESource that changed
+	 *
+	 * Emitted when an #ESource registered with @registry emits
+	 * its #ESource::changed signal.
+	 **/
+	signals[SOURCE_CHANGED] = g_signal_new (
+		"source-changed",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (ESourceRegistryClass, source_changed),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__OBJECT,
+		G_TYPE_NONE, 1,
+		E_TYPE_SOURCE);
+
+	/**
+	 * ESourceRegistry::source-removed:
+	 * @registry: the #ESourceRegistry which emitted the signal
+	 * @source: the #ESource that got removed
+	 *
+	 * Emitted when an #ESource is removed from @registry.
+	 **/
+	signals[SOURCE_REMOVED] = g_signal_new (
+		"source-removed",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (ESourceRegistryClass, source_removed),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__OBJECT,
+		G_TYPE_NONE, 1,
+		E_TYPE_SOURCE);
+
+	/* Register built-in ESourceExtension types. */
+	E_TYPE_SOURCE_ALARMS;
+	E_TYPE_SOURCE_AUTHENTICATION;
+	E_TYPE_SOURCE_AUTOCOMPLETE;
+	E_TYPE_SOURCE_OFFLINE;
+	E_TYPE_SOURCE_REFRESH;
+	E_TYPE_SOURCE_SECURITY;
+	E_TYPE_SOURCE_SELECTABLE;
+	E_TYPE_SOURCE_WEBDAV;
+}
+
+static void
+e_source_registry_init (ESourceRegistry *registry)
+{
+	registry->priv = E_SOURCE_REGISTRY_GET_PRIVATE (registry);
+
+	/* UID string -> ESource */
+	registry->priv->sources = g_hash_table_new_full (
+		(GHashFunc) g_str_hash,
+		(GEqualFunc) g_str_equal,
+		(GDestroyNotify) g_free,
+		(GDestroyNotify) source_registry_unref_source);
+
+	/* Parent UID string -> GQueue of ESources */
+	registry->priv->orphans = g_hash_table_new_full (
+		(GHashFunc) g_str_hash,
+		(GEqualFunc) g_str_equal,
+		(GDestroyNotify) g_free,
+		(GDestroyNotify) g_ptr_array_unref);
+
+	/* GFile -> GFileMonitor */
+	registry->priv->monitors = g_hash_table_new_full (
+		(GHashFunc) g_file_hash,
+		(GEqualFunc) g_file_equal,
+		(GDestroyNotify) g_object_unref,
+		(GDestroyNotify) g_object_unref);
+
+	registry->priv->settings = g_settings_new (SETTINGS_SCHEMA);
+
+	g_signal_connect (
+		registry->priv->settings, "changed",
+		G_CALLBACK (source_registry_settings_changed_cb), registry);
+}
+
+/**
+ * e_source_registry_get_default:
+ *
+ * Gets a unique instance of #ESourceRegistry that you can share in your
+ * application without caring about memory management.
+ *
+ * Applications must call e_source_registry_load_sources() on the unique
+ * #ESourceRegistry instance before it can be used.
+ *
+ * Returns: a unique #ESourceRegistry
+ *
+ * Since: 2.92
+ **/
+ESourceRegistry *
+e_source_registry_get_default (void)
+{
+	if (G_UNLIKELY (source_registry_singleton == NULL))
+		source_registry_singleton =
+			g_object_new (E_TYPE_SOURCE_REGISTRY, NULL);
+
+	return source_registry_singleton;
+}
+
+/**
+ * e_source_registry_add_source:
+ * @registry: an #ESourceRegistry
+ * @source: an #ESource
+ *
+ * Adds @source to @registry.
+ *
+ * Since: 2.92
+ **/
+void
+e_source_registry_add_source (ESourceRegistry *registry,
+                              ESource *source)
+{
+	const gchar *uid;
+
+	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+	g_return_if_fail (E_IS_SOURCE (source));
+
+	uid = e_source_get_uid (source);
+
+	/* Check if we already have this source in the registry. */
+	if (e_source_registry_lookup_by_uid (registry, uid) != NULL)
+		return;
+
+	/* Make sure the parent source (if any) is in the registry. */
+	if (!source_registry_find_parent (registry, source))
+		return;
+
+	g_signal_connect (
+		source, "changed",
+		G_CALLBACK (source_registry_source_changed_cb), registry);
+
+	g_hash_table_insert (
+		registry->priv->sources,
+		g_strdup (uid), g_object_ref (source));
+
+	g_signal_emit (registry, signals[SOURCE_ADDED], 0, source);
+
+	/* Adopt any orphans that have been waiting for this source. */
+	source_registry_adopt_orphans (registry, source);
+}
+
+/**
+ * e_source_registry_remove_source:
+ * @registry: an #ESourceRegistry
+ * @source: an #ESource
+ *
+ * Removes @source and its children from @registry.
+ *
+ * Since: 2.92
+ **/
+void
+e_source_registry_remove_source (ESourceRegistry *registry,
+                                 ESource *source)
+{
+	GNode *node;
+	const gchar *uid;
+
+	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+	g_return_if_fail (E_IS_SOURCE (source));
+
+	/* The system source cannot be removed. */
+	uid = e_source_get_uid (source);
+	if (g_strcmp0 (uid, "system") == 0)
+		return;
+
+	node = e_source_get_node (source);
+
+	/* Removing an ESource also removes its children.  We remove
+	 * children first so they are never without a parent source. */
+	g_node_traverse (
+		node, G_POST_ORDER, G_TRAVERSE_ALL, -1,
+		(GNodeTraverseFunc) source_registry_remove_cb, registry);
+}
+
+/**
+ * e_source_registry_load_sources:
+ * @registry: an #ESourceRegistry
+ * @error: return location for a #GError, or %NULL
+ *
+ * Loads data source key files from standard system-wide and user-specific
+ * locations.  Because multiple errors can occur when loading multiple files,
+ * @error is only set if a directory can not be opened.  If a key file fails
+ * to load, the error is broadcast through the #ESourceRegistry::load-error
+ * signal.
+ *
+ * Returns: %TRUE if the standard directories were successfully opened,
+ *          but this does not imply the key files were successfully loaded.
+ *
+ * Since: 2.92
+ **/
+gboolean
+e_source_registry_load_sources (ESourceRegistry *registry,
+                                GError **error)
+{
+	const gchar *data_dir;
+	gboolean success;
+	gchar *path;
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
+
+	/* Load the user's sources directory first so that user-specific
+	 * data sources overshadow predefined data sources with identical
+	 * UIDs.  The "system" data source is one such example. */
+
+	data_dir = e_get_user_data_dir ();
+	path = g_build_filename (data_dir, "sources", NULL);
+	success = e_source_registry_load_directory (
+		registry, path, TRUE, error);
+	g_prefix_error (error, "%s: ", path);
+	g_free (path);
+
+	if (!success)
+		return FALSE;
+
+	data_dir = E_DATA_SERVER_PRIVDATADIR;
+	path = g_build_filename (data_dir, "sources", NULL);
+	success = e_source_registry_load_directory (
+		registry, path, FALSE, error);
+	g_prefix_error (error, "%s: ", path);
+	g_free (path);
+
+	return success;
+}
+
+/**
+ * e_source_registry_load_directory:
+ * @registry: an #ESourceRegistry
+ * @path: the path to the directory to load
+ * @monitor_for_changes: monitor the directory for changes
+ * @error: return location for a #GError, or %NULL
+ *
+ * Loads data source key files in @path.  Because multiple errors can
+ * occur when loading multiple files, @error is only set if @path can
+ * not be opened.  If a key file fails to load, the error is broadcast
+ * through the #ESourceRegistry::load-error signal.
+ *
+ * If @monitor_for_changes is %TRUE, then the @registry will emit
+ * ESourceRegistry::source-added and ESourceRegistry::source-removed
+ * signals when key files are created and deleted in @path.
+ *
+ * Returns: %TRUE if @path was successfully opened, but this
+ *          does not imply the key files were successfully loaded
+ *
+ * Since: 2.92
+ **/
+gboolean
+e_source_registry_load_directory (ESourceRegistry *registry,
+                                  const gchar *path,
+                                  gboolean monitor_for_changes,
+                                  GError **error)
+{
+	GDir *dir;
+	GFile *file;
+	const gchar *name;
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
+	g_return_val_if_fail (path != NULL, FALSE);
+
+	/* If the directory doesn't exist then there's nothing to load.
+	 * Note we do not use G_FILE_TEST_DIR here.  If the given path
+	 * exists but is not a directory then we let g_dir_open() fail. */
+	if (!g_file_test (path, G_FILE_TEST_EXISTS))
+		return TRUE;
+
+	dir = g_dir_open (path, 0, error);
+	if (dir == NULL)
+		return FALSE;
+
+	file = g_file_new_for_path (path);
+
+	while ((name = g_dir_read_name (dir)) != NULL) {
+		GFile *child;
+		GError *local_error = NULL;
+
+		/* XXX Ignore hidden files so we don't try
+		 *     to load .goutputstream-XXXXXX files. */
+		if (g_str_has_prefix (name, "."))
+			continue;
+
+		child = g_file_get_child (file, name);
+
+		e_source_registry_load_file (
+			registry, child, &local_error);
+
+		if (local_error != NULL) {
+			e_source_registry_load_error (
+				registry, child, local_error);
+			g_error_free (local_error);
+		}
+
+		g_object_unref (child);
+	}
+
+	g_dir_close (dir);
+
+	if (monitor_for_changes) {
+		GFileMonitor *monitor;
+
+		monitor = g_file_monitor_directory (
+			file, G_FILE_MONITOR_NONE, NULL, error);
+		if (monitor == NULL)
+			return FALSE;
+
+		g_signal_connect (
+			monitor, "changed",
+			G_CALLBACK (source_registry_monitor_changed),
+			registry);
+
+		g_hash_table_insert (
+			registry->priv->monitors,
+			g_object_ref (file), monitor);
+	}
+
+	return TRUE;
+}
+
+/**
+ * e_source_registry_load_file:
+ * @registry: an #ESourceRegistry
+ * @file: the data source key file to load
+ * @error: return location for a #GError, or %NULL
+ *
+ * Creates an #ESource for a native key file and adds it to @registry.
+ * If an error occurs, the function returns %NULL and sets @error.
+ *
+ * Returns: the newly-added #ESource, or %NULL on error
+ *
+ * Since: 2.92
+ **/
+ESource *
+e_source_registry_load_file (ESourceRegistry *registry,
+                             GFile *file,
+                             GError **error)
+{
+	ESource *source;
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+	g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+	/* Check if we already have this file loaded. */
+	source = e_source_registry_lookup_by_file (registry, file);
+	if (source != NULL)
+		return source;
+
+	/* Create a new ESource and add it to the registry. */
+	source = e_source_new (file, error);
+	if (source != NULL) {
+		e_source_registry_add_source (registry, source);
+		g_object_unref (source);
+	}
+
+	return source;
+}
+
+/**
+ * e_source_registry_load_error:
+ * @registry: an #ESourceRegistry
+ * @file: the #GFile that failed to load
+ * @error: a #GError describing the load error
+ *
+ * Emits the #ESourceRegistry::load-error signal.
+ *
+ * Since: 2.92
+ **/
+void
+e_source_registry_load_error (ESourceRegistry *registry,
+                              GFile *file,
+                              const GError *error)
+{
+	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+	g_return_if_fail (G_IS_FILE (file));
+	g_return_if_fail (error != NULL);
+
+	g_signal_emit (registry, signals[LOAD_ERROR], 0, file, error);
+}
+
+/**
+ * e_source_registry_lookup_by_file:
+ * @registry: an #ESourceRegistry
+ * @file: a #GFile
+ *
+ * Looks up an #ESource in @registry by its #GFile.
+ *
+ * Returns: an #ESource, or %NULL if no match was found
+ *
+ * Since: 2.92
+ **/
+ESource *
+e_source_registry_lookup_by_file (ESourceRegistry *registry,
+                                  GFile *file)
+{
+	ESource *source;
+	gchar *uid;
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+	g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+	uid = g_file_get_basename (file);
+	source = e_source_registry_lookup_by_uid (registry, uid);
+	g_free (uid);
+
+	return source;
+}
+
+/**
+ * e_source_registry_lookup_by_uid:
+ * @registry: an #ESourceRegistry
+ * @uid: a unique identifier string
+ *
+ * Looks up an #ESource in @registry by its unique identifier string.
+ *
+ * Returns: an #ESource, or %NULL if no match was found
+ *
+ * Since: 2.92
+ **/
+ESource *
+e_source_registry_lookup_by_uid (ESourceRegistry *registry,
+                                 const gchar *uid)
+{
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+	g_return_val_if_fail (uid != NULL, NULL);
+
+	return g_hash_table_lookup (registry->priv->sources, uid);
+}
+
+/**
+ * e_source_registry_list_sources:
+ * @registry: an #ESourceRegistry
+ * @extension_name: an extension name, or %NULL
+ *
+ * Returns a list of registered sources.  If @extension_name is given,
+ * restrict the list to sources having that extension name.  Free the
+ * returned list with g_list_free().
+ *
+ * Returns: a list of sources
+ *
+ * Since: 2.92
+ **/
+GList *
+e_source_registry_list_sources (ESourceRegistry *registry,
+                                const gchar *extension_name)
+{
+	GList *list, *iter;
+	GList *trash = NULL;
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+	list = g_hash_table_get_values (registry->priv->sources);
+	if (extension_name == NULL)
+		return list;
+
+	for (iter = list; iter != NULL; iter = g_list_next (iter)) {
+		ESource *source = E_SOURCE (iter->data);
+
+		if (!e_source_has_extension (source, extension_name))
+			trash = g_list_prepend (trash, iter);
+	}
+
+	for (iter = trash; iter != NULL; iter = g_list_next (iter))
+		list = g_list_delete_link (list, iter->data);
+
+	g_list_free (trash);
+
+	return list;
+}
+
+/* Helper for e_source_registry_list_sources_for_display() */
+static gint
+source_registry_compare_nodes (GNode *node_a,
+                               GNode *node_b)
+{
+	ESource *source_a = E_SOURCE (node_a->data);
+	ESource *source_b = E_SOURCE (node_b->data);
+
+	/* The built-in "local" source comes first at depth 1. */
+
+	if (g_strcmp0 (e_source_get_uid (source_a), "local") == 0)
+		return -1;
+
+	if (g_strcmp0 (e_source_get_uid (source_b), "local") == 0)
+		return 1;
+
+	/* The built-in "system" source comes first at depth 2. */
+
+	if (g_strcmp0 (e_source_get_uid (source_a), "system") == 0)
+		return -1;
+
+	if (g_strcmp0 (e_source_get_uid (source_b), "system") == 0)
+		return 1;
+
+	return e_source_compare_by_display_name (source_a, source_b);
+}
+
+/* Helper for e_source_registry_list_sources_for_display() */
+static gboolean
+source_registry_prune_nodes (GNode *node,
+                             const gchar *extension_name)
+{
+	GQueue queue = G_QUEUE_INIT;
+	GNode *child;
+
+	/* Unlink all the child nodes and place them in a queue. */
+	while ((child = g_node_first_child (node)) != NULL) {
+		g_node_unlink (child);
+		g_queue_push_tail (&queue, child);
+	}
+
+	/* Sort the queue by source name. */
+	g_queue_sort (
+		&queue, (GCompareDataFunc)
+		source_registry_compare_nodes, NULL);
+
+	/* Pop nodes off the head of the queue until the queue is empty.
+	 * If the node has either its own children or the given extension
+	 * name, put it back under the parent node (preserving the sorted
+	 * order).  Otherwise delete the node. */
+	while ((child = g_queue_pop_head (&queue)) != NULL) {
+		ESource *source = E_SOURCE (child->data);
+
+		if (extension_name == NULL)
+			g_node_append (node, child);
+
+		else if (e_source_has_extension (source, extension_name))
+			g_node_append (node, child);
+
+		else if (g_node_first_child (child) != NULL)
+			g_node_append (node, child);
+
+		else
+			g_node_destroy (child);
+	}
+
+	return FALSE;
+}
+
+/**
+ * e_source_registry_build_display_tree:
+ * @registry: an #ESourceRegistry
+ * @extension_name: an extension name, or %NULL
+ *
+ * Returns a single #GNode tree of registered sources that can be used to
+ * populate a #GtkTreeModel.  (The root #GNode is just an empty placeholder.)
+ *
+ * Similar to e_source_registry_list_sources(), an @extension_name can be
+ * given to restrict the tree to sources having that extension name.  Parents
+ * of matched sources are included in the tree regardless of whether they have
+ * an extension named @extension_name.
+ *
+ * Free the returned #GNode tree with g_node_destroy().
+ *
+ * Returns: a tree of sources, arranged for display
+ *
+ * Since: 2.92
+ **/
+GNode *
+e_source_registry_build_display_tree (ESourceRegistry *registry,
+                                      const gchar *extension_name)
+{
+	GNode *root;
+	GHashTableIter iter;
+	gpointer value;
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+	root = g_node_new (NULL);
+
+	/* Copy each source tree and append it to the root node. */
+	g_hash_table_iter_init (&iter, registry->priv->sources);
+	while (g_hash_table_iter_next (&iter, NULL, &value)) {
+		ESource *source = E_SOURCE (value);
+		GNode *node = e_source_get_node (source);
+
+		if (node != NULL && G_NODE_IS_ROOT (node))
+			g_node_append (root, g_node_copy (node));
+	}
+
+	/* Prune unwanted nodes from the copied source trees.
+	 * This must be done in "post" order (children first)
+	 * since it reorders and deletes child nodes. */
+	g_node_traverse (
+		root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
+		(GNodeTraverseFunc) source_registry_prune_nodes,
+		(gpointer) extension_name);
+
+	return root;
+}
+
+/**
+ * e_source_registry_get_default_address_book:
+ * @registry: an #ESourceRegistry
+ *
+ * Returns the #ESource most recently passed to
+ * e_source_registry_set_default_address_book() either in this session
+ * or a previous session, or else falls back to the "system" #ESource.
+ * Therefore as long as data sources have been loaded into @registry,
+ * it should be safe to assume the return value is a valid #ESource.
+ *
+ * Returns: the default address book #ESource
+ *
+ * Since: 2.92
+ **/
+ESource *
+e_source_registry_get_default_address_book (ESourceRegistry *registry)
+{
+	const gchar *key = "default-address-book";
+	ESource *source;
+	gchar *uid;
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+	uid = g_settings_get_string (registry->priv->settings, key);
+	source = e_source_registry_lookup_by_uid (registry, uid);
+	g_free (uid);
+
+	/* The "system" source should always be present. */
+	if (source == NULL)
+		source = e_source_registry_lookup_by_uid (registry, "system");
+
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+	return source;
+}
+
+/**
+ * e_source_registry_set_default_address_book:
+ * @registry: an #ESourceRegistry
+ * @default_source: an address book #ESource, or %NULL
+ *
+ * Sets @default_source as the default address book.  If @default_source
+ * is %NULL, the default address book is reset to the "system" #ESource.
+ * This setting will persist across sessions until changed.
+ *
+ * Since: 2.92
+ **/
+void
+e_source_registry_set_default_address_book (ESourceRegistry *registry,
+                                            ESource *default_source)
+{
+	const gchar *key = "default-address-book";
+	const gchar *uid = "system";
+
+	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+
+	if (default_source != NULL) {
+		g_return_if_fail (E_IS_SOURCE (default_source));
+		uid = e_source_get_uid (default_source);
+	}
+
+	g_settings_set_string (registry->priv->settings, key, uid);
+
+	/* The GSettings::changed signal will trigger a "notify" signal
+	 * from the registry, so no need to call g_object_notify() here. */
+}
+
+/**
+ * e_source_registry_get_default_calendar:
+ * @registry: an #ESourceRegistry
+ *
+ * Returns the #ESource most recently passed to
+ * e_source_registry_set_default_calendar() either in this session
+ * or a previous session, or else falls back to the "system" #ESource.
+ * Therefore as long as data sources have been loaded into @registry,
+ * it should be safe to assume the return value is a valid #ESource.
+ *
+ * Returns: the default calendar #ESource
+ *
+ * Since: 2.92
+ **/
+ESource *
+e_source_registry_get_default_calendar (ESourceRegistry *registry)
+{
+	const gchar *key = "default-calendar";
+	ESource *source;
+	gchar *uid;
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+	uid = g_settings_get_string (registry->priv->settings, key);
+	source = e_source_registry_lookup_by_uid (registry, uid);
+	g_free (uid);
+
+	/* The "system" source should always be present. */
+	if (source == NULL)
+		source = e_source_registry_lookup_by_uid (registry, "system");
+
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+	return source;
+}
+
+/**
+ * e_source_registry_set_default_calendar:
+ * @registry: an #ESourceRegistry
+ * @default_source: a calendar #ESource, or %NULL
+ *
+ * Sets @default_source as the default calendar.  If @default_source
+ * is %NULL, the default calendar is reset to the "system" #ESource.
+ * This setting will persist across sessions until changed.
+ *
+ * Since: 2.92
+ **/
+void
+e_source_registry_set_default_calendar (ESourceRegistry *registry,
+                                        ESource *default_source)
+{
+	const gchar *key = "default-calendar";
+	const gchar *uid = "system";
+
+	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+
+	if (default_source != NULL) {
+		g_return_if_fail (E_IS_SOURCE (default_source));
+		uid = e_source_get_uid (default_source);
+	}
+
+	g_settings_set_string (registry->priv->settings, key, uid);
+
+	/* The GSettings::changed signal will trigger a "notify" signal
+	 * from the registry, so no need to call g_object_notify() here. */
+}
+
+/**
+ * e_source_registry_get_default_memo_list:
+ * @registry: an #ESourceRegistry
+ *
+ * Returns the #ESource most recently passed to
+ * e_source_registry_set_default_memo_list() either in this session
+ * or a previous session, or else falls back to the "system" #ESource.
+ * Therefore as long as data sources have been loaded into @registry,
+ * it should be safe to assume the return valud is a valid #Esource.
+ *
+ * Returns: the default memo list #ESource
+ *
+ * Since: 2.92
+ **/
+ESource *
+e_source_registry_get_default_memo_list (ESourceRegistry *registry)
+{
+	const gchar *key = "default-memo-list";
+	ESource *source;
+	gchar *uid;
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+	uid = g_settings_get_string (registry->priv->settings, key);
+	source = e_source_registry_lookup_by_uid (registry, uid);
+	g_free (uid);
+
+	/* The "system" source should always be present. */
+	if (source == NULL)
+		source = e_source_registry_lookup_by_uid (registry, "system");
+
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+	return source;
+}
+
+/**
+ * e_source_registry_set_default_memo_list:
+ * @registry: an #ESourceRegistry
+ * @default_source: a memo list #ESource, or %NULL
+ *
+ * Sets @default_source as the default memo list.  If @default_source
+ * is %NULL, the default memo list is reset to the "system" #ESource.
+ * This setting will persist across sessions until changed.
+ *
+ * Since: 2.92
+ **/
+void
+e_source_registry_set_default_memo_list (ESourceRegistry *registry,
+                                         ESource *default_source)
+{
+	const gchar *key = "default-memo-list";
+	const gchar *uid = "system";
+
+	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+
+	if (default_source != NULL) {
+		g_return_if_fail (E_IS_SOURCE (default_source));
+		uid = e_source_get_uid (default_source);
+	}
+
+	g_settings_set_string (registry->priv->settings, key, uid);
+
+	/* The GSettings::changed signal will trigger a "notify" signal
+	 * from the registry, so no need to call g_object_notify() here. */
+}
+
+/**
+ * e_source_registry_get_default_task_list:
+ * @registry: an #ESourceRegistry
+ *
+ * Returns the #ESource most recently passed to
+ * e_source_registry_set_default_task_list() either in this session
+ * or a previous session, or else falls back to the "system" #ESource.
+ * Therefore as long as data sources have been loaded into @registry,
+ * it should be safe to assume the return value is a valid #ESource.
+ *
+ * Returns: the default task list #ESource
+ *
+ * Since: 2.92
+ **/
+ESource *
+e_source_registry_get_default_task_list (ESourceRegistry *registry)
+{
+	const gchar *key = "default-task-list";
+	ESource *source;
+	gchar *uid;
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+	uid = g_settings_get_string (registry->priv->settings, key);
+	source = e_source_registry_lookup_by_uid (registry, uid);
+	g_free (uid);
+
+	/* The "system" source should always be present. */
+	if (source == NULL)
+		source = e_source_registry_lookup_by_uid (registry, "system");
+
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+	return source;
+}
+
+/**
+ * e_source_registry_set_default_task_list:
+ * @registry: an #ESourceRegistry
+ * @default_source: a task list #ESource, or %NULL
+ *
+ * Sets @default_source as the default task list.  If @default_source
+ * is %NULL, the default task list is reset to the "system" #ESource.
+ * This setting will persist across sessions until changed.
+ *
+ * Since: 2.92
+ **/
+void
+e_source_registry_set_default_task_list (ESourceRegistry *registry,
+                                         ESource *default_source)
+{
+	const gchar *key = "default-task-list";
+	const gchar *uid = "system";
+
+	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+
+	if (default_source != NULL) {
+		g_return_if_fail (E_IS_SOURCE (default_source));
+		uid = e_source_get_uid (default_source);
+	}
+
+	g_settings_set_string (registry->priv->settings, key, uid);
+
+	/* The GSettings::changed signal will trigger a "notify" signal
+	 * from the registry, so no need to call g_object_notify() here. */
+}
diff --git a/libedataserver/e-source-registry.h b/libedataserver/e-source-registry.h
new file mode 100644
index 0000000..9d43b2b
--- /dev/null
+++ b/libedataserver/e-source-registry.h
@@ -0,0 +1,127 @@
+/*
+ * e-source-registry.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_REGISTRY_H
+#define E_SOURCE_REGISTRY_H
+
+#include <libedataserver/e-source.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_REGISTRY \
+	(e_source_registry_get_type ())
+#define E_SOURCE_REGISTRY(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_REGISTRY, ESourceRegistry))
+#define E_SOURCE_REGISTRY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_REGISTRY, ESourceRegistryClass))
+#define E_IS_SOURCE_REGISTRY(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_REGISTRY))
+#define E_IS_SOURCE_REGISTRY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_REGISTRY))
+#define E_SOURCE_REGISTRY_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_REGISTRY, ESourceRegistryClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceRegistry ESourceRegistry;
+typedef struct _ESourceRegistryClass ESourceRegistryClass;
+typedef struct _ESourceRegistryPrivate ESourceRegistryPrivate;
+
+struct _ESourceRegistry {
+	GObject parent;
+	ESourceRegistryPrivate *priv;
+};
+
+struct _ESourceRegistryClass {
+	GObjectClass parent_class;
+
+	/* Signals */
+	void		(*load_error)		(ESourceRegistry *registry,
+						 GFile *file,
+						 const GError *error);
+	void		(*source_added)		(ESourceRegistry *registry,
+						 ESource *source);
+	void		(*source_changed)	(ESourceRegistry *registry,
+						 ESource *source);
+	void		(*source_removed)	(ESourceRegistry *registry,
+						 ESource *source);
+};
+
+GType		e_source_registry_get_type	(void) G_GNUC_CONST;
+ESourceRegistry *
+		e_source_registry_get_default	(void);
+void		e_source_registry_add_source	(ESourceRegistry *registry,
+						 ESource *source);
+void		e_source_registry_remove_source	(ESourceRegistry *registry,
+						 ESource *source);
+gboolean	e_source_registry_load_sources	(ESourceRegistry *registry,
+						 GError **error);
+gboolean	e_source_registry_load_directory
+						(ESourceRegistry *registry,
+						 const gchar *path,
+						 gboolean monitor_for_changes,
+						 GError **error);
+ESource *	e_source_registry_load_file	(ESourceRegistry *registry,
+						 GFile *file,
+						 GError **error);
+void		e_source_registry_load_error	(ESourceRegistry *registry,
+						 GFile *file,
+						 const GError *error);
+ESource *	e_source_registry_lookup_by_file
+						(ESourceRegistry *registry,
+						 GFile *file);
+ESource *	e_source_registry_lookup_by_uid	(ESourceRegistry *registry,
+						 const gchar *uid);
+GList *		e_source_registry_list_sources	(ESourceRegistry *registry,
+						 const gchar *extension_name);
+GNode *		e_source_registry_build_display_tree
+						(ESourceRegistry *registry,
+						 const gchar *extension_name);
+
+/* The following is a front-end for the "org.gnome.Evolution.DefaultSources"
+ * GSettings schema, except that it gets and sets ESource objects instead of
+ * ESource UID strings. */
+
+ESource *	e_source_registry_get_default_address_book
+						(ESourceRegistry *registry);
+void		e_source_registry_set_default_address_book
+						(ESourceRegistry *registry,
+						 ESource *default_source);
+ESource *	e_source_registry_get_default_calendar
+						(ESourceRegistry *registry);
+void		e_source_registry_set_default_calendar
+						(ESourceRegistry *registry,
+						 ESource *default_source);
+ESource *	e_source_registry_get_default_memo_list
+						(ESourceRegistry *registry);
+void		e_source_registry_set_default_memo_list
+						(ESourceRegistry *registry,
+						 ESource *default_source);
+ESource *	e_source_registry_get_default_task_list
+						(ESourceRegistry *registry);
+void		e_source_registry_set_default_task_list
+						(ESourceRegistry *registry,
+						 ESource *default_source);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_REGISTRY_H */
diff --git a/libedataserver/e-source-security.c b/libedataserver/e-source-security.c
new file mode 100644
index 0000000..b930ffd
--- /dev/null
+++ b/libedataserver/e-source-security.c
@@ -0,0 +1,203 @@
+/*
+ * e-source-security.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-security.h"
+
+#define E_SOURCE_SECURITY_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_SECURITY, ESourceSecurityPrivate))
+
+#define SECURE_METHOD "tls"
+
+struct _ESourceSecurityPrivate {
+	gchar *method;
+};
+
+enum {
+	PROP_0,
+	PROP_METHOD,
+	PROP_SECURE
+};
+
+G_DEFINE_TYPE (
+	ESourceSecurity,
+	e_source_security,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_security_set_property (GObject *object,
+                              guint property_id,
+                              const GValue *value,
+                              GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_METHOD:
+			e_source_security_set_method (
+				E_SOURCE_SECURITY (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_SECURE:
+			e_source_security_set_secure (
+				E_SOURCE_SECURITY (object),
+				g_value_get_boolean (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_security_get_property (GObject *object,
+                              guint property_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_METHOD:
+			g_value_set_string (
+				value,
+				e_source_security_get_method (
+				E_SOURCE_SECURITY (object)));
+			return;
+
+		case PROP_SECURE:
+			g_value_set_boolean (
+				value,
+				e_source_security_get_secure (
+				E_SOURCE_SECURITY (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_security_finalize (GObject *object)
+{
+	ESourceSecurityPrivate *priv;
+
+	priv = E_SOURCE_SECURITY_GET_PRIVATE (object);
+
+	g_free (priv->method);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_security_parent_class)->finalize (object);
+}
+
+static void
+e_source_security_class_init (ESourceSecurityClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceSecurityPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_security_set_property;
+	object_class->get_property = source_security_get_property;
+	object_class->finalize = source_security_finalize;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_SECURITY;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_METHOD,
+		g_param_spec_string (
+			"method",
+			"Method",
+			"Security method",
+			"none",
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SECURE,
+		g_param_spec_boolean (
+			"secure",
+			"Secure",
+			"Secure the network connection",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_source_security_init (ESourceSecurity *extension)
+{
+	extension->priv = E_SOURCE_SECURITY_GET_PRIVATE (extension);
+}
+
+const gchar *
+e_source_security_get_method (ESourceSecurity *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SECURITY (extension), FALSE);
+
+	return extension->priv->method;
+}
+
+void
+e_source_security_set_method (ESourceSecurity *extension,
+                              const gchar *method)
+{
+	GObject *object;
+
+	g_return_if_fail (E_IS_SOURCE_SECURITY (extension));
+
+	/* Convert empty strings to "none". */
+	if (method == NULL || *method == '\0')
+		method = "none";
+
+	g_free (extension->priv->method);
+	extension->priv->method = g_strdup (method);
+
+	object = G_OBJECT (extension);
+	g_object_freeze_notify (object);
+	g_object_notify (object, "method");
+	g_object_notify (object, "secure");
+	g_object_thaw_notify (object);
+}
+
+gboolean
+e_source_security_get_secure (ESourceSecurity *extension)
+{
+	const gchar *method;
+
+	g_return_val_if_fail (E_IS_SOURCE_SECURITY (extension), FALSE);
+
+	method = e_source_security_get_method (extension);
+	g_return_val_if_fail (method != NULL, FALSE);
+
+	return (g_strcmp0 (method, "none") != 0);
+}
+
+void
+e_source_security_set_secure (ESourceSecurity *extension,
+                              gboolean secure)
+{
+	const gchar *method;
+
+	g_return_if_fail (E_IS_SOURCE_SECURITY (extension));
+
+	method = secure ? SECURE_METHOD : "none";
+	e_source_security_set_method (extension, method);
+}
diff --git a/libedataserver/e-source-security.h b/libedataserver/e-source-security.h
new file mode 100644
index 0000000..16a6fe6
--- /dev/null
+++ b/libedataserver/e-source-security.h
@@ -0,0 +1,70 @@
+/*
+ * e-source-security.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_SECURITY_H
+#define E_SOURCE_SECURITY_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_SECURITY \
+	(e_source_security_get_type ())
+#define E_SOURCE_SECURITY(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_SECURITY, ESourceSecurity))
+#define E_SOURCE_SECURITY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_SECURITY, ESourceSecurityClass))
+#define E_IS_SOURCE_SECURITY(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_SECURITY))
+#define E_IS_SOURCE_SECURITY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_SECURITY))
+#define E_SOURCE_SECURITY_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_SECURITY, ESourceSecurityClass))
+
+#define E_SOURCE_EXTENSION_SECURITY "Security"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceSecurity ESourceSecurity;
+typedef struct _ESourceSecurityClass ESourceSecurityClass;
+typedef struct _ESourceSecurityPrivate ESourceSecurityPrivate;
+
+struct _ESourceSecurity {
+	ESourceExtension parent;
+	ESourceSecurityPrivate *priv;
+};
+
+struct _ESourceSecurityClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_security_get_type	(void);
+const gchar *	e_source_security_get_method	(ESourceSecurity *extension);
+void		e_source_security_set_method	(ESourceSecurity *extension,
+						 const gchar *method);
+gboolean	e_source_security_get_secure	(ESourceSecurity *extension);
+void		e_source_security_set_secure	(ESourceSecurity *extension,
+						 gboolean secure);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_SECURITY_H */
diff --git a/libedataserver/e-source-selectable.c b/libedataserver/e-source-selectable.c
new file mode 100644
index 0000000..5a28805
--- /dev/null
+++ b/libedataserver/e-source-selectable.c
@@ -0,0 +1,235 @@
+/*
+ * e-source-selectable.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-selectable.h"
+
+#define E_SOURCE_SELECTABLE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_SELECTABLE, ESourceSelectablePrivate))
+
+struct _ESourceSelectablePrivate {
+	gchar *color;
+	gboolean enabled;
+	gboolean writable_hint;
+};
+
+enum {
+	PROP_0,
+	PROP_COLOR,
+	PROP_ENABLED,
+	PROP_WRITABLE_HINT
+};
+
+G_DEFINE_ABSTRACT_TYPE (
+	ESourceSelectable,
+	e_source_selectable,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_selectable_set_property (GObject *object,
+                                guint property_id,
+                                const GValue *value,
+                                GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_COLOR:
+			e_source_selectable_set_color (
+				E_SOURCE_SELECTABLE (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_ENABLED:
+			e_source_selectable_set_enabled (
+				E_SOURCE_SELECTABLE (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_WRITABLE_HINT:
+			e_source_selectable_set_writable_hint (
+				E_SOURCE_SELECTABLE (object),
+				g_value_get_boolean (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_selectable_get_property (GObject *object,
+                                guint property_id,
+                                GValue *value,
+                                GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_COLOR:
+			g_value_set_string (
+				value,
+				e_source_selectable_get_color (
+				E_SOURCE_SELECTABLE (object)));
+			return;
+
+		case PROP_ENABLED:
+			g_value_set_boolean (
+				value,
+				e_source_selectable_get_enabled (
+				E_SOURCE_SELECTABLE (object)));
+			return;
+
+		case PROP_WRITABLE_HINT:
+			g_value_set_boolean (
+				value,
+				e_source_selectable_get_writable_hint (
+				E_SOURCE_SELECTABLE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_selectable_finalize (GObject *object)
+{
+	ESourceSelectablePrivate *priv;
+
+	priv = E_SOURCE_SELECTABLE_GET_PRIVATE (object);
+
+	g_free (priv->color);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_selectable_parent_class)->finalize (object);
+}
+
+static void
+e_source_selectable_class_init (ESourceSelectableClass *class)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (class, sizeof (ESourceSelectablePrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_selectable_set_property;
+	object_class->get_property = source_selectable_get_property;
+	object_class->finalize = source_selectable_finalize;
+
+	/* We do not provide an extension name,
+	 * which is why the class is abstract. */
+
+	g_object_class_install_property (
+		object_class,
+		PROP_COLOR,
+		g_param_spec_string (
+			"color",
+			"Color",
+			"Textual specification of a color",
+			"#becedd",
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ENABLED,
+		g_param_spec_boolean (
+			"enabled",
+			"Enabled",
+			"Whether the data source is enabled",
+			TRUE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_WRITABLE_HINT,
+		g_param_spec_boolean (
+			"writable-hint",
+			"Writable Hint",
+			"Hints at whether the data source is writable",
+			TRUE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_selectable_init (ESourceSelectable *extension)
+{
+	extension->priv = E_SOURCE_SELECTABLE_GET_PRIVATE (extension);
+}
+
+const gchar *
+e_source_selectable_get_color (ESourceSelectable *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SELECTABLE (extension), NULL);
+
+	return extension->priv->color;
+}
+
+void
+e_source_selectable_set_color (ESourceSelectable *extension,
+                               const gchar *color)
+{
+	g_return_if_fail (E_IS_SOURCE_SELECTABLE (extension));
+	g_return_if_fail (color != NULL);
+
+	g_free (extension->priv->color);
+	extension->priv->color = g_strdup (color);
+
+	g_object_notify (G_OBJECT (extension), "color");
+}
+
+gboolean
+e_source_selectable_get_enabled (ESourceSelectable *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SELECTABLE (extension), FALSE);
+
+	return extension->priv->enabled;
+}
+
+void
+e_source_selectable_set_enabled (ESourceSelectable *extension,
+                                 gboolean enabled)
+{
+	g_return_if_fail (E_IS_SOURCE_SELECTABLE (extension));
+
+	extension->priv->enabled = enabled;
+
+	g_object_notify (G_OBJECT (extension), "enabled");
+}
+
+gboolean
+e_source_selectable_get_writable_hint (ESourceSelectable *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SELECTABLE (extension), FALSE);
+
+	return extension->priv->writable_hint;
+}
+
+void
+e_source_selectable_set_writable_hint (ESourceSelectable *extension,
+                                       gboolean writable_hint)
+{
+	g_return_if_fail (E_IS_SOURCE_SELECTABLE (extension));
+
+	extension->priv->writable_hint = writable_hint;
+
+	g_object_notify (G_OBJECT (extension), "writable-hint");
+}
diff --git a/libedataserver/e-source-selectable.h b/libedataserver/e-source-selectable.h
new file mode 100644
index 0000000..2fdf52c
--- /dev/null
+++ b/libedataserver/e-source-selectable.h
@@ -0,0 +1,73 @@
+/*
+ * e-source-selectable.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_SELECTABLE_H
+#define E_SOURCE_SELECTABLE_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_SELECTABLE \
+	(e_source_selectable_get_type ())
+#define E_SOURCE_SELECTABLE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_SELECTABLE, ESourceSelectable))
+#define E_SOURCE_SELECTABLE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_SELECTABLE, ESourceSelectableClass))
+#define E_IS_SOURCE_SELECTABLE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_SELECTABLE))
+#define E_IS_SOURCE_SELECTABLE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_SELECTABLE))
+#define E_SOURCE_SELECTABLE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_SELECTABLE, ESourceSelectableClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceSelectable ESourceSelectable;
+typedef struct _ESourceSelectableClass ESourceSelectableClass;
+typedef struct _ESourceSelectablePrivate ESourceSelectablePrivate;
+
+struct _ESourceSelectable {
+	ESourceExtension parent;
+	ESourceSelectablePrivate *priv;
+};
+
+struct _ESourceSelectableClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_selectable_get_type	(void);
+const gchar *	e_source_selectable_get_color	(ESourceSelectable *extension);
+void		e_source_selectable_set_color	(ESourceSelectable *extension,
+						 const gchar *color);
+gboolean	e_source_selectable_get_enabled	(ESourceSelectable *extension);
+void		e_source_selectable_set_enabled	(ESourceSelectable *extension,
+						 gboolean enabled);
+gboolean	e_source_selectable_get_writable_hint
+						(ESourceSelectable *extension);
+void		e_source_selectable_set_writable_hint
+						(ESourceSelectable *extension,
+						 gboolean writable_hint);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_SELECTABLE_H */
diff --git a/libedataserver/e-source-webdav.c b/libedataserver/e-source-webdav.c
new file mode 100644
index 0000000..2114f5f
--- /dev/null
+++ b/libedataserver/e-source-webdav.c
@@ -0,0 +1,552 @@
+/*
+ * e-source-webdav.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-webdav.h"
+
+#include <libedataserver/e-source-authentication.h>
+#include <libedataserver/e-source-security.h>
+
+#define E_SOURCE_WEBDAV_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_WEBDAV, ESourceWebdavPrivate))
+
+struct _ESourceWebdavPrivate {
+	gchar *display_name;
+	gboolean avoid_ifmatch;
+	SoupURI *uri;
+};
+
+enum {
+	PROP_0,
+	PROP_AVOID_IFMATCH,
+	PROP_DISPLAY_NAME,
+	PROP_HOST,
+	PROP_PATH,
+	PROP_PORT,
+	PROP_SECURE,
+	PROP_SOUP_URI,
+	PROP_USER
+};
+
+G_DEFINE_TYPE (
+	ESourceWebdav,
+	e_source_webdav,
+	E_TYPE_SOURCE_EXTENSION)
+
+static gboolean
+source_webdav_user_to_method (GBinding *binding,
+                              const GValue *source_value,
+                              GValue *target_value,
+                              gpointer user_data)
+{
+	const gchar *user;
+
+	user = g_value_get_string (source_value);
+	if (user == NULL || *user == '\0')
+		g_value_set_string (target_value, "none");
+	else
+		g_value_set_string (target_value, "plain/password");
+
+	return TRUE;
+}
+
+static const gchar *
+source_webdav_get_host (ESourceWebdav *extension)
+{
+	return extension->priv->uri->host;
+}
+
+static void
+source_webdav_set_host (ESourceWebdav *extension,
+                        const gchar *host)
+{
+	GObject *object = G_OBJECT (extension);
+
+	soup_uri_set_host (extension->priv->uri, host);
+
+	g_object_freeze_notify (object);
+	g_object_notify (object, "host");
+	g_object_notify (object, "soup-uri");
+	g_object_thaw_notify (object);
+}
+
+static const gchar *
+source_webdav_get_path (ESourceWebdav *extension)
+{
+	return extension->priv->uri->path;
+}
+
+static void
+source_webdav_set_path (ESourceWebdav *extension,
+                        const gchar *path)
+{
+	GObject *object = G_OBJECT (extension);
+
+	if (path == NULL || *path == '\0')
+		path = "/";
+
+	soup_uri_set_path (extension->priv->uri, path);
+
+	g_object_freeze_notify (object);
+	g_object_notify (object, "path");
+	g_object_notify (object, "soup-uri");
+	g_object_thaw_notify (object);
+}
+
+static guint16
+source_webdav_get_port (ESourceWebdav *extension)
+{
+	return (guint16) extension->priv->uri->port;
+}
+
+static void
+source_webdav_set_port (ESourceWebdav *extension,
+                        guint16 port)
+{
+	GObject *object = G_OBJECT (extension);
+
+	soup_uri_set_port (extension->priv->uri, port);
+
+	g_object_freeze_notify (object);
+	g_object_notify (object, "port");
+	g_object_notify (object, "soup-uri");
+	g_object_thaw_notify (object);
+}
+
+static gboolean
+source_webdav_get_secure (ESourceWebdav *extension)
+{
+	return (extension->priv->uri->scheme == SOUP_URI_SCHEME_HTTPS);
+}
+
+static void
+source_webdav_set_secure (ESourceWebdav *extension,
+                          gboolean secure)
+{
+	GObject *object = G_OBJECT (extension);
+	const gchar *scheme;
+
+	scheme = secure ? SOUP_URI_SCHEME_HTTPS : SOUP_URI_SCHEME_HTTP;
+	soup_uri_set_scheme (extension->priv->uri, scheme);
+
+	g_object_freeze_notify (object);
+	g_object_notify (object, "port");
+	g_object_notify (object, "secure");
+	g_object_notify (object, "soup-uri");
+	g_object_thaw_notify (object);
+}
+
+static const gchar *
+source_webdav_get_user (ESourceWebdav *extension)
+{
+	return extension->priv->uri->user;
+}
+
+static void
+source_webdav_set_user (ESourceWebdav *extension,
+                        const gchar *user)
+{
+	GObject *object = G_OBJECT (extension);
+
+	soup_uri_set_user (extension->priv->uri, user);
+
+	g_object_freeze_notify (object);
+	g_object_notify (object, "user");
+	g_object_notify (object, "soup-uri");
+	g_object_thaw_notify (object);
+}
+
+static void
+source_webdav_set_property (GObject *object,
+                            guint property_id,
+                            const GValue *value,
+                            GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_AVOID_IFMATCH:
+			e_source_webdav_set_avoid_ifmatch (
+				E_SOURCE_WEBDAV (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_DISPLAY_NAME:
+			e_source_webdav_set_display_name (
+				E_SOURCE_WEBDAV (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_HOST:
+			source_webdav_set_host (
+				E_SOURCE_WEBDAV (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_PATH:
+			source_webdav_set_path (
+				E_SOURCE_WEBDAV (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_PORT:
+			source_webdav_set_port (
+				E_SOURCE_WEBDAV (object),
+				g_value_get_uint (value));
+			return;
+
+		case PROP_SECURE:
+			source_webdav_set_secure (
+				E_SOURCE_WEBDAV (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_SOUP_URI:
+			e_source_webdav_set_soup_uri (
+				E_SOURCE_WEBDAV (object),
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_USER:
+			source_webdav_set_user (
+				E_SOURCE_WEBDAV (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_webdav_get_property (GObject *object,
+                            guint property_id,
+                            GValue *value,
+                            GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_AVOID_IFMATCH:
+			g_value_set_boolean (
+				value,
+				e_source_webdav_get_avoid_ifmatch (
+				E_SOURCE_WEBDAV (object)));
+			return;
+
+		case PROP_DISPLAY_NAME:
+			g_value_set_string (
+				value,
+				e_source_webdav_get_display_name (
+				E_SOURCE_WEBDAV (object)));
+			return;
+
+		case PROP_HOST:
+			g_value_set_string (
+				value,
+				source_webdav_get_host (
+				E_SOURCE_WEBDAV (object)));
+			return;
+
+		case PROP_PATH:
+			g_value_set_string (
+				value,
+				source_webdav_get_path (
+				E_SOURCE_WEBDAV (object)));
+			return;
+
+		case PROP_PORT:
+			g_value_set_uint (
+				value,
+				source_webdav_get_port (
+				E_SOURCE_WEBDAV (object)));
+			return;
+
+		case PROP_SECURE:
+			g_value_set_boolean (
+				value,
+				source_webdav_get_secure (
+				E_SOURCE_WEBDAV (object)));
+			return;
+
+		case PROP_SOUP_URI:
+			g_value_take_boxed (
+				value,
+				e_source_webdav_get_soup_uri (
+				E_SOURCE_WEBDAV (object)));
+			return;
+
+		case PROP_USER:
+			g_value_set_string (
+				value,
+				source_webdav_get_user (
+				E_SOURCE_WEBDAV (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_webdav_finalize (GObject *object)
+{
+	ESourceWebdavPrivate *priv;
+
+	priv = E_SOURCE_WEBDAV_GET_PRIVATE (object);
+
+	soup_uri_free (priv->uri);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_webdav_parent_class)->finalize (object);
+}
+
+static void
+source_webdav_constructed (GObject *object)
+{
+	ESource *source;
+	ESourceExtension *this_extension;
+	ESourceExtension *other_extension;
+	const gchar *extension_name;
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (e_source_webdav_parent_class)->constructed (object);
+
+	this_extension = E_SOURCE_EXTENSION (object);
+	source = e_source_extension_get_source (this_extension);
+
+	/* Bind to properties of other extensions for convenience. */
+
+	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
+	other_extension = e_source_get_extension (source, extension_name);
+
+	g_object_bind_property (
+		other_extension, "host",
+		this_extension, "host",
+		G_BINDING_BIDIRECTIONAL |
+		G_BINDING_SYNC_CREATE);
+
+	g_object_bind_property (
+		other_extension, "port",
+		this_extension, "port",
+		G_BINDING_BIDIRECTIONAL |
+		G_BINDING_SYNC_CREATE);
+
+	g_object_bind_property (
+		other_extension, "user",
+		this_extension, "user",
+		G_BINDING_BIDIRECTIONAL |
+		G_BINDING_SYNC_CREATE);
+
+	/* XXX Avoid binding the "user" and "method" properties of
+	 *     other_extension until we require GLib 2.28, or else
+	 *     it causes a crash in GBinding.  I reported this in:
+	 *     https://bugzilla.gnome.org/show_bug.cgi?id=639873. */
+	g_object_bind_property_full (
+		this_extension, "user",
+		other_extension, "method",
+		G_BINDING_SYNC_CREATE,
+		source_webdav_user_to_method,
+		NULL,
+		NULL, (GDestroyNotify) NULL);
+
+	extension_name = E_SOURCE_EXTENSION_SECURITY;
+	other_extension = e_source_get_extension (source, extension_name);
+
+	g_object_bind_property (
+		other_extension, "secure",
+		this_extension, "secure",
+		G_BINDING_BIDIRECTIONAL |
+		G_BINDING_SYNC_CREATE);
+}
+
+static void
+e_source_webdav_class_init (ESourceWebdavClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceWebdavPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_webdav_set_property;
+	object_class->get_property = source_webdav_get_property;
+	object_class->finalize = source_webdav_finalize;
+	object_class->constructed = source_webdav_constructed;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_AVOID_IFMATCH,
+		g_param_spec_boolean (
+			"avoid-ifmatch",
+			"Avoid If-Match",
+			"Work around a bug in old Apache servers",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DISPLAY_NAME,
+		g_param_spec_string (
+			"display-name",
+			"Display Name",
+			"Display name of the WebDAV resource",
+			"",
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_HOST,
+		g_param_spec_string (
+			"host",
+			"Host",
+			"WebDAV service host name",
+			NULL,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_PATH,
+		g_param_spec_string (
+			"path",
+			"Path",
+			"WebDAV service path",
+			"/",
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_PORT,
+		g_param_spec_uint (
+			"port",
+			"Port",
+			"WebDAV service port number",
+			0, G_MAXUINT16, 0,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SECURE,
+		g_param_spec_boolean (
+			"secure",
+			"Secure",
+			"Secure the network connection",
+			FALSE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SOUP_URI,
+		g_param_spec_boxed (
+			"soup-uri",
+			"SoupURI",
+			"WebDAV service as a SoupURI",
+			SOUP_TYPE_URI,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_USER,
+		g_param_spec_string (
+			"user",
+			"User",
+			"WebDAV service user name",
+			NULL,
+			G_PARAM_READWRITE));
+}
+
+static void
+e_source_webdav_init (ESourceWebdav *extension)
+{
+	extension->priv = E_SOURCE_WEBDAV_GET_PRIVATE (extension);
+	extension->priv->uri = soup_uri_new (NULL);
+}
+
+gboolean
+e_source_webdav_get_avoid_ifmatch (ESourceWebdav *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
+
+	return extension->priv->avoid_ifmatch;
+}
+
+void
+e_source_webdav_set_avoid_ifmatch (ESourceWebdav *extension,
+                                   gboolean avoid_ifmatch)
+{
+	g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
+
+	extension->priv->avoid_ifmatch = avoid_ifmatch;
+
+	g_object_notify (G_OBJECT (extension), "avoid-ifmatch");
+}
+
+const gchar *
+e_source_webdav_get_display_name (ESourceWebdav *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
+
+	return extension->priv->display_name;
+}
+
+void
+e_source_webdav_set_display_name (ESourceWebdav *extension,
+                                  const gchar *display_name)
+{
+	g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
+
+	g_free (extension->priv->display_name);
+	extension->priv->display_name = g_strdup (display_name);
+
+	g_object_notify (G_OBJECT (extension), "display-name");
+}
+
+SoupURI *
+e_source_webdav_get_soup_uri (ESourceWebdav *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), NULL);
+
+	return soup_uri_copy (extension->priv->uri);
+}
+
+void
+e_source_webdav_set_soup_uri (ESourceWebdav *extension,
+                              SoupURI *uri)
+{
+	GObject *object;
+
+	g_return_if_fail (extension != NULL);
+	g_return_if_fail (uri != NULL);
+
+	soup_uri_free (extension->priv->uri);
+	extension->priv->uri = soup_uri_copy (uri);
+
+	object = G_OBJECT (extension);
+	g_object_freeze_notify (object);
+	g_object_notify (object, "host");
+	g_object_notify (object, "path");
+	g_object_notify (object, "port");
+	g_object_notify (object, "secure");
+	g_object_notify (object, "soup-uri");
+	g_object_notify (object, "user");
+	g_object_thaw_notify (object);
+}
+
diff --git a/libedataserver/e-source-webdav.h b/libedataserver/e-source-webdav.h
new file mode 100644
index 0000000..457f90d
--- /dev/null
+++ b/libedataserver/e-source-webdav.h
@@ -0,0 +1,95 @@
+/*
+ * e-source-webdav.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_WEBDAV_H
+#define E_SOURCE_WEBDAV_H
+
+/* This class exists in libedataserver because we have several
+ * WebDAV-based backends.  Each of these backends is free to use
+ * this class directly or subclass it with additional settings.
+ * Subclasses should override the extension name.
+ *
+ * The SoupURI is parsed into components and distributed across
+ * several other built-in extensions such as Authentication and
+ * Security. */
+
+#include <libsoup/soup.h>
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_WEBDAV \
+	(e_source_webdav_get_type ())
+#define E_SOURCE_WEBDAV(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_WEBDAV, ESourceWebdav))
+#define E_SOURCE_WEBDAV_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_WEBDAV, ESourceWebdavClass))
+#define E_IS_SOURCE_WEBDAV(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_WEBDAV))
+#define E_IS_SOURCE_WEBDAV_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_WEBDAV))
+#define E_SOURCE_WEBDAV_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_WEBDAV, ESourceWebdavClass))
+
+#define E_SOURCE_EXTENSION_WEBDAV_BACKEND "WebDAV Backend"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceWebdav ESourceWebdav;
+typedef struct _ESourceWebdavClass ESourceWebdavClass;
+typedef struct _ESourceWebdavPrivate ESourceWebdavPrivate;
+
+struct _ESourceWebdav {
+	ESourceExtension parent;
+	ESourceWebdavPrivate *priv;
+};
+
+struct _ESourceWebdavClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_webdav_get_type	(void);
+const gchar *	e_source_webdav_get_display_name
+						(ESourceWebdav *extension);
+void		e_source_webdav_set_display_name
+						(ESourceWebdav *extension,
+						 const gchar *display_name);
+SoupURI *	e_source_webdav_get_soup_uri	(ESourceWebdav *extension);
+void		e_source_webdav_set_soup_uri	(ESourceWebdav *extension,
+						 SoupURI *uri);
+
+/* XXX This setting works around a bug [1] in older Apache mod_dav
+ *     versions.  We may deprecate this once Apache 2.2.8 or newer
+ *     becomes sufficiently ubiquitous, or we figure out a way to
+ *     detect and work around the bug automatically.
+ *
+ *     [1] https://issues.apache.org/bugzilla/show_bug.cgi?id=38034
+ */
+gboolean	e_source_webdav_get_avoid_ifmatch
+						(ESourceWebdav *extension);
+void		e_source_webdav_set_avoid_ifmatch
+						(ESourceWebdav *extension,
+						 gboolean avoid_ifmatch);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_WEBDAV_H */
diff --git a/libedataserver/e-source.c b/libedataserver/e-source.c
index 49121db..ade9614 100644
--- a/libedataserver/e-source.c
+++ b/libedataserver/e-source.c
@@ -1,958 +1,1300 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* e-source.c
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+/*
+ * e-source.c
  *
  * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU Lesser General Public
- * License as published by the Free Software Foundation.
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
  *
  * This program 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.
+ * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
  *
- * Author: Ettore Perazzoli <ettore ximian com>
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "e-source.h"
 
+#include <config.h>
 #include <string.h>
+
+#include <glib/gi18n-lib.h>
+
+#include "e-data-server-util.h"
+#include "e-source-extension.h"
 #include "e-uid.h"
-#include "e-source.h"
 
-#define ES_CLASS(obj)  E_SOURCE_CLASS (G_OBJECT_GET_CLASS (obj))
+#define E_SOURCE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE, ESourcePrivate))
 
-/* Private members.  */
+#define E_SOURCE_GROUP_NAME	"Data Source"
 
 struct _ESourcePrivate {
-	ESourceGroup *group;
+	GFile *file;
+	GNode node;
 
+	gchar *backend_name;
+	gchar *display_name;
+	gchar *parent;
 	gchar *uid;
-	gchar *name;
-	gchar *relative_uri;
-	gchar *absolute_uri;
-
-	gboolean readonly;
-
-	gchar *color_spec;
 
-	GHashTable *properties;
+	GKeyFile *key_file;
+	GHashTable *extensions;
+	GFileMonitor *file_monitor;
 };
 
-/* Signals.  */
+enum {
+	PROP_0,
+	PROP_BACKEND_NAME,
+	PROP_DISPLAY_NAME,
+	PROP_FILE,
+	PROP_PARENT,
+	PROP_UID
+};
 
 enum {
 	CHANGED,
 	LAST_SIGNAL
 };
-static guint signals[LAST_SIGNAL] = { 0 };
 
-/* Callbacks.  */
+static guint signals[LAST_SIGNAL];
+
+static void	e_source_initable_init		(GInitableIface *interface);
+
+G_DEFINE_TYPE_WITH_CODE (
+	ESource,
+	e_source,
+	G_TYPE_OBJECT,
+	G_IMPLEMENT_INTERFACE (
+		G_TYPE_INITABLE,
+		e_source_initable_init))
 
 static void
-group_weak_notify (ESource *source,
-		   GObject **where_the_object_was)
+source_find_extension_classes_rec (GType parent_type,
+                                   GHashTable *hash_table)
 {
-	source->priv->group = NULL;
+	GType *children;
+	guint n_children, ii;
 
-	g_signal_emit (source, signals[CHANGED], 0);
-}
+	children = g_type_children (parent_type, &n_children);
 
-/* GObject methods.  */
+	for (ii = 0; ii < n_children; ii++) {
+		GType type = children[ii];
+		ESourceExtensionClass *class;
+		gpointer key;
 
-G_DEFINE_TYPE (ESource, e_source, G_TYPE_OBJECT)
+		/* Recurse over the child's children. */
+		source_find_extension_classes_rec (type, hash_table);
 
-static void
-impl_finalize (GObject *object)
-{
-	ESourcePrivate *priv = E_SOURCE (object)->priv;
+		/* Skip abstract types. */
+		if (G_TYPE_IS_ABSTRACT (type))
+			continue;
 
-	g_free (priv->uid);
-	g_free (priv->name);
-	g_free (priv->relative_uri);
-	g_free (priv->absolute_uri);
-	g_free (priv->color_spec);
+		class = g_type_class_ref (type);
+		key = (gpointer) class->name;
 
-	g_hash_table_destroy (priv->properties);
+		if (key != NULL)
+			g_hash_table_insert (hash_table, key, class);
+		else
+			g_type_class_unref (class);
+	}
 
-	g_free (priv);
+	g_free (children);
+}
 
-	(* G_OBJECT_CLASS (e_source_parent_class)->finalize) (object);
+static GHashTable *
+source_find_extension_classes (void)
+{
+	GHashTable *hash_table;
+
+	hash_table = g_hash_table_new_full (
+		(GHashFunc) g_str_hash,
+		(GEqualFunc) g_str_equal,
+		(GDestroyNotify) NULL,
+		(GDestroyNotify) g_type_class_unref);
+
+	source_find_extension_classes_rec (
+		E_TYPE_SOURCE_EXTENSION, hash_table);
+
+	return hash_table;
 }
 
-static void
-impl_dispose (GObject *object)
+static gchar *
+source_name_to_key (const gchar *name)
 {
-	ESourcePrivate *priv = E_SOURCE (object)->priv;
+	gboolean uppercase = TRUE;
+	gchar *key, *cp;
+	gint ii;
+
+	/* Convert the property name to CamelCase. */
+
+	key = cp = g_malloc0 (strlen (name) + 1);
 
-	if (priv->group != NULL) {
-		g_object_weak_unref (G_OBJECT (priv->group), (GWeakNotify) group_weak_notify, object);
-		priv->group = NULL;
+	for (ii = 0; name[ii] != '\0'; ii++) {
+		if (g_ascii_isalnum (name[ii]) && uppercase) {
+			*cp++ = g_ascii_toupper (name[ii]);
+			uppercase = FALSE;
+		} else if (name[ii] == '-' || name[ii] == '_')
+			uppercase = TRUE;
+		else
+			*cp++ = name[ii];
 	}
 
-	(* G_OBJECT_CLASS (e_source_parent_class)->dispose) (object);
+	return key;
 }
 
-/* Initialization.  */
-
 static void
-e_source_class_init (ESourceClass *class)
+source_set_key_file_from_property (GObject *object,
+                                   GParamSpec *pspec,
+                                   GKeyFile *key_file,
+                                   const gchar *group_name)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (class);
+	GValue *pvalue;
+	GValue *svalue;
+	gchar *key;
+
+	pvalue = g_slice_new0 (GValue);
+	g_value_init (pvalue, pspec->value_type);
+	g_object_get_property (object, pspec->name, pvalue);
+
+	svalue = g_slice_new0 (GValue);
+	g_value_init (svalue, G_TYPE_STRING);
+
+	key = source_name_to_key (pspec->name);
+
+	/* For the most part we can just transform any supported
+	 * property type to a string, with a couple exceptions. */
+
+	/* Transforming a boolean GValue to a string results in
+	 * "TRUE" or "FALSE" (all uppercase), but GKeyFile only
+	 * recognizes "true" or "false" (all lowercase).  So we
+	 * have to use g_key_file_set_boolean(). */
+	if (G_VALUE_HOLDS_BOOLEAN (pvalue)) {
+		gboolean v_boolean = g_value_get_boolean (pvalue);
+		g_key_file_set_boolean (key_file, group_name, key, v_boolean);
+
+	/* String GValues may contain characters that need escaping. */
+	} else if (G_VALUE_HOLDS_STRING (pvalue)) {
+		const gchar *v_string = g_value_get_string (pvalue);
+		g_key_file_set_string (
+			key_file, group_name, key,
+			(v_string != NULL) ? v_string : "");
+
+	/* Transforming an enum GValue to a string results in
+	 * the GEnumValue name.  We want the shorter nickname. */
+	} else if (G_VALUE_HOLDS_ENUM (pvalue)) {
+		GParamSpecEnum *enum_pspec;
+		GEnumClass *enum_class;
+		GEnumValue *enum_value;
+		gint value;
+
+		enum_pspec = G_PARAM_SPEC_ENUM (pspec);
+		enum_class = enum_pspec->enum_class;
+
+		value = g_value_get_enum (pvalue);
+		enum_value = g_enum_get_value (enum_class, value);
+
+		if (enum_value == NULL) {
+			value = enum_pspec->default_value;
+			enum_value = g_enum_get_value (enum_class, value);
+		}
 
-	object_class->dispose  = impl_dispose;
-	object_class->finalize = impl_finalize;
+		if (enum_value != NULL)
+			g_key_file_set_string (
+				key_file, group_name, key,
+				enum_value->value_nick);
+
+	/* For GValues holding a GFile object we save the URI. */
+	} else if (G_VALUE_HOLDS (pvalue, G_TYPE_FILE)) {
+		GFile *file = g_value_get_object (pvalue);
+		gchar *uri = NULL;
+
+		if (file != NULL)
+			uri = g_file_get_uri (file);
+		g_key_file_set_string (
+			key_file, group_name, key,
+			(uri != NULL) ? uri : "");
+		g_free (uri);
+
+	} else if (g_value_transform (pvalue, svalue)) {
+		const gchar *value = g_value_get_string (svalue);
+		g_key_file_set_value (key_file, group_name, key, value);
+	}
 
-	signals[CHANGED] =
-		g_signal_new ("changed",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (ESourceClass, changed),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE, 0);
+	g_free (key);
+	g_value_unset (pvalue);
+	g_value_unset (svalue);
+	g_slice_free (GValue, pvalue);
+	g_slice_free (GValue, svalue);
 }
 
 static void
-e_source_init (ESource *source)
+source_set_property_from_key_file (GObject *object,
+                                   GParamSpec *pspec,
+                                   GKeyFile *key_file,
+                                   const gchar *group_name)
 {
-	ESourcePrivate *priv;
+	gchar *key;
+	GValue *value;
+	GError *error = NULL;
+
+	value = g_slice_new0 (GValue);
+	key = source_name_to_key (pspec->name);
+
+	if (G_IS_PARAM_SPEC_CHAR (pspec) ||
+	    G_IS_PARAM_SPEC_UCHAR (pspec) ||
+	    G_IS_PARAM_SPEC_INT (pspec) ||
+	    G_IS_PARAM_SPEC_UINT (pspec) ||
+	    G_IS_PARAM_SPEC_LONG (pspec) ||
+	    G_IS_PARAM_SPEC_ULONG (pspec)) {
+		gint v_int;
+
+		v_int = g_key_file_get_integer (
+			key_file, group_name, key, &error);
+		if (error == NULL) {
+			g_value_init (value, G_TYPE_INT);
+			g_value_set_int (value, v_int);
+		}
 
-	priv = g_new0 (ESourcePrivate, 1);
-	source->priv = priv;
+	} else if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) {
+		gboolean v_boolean;
 
-	priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal,
-						  g_free, g_free);
-}
+		v_boolean = g_key_file_get_boolean (
+			key_file, group_name, key, &error);
+		if (error == NULL) {
+			g_value_init (value, G_TYPE_BOOLEAN);
+			g_value_set_boolean (value, v_boolean);
+		}
 
-/* Private methods. */
+	} else if (G_IS_PARAM_SPEC_ENUM (pspec)) {
+		gchar *nick;
+
+		nick = g_key_file_get_string (
+			key_file, group_name, key, &error);
+		if (error == NULL) {
+			GParamSpecEnum *enum_pspec;
+			GEnumValue *enum_value;
+
+			enum_pspec = G_PARAM_SPEC_ENUM (pspec);
+			enum_value = g_enum_get_value_by_nick (
+				enum_pspec->enum_class, nick);
+			if (enum_value != NULL) {
+				g_value_init (value, pspec->value_type);
+				g_value_set_enum (value, enum_value->value);
+			}
+			g_free (nick);
+		}
 
-static gboolean
-set_color_spec (ESource *source,
-                const gchar *color_spec)
-{
-	ESourcePrivate *priv = source->priv;
-	gboolean do_cmp;
+	} else if (G_IS_PARAM_SPEC_FLOAT (pspec) ||
+		   G_IS_PARAM_SPEC_DOUBLE (pspec)) {
+		gdouble v_double;
 
-	if (color_spec == priv->color_spec)
-		return FALSE;
+		v_double = g_key_file_get_double (
+			key_file, group_name, key, &error);
+		if (error == NULL) {
+			g_value_init (value, G_TYPE_DOUBLE);
+			g_value_set_double (value, v_double);
+		}
 
-	do_cmp = (color_spec != NULL && priv->color_spec != NULL);
-	if (do_cmp && g_ascii_strcasecmp (color_spec, priv->color_spec) == 0)
-		return FALSE;
+	} else if (G_IS_PARAM_SPEC_STRING (pspec)) {
+		gchar *v_string;
 
-	g_free (priv->color_spec);
-	priv->color_spec = g_strdup (color_spec);
+		/* Get the localized string if present. */
+		v_string = g_key_file_get_locale_string (
+			key_file, group_name, key, NULL, &error);
+		if (error == NULL) {
+			g_value_init (value, G_TYPE_STRING);
+			g_value_set_string (value, v_string);
+			g_free (v_string);
+		}
 
-	return TRUE;
-}
+	} else if (g_type_is_a (pspec->value_type, G_TYPE_FILE)) {
+		gchar *uri;
+
+		/* Create the GFile from the URI string. */
+		uri = g_key_file_get_locale_string (
+			key_file, group_name, key, NULL, &error);
+		if (error == NULL) {
+			GFile *file = NULL;
+			if (uri != NULL && *uri != '\0')
+				file = g_file_new_for_uri (uri);
+			g_value_init (value, pspec->value_type);
+			g_value_take_object (value, file);
+			g_free (uri);
+		}
 
-/* Public methods.  */
+	} else {
+		g_warning (
+			"No GKeyFile-to-GValue converter defined "
+			"for type '%s'", G_VALUE_TYPE_NAME (value));
+	}
 
-ESource *
-e_source_new  (const gchar *name,
-	       const gchar *relative_uri)
+	/* If a value could not be retrieved from the key
+	 * file, restore the property to its default value. */
+	if (error != NULL) {
+		g_value_init (value, pspec->value_type);
+		g_param_value_set_default (pspec, value);
+		g_error_free (error);
+	}
+
+	if (G_IS_VALUE (value)) {
+		g_object_set_property (object, pspec->name, value);
+		g_value_unset (value);
+	}
+
+	g_slice_free (GValue, value);
+	g_free (key);
+}
+
+static void
+source_load_from_key_file (GObject *object,
+                           GKeyFile *key_file,
+                           const gchar *group_name)
 {
-	ESource *source;
+	GObjectClass *class;
+	GParamSpec **properties;
+	guint n_properties, ii;
 
-	g_return_val_if_fail (name != NULL, NULL);
-	g_return_val_if_fail (relative_uri != NULL, NULL);
+	class = G_OBJECT_GET_CLASS (object);
+	properties = g_object_class_list_properties (class, &n_properties);
 
-	source = g_object_new (e_source_get_type (), NULL);
-	source->priv->uid = e_uid_new ();
+	g_object_freeze_notify (object);
+
+	for (ii = 0; ii < n_properties; ii++) {
+		if (properties[ii]->flags & E_SOURCE_PARAM_SETTING) {
+			source_set_property_from_key_file (
+				object, properties[ii], key_file, group_name);
+		}
+	}
 
-	e_source_set_name (source, name);
-	e_source_set_relative_uri (source, relative_uri);
-	return source;
+	g_object_thaw_notify (object);
+
+	g_free (properties);
 }
 
-ESource *
-e_source_new_with_absolute_uri (const gchar *name,
-				const gchar *absolute_uri)
+static void
+source_save_to_key_file (GObject *object,
+                         GKeyFile *key_file,
+                         const gchar *group_name)
 {
-	ESource *source;
+	GObjectClass *class;
+	GParamSpec **properties;
+	guint n_properties, ii;
 
-	g_return_val_if_fail (name != NULL, NULL);
-	g_return_val_if_fail (absolute_uri != NULL, NULL);
+	class = G_OBJECT_GET_CLASS (object);
+	properties = g_object_class_list_properties (class, &n_properties);
 
-	source = g_object_new (e_source_get_type (), NULL);
-	source->priv->uid = e_uid_new ();
+	for (ii = 0; ii < n_properties; ii++) {
+		if (properties[ii]->flags & E_SOURCE_PARAM_SETTING) {
+			source_set_key_file_from_property (
+				object, properties[ii], key_file, group_name);
+		}
+	}
 
-	e_source_set_name (source, name);
-	e_source_set_absolute_uri (source, absolute_uri);
-	return source;
+	g_free (properties);
 }
 
-ESource *
-e_source_new_from_xml_node (xmlNodePtr node)
+static void
+source_file_monitor_changed (GFileMonitor *file_monitor,
+                             GFile *file,
+                             GFile *other_file,
+                             GFileMonitorEvent event_type,
+                             ESource *source)
 {
-	ESource *source;
-	xmlChar *uid;
+	GError *error = NULL;
 
-	uid = xmlGetProp (node, (xmlChar*)"uid");
-	if (uid == NULL)
-		return NULL;
+	/* Ignore file deletion events. */
+	if (event_type != G_FILE_MONITOR_EVENT_DELETED)
+		e_source_reload (source, &error);
 
-	source = g_object_new (e_source_get_type (), NULL);
+	/* FIXME Need better error handling. */
+	if (error != NULL) {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
+}
 
-	source->priv->uid = g_strdup ((gchar *)uid);
-	xmlFree (uid);
+static void
+source_setup_file_monitor (ESource *source)
+{
+	GFile *file;
 
-	if (e_source_update_from_xml_node (source, node, NULL))
-		return source;
+	file = e_source_get_file (source);
 
-	g_object_unref (source);
-	return NULL;
+	if (source->priv->file_monitor != NULL)
+		g_object_unref (source->priv->file_monitor);
+
+	source->priv->file_monitor = g_file_monitor (
+		file, G_FILE_MONITOR_NONE, NULL, NULL);
+
+	if (source->priv->file_monitor != NULL)
+		g_signal_connect (
+			source->priv->file_monitor, "changed",
+			G_CALLBACK (source_file_monitor_changed), source);
 }
 
 static void
-import_properties (ESource *source,
-		   xmlNodePtr prop_root)
+source_set_file (ESource *source,
+                 GFile *file)
 {
-	ESourcePrivate *priv = source->priv;
-	xmlNodePtr prop_node;
+	g_return_if_fail (source->priv->file == NULL);
 
-	for (prop_node = prop_root->children; prop_node; prop_node = prop_node->next) {
-		xmlChar *name, *value;
+	if (G_IS_FILE (file))
+		g_object_ref (file);
+	else {
+		const gchar *data_dir;
+		gchar *uid = e_uid_new ();
+		gchar *path;
 
-		if (!prop_node->name || strcmp ((gchar *)prop_node->name, "property"))
-			continue;
+		e_filename_make_safe (uid);
 
-		name = xmlGetProp (prop_node, (xmlChar*)"name");
-		value = xmlGetProp (prop_node, (xmlChar*)"value");
+		data_dir = e_get_user_data_dir ();
+		path = g_build_filename (data_dir, "sources", uid, NULL);
 
-		if (name && value)
-			g_hash_table_insert (priv->properties, g_strdup ((gchar *)name), g_strdup ((gchar *)value));
+		file = g_file_new_for_path (path);
 
-		if (name)
-			xmlFree (name);
-		if (value)
-			xmlFree (value);
+		g_free (path);
+		g_free (uid);
 	}
+
+	source->priv->file = file;
+	source->priv->uid = g_file_get_basename (file);
+
+	source_setup_file_monitor (source);
 }
 
-typedef struct
+static void
+source_set_property (GObject *object,
+                     guint property_id,
+                     const GValue *value,
+                     GParamSpec *pspec)
 {
-	gboolean equal;
-	GHashTable *table2;
-} hash_compare_data;
+	switch (property_id) {
+		case PROP_BACKEND_NAME:
+			e_source_set_backend_name (
+				E_SOURCE (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_DISPLAY_NAME:
+			e_source_set_display_name (
+				E_SOURCE (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_FILE:
+			source_set_file (
+				E_SOURCE (object),
+				g_value_get_object (value));
+			return;
+
+		case PROP_PARENT:
+			e_source_set_parent (
+				E_SOURCE (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
 
 static void
-compare_str_hash (gpointer key, gpointer value, hash_compare_data *cd)
+source_get_property (GObject *object,
+                     guint property_id,
+                     GValue *value,
+                     GParamSpec *pspec)
 {
-	gpointer value2 = g_hash_table_lookup (cd->table2, key);
-	if (value2 == NULL || g_str_equal (value, value2) == FALSE)
-		cd->equal = FALSE;
+	switch (property_id) {
+		case PROP_BACKEND_NAME:
+			g_value_set_string (
+				value, e_source_get_backend_name (
+				E_SOURCE (object)));
+			return;
+
+		case PROP_DISPLAY_NAME:
+			g_value_set_string (
+				value, e_source_get_display_name (
+				E_SOURCE (object)));
+			return;
+
+		case PROP_FILE:
+			g_value_set_object (
+				value, e_source_get_file (
+				E_SOURCE (object)));
+			return;
+
+		case PROP_PARENT:
+			g_value_set_string (
+				value, e_source_get_parent (
+				E_SOURCE (object)));
+			return;
+
+		case PROP_UID:
+			g_value_set_string (
+				value, e_source_get_uid (
+				E_SOURCE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
-static gboolean
-compare_str_hashes (GHashTable *table1, GHashTable *table2)
+static void
+source_dispose (GObject *object)
 {
-	hash_compare_data cd;
+	ESourcePrivate *priv;
 
-	if (g_hash_table_size (table1) != g_hash_table_size (table2))
-		return FALSE;
+	priv = E_SOURCE_GET_PRIVATE (object);
+
+	if (priv->file != NULL) {
+		g_object_unref (priv->file);
+		priv->file = NULL;
+	}
+
+	if (priv->file_monitor != NULL) {
+		g_object_unref (priv->file_monitor);
+		priv->file_monitor = NULL;
+	}
 
-	cd.equal = TRUE;
-	cd.table2 = table2;
-	g_hash_table_foreach (table1, (GHFunc) compare_str_hash, &cd);
-	return cd.equal;
+	g_hash_table_remove_all (priv->extensions);
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (e_source_parent_class)->dispose (object);
 }
 
-/**
- * e_source_update_from_xml_node:
- * @source: An ESource.
- * @node: A pointer to the node to parse.
- *
- * Update the ESource properties from @node.
- *
- * Returns: %TRUE if the data in @node was recognized and parsed into
- * acceptable values for @source, %FALSE otherwise.
- **/
-gboolean
-e_source_update_from_xml_node (ESource *source,
-			       xmlNodePtr node,
-			       gboolean *changed_return)
-{
-	xmlChar *name;
-	xmlChar *relative_uri;
-	xmlChar *absolute_uri;
-	xmlChar *color_spec;
-	xmlChar *color;
-	gboolean retval = FALSE;
-	gboolean changed = FALSE;
-
-	name = xmlGetProp (node, (xmlChar*)"name");
-	relative_uri = xmlGetProp (node, (xmlChar*)"relative_uri");
-	absolute_uri = xmlGetProp (node, (xmlChar*)"uri");
-	color_spec = xmlGetProp (node, (xmlChar*)"color_spec");
-	color = xmlGetProp (node, (xmlChar*)"color");  /* obsolete */
-
-	if (name == NULL || (relative_uri == NULL && absolute_uri == NULL))
-		goto done;
-
-	if (color_spec != NULL && color != NULL)
-		goto done;
-
-	if (source->priv->name == NULL
-	    || strcmp ((gchar *)name, source->priv->name) != 0
-	    || (source->priv->relative_uri == NULL && relative_uri != NULL)
-	    || (source->priv->relative_uri != NULL && relative_uri == NULL)
-	    || (relative_uri && source->priv->relative_uri && strcmp ((gchar *)relative_uri, source->priv->relative_uri) != 0)) {
-		gchar *abs_uri = NULL;
-
-		g_free (source->priv->name);
-		source->priv->name = g_strdup ((gchar *)name);
-
-		if (source->priv->group) {
-			abs_uri = e_source_build_absolute_uri (source);
-		}
+static void
+source_finalize (GObject *object)
+{
+	ESourcePrivate *priv;
 
-		if (abs_uri && source->priv->absolute_uri && g_str_equal (abs_uri, source->priv->absolute_uri)) {
-			/* reset the absolute uri to NULL to be regenerated when asked for,
-			   but only when it was generated also before */
-			g_free (source->priv->absolute_uri);
-			source->priv->absolute_uri = NULL;
-		} else if (source->priv->absolute_uri &&
-			   source->priv->relative_uri &&
-			   g_str_has_suffix (source->priv->absolute_uri, source->priv->relative_uri)) {
-			gchar *tmp = source->priv->absolute_uri;
+	priv = E_SOURCE_GET_PRIVATE (object);
 
-			tmp[strlen (tmp) - strlen (source->priv->relative_uri)] = 0;
-			source->priv->absolute_uri = g_strconcat (tmp, (gchar *)relative_uri, NULL);
+	g_node_unlink (&priv->node);
 
-			g_free (tmp);
-		}
+	g_free (priv->backend_name);
+	g_free (priv->display_name);
+	g_free (priv->parent);
+	g_free (priv->uid);
 
-		g_free (abs_uri);
+	g_key_file_free (priv->key_file);
+	g_hash_table_destroy (priv->extensions);
 
-		g_free (source->priv->relative_uri);
-		source->priv->relative_uri = g_strdup ((gchar *)relative_uri);
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_parent_class)->finalize (object);
+}
 
-		changed = TRUE;
-	}
+static void
+source_notify (GObject *object,
+               GParamSpec *pspec)
+{
+	e_source_changed (E_SOURCE (object));
+}
 
-	if (absolute_uri != NULL) {
-		g_free (source->priv->absolute_uri);
+static gboolean
+source_initable_init (GInitable *initable,
+                      GCancellable *cancellable,
+                      GError **error)
+{
+	gboolean success;
+	GError *local_error = NULL;
 
-		if (relative_uri && g_str_equal ((const gchar *) relative_uri, "system") &&
-		    (g_str_has_prefix ((const gchar *) absolute_uri, "file:") || g_str_equal ((const gchar *) absolute_uri, "local:/system")))
-			source->priv->absolute_uri = NULL;
-		else
-			source->priv->absolute_uri = g_strdup ((gchar *)absolute_uri);
-		changed = TRUE;
-	}
+	success = e_source_reload (E_SOURCE (initable), &local_error);
 
-	if (color == NULL) {
-		/* It is okay for color_spec to be NULL. */
-		changed |= set_color_spec (source, (gchar *)color_spec);
-	} else {
-		gchar buffer[8];
-		g_snprintf (buffer, sizeof (buffer), "#%s", color);
-		changed |= set_color_spec (source, buffer);
-	}
+	/* The key file will not exist yet if this is a new data source. */
+	if (g_error_matches (local_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
+		g_clear_error (&local_error);
+		success = TRUE;
 
-	if (g_hash_table_size (source->priv->properties) && !node->children) {
-		g_hash_table_destroy (source->priv->properties);
-		source->priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal,
-								  g_free, g_free);
-		changed = TRUE;
-	}
+	} else if (local_error != NULL)
+		g_propagate_error (error, local_error);
 
-	for (node = node->children; node; node = node->next) {
-		if (!node->name)
-			continue;
+	return success;
+}
 
-		if (!strcmp ((gchar *)node->name, "properties")) {
-			GHashTable *temp = source->priv->properties;
-			source->priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal,
-									  g_free, g_free);
-			import_properties (source, node);
-			if (!compare_str_hashes (temp, source->priv->properties))
-				changed = TRUE;
-			g_hash_table_destroy (temp);
-			break;
-		}
-	}
+static void
+e_source_class_init (ESourceClass *class)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (class, sizeof (ESourcePrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_set_property;
+	object_class->get_property = source_get_property;
+	object_class->dispose = source_dispose;
+	object_class->finalize = source_finalize;
+	object_class->notify = source_notify;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_BACKEND_NAME,
+		g_param_spec_string (
+			"backend-name",
+			"Backend Name",
+			"The name of the backend handling the data source",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DISPLAY_NAME,
+		g_param_spec_string (
+			"display-name",
+			"Display Name",
+			"The human-readable name of the data source",
+			_("New Source"),
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FILE,
+		g_param_spec_object (
+			"file",
+			"File",
+			"The key file for the data source",
+			G_TYPE_FILE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY |
+			G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_PARENT,
+		g_param_spec_string (
+			"parent",
+			"Parent",
+			"The unique identity of the parent data source",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_UID,
+		g_param_spec_string (
+			"uid",
+			"UID",
+			"The unique identity of the data source",
+			NULL,
+			G_PARAM_READABLE |
+			G_PARAM_STATIC_STRINGS));
+
+	signals[CHANGED] = g_signal_new (
+		"changed",
+		G_TYPE_FROM_CLASS (class),
+		G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
+		G_STRUCT_OFFSET (ESourceClass, changed),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+}
 
-	retval = TRUE;
+static void
+e_source_initable_init (GInitableIface *interface)
+{
+	interface->init = source_initable_init;
+}
 
- done:
-	if (changed)
-		g_signal_emit (source, signals[CHANGED], 0);
+static void
+e_source_init (ESource *source)
+{
+	GHashTable *extensions;
 
-	if (changed_return != NULL)
-		*changed_return = changed;
+	extensions = g_hash_table_new_full (
+		(GHashFunc) g_str_hash,
+		(GEqualFunc) g_str_equal,
+		(GDestroyNotify) g_free,
+		(GDestroyNotify) g_object_unref);
 
-	if (name != NULL)
-		xmlFree (name);
-	if (relative_uri != NULL)
-		xmlFree (relative_uri);
-	if (absolute_uri != NULL)
-		xmlFree (absolute_uri);
-	if (color_spec != NULL)
-		xmlFree (color_spec);
-	if (color != NULL)
-		xmlFree (color);
+	source->priv = E_SOURCE_GET_PRIVATE (source);
+	source->priv->key_file = g_key_file_new ();
+	source->priv->extensions = extensions;
 
-	return retval;
+	memset (&source->priv->node, 0, sizeof (GNode));
+	source->priv->node.data = source;
 }
 
 /**
- * e_source_name_from_xml_node:
- * @node: A pointer to an XML node.
+ * e_source_new:
+ * @file: a #GFile, or %NULL
+ * @error: return location for a #GError, or %NULL
  *
- * Assuming that @node is a valid ESource specification, retrieve the name of
- * the source from it.
+ * Creates a new #ESource for the key file described by @file.  If the
+ * key file does not exist, cannot be opened, has syntax errors or fails
+ * to pass some basic integrity checks, the function returns %NULL and
+ * sets @error.
  *
- * Returns: Name of the source in the specified @node.  The caller must
- * free the string.
+ * If @file is %NULL, the #ESource will generate a new unique identifier
+ * string and construct a #GFile from it.  This is useful when creating a
+ * new data source.  The key file will be written to the user's "sources"
+ * directory after changes are applied to the returned #ESource.
+ *
+ * Returns: a newly-created #ESource, or %NULL on error
+ *
+ * Since: 2.92
  **/
-gchar *
-e_source_uid_from_xml_node (xmlNodePtr node)
+ESource *
+e_source_new (GFile *file,
+              GError **error)
 {
-	xmlChar *uid = xmlGetProp (node, (xmlChar*)"uid");
-	gchar *retval;
+	g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);
 
-	if (uid == NULL)
-		return NULL;
-
-	retval = g_strdup ((gchar *)uid);
-	xmlFree (uid);
-	return retval;
+	return g_initable_new (
+		E_TYPE_SOURCE, NULL, error, "file", file, NULL);
 }
 
-gchar *
-e_source_build_absolute_uri (ESource *source)
+/**
+ * e_source_hash:
+ * @source: an #ESource
+ *
+ * Generates a hash value for @source.  This function is intended for
+ * easily hashing an #ESource to add to a #GHashTable or similar data
+ * structure.
+ *
+ * Returns: a hash value for @source.
+ *
+ * Since: 2.92
+ **/
+guint
+e_source_hash (ESource *source)
 {
-	const gchar *base_uri_str;
-	gchar *uri_str;
+	const gchar *uid;
 
-	g_return_val_if_fail (source->priv->group != NULL, NULL);
+	g_return_val_if_fail (E_IS_SOURCE (source), 0);
 
-	base_uri_str = e_source_group_peek_base_uri (source->priv->group);
-
-	/* If last character in base URI is a slash, just concat the
-	 * strings.  We don't want to compress e.g. the trailing ://
-	 * in a protocol specification Note: Do not use
-	 * G_DIR_SEPARATOR or g_build_filename() when manipulating
-	 * URIs. URIs use normal ("forward") slashes also on Windows.
-	 */
-	if (*base_uri_str && *(base_uri_str + strlen (base_uri_str) - 1) == '/')
-		uri_str = g_strconcat (base_uri_str, source->priv->relative_uri, NULL);
-	else {
-		if (source->priv->relative_uri != NULL)
-			uri_str = g_strconcat (base_uri_str, g_str_equal (base_uri_str, "local:") ? "" : "/", source->priv->relative_uri,
-				       NULL);
-		else
-			uri_str = g_strdup (base_uri_str);
-	}
+	uid = e_source_get_uid (source);
 
-	return uri_str;
+	return g_str_hash (uid);
 }
 
-void
-e_source_set_group (ESource *source,
-		    ESourceGroup *group)
+/**
+ * e_source_equal:
+ * @source1: the first #ESource
+ * @source2: the second #ESource
+ *
+ * Checks two #ESource instances for equality.  #ESource instances are
+ * equal if their unique identifier strings are equal.
+ *
+ * Returns: %TRUE if @source1 and @source2 are equal
+ *
+ * Since: 2.92
+ **/
+gboolean
+e_source_equal (ESource *source1,
+                ESource *source2)
 {
-	g_return_if_fail (E_IS_SOURCE (source));
-	g_return_if_fail (group == NULL || E_IS_SOURCE_GROUP (group));
+	const gchar *uid1, *uid2;
 
-	if (source->priv->readonly)
-		return;
-
-	if (source->priv->group == group)
-		return;
+	g_return_val_if_fail (E_IS_SOURCE (source1), FALSE);
+	g_return_val_if_fail (E_IS_SOURCE (source2), FALSE);
 
-	if (source->priv->group != NULL)
-		g_object_weak_unref (G_OBJECT (source->priv->group), (GWeakNotify) group_weak_notify, source);
+	if (source1 == source2)
+		return TRUE;
 
-	source->priv->group = group;
-	if (group != NULL) {
-		g_object_weak_ref (G_OBJECT (group), (GWeakNotify) group_weak_notify, source);
-	}
+	uid1 = e_source_get_uid (source1);
+	uid2 = e_source_get_uid (source2);
 
-	g_signal_emit (source, signals[CHANGED], 0);
+	return g_str_equal (uid1, uid2);
 }
 
-void
-e_source_set_name (ESource *source,
-		   const gchar *name)
+/**
+ * e_source_sync:
+ * @source: an #ESource
+ * @error: return location for a #GError, or %NULL
+ *
+ * Creates or replaces a key file at the location pointed to by the
+ * ESource:file property.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ **/
+gboolean
+e_source_sync (ESource *source,
+               GError **error)
 {
-	g_return_if_fail (E_IS_SOURCE (source));
-	g_return_if_fail (name != NULL);
+	GKeyFile *key_file;
+	GHashTableIter iter;
+	gpointer extension;
+	gpointer group_name;
+	gboolean success;
+	gchar *contents;
+	gsize length;
+	GFile *file;
 
-	if (source->priv->readonly)
-		return;
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
 
-	if (source->priv->name != NULL &&
-	    strcmp (source->priv->name, name) == 0)
-		return;
+	file = e_source_get_file (source);
+	key_file = source->priv->key_file;
 
-	g_free (source->priv->name);
-	source->priv->name = g_strdup (name);
+	source_save_to_key_file (
+		G_OBJECT (source), key_file, E_SOURCE_GROUP_NAME);
 
-	g_signal_emit (source, signals[CHANGED], 0);
-}
+	g_hash_table_iter_init (&iter, source->priv->extensions);
+	while (g_hash_table_iter_next (&iter, &group_name, &extension))
+		source_save_to_key_file (extension, key_file, group_name);
 
-void
-e_source_set_relative_uri (ESource *source,
-			   const gchar *relative_uri)
-{
-	gchar *absolute_uri, *old_abs_uri = NULL;
+	contents = g_key_file_to_data (key_file, &length, NULL);
 
-	g_return_if_fail (E_IS_SOURCE (source));
+	success = g_file_replace_contents (
+		file, contents, length, NULL, FALSE,
+		G_FILE_CREATE_NONE, NULL, NULL, error);
 
-	if (source->priv->readonly)
-		return;
+	g_free (contents);
 
-	if (source->priv->relative_uri == relative_uri ||
-	    (source->priv->relative_uri && relative_uri && g_str_equal (source->priv->relative_uri, relative_uri)))
-		return;
+	return success;
+}
+
+/**
+ * e_source_reload:
+ * @source: an #ESource
+ * @error: return location for a #GError, or %NULL
+ *
+ * Reloads the key file for @source and updates all the extensions.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ **/
+gboolean
+e_source_reload (ESource *source,
+                 GError **error)
+{
+	GKeyFile *key_file;
+	GFile *file;
+	gchar *path;
+	gchar **groups;
+	gsize length, ii;
+	gboolean success;
 
-	if (source->priv->group)
-		old_abs_uri = e_source_build_absolute_uri (source);
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
 
-	g_free (source->priv->relative_uri);
-	source->priv->relative_uri = g_strdup (relative_uri);
+	file = e_source_get_file (source);
+	key_file = source->priv->key_file;
 
-	/* reset the absolute uri, if it's a generated one */
-	if (source->priv->absolute_uri &&
-	    (!old_abs_uri || g_str_equal (source->priv->absolute_uri, old_abs_uri)) &&
-	    (absolute_uri = e_source_build_absolute_uri (source))) {
-		g_free (source->priv->absolute_uri);
-		source->priv->absolute_uri = absolute_uri;
+	path = g_file_get_path (file);
+	if (path == NULL) {
+		g_set_error (
+			error, G_IO_ERROR,
+			G_IO_ERROR_INVALID_FILENAME,
+			_("Sources can only be loaded from native files"));
+		return FALSE;
 	}
 
-	g_free (old_abs_uri);
+	success = g_key_file_load_from_file (
+		key_file, path, G_KEY_FILE_KEEP_COMMENTS |
+		G_KEY_FILE_KEEP_TRANSLATIONS, error);
+
+	if (!success)
+		goto exit;
+
+	/* Make sure the key file has the main group. */
+	if (!g_key_file_has_group (key_file, E_SOURCE_GROUP_NAME)) {
+		g_set_error (
+			error, G_KEY_FILE_ERROR,
+			G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
+			_("Source file is missing a [%s] group"),
+			E_SOURCE_GROUP_NAME);
+		success = FALSE;
+		goto exit;
+	}
 
-	g_signal_emit (source, signals[CHANGED], 0);
-}
+	groups = g_key_file_get_groups (key_file, &length);
+	for (ii = 0; ii < length; ii++) {
+		GObject *object;
 
-void
-e_source_set_absolute_uri (ESource *source,
-			   const gchar *absolute_uri)
-{
-	g_return_if_fail (E_IS_SOURCE (source));
+		if (g_str_equal (groups[ii], E_SOURCE_GROUP_NAME))
+			object = G_OBJECT (source);
+		else
+			object = e_source_get_extension (source, groups[ii]);
 
-	if ((absolute_uri == source->priv->absolute_uri && absolute_uri == NULL)
-	    || (absolute_uri && source->priv->absolute_uri && !strcmp (source->priv->absolute_uri, absolute_uri)))
-		return;
+		/* Skip unrecognized groups. */
+		if (object == NULL)
+			continue;
 
-	g_free (source->priv->absolute_uri);
-	source->priv->absolute_uri = g_strdup (absolute_uri);
+		source_load_from_key_file (object, key_file, groups[ii]);
+	}
+	g_strfreev (groups);
 
-	g_signal_emit (source, signals[CHANGED], 0);
+exit:
+	g_free (path);
+
+	return success;
 }
 
+/**
+ * e_source_redirect:
+ * @source: an #ESource
+ * @directory: a native directory
+ *
+ * Redirects all future sync operations to @directory instead of the
+ * directory from which @source was originally loaded.  This is useful
+ * if @source was created from a read-only template key file but you
+ * want to allow for modifications.
+ **/
 void
-e_source_set_readonly (ESource  *source,
-		       gboolean  readonly)
+e_source_redirect (ESource *source,
+                   GFile *directory)
 {
+	GFile *file;
+	const gchar *uid;
+
 	g_return_if_fail (E_IS_SOURCE (source));
+	g_return_if_fail (G_IS_FILE (directory));
 
-	if (source->priv->readonly == readonly)
+	uid = e_source_get_uid (source);
+	file = g_file_get_child (directory, uid);
+
+	if (g_file_equal (file, source->priv->file)) {
+		g_object_unref (file);
 		return;
+	}
 
-	source->priv->readonly = readonly;
+	g_object_unref (source->priv->file);
+	source->priv->file = file;
 
-	g_signal_emit (source, signals[CHANGED], 0);
+	source_setup_file_monitor (source);
 
+	g_object_notify (G_OBJECT (source), "file");
 }
 
 /**
- * e_source_set_color_spec:
- * @source: an ESource
- * @color_spec: a string specifying the color
+ * e_source_changed:
+ * @source: an #ESource
  *
- * Store a textual representation of a color in @source.  The @color_spec
- * string should be parsable by #gdk_color_parse(), or %NULL to unset the
- * color in @source.
+ * Emits the #ESource::changed signal.
  *
- * Since: 1.10
+ * This function is primarily intended for use by #ESourceExtension
+ * when emitting a #GObject::notify signal on one of its properties.
+ *
+ * Since: 2.92
  **/
 void
-e_source_set_color_spec (ESource *source,
-			 const gchar *color_spec)
+e_source_changed (ESource *source)
 {
 	g_return_if_fail (E_IS_SOURCE (source));
 
-	if (!source->priv->readonly && set_color_spec (source, color_spec))
-		g_signal_emit (source, signals[CHANGED], 0);
-}
-
-ESourceGroup *
-e_source_peek_group (ESource *source)
-{
-	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
-
-	return source->priv->group;
+	g_signal_emit (source, signals[CHANGED], 0);
 }
 
+/**
+ * e_source_get_uid:
+ * @source: an #ESource
+ *
+ * Returns the unique identifier string for @source.
+ *
+ * Returns: the UID for @source
+ *
+ * Since: 2.92
+ **/
 const gchar *
-e_source_peek_uid (ESource *source)
+e_source_get_uid (ESource *source)
 {
 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
 	return source->priv->uid;
 }
 
-const gchar *
-e_source_peek_name (ESource *source)
-{
-	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
-
-	return source->priv->name;
-}
-
-const gchar *
-e_source_peek_relative_uri (ESource *source)
+/**
+ * e_source_get_file:
+ * @source: an #ESource
+ *
+ * Returns a #GFile referring to the on-disk key file for @source.
+ *
+ * Returns: the #GFile for @source
+ *
+ * Since: 2.92
+ **/
+GFile *
+e_source_get_file (ESource *source)
 {
 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	return source->priv->relative_uri;
+	return source->priv->file;
 }
 
-const gchar *
-e_source_peek_absolute_uri (ESource *source)
+/**
+ * e_source_get_node:
+ * @source: an #ESource
+ *
+ * Returns a #GNode representing the source's position within a hierarchy
+ * of sources.  The #GNode<!-- -->'s data value points back to @source.
+ *
+ * Often data such as the backend name must be fetched from a parent
+ * #ESource.  This is the mechanism for accessing a parent #ESource.
+ *
+ * Returns: the #GNode for @source
+ *
+ * Since: 2.92
+ **/
+GNode *
+e_source_get_node (ESource *source)
 {
 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	return source->priv->absolute_uri;
+	return &source->priv->node;
 }
 
 /**
- * e_source_peek_color_spec:
- * @source: an ESource
+ * e_source_get_parent:
+ * @source: an #ESource
  *
- * Return the textual representation of the color for @source, or %NULL if it
- * has none.  The returned string should be parsable by #gdk_color_parse().
+ * Returns the unique identifier string of the parent #ESource.
  *
- * Returns: a string specifying the color
+ * Returns: the UID of the parent #ESource
  *
- * Since: 1.10
+ * Since: 2.92
  **/
 const gchar *
-e_source_peek_color_spec (ESource *source)
+e_source_get_parent (ESource *source)
 {
 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	return source->priv->color_spec;
+	return source->priv->parent;
 }
 
-gboolean
-e_source_get_readonly (ESource *source)
-{
-	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
-
-	return source->priv->readonly;
-}
-
-gchar *
-e_source_get_uri (ESource *source)
+/**
+ * e_source_set_parent:
+ * @source: an #ESource
+ * @parent: the UID of the parent #ESource
+ *
+ * Identifies the parent of @source by its unique identifier string.
+ * This can only be set prior to adding @source to an #ESourceRegistry.
+ *
+ * Since: 2.92
+ **/
+void
+e_source_set_parent (ESource *source,
+                     const gchar *parent)
 {
-	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
-
-	if (source->priv->group == NULL) {
-		if (source->priv->absolute_uri != NULL)
-			return g_strdup (source->priv->absolute_uri);
+	GNode *node;
 
-		g_warning ("e_source_get_uri () called on source with no absolute URI!");
-		return NULL;
-	}
-	else if (source->priv->absolute_uri != NULL) /* source->priv->group != NULL */
-		return g_strdup (source->priv->absolute_uri);
-	else
-		return e_source_build_absolute_uri (source);
-}
-
-static void
-property_dump_cb (const xmlChar *key, const xmlChar *value, xmlNodePtr root)
-{
-	xmlNodePtr node;
+	g_return_if_fail (E_IS_SOURCE (source));
 
-	node = xmlNewChild (root, NULL, (xmlChar*)"property", NULL);
-	xmlSetProp (node, (xmlChar*)"name", key);
-	xmlSetProp (node, (xmlChar*)"value", value);
-}
+	node = e_source_get_node (source);
+	if (node->parent != NULL)
+		return;
 
-static xmlNodePtr
-dump_common_to_xml_node (ESource *source,
-			 xmlNodePtr parent_node)
-{
-	ESourcePrivate *priv;
-	xmlNodePtr node;
-	const gchar *abs_uri = NULL, *relative_uri = NULL;
-
-	priv = source->priv;
-
-	if (parent_node)
-		node = xmlNewChild (parent_node, NULL, (xmlChar*)"source", NULL);
-	else
-		node = xmlNewNode (NULL, (xmlChar*)"source");
-
-	xmlSetProp (node, (xmlChar*)"uid", (xmlChar*)e_source_peek_uid (source));
-	xmlSetProp (node, (xmlChar*)"name", (xmlChar*)e_source_peek_name (source));
-	abs_uri = e_source_peek_absolute_uri (source);
-	/* do not store absolute uris for local:system sources */
-	relative_uri = e_source_peek_relative_uri (source);
-	if (abs_uri && !(relative_uri && g_str_equal (relative_uri, "system") &&
-		    (g_str_has_prefix (abs_uri, "file:") || g_str_has_prefix (abs_uri, "local:"))))
-		xmlSetProp (node, (xmlChar*)"uri", (xmlChar*)abs_uri);
-	if (relative_uri)
-		xmlSetProp (node, (xmlChar*)"relative_uri", (xmlChar*)relative_uri);
-
-	if (priv->color_spec != NULL)
-		xmlSetProp (node, (xmlChar*)"color_spec", (xmlChar*)priv->color_spec);
-
-	if (g_hash_table_size (priv->properties) != 0) {
-		xmlNodePtr properties_node;
-
-		properties_node = xmlNewChild (node, NULL, (xmlChar*)"properties", NULL);
-		g_hash_table_foreach (priv->properties, (GHFunc) property_dump_cb, properties_node);
-	}
+	g_free (source->priv->parent);
+	source->priv->parent = g_strdup (parent);
 
-	return node;
+	g_object_notify (G_OBJECT (source), "parent");
 }
 
-void
-e_source_dump_to_xml_node (ESource *source,
-			   xmlNodePtr parent_node)
-{
-	g_return_if_fail (E_IS_SOURCE (source));
-
-	dump_common_to_xml_node (source, parent_node);
-}
-
-gchar *
-e_source_to_standalone_xml (ESource *source)
+/**
+ * e_source_get_extension:
+ * @source: an #ESource
+ * @name: an extension name
+ *
+ * Returns an instance of some #ESourceExtension subclass which registered
+ * itself under @name.  If no such instance exists within @source, one will
+ * be created.  It is the caller's responsibility to know which subclass is
+ * being returned.
+ *
+ * If you just want to test for the existence of an extension within @source
+ * without creating it, use e_source_has_extension().
+ *
+ * Extension instances are owned by their #ESource and should not be
+ * referenced directly.  Instead, reference the #ESource instance and
+ * use this function to fetch the extension instance as needed.
+ *
+ * Returns: an instance of some #ESourceExtension subclass
+ *
+ * Since: 2.92
+ **/
+gpointer
+e_source_get_extension (ESource *source,
+                        const gchar *name)
 {
-	xmlDocPtr doc;
-	xmlNodePtr node;
-	xmlChar *xml_buffer;
-	gchar *returned_buffer;
-	gint xml_buffer_size;
-	gchar *uri;
+	ESourceExtension *extension;
+	GHashTable *hash_table;
+	GTypeClass *class;
 
 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+	g_return_val_if_fail (name != NULL, NULL);
 
-	doc = xmlNewDoc ((xmlChar*)"1.0");
-	node = dump_common_to_xml_node (source, NULL);
-
-	xmlDocSetRootElement (doc, node);
-
-	uri = e_source_get_uri (source);
-	xmlSetProp (node, (xmlChar*)"uri", (xmlChar*)uri);
-	g_free (uri);
-
-	xmlDocDumpMemory (doc, &xml_buffer, &xml_buffer_size);
-	xmlFreeDoc (doc);
+	/* Check if we already have the extension. */
+	extension = g_hash_table_lookup (source->priv->extensions, name);
+	if (extension != NULL)
+		return extension;
+
+	/* Find all subclasses of ESourceExtensionClass. */
+	hash_table = source_find_extension_classes ();
+	class = g_hash_table_lookup (hash_table, name);
+
+	/* Create a new instance of the appropriate GType. */
+	if (class != NULL) {
+		extension = g_object_new (
+			G_TYPE_FROM_CLASS (class),
+			"source", source, NULL);
+		g_hash_table_insert (
+			source->priv->extensions,
+			g_strdup (name), extension);
+	} else {
+		/* XXX Tie this into a debug setting for ESources. */
+		g_critical (
+			"No registered GType for ESource "
+			"extension '%s'", name);
+	}
 
-	returned_buffer = g_malloc (xml_buffer_size + 1);
-	memcpy (returned_buffer, xml_buffer, xml_buffer_size);
-	returned_buffer[xml_buffer_size] = '\0';
-	xmlFree (xml_buffer);
+	g_hash_table_destroy (hash_table);
 
-	return returned_buffer;
+	return extension;
 }
 
 /**
- * e_source_equal:
- * @a: An ESource
- * @b: Another ESource
+ * e_source_has_extension:
+ * @source: an #ESource
+ * @name: an extension name
  *
- * Compares if @a is equivalent to @b.
+ * Checks whether @source has an #ESourceExtension with the given name.
  *
- * Returns: %TRUE if @a is equivalent to @b,
- * %FALSE otherwise.
+ * Returns: %TRUE if @source has such an extension, %FALSE if not
  *
- * Since: 2.24
+ * Since: 2.92
  **/
 gboolean
-e_source_equal (ESource *a, ESource *b)
+e_source_has_extension (ESource *source,
+                        const gchar *name)
 {
-	g_return_val_if_fail (E_IS_SOURCE (a), FALSE);
-	g_return_val_if_fail (E_IS_SOURCE (b), FALSE);
-
-	#define ONLY_ONE_NULL(aa, bb) (((aa) == NULL && (bb) != NULL) || ((aa) != NULL && (bb) == NULL))
-
-	/* Compare source stuff */
-	if (a->priv->uid
-	 && b->priv->uid
-	 && g_ascii_strcasecmp (a->priv->uid, b->priv->uid))
-		return FALSE;
-
-	if (a->priv->name
-	 && b->priv->name
-	 && g_ascii_strcasecmp (a->priv->name, b->priv->name))
-		return FALSE;
-
-	if (a->priv->relative_uri
-	 && b->priv->relative_uri
-	 && g_ascii_strcasecmp (a->priv->relative_uri, b->priv->relative_uri))
-		return FALSE;
+	ESourceExtension *extension;
 
-	if (a->priv->absolute_uri
-	 && b->priv->absolute_uri
-	 && g_ascii_strcasecmp (a->priv->absolute_uri, b->priv->absolute_uri))
-		return FALSE;
-
-	if ((a->priv->color_spec
-	 && b->priv->color_spec
-	 && g_ascii_strcasecmp (a->priv->color_spec, b->priv->color_spec)) ||
-	 (ONLY_ONE_NULL (a->priv->color_spec, b->priv->color_spec)))
-		return FALSE;
-
-	if (a->priv->readonly != b->priv->readonly)
-		return FALSE;
-
-	if (!compare_str_hashes (a->priv->properties, b->priv->properties))
-		return FALSE;
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+	g_return_val_if_fail (name != NULL, FALSE);
 
-	#undef ONLY_ONE_NULL
+	extension = g_hash_table_lookup (source->priv->extensions, name);
 
-	return TRUE;
+	return (extension != NULL);
 }
 
 /**
- * e_source_xmlstr_equal:
- * @a: XML representation of an ESource
- * @b: XML representation of another ESource
+ * e_source_get_backend_name:
+ * @source: an #ESource
  *
- * Compares if @a is equivalent to @b.
+ * Returns the backend name for @source.
  *
- * Returns: %TRUE if @a is equivalent to @b,
- * %FALSE otherwise.
+ * Returns: the backend name for @source
  *
- * Since: 2.24
+ * Since: 2.92
  **/
-gboolean
-e_source_xmlstr_equal (const gchar *a, const gchar *b)
+const gchar *
+e_source_get_backend_name (ESource *source)
 {
-	ESource *srca, *srcb;
-	gboolean retval;
-
-	srca = e_source_new_from_standalone_xml (a);
-	srcb = e_source_new_from_standalone_xml (b);
-
-	retval = e_source_equal (srca, srcb);
-
-	g_object_unref (srca);
-	g_object_unref (srcb);
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	return retval;
-}
+	/* Check the given ESource and its parents
+	 * until we find a non-empty backend string. */
 
-ESource *
-e_source_new_from_standalone_xml (const gchar *xml)
-{
-	xmlDocPtr doc;
-	xmlNodePtr root;
-	ESource *source;
+	while (E_IS_SOURCE (source)) {
+		GNode *node;
+		const gchar *backend_name;
 
-	doc = xmlParseDoc ((xmlChar*)xml);
-	if (doc == NULL)
-		return NULL;
+		backend_name = source->priv->backend_name;
+		if (backend_name != NULL && *backend_name != '\0')
+			return backend_name;
 
-	root = doc->children;
-	if (strcmp ((gchar *)root->name, "source") != 0)
-		return NULL;
-
-	source = e_source_new_from_xml_node (root);
-	xmlFreeDoc (doc);
+		node = e_source_get_node (source);
+		g_return_val_if_fail (node != NULL, NULL);
+		source = (node->parent != NULL) ? node->parent->data : NULL;
+	}
 
-	return source;
+	return NULL;
 }
 
-const gchar *
-e_source_get_property (ESource *source,
-		       const gchar *property)
+/**
+ * e_source_set_backend_name:
+ * @source: an #ESource
+ * @backend_name: a backend name
+ *
+ * Sets the backend name for @source.
+ *
+ * Since: 2.92
+ **/
+void
+e_source_set_backend_name (ESource *source,
+                           const gchar *backend_name)
 {
-	ESourcePrivate *priv;
+	g_return_if_fail (E_IS_SOURCE (source));
 
-	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
-	priv = source->priv;
+	g_free (source->priv->backend_name);
+	source->priv->backend_name = g_strdup (backend_name);
 
-	return g_hash_table_lookup (priv->properties, property);
+	g_object_notify (G_OBJECT (source), "backend-name");
 }
 
 /**
- * e_source_get_duped_property:
+ * e_source_get_display_name:
+ * @source: an #ESource
+ *
+ * Returns the display name for @source.  Use the display name to
+ * represent the #ESource in a user interface.
+ *
+ * Returns: the display name for @source
  *
- * Since: 1.12
+ * Since: 2.92
  **/
-gchar *
-e_source_get_duped_property (ESource *source, const gchar *property)
+const gchar *
+e_source_get_display_name (ESource *source)
 {
-	ESourcePrivate *priv;
-
 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
-	priv = source->priv;
-
-	return g_strdup (g_hash_table_lookup (priv->properties, property));
-}
 
-void
-e_source_set_property (ESource *source,
-		       const gchar *property,
-		       const gchar *value)
-{
-	ESourcePrivate *priv;
-
-	g_return_if_fail (E_IS_SOURCE (source));
-	priv = source->priv;
-
-	if (value)
-		g_hash_table_replace (priv->properties, g_strdup (property), g_strdup (value));
-	else
-		g_hash_table_remove (priv->properties, property);
-
-	g_signal_emit (source, signals[CHANGED], 0);
+	return source->priv->display_name;
 }
 
+/**
+ * e_source_set_display_name:
+ * @source: an #ESource
+ * @display_name: a display name
+ *
+ * Sets the display name for @source to a valid UTF-8 string.  Use the
+ * display name to represent the #ESource in a user interface.
+ *
+ * Since: 2.92
+ **/
 void
-e_source_foreach_property (ESource *source, GHFunc func, gpointer data)
+e_source_set_display_name (ESource *source,
+                           const gchar *display_name)
 {
-	ESourcePrivate *priv;
-
 	g_return_if_fail (E_IS_SOURCE (source));
-	priv = source->priv;
+	g_return_if_fail (display_name != NULL);
+	g_return_if_fail (g_utf8_validate (display_name, -1, NULL));
 
-	g_hash_table_foreach (priv->properties, func, data);
-}
+	g_free (source->priv->display_name);
+	source->priv->display_name = g_strdup (display_name);
 
-static void
-copy_property (const gchar *key, const gchar *value, ESource *new_source)
-{
-	e_source_set_property (new_source, key, value);
+	g_object_notify (G_OBJECT (source), "display-name");
 }
 
-ESource *
-e_source_copy (ESource *source)
+/**
+ * e_source_compare_by_display_name:
+ * @source1: the first #ESource
+ * @source2: the second #ESource
+ *
+ * Compares two #ESource instances by their display names.  Useful for
+ * ordering sources in a user interface.
+ *
+ * Returns: a negative value if @source1 compares before @source2, zero if
+ *          they compare equal, or a positive value if @source1 compares
+ *          after @source2
+ *
+ * Since: 2.92
+ **/
+gint
+e_source_compare_by_display_name (ESource *source1,
+                                  ESource *source2)
 {
-	ESource *new_source;
-
-	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+	const gchar *display_name1;
+	const gchar *display_name2;
 
-	new_source = g_object_new (e_source_get_type (), NULL);
-	new_source->priv->uid = g_strdup (e_source_peek_uid (source));
+	display_name1 = e_source_get_display_name (source1);
+	display_name2 = e_source_get_display_name (source2);
 
-	e_source_set_name (new_source, e_source_peek_name (source));
-
-	new_source->priv->color_spec = g_strdup (source->priv->color_spec);
-
-	new_source->priv->absolute_uri = g_strdup (e_source_peek_absolute_uri (source));
-
-	e_source_foreach_property (source, (GHFunc) copy_property, new_source);
-
-	return new_source;
+	return g_utf8_collate (display_name1, display_name2);
 }
-
diff --git a/libedataserver/e-source.h b/libedataserver/e-source.h
index ad68133..6f02335 100644
--- a/libedataserver/e-source.h
+++ b/libedataserver/e-source.h
@@ -1,117 +1,105 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* e-source.h
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+/*
+ * e-source.h
  *
  * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU Lesser General Public
- * License as published by the Free Software Foundation.
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
  *
  * This program 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.
+ * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
  *
- * Author: Ettore Perazzoli <ettore ximian com>
  */
 
-#ifndef _E_SOURCE_H_
-#define _E_SOURCE_H_
-
-#include <glib-object.h>
-#include <libxml/tree.h>
+#ifndef E_SOURCE_H
+#define E_SOURCE_H
+
+#include <gio/gio.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE \
+	(e_source_get_type ())
+#define E_SOURCE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE, ESource))
+#define E_SOURCE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE, ESourceClass))
+#define E_IS_SOURCE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE))
+#define E_IS_SOURCE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE))
+#define E_SOURCE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE, ESourceClass))
+
+/**
+ * E_SOURCE_PARAM_SETTING:
+ *
+ * Extends #GParamFlags to indicate the #GObject property is associated
+ * with a key file value.  Use this flag when installing #GObject properties
+ * in #ESourceExtension subclasses.
+ **/
+#define E_SOURCE_PARAM_SETTING (1 << G_PARAM_USER_SHIFT)
 
 G_BEGIN_DECLS
 
-#define E_TYPE_SOURCE			(e_source_get_type ())
-#define E_SOURCE(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_SOURCE, ESource))
-#define E_SOURCE_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_SOURCE, ESourceClass))
-#define E_IS_SOURCE(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_SOURCE))
-#define E_IS_SOURCE_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_SOURCE))
-
-typedef struct _ESource        ESource;
+typedef struct _ESource ESource;
+typedef struct _ESourceClass ESourceClass;
 typedef struct _ESourcePrivate ESourcePrivate;
-typedef struct _ESourceClass   ESourceClass;
-
-#include "e-source-group.h"
 
 struct _ESource {
 	GObject parent;
-
 	ESourcePrivate *priv;
 };
 
 struct _ESourceClass {
 	GObjectClass parent_class;
 
-	/* Signals.  */
-	void (* changed) (ESource *source);
+	/* Signals */
+	void		(*changed)		(ESource *source);
 };
 
-GType    e_source_get_type (void);
-
-ESource *e_source_new                (const gchar   *name,
-				      const gchar   *relative_uri);
-ESource *e_source_new_with_absolute_uri (const gchar   *name,
-					const gchar   *absolute_uri);
-ESource *e_source_new_from_xml_node  (xmlNodePtr    node);
-ESource *e_source_new_from_standalone_xml (const gchar *xml);
-
-ESource *e_source_copy (ESource *source);
-
-gboolean  e_source_update_from_xml_node  (ESource    *source,
-					  xmlNodePtr  node,
-					  gboolean   *changed_return);
-
-gchar *e_source_uid_from_xml_node  (xmlNodePtr node);
-
-void  e_source_set_group         (ESource      *source,
-				  ESourceGroup *group);
-void  e_source_set_name          (ESource      *source,
-				  const gchar   *name);
-void  e_source_set_relative_uri  (ESource      *source,
-				  const gchar   *relative_uri);
-void  e_source_set_absolute_uri  (ESource      *source,
-				  const gchar   *absolute_uri);
-void  e_source_set_color_spec    (ESource      *source,
-				  const gchar  *color_spec);
-void  e_source_set_readonly      (ESource      *source,
-				  gboolean      readonly);
-
-ESourceGroup *e_source_peek_group         (ESource *source);
-const gchar   *e_source_peek_uid           (ESource *source);
-const gchar   *e_source_peek_name          (ESource *source);
-const gchar   *e_source_peek_relative_uri  (ESource *source);
-const gchar   *e_source_peek_absolute_uri  (ESource *source);
-const gchar   *e_source_peek_color_spec    (ESource *source);
-gboolean      e_source_get_readonly       (ESource *source);
-
-gchar *e_source_get_uri  (ESource *source);
-
-void  e_source_dump_to_xml_node  (ESource    *source,
-				  xmlNodePtr  parent_node);
-gchar *e_source_to_standalone_xml (ESource *source);
-
-const gchar *e_source_get_property     (ESource *source,
-					const gchar *property);
-void         e_source_set_property     (ESource *source,
-					const gchar *property,
-					const gchar *value);
-void         e_source_foreach_property (ESource *source,
-					GHFunc func,
-					gpointer data);
-
-gchar *e_source_get_duped_property (ESource *source, const gchar *property);
-gchar *e_source_build_absolute_uri (ESource *source);
-
-gboolean e_source_equal (ESource *a, ESource *b);
-gboolean e_source_xmlstr_equal (const gchar *a, const gchar *b);
+GType		e_source_get_type		(void) G_GNUC_CONST;
+ESource *	e_source_new			(GFile *file,
+						 GError **error);
+guint		e_source_hash			(ESource *source);
+gboolean	e_source_equal			(ESource *source1,
+						 ESource *source2);
+gboolean	e_source_sync			(ESource *source,
+						 GError **error);
+gboolean	e_source_reload			(ESource *source,
+						 GError **error);
+void		e_source_changed		(ESource *source);
+void		e_source_redirect		(ESource *source,
+						 GFile *directory);
+const gchar *	e_source_get_uid		(ESource *source);
+GFile *		e_source_get_file		(ESource *source);
+GNode *		e_source_get_node		(ESource *source);
+const gchar *	e_source_get_parent		(ESource *source);
+void		e_source_set_parent		(ESource *source,
+						 const gchar *parent);
+gpointer	e_source_get_extension		(ESource *source,
+						 const gchar *extension_name);
+gboolean	e_source_has_extension		(ESource *source,
+						 const gchar *extension_name);
+const gchar *	e_source_get_backend_name	(ESource *source);
+void		e_source_set_backend_name	(ESource *source,
+						 const gchar *backend_name);
+const gchar *	e_source_get_display_name	(ESource *source);
+void		e_source_set_display_name	(ESource *source,
+						 const gchar *display_name);
+gint		e_source_compare_by_display_name
+						(ESource *source1,
+						 ESource *source2);
 
 G_END_DECLS
 
-#endif /* _E_SOURCE_H_ */
+#endif /* E_SOURCE_H */
diff --git a/libedataserver/e-system-source.c b/libedataserver/e-system-source.c
new file mode 100644
index 0000000..12a7d1a
--- /dev/null
+++ b/libedataserver/e-system-source.c
@@ -0,0 +1,117 @@
+/*
+ * e-system-source.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-system-source.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include "e-data-server-util.h"
+
+G_DEFINE_TYPE (
+	ESystemSource,
+	e_system_source,
+	E_TYPE_SOURCE)
+
+static void
+system_source_notify (GObject *object,
+                      GParamSpec *pspec)
+{
+	ESource *source = E_SOURCE (object);
+
+	/* GObject does not allow subclasses to override property flags,
+	 * so we'll keep the "backend-name" and "display-name" properties
+	 * fixed by intercepting attempts to change them and setting them
+	 * back to their proper values.  Hokey but works. */
+
+	if (g_strcmp0 (pspec->name, "backend-name") == 0) {
+		if (e_source_get_backend_name (source) != NULL) {
+			e_source_set_backend_name (source, NULL);
+			return;
+		}
+	}
+
+	if (g_strcmp0 (pspec->name, "display-name") == 0) {
+		const gchar *display_name;
+		const gchar *proper_value;
+
+		display_name = e_source_get_display_name (source);
+		proper_value = _("Personal");
+
+		if (g_strcmp0 (display_name, proper_value) != 0) {
+			e_source_set_display_name (source, proper_value);
+			return;
+		}
+	}
+
+	/* Chain up to parent's notify() method. */
+	G_OBJECT_CLASS (e_system_source_parent_class)->notify (object, pspec);
+}
+
+static void
+e_system_source_class_init (ESystemSourceClass *class)
+{
+	GObjectClass *object_class;
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->notify = system_source_notify;
+}
+
+static void
+e_system_source_init (ESystemSource *source)
+{
+}
+
+ESource *
+e_system_source_new (void)
+{
+	GSettings *settings;
+	ESource *source;
+	GFile *file;
+	const gchar *data_dir;
+	gchar *path;
+
+	data_dir = e_get_user_data_dir ();
+	path = g_build_filename (data_dir, "sources", "system", NULL);
+	file = g_file_new_for_path (path);
+	g_free (path);
+
+	/* This function must not fail, so if a "system" key file
+	 * exists and fails to load, delete it and try again. */
+	source = g_initable_new (
+		E_TYPE_SYSTEM_SOURCE, NULL, NULL, "file", file, NULL);
+	if (source == NULL) {
+		g_file_delete (file, NULL, NULL);
+		source = g_initable_new (
+			E_TYPE_SYSTEM_SOURCE, NULL, NULL, "file", file, NULL);
+	}
+
+	g_object_unref (file);
+
+	g_return_val_if_fail (E_IS_SYSTEM_SOURCE (source), NULL);
+
+	/* Set the "parent" key directly through its GSettings.
+	 *
+	 * XXX To set this during object construction we would have
+	 *     to override the GInitable interface.  Too much hassle
+	 *     for now.  Maybe revisit this in the future. */
+	settings = e_source_get_settings (source);
+	g_settings_set_string (settings, "parent", "local");
+
+	return source;
+}
diff --git a/libedataserver/e-system-source.h b/libedataserver/e-system-source.h
new file mode 100644
index 0000000..959a8f2
--- /dev/null
+++ b/libedataserver/e-system-source.h
@@ -0,0 +1,63 @@
+/*
+ * e-system-source.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SYSTEM_SOURCE_H
+#define E_SYSTEM_SOURCE_H
+
+#include <libedataserver/e-source.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SYSTEM_SOURCE \
+	(e_system_source_get_type ())
+#define E_SYSTEM_SOURCE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SYSTEM_SOURCE, ESystemSource))
+#define E_SYSTEM_SOURCE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SYSTEM_SOURCE, ESystemSourceClass))
+#define E_IS_SYSTEM_SOURCE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SYSTEM_SOURCE))
+#define E_IS_SYSTEM_SOURCE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SYSTEM_SOURCE))
+#define E_SYSTEM_SOURCE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE, ESystemSourceClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESystemSource ESystemSource;
+typedef struct _ESystemSourceClass ESystemSourceClass;
+typedef struct _ESystemSourcePrivate ESystemSourcePrivate;
+
+struct _ESystemSource {
+	ESource parent;
+	ESystemSourcePrivate *priv;
+};
+
+struct _ESystemSourceClass {
+	ESourceClass parent_class;
+};
+
+GType		e_system_source_get_type	(void) G_GNUC_CONST;
+ESource *	e_system_source_new		(void);
+
+G_END_DECLS
+
+#endif /* E_SYSTEM_SOURCE_H */
diff --git a/libedataserver/libedataserver.pc.in b/libedataserver/libedataserver.pc.in
index 9ee5be4..e81eba1 100644
--- a/libedataserver/libedataserver.pc.in
+++ b/libedataserver/libedataserver.pc.in
@@ -10,6 +10,6 @@ privincludedir= privincludedir@
 Name: libedataserver
 Description: Utility library for Evolution Data Server
 Version: @VERSION@
-Requires: gio-2.0 libxml-2.0 gconf-2.0 libsoup-2.4
+Requires: gio-2.0 gnome-keyring-1 libxml-2.0 gconf-2.0 libsoup-2.4
 Libs: -L${libdir} -ledataserver- API_VERSION@
 Cflags: -I${privincludedir}



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