[evolution-data-server/account-mgmt: 7/38] Add new ESource classes.



commit 19c066c9bff9ac90f01fda51357656dea0fc5229
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       |   40 +
 addressbook/libebook/e-source-address-book.h       |   83 +
 calendar/libecal/Makefile.am                       |    6 +-
 calendar/libecal/e-cal.c                           |    6 +
 calendar/libecal/e-source-calendar.c               |   78 +
 calendar/libecal/e-source-calendar.h               |  185 ++
 configure.ac                                       |    2 +-
 .../addressbook/libebook/libebook-docs.sgml        |    1 +
 .../addressbook/libebook/libebook-sections.txt     |   19 +
 docs/reference/addressbook/libebook/libebook.types |    2 +
 .../libebook/tmpl/e-source-address-book.sgml       |   35 +
 docs/reference/calendar/libecal/libecal-docs.sgml  |    3 +
 .../calendar/libecal/libecal-sections.txt          |  147 ++
 docs/reference/calendar/libecal/libecal.types      |    4 +
 .../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 +
 docs/reference/libedataserver/Makefile.am          |    2 +
 .../libedataserver/libedataserver-docs.sgml        |   46 +-
 .../libedataserver/libedataserver-sections.txt     |  627 +++++-
 docs/reference/libedataserver/libedataserver.types |   38 +
 .../libedataserverui/libedataserverui-sections.txt |    4 +-
 libedataserver/Makefile.am                         |   73 +-
 libedataserver/e-marshal.list                      |    1 +
 libedataserver/e-source-alarms.c                   |  259 +++
 libedataserver/e-source-alarms.h                   |   88 +
 libedataserver/e-source-authentication.c           |  573 +++++
 libedataserver/e-source-authentication.h           |  112 +
 libedataserver/e-source-authenticator.c            |  235 ++
 libedataserver/e-source-authenticator.h            |   91 +
 libedataserver/e-source-autocomplete.c             |  168 ++
 libedataserver/e-source-autocomplete.h             |   85 +
 libedataserver/e-source-enums.h                    |   62 +
 libedataserver/e-source-extension.c                |  301 +++
 libedataserver/e-source-extension.h                |   77 +
 libedataserver/e-source-mail-account.c             |  288 +++
 libedataserver/e-source-mail-account.h             |   94 +
 libedataserver/e-source-mail-composition.c         |  647 ++++++
 libedataserver/e-source-mail-composition.h         |  117 +
 libedataserver/e-source-mail-identity.c            |  504 ++++
 libedataserver/e-source-mail-identity.h            |  107 +
 libedataserver/e-source-mail-signature.c           |  721 ++++++
 libedataserver/e-source-mail-signature.h           |  112 +
 libedataserver/e-source-mail-submission.c          |  285 +++
 libedataserver/e-source-mail-submission.h          |   92 +
 libedataserver/e-source-mail-transport.c           |  130 ++
 libedataserver/e-source-mail-transport.h           |   80 +
 libedataserver/e-source-offline.c                  |  168 ++
 libedataserver/e-source-offline.h                  |   85 +
 libedataserver/e-source-openpgp.c                  |  453 ++++
 libedataserver/e-source-openpgp.h                  |  104 +
 libedataserver/e-source-password.c                 |  601 +++++
 libedataserver/e-source-password.h                 |   85 +
 libedataserver/e-source-refresh.c                  |  242 ++
 libedataserver/e-source-refresh.h                  |   88 +
 libedataserver/e-source-registry.c                 | 1647 +++++++++++++
 libedataserver/e-source-registry.h                 |  154 ++
 libedataserver/e-source-security.c                 |  276 +++
 libedataserver/e-source-security.h                 |   86 +
 libedataserver/e-source-selectable.c               |  321 +++
 libedataserver/e-source-selectable.h               |   81 +
 libedataserver/e-source-smime.c                    |  522 +++++
 libedataserver/e-source-smime.h                    |  111 +
 libedataserver/e-source-webdav.c                   |  667 ++++++
 libedataserver/e-source-webdav.h                   |   94 +
 libedataserver/e-source.c                          | 2418 +++++++++++++-------
 libedataserver/e-source.h                          |  159 +-
 libedataserver/e-system-source.c                   |  117 +
 libedataserver/e-system-source.h                   |   63 +
 libedataserver/libedataserver.pc.in                |    2 +-
 74 files changed, 14418 insertions(+), 939 deletions(-)
---
diff --git a/addressbook/libebook/Makefile.am b/addressbook/libebook/Makefile.am
index fce463e..b68d1be 100644
--- a/addressbook/libebook/Makefile.am
+++ b/addressbook/libebook/Makefile.am
@@ -34,7 +34,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
 
@@ -61,6 +62,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 98218fe..320e33e 100644
--- a/addressbook/libebook/e-book.c
+++ b/addressbook/libebook/e-book.c
@@ -44,6 +44,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"
 
@@ -259,6 +260,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..d1866d4
--- /dev/null
+++ b/addressbook/libebook/e-source-address-book.c
@@ -0,0 +1,40 @@
+/*
+ * 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
+e_source_address_book_class_init (ESourceAddressBookClass *class)
+{
+	ESourceExtensionClass *extension_class;
+
+	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..b3d8cb7
--- /dev/null
+++ b/addressbook/libebook/e-source-address-book.h
@@ -0,0 +1,83 @@
+/*
+ * 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))
+
+/**
+ * E_SOURCE_EXTENSION_ADDRESS_BOOK:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceAddressBook.  This is also used as a group name in key files.
+ *
+ * Since: 3.2
+ **/
+#define E_SOURCE_EXTENSION_ADDRESS_BOOK "Address Book"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceAddressBook ESourceAddressBook;
+typedef struct _ESourceAddressBookClass ESourceAddressBookClass;
+typedef struct _ESourceAddressBookPrivate ESourceAddressBookPrivate;
+
+/**
+ * ESourceAddressBook:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.2
+ **/
+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 de74a1e..bcf6a5a 100644
--- a/calendar/libecal/Makefile.am
+++ b/calendar/libecal/Makefile.am
@@ -34,7 +34,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 	\
@@ -58,7 +59,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 bef8cab..8e369fd 100644
--- a/calendar/libecal/e-cal.c
+++ b/calendar/libecal/e-cal.c
@@ -52,6 +52,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-cal.h"
 #include "e-gdbus-cal-view.h"
@@ -678,6 +679,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..786b4de
--- /dev/null
+++ b/calendar/libecal/e-source-calendar.c
@@ -0,0 +1,78 @@
+/*
+ * 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
+e_source_calendar_class_init (ESourceCalendarClass *class)
+{
+	ESourceExtensionClass *extension_class;
+
+	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)
+{
+	ESourceExtensionClass *extension_class;
+
+	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)
+{
+	ESourceExtensionClass *extension_class;
+
+	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..6d08596
--- /dev/null
+++ b/calendar/libecal/e-source-calendar.h
@@ -0,0 +1,185 @@
+/*
+ * 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))
+
+/**
+ * E_SOURCE_EXTENSION_CALENDAR:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceCalendar.  This is also used as a group name in key files.
+ *
+ * Since: 3.2
+ **/
+#define E_SOURCE_EXTENSION_CALENDAR  "Calendar"
+
+/**
+ * E_SOURCE_EXTENSION_MEMO_LIST:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceMemoList.  This is also used as a group name in key files.
+ *
+ * Since: 3.2
+ **/
+#define E_SOURCE_EXTENSION_MEMO_LIST "Memo List"
+
+/**
+ * E_SOURCE_EXTENSION_TASK_LIST:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceTaskList.  This is also used as a group name in key files.
+ *
+ * Since: 3.2
+ **/
+#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;
+
+/**
+ * ESourceCalendar:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.2
+ **/
+struct _ESourceCalendar {
+	ESourceSelectable parent;
+	ESourceCalendarPrivate *priv;
+};
+
+struct _ESourceCalendarClass {
+	ESourceSelectableClass parent_class;
+};
+
+/**
+ * ESourceMemoList:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.2
+ **/
+struct _ESourceMemoList {
+	ESourceSelectable parent;
+	ESourceMemoListPrivate *priv;
+};
+
+struct _ESourceMemoListClass {
+	ESourceSelectableClass parent_class;
+};
+
+/**
+ * ESourceTaskList:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.2
+ **/
+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 d27ef93..83bb7ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1285,7 +1285,7 @@ PKG_CHECK_MODULES(SQLITE3, [sqlite3 >= sqlite_minimum_version])
 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 2bf3555..613b8e2 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>
 
   <chapter>
diff --git a/docs/reference/addressbook/libebook/libebook-sections.txt b/docs/reference/addressbook/libebook/libebook-sections.txt
index 877f3ba..8395cc3 100644
--- a/docs/reference/addressbook/libebook/libebook-sections.txt
+++ b/docs/reference/addressbook/libebook/libebook-sections.txt
@@ -524,3 +524,22 @@ E_DESTINATION_GET_CLASS
 EDestinationClass
 e_destination_get_type
 </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 a52ebb9..d7bec67 100644
--- a/docs/reference/addressbook/libebook/libebook.types
+++ b/docs/reference/addressbook/libebook/libebook.types
@@ -5,6 +5,7 @@
 #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_client_get_type
@@ -13,3 +14,4 @@ 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-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/calendar/libecal/libecal-docs.sgml b/docs/reference/calendar/libecal/libecal-docs.sgml
index 0a22843..27f8b37 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>
 
   <chapter>
diff --git a/docs/reference/calendar/libecal/libecal-sections.txt b/docs/reference/calendar/libecal/libecal-sections.txt
index 110fc8c..d41a0e1 100644
--- a/docs/reference/calendar/libecal/libecal-sections.txt
+++ b/docs/reference/calendar/libecal/libecal-sections.txt
@@ -389,6 +389,92 @@ e_cal_component_get_type
 </SECTION>
 
 <SECTION>
+<FILE>e-cal</FILE>
+<TITLE>ECal</TITLE>
+ECal
+ECalSourceType
+ECalSetModeStatus
+ECalLoadState
+ECalAuthFunc
+e_cal_new
+e_cal_new_from_uri
+e_cal_new_system_calendar
+e_cal_new_system_tasks
+e_cal_new_system_memos
+e_cal_set_auth_func
+e_cal_open
+e_cal_open_async
+e_cal_refresh
+e_cal_remove
+e_cal_uri_list
+e_cal_get_source_type
+e_cal_get_load_state
+e_cal_get_source
+e_cal_get_uri
+e_cal_is_read_only
+e_cal_get_cal_address
+e_cal_get_alarm_email_address
+e_cal_get_ldap_attribute
+e_cal_get_one_alarm_only
+e_cal_get_organizer_must_attend
+e_cal_get_save_schedules
+e_cal_get_static_capability
+e_cal_get_organizer_must_accept
+e_cal_get_refresh_supported
+e_cal_set_mode
+e_cal_get_default_object
+e_cal_get_object
+e_cal_get_objects_for_uid
+e_cal_get_changes
+e_cal_free_change_list
+e_cal_get_object_list
+e_cal_get_object_list_as_comp
+e_cal_free_object_list
+e_cal_get_free_busy
+e_cal_generate_instances
+e_cal_generate_instances_for_object
+e_cal_get_alarms_in_range
+e_cal_free_alarms
+e_cal_get_alarms_for_object
+e_cal_create_object
+e_cal_modify_object
+e_cal_remove_object
+e_cal_remove_object_with_mod
+e_cal_discard_alarm
+e_cal_receive_objects
+e_cal_send_objects
+e_cal_get_timezone
+e_cal_add_timezone
+e_cal_set_default_timezone
+e_cal_get_query
+e_cal_resolve_tzid_cb
+e_cal_get_component_as_string
+e_cal_get_error_message
+e_cal_open_default
+e_cal_set_default
+e_cal_set_default_source
+e_cal_get_local_attachment_store
+e_cal_get_recurrences_no_master
+e_cal_get_attachments_for_comp
+<SUBSECTION Standard>
+E_CAL
+E_IS_CAL
+E_TYPE_CAL
+E_CAL_CLASS
+E_IS_CAL_CLASS
+E_TYPE_CAL_SOURCE_TYPE
+E_CAL_SET_MODE_STATUS_ENUM_TYPE
+CAL_MODE_ENUM_TYPE
+ECalClass
+<SUBSECTION Private>
+ECalPrivate
+e_cal_get_type
+e_cal_set_mode_status_enum_get_type
+e_cal_source_type_enum_get_type
+cal_mode_enum_get_type
+</SECTION>
+
+<SECTION>
 <FILE>e-cal-recur</FILE>
 ECalRecurInstanceFn
 ECalRecurResolveTimezoneFn
@@ -519,3 +605,64 @@ e_cal_view_get_type
 e_cal_view_new
 </SECTION>
 
+<SECTION>
+<FILE>e-cal-check-timezones</FILE>
+e_cal_check_timezones
+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 62b32cc..a1f72d9 100644
--- a/docs/reference/calendar/libecal/libecal.types
+++ b/docs/reference/calendar/libecal/libecal.types
@@ -3,9 +3,13 @@
 #include <libecal/e-cal-client-view.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_client_get_type
 e_cal_client_view_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-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/libedataserver/Makefile.am b/docs/reference/libedataserver/Makefile.am
index a93fce2..7a48782 100644
--- a/docs/reference/libedataserver/Makefile.am
+++ b/docs/reference/libedataserver/Makefile.am
@@ -16,8 +16,10 @@ CFILE_GLOB = $(top_srcdir)/libedataserver/*.c
 
 IGNORE_HFILES = 					\
 	e-client-private.h				\
+	e-marshal.h					\
 	e-gdbus-marshallers.h				\
 	e-gdbus-templates.h				\
+	e-source-enumtypes.h				\
 	libedataserver-private.h
 
 GTKDOC_CFLAGS  =					\
diff --git a/docs/reference/libedataserver/libedataserver-docs.sgml b/docs/reference/libedataserver/libedataserver-docs.sgml
index 2050a31..b3198f4 100644
--- a/docs/reference/libedataserver/libedataserver-docs.sgml
+++ b/docs/reference/libedataserver/libedataserver-docs.sgml
@@ -11,35 +11,29 @@
   <chapter>
     <title>Data Sources</title>
     <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-authenticator.xml"/>
+    <xi:include href="xml/e-source-password.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-mail-account.xml"/>
+    <xi:include href="xml/e-source-mail-composition.xml"/>
     <xi:include href="xml/e-source-mail-identity.xml"/>
+    <xi:include href="xml/e-source-mail-signature.xml"/>
+    <xi:include href="xml/e-source-mail-submission.xml"/>
+    <xi:include href="xml/e-source-mail-transport.xml"/>
     <xi:include href="xml/e-source-offline.xml"/>
+    <xi:include href="xml/e-source-openpgp.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-smime.xml"/>
     <xi:include href="xml/e-source-webdav.xml"/>
   </chapter>
 
   <chapter>
-    <title>Generated Types</title>
-    <xi:include href="xml/e-dbus-object.xml"/>
-    <xi:include href="xml/e-dbus-object-proxy.xml"/>
-    <xi:include href="xml/e-dbus-object-skeleton.xml"/>
-    <xi:include href="xml/e-dbus-source.xml"/>
-    <xi:include href="xml/e-dbus-source-proxy.xml"/>
-    <xi:include href="xml/e-dbus-source-skeleton.xml"/>
-    <xi:include href="xml/e-dbus-source-manager.xml"/>
-    <xi:include href="xml/e-dbus-source-manager-proxy.xml"/>
-    <xi:include href="xml/e-dbus-source-manager-skeleton.xml"/>
-    <xi:include href="xml/e-dbus-object-manager-client.xml"/>
-  </chapter>
-
-  <chapter>
     <title>Miscellaneous Utilities</title>
     <xi:include href="xml/e-categories.xml"/>
     <xi:include href="xml/e-client.xml"/>
@@ -53,7 +47,6 @@
     <xi:include href="xml/e-operation-pool.xml"/>
     <xi:include href="xml/e-proxy.xml"/>
     <xi:include href="xml/e-sexp.xml"/>
-    <xi:include href="xml/e-source.xml"/>
     <xi:include href="xml/e-time-utils.xml"/>
     <xi:include href="xml/e-uid.xml"/>
     <xi:include href="xml/e-util.xml"/>
@@ -62,6 +55,23 @@
     <xi:include href="xml/eds-version.xml"/>
   </chapter>
 
+  <chapter>
+    <title>Generated D-Bus Objects</title>
+    <xi:include href="xml/e-dbus-object.xml"/>
+    <xi:include href="xml/e-dbus-object-proxy.xml"/>
+    <xi:include href="xml/e-dbus-object-skeleton.xml"/>
+    <xi:include href="xml/e-dbus-source.xml"/>
+    <xi:include href="xml/e-dbus-source-proxy.xml"/>
+    <xi:include href="xml/e-dbus-source-skeleton.xml"/>
+    <xi:include href="xml/e-dbus-source-manager.xml"/>
+    <xi:include href="xml/e-dbus-source-manager-proxy.xml"/>
+    <xi:include href="xml/e-dbus-source-manager-skeleton.xml"/>
+    <xi:include href="xml/e-dbus-object-manager-client.xml"/>
+    <xi:include href="xml/e-dbus-authenticator.xml"/>
+    <xi:include href="xml/e-dbus-authenticator-proxy.xml"/>
+    <xi:include href="xml/e-dbus-authenticator-skeleton.xml"/>
+  </chapter>
+
   <index id="api-index-full">
     <title>Index</title>
     <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
@@ -70,6 +80,10 @@
     <title>Index of deprecated symbols</title>
     <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
   </index>
+  <index id="api-index-3.4" role="3.4">
+    <title>Index of new symbols in 3.4</title>
+    <xi:include href="xml/api-index-3.4.xml"><xi:fallback /></xi:include>
+  </index>
   <index id="api-index-3.2" role="3.2">
     <title>Index of new symbols in 3.2</title>
     <xi:include href="xml/api-index-3.2.xml"><xi:fallback /></xi:include>
diff --git a/docs/reference/libedataserver/libedataserver-sections.txt b/docs/reference/libedataserver/libedataserver-sections.txt
index 6c14767..1dd2733 100644
--- a/docs/reference/libedataserver/libedataserver-sections.txt
+++ b/docs/reference/libedataserver/libedataserver-sections.txt
@@ -190,6 +190,80 @@ e_dbus_authenticator_skeleton_get_type
 </SECTION>
 
 <SECTION>
+<FILE>e-dbus-authenticator</FILE>
+<TITLE>EDBusAuthenticator</TITLE>
+EDBusAuthenticator
+e_dbus_authenticator_call_ready_sync
+e_dbus_authenticator_call_ready
+e_dbus_authenticator_call_ready_finish
+e_dbus_authenticator_complete_ready
+e_dbus_authenticator_call_cancel_sync
+e_dbus_authenticator_call_cancel
+e_dbus_authenticator_call_cancel_finish
+e_dbus_authenticator_complete_cancel
+e_dbus_authenticator_call_secret_accepted_sync
+e_dbus_authenticator_call_secret_accepted
+e_dbus_authenticator_call_secret_accepted_finish
+e_dbus_authenticator_complete_secret_accepted
+e_dbus_authenticator_call_secret_rejected_sync
+e_dbus_authenticator_call_secret_rejected
+e_dbus_authenticator_call_secret_rejected_finish
+e_dbus_authenticator_complete_secret_rejected
+e_dbus_authenticator_emit_response
+e_dbus_authenticator_interface_info
+e_dbus_authenticator_override_properties
+<SUBSECTION Standard>
+E_DBUS_AUTHENTICATOR
+E_DBUS_IS_AUTHENTICATOR
+E_DBUS_TYPE_AUTHENTICATOR
+E_DBUS_AUTHENTICATOR_GET_IFACE
+EDBusAuthenticatorIface
+<SUBSECTION Private>
+e_dbus_authenticator_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-dbus-authenticator-proxy</FILE>
+<TITLE>EDBusAuthenticatorProxy</TITLE>
+EDBusAuthenticatorProxy
+e_dbus_authenticator_proxy_new_sync
+e_dbus_authenticator_proxy_new
+e_dbus_authenticator_proxy_new_finish
+e_dbus_authenticator_proxy_new_for_bus_sync
+e_dbus_authenticator_proxy_new_for_bus
+e_dbus_authenticator_proxy_new_for_bus_finish
+<SUBSECTION Standard>
+E_DBUS_AUTHENTICATOR_PROXY
+E_DBUS_IS_AUTHENTICATOR_PROXY
+E_DBUS_TYPE_AUTHENTICATOR_PROXY
+E_DBUS_AUTHENTICATOR_PROXY_CLASS
+E_DBUS_IS_AUTHENTICATOR_PROXY_CLASS
+E_DBUS_AUTHENTICATOR_PROXY_GET_CLASS
+EDBusAuthenticatorProxyClass
+<SUBSECTION Private>
+EDBusAuthenticatorProxyPrivate
+e_dbus_authenticator_proxy_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-dbus-authenticator-skeleton</FILE>
+<TITLE>EDBusAuthenticatorSkeleton</TITLE>
+EDBusAuthenticatorSkeleton
+e_dbus_authenticator_skeleton_new
+<SUBSECTION Standard>
+E_DBUS_AUTHENTICATOR_SKELETON
+E_DBUS_IS_AUTHENTICATOR_SKELETON
+E_DBUS_TYPE_AUTHENTICATOR_SKELETON
+E_DBUS_AUTHENTICATOR_SKELETON_CLASS
+E_DBUS_IS_AUTHENTICATOR_SKELETON_CLASS
+E_DBUS_AUTHENTICATOR_SKELETON_GET_CLASS
+EDBusAuthenticatorSkeletonClass
+<SUBSECTION Private>
+EDBusAuthenticatorSkeletonPrivate
+e_dbus_authenticator_skeleton_get_type
+</SECTION>
+
+<SECTION>
 <FILE>e-dbus-object</FILE>
 <TITLE>EDBusObject</TITLE>
 EDBusObject
@@ -282,6 +356,14 @@ e_dbus_source_call_submit_data_sync
 e_dbus_source_call_submit_data
 e_dbus_source_call_submit_data_finish
 e_dbus_source_complete_submit_data
+e_dbus_source_call_authenticate_sync
+e_dbus_source_call_authenticate
+e_dbus_source_call_authenticate_finish
+e_dbus_source_complete_authenticate
+e_dbus_source_call_reset_auth_dismissal_sync
+e_dbus_source_call_reset_auth_dismissal
+e_dbus_source_call_reset_auth_dismissal_finish
+e_dbus_source_complete_reset_auth_dismissal
 e_dbus_source_interface_info
 e_dbus_source_override_properties
 <SUBSECTION Standard>
@@ -347,8 +429,6 @@ e_dbus_source_skeleton_get_type
 <FILE>e-dbus-source-manager</FILE>
 <TITLE>EDBusSourceManager</TITLE>
 EDBusSourceManager
-e_dbus_source_manager_interface_info
-e_dbus_source_manager_override_properties
 e_dbus_source_manager_call_create_source_sync
 e_dbus_source_manager_call_create_source
 e_dbus_source_manager_call_create_source_finish
@@ -357,6 +437,8 @@ e_dbus_source_manager_call_remove_sources_sync
 e_dbus_source_manager_call_remove_sources
 e_dbus_source_manager_call_remove_sources_finish
 e_dbus_source_manager_complete_remove_sources
+e_dbus_source_manager_interface_info
+e_dbus_source_manager_override_properties
 <SUBSECTION Standard>
 E_DBUS_SOURCE_MANAGER
 E_DBUS_IS_SOURCE_MANAGER
@@ -529,35 +611,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_changed
+e_source_get_uid
+e_source_get_node
+e_source_get_parent
+e_source_set_parent
+e_source_get_enabled
+e_source_set_enabled
+e_source_get_extension
+e_source_has_extension
+e_source_get_dbus_object
+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
+e_source_to_string
+e_source_parameter_to_key
+e_source_authenticate_sync
+e_source_authenticate
+e_source_authenticate_finish
+e_source_submit_sync
+e_source_submit
+e_source_submit_finish
 <SUBSECTION Standard>
 E_SOURCE
 E_IS_SOURCE
@@ -572,6 +650,495 @@ 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-authenticator</FILE>
+<TITLE>ESourceAuthenticator</TITLE>
+ESourceAuthenticator
+ESourceAuthenticatorInterface
+ESourceAuthenticationResult
+e_source_authenticator_try_password_sync
+e_source_authenticator_try_password
+e_source_authenticator_try_password_finish
+<SUBSECTION Standard>
+E_SOURCE_AUTHENTICATOR
+E_IS_SOURCE_AUTHENTICATOR
+E_TYPE_SOURCE_AUTHENTICATOR
+E_SOURCE_AUTHENTICATOR_GET_INTERFACE
+<SUBSECTION Private>
+e_source_authenticator_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
+e_source_extension_resolve_reference
+<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-mail-account</FILE>
+<TITLE>ESourceMailAccount</TITLE>
+ESourceMailAccount
+E_SOURCE_EXTENSION_MAIL_ACCOUNT
+e_source_mail_account_get_identity
+e_source_mail_account_get_identity_uid
+e_source_mail_account_set_identity_uid
+EMdnRequestPolicy
+e_source_mail_account_get_mdn_request_policy
+e_source_mail_account_set_mdn_request_policy
+<SUBSECTION Standard>
+E_SOURCE_MAIL_ACCOUNT
+E_IS_SOURCE_MAIL_ACCOUNT
+E_TYPE_SOURCE_MAIL_ACCOUNT
+E_SOURCE_MAIL_ACCOUNT_CLASS
+E_IS_SOURCE_MAIL_ACCOUNT_CLASS
+E_SOURCE_MAIL_ACCOUNT_GET_CLASS
+ESourceMailAccountClass
+<SUBSECTION Private>
+ESourceMailAccountPrivate
+e_source_mail_account_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-mail-composition</FILE>
+<TITLE>ESourceMailComposition</TITLE>
+ESourceMailComposition
+E_SOURCE_EXTENSION_MAIL_COMPOSITION
+e_source_mail_composition_get_bcc
+e_source_mail_composition_set_bcc
+e_source_mail_composition_get_cc
+e_source_mail_composition_set_cc
+e_source_mail_composition_get_drafts_folder
+e_source_mail_composition_set_drafts_folder
+e_source_mail_composition_get_sign_imip
+e_source_mail_composition_set_sign_imip
+e_source_mail_composition_get_smime_encrypt
+e_source_mail_composition_set_smime_encrypt
+e_source_mail_composition_get_smime_sign
+e_source_mail_composition_set_smime_sign
+e_source_mail_composition_get_templates_folder
+e_source_mail_composition_set_templates_folder
+<SUBSECTION Standard>
+E_SOURCE_MAIL_COMPOSITION
+E_IS_SOURCE_MAIL_COMPOSITION
+E_TYPE_SOURCE_MAIL_COMPOSITION
+E_SOURCE_MAIL_COMPOSITION_CLASS
+E_IS_SOURCE_MAIL_COMPOSITION_CLASS
+E_SOURCE_MAIL_COMPOSITION_GET_CLASS
+ESourceMailCompositionClass
+<SUBSECTION Private>
+ESourceMailCompositionPrivate
+e_source_mail_composition_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-mail-signature</FILE>
+<TITLE>ESourceMailSignature</TITLE>
+ESourceMailSignature
+E_SOURCE_EXTENSION_MAIL_SIGNATURE
+e_source_mail_signature_get_file
+e_source_mail_signature_get_mime_type
+e_source_mail_signature_set_mime_type
+e_source_mail_signature_load
+e_source_mail_signature_load_finish
+e_source_mail_signature_replace
+e_source_mail_signature_replace_finish
+<SUBSECTION Standard>
+E_SOURCE_MAIL_SIGNATURE
+E_IS_SOURCE_MAIL_SIGNATURE
+E_TYPE_SOURCE_MAIL_SIGNATURE
+E_SOURCE_MAIL_SIGNATURE_CLASS
+E_IS_SOURCE_MAIL_SIGNATURE_CLASS
+E_SOURCE_MAIL_SIGNATURE_GET_CLASS
+ESourceMailSignatureClass
+<SUBSECTION Private>
+ESourceMailSignaturePrivate
+e_source_mail_signature_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-mail-identity</FILE>
+<TITLE>ESourceMailIdentity</TITLE>
+ESourceMailIdentity
+E_SOURCE_EXTENSION_MAIL_IDENTITY
+e_source_mail_identity_get_address
+e_source_mail_identity_set_address
+e_source_mail_identity_get_name
+e_source_mail_identity_set_name
+e_source_mail_identity_get_organization
+e_source_mail_identity_set_organization
+e_source_mail_identity_get_reply_to
+e_source_mail_identity_set_reply_to
+e_source_mail_identity_get_signature
+e_source_mail_identity_get_signature_uid
+e_source_mail_identity_set_signature_uid
+<SUBSECTION Standard>
+E_SOURCE_MAIL_IDENTITY
+E_IS_SOURCE_MAIL_IDENTITY
+E_TYPE_SOURCE_MAIL_IDENTITY
+E_SOURCE_MAIL_IDENTITY_CLASS
+E_IS_SOURCE_MAIL_IDENTITY_CLASS
+E_SOURCE_MAIL_IDENTITY_GET_CLASS
+ESourceMailIdentityClass
+<SUBSECTION Private>
+ESourceMailIdentityPrivate
+e_source_mail_identity_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-mail-submission</FILE>
+<TITLE>ESourceMailSubmission</TITLE>
+ESourceMailSubmission
+E_SOURCE_EXTENSION_MAIL_SUBMISSION
+e_source_mail_submission_get_sent_folder
+e_source_mail_submission_set_sent_folder
+e_source_mail_submission_get_transport
+e_source_mail_submission_get_transport_uid
+e_source_mail_submission_set_transport_uid
+<SUBSECTION Standard>
+E_SOURCE_MAIL_SUBMISSION
+E_IS_SOURCE_MAIL_SUBMISSION
+E_TYPE_SOURCE_MAIL_SUBMISSION
+E_SOURCE_MAIL_SUBMISSION_CLASS
+E_IS_SOURCE_MAIL_SUBMISSION_CLASS
+E_SOURCE_MAIL_SUBMISSION_GET_CLASS
+ESourceMailSubmissionClass
+<SUBSECTION Private>
+ESourceMailSubmissionPrivate
+e_source_mail_submission_get_type
+</SECTION>
+
+<SECTION>
+<FILE>e-source-mail-transport</FILE>
+<TITLE>ESourceMailTransport</TITLE>
+ESourceMailTransport
+E_SOURCE_EXTENSION_MAIL_TRANSPORT
+<SUBSECTION Standard>
+E_SOURCE_MAIL_TRANSPORT
+E_IS_SOURCE_MAIL_TRANSPORT
+E_TYPE_SOURCE_MAIL_TRANSPORT
+E_SOURCE_MAIL_TRANSPORT_CLASS
+E_IS_SOURCE_MAIL_TRANSPORT_CLASS
+E_SOURCE_MAIL_TRANSPORT_GET_CLASS
+ESourceMailSubmissionClass
+<SUBSECTION Private>
+ESourceMailTransportPrivate
+e_source_mail_transport_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-openpgp</FILE>
+<TITLE>ESourceOpenPGP</TITLE>
+ESourceOpenPGP
+E_SOURCE_EXTENSION_OPENPGP
+e_source_openpgp_get_always_trust
+e_source_openpgp_set_always_trust
+e_source_openpgp_get_encrypt_to_self
+e_source_openpgp_set_encrypt_to_self
+e_source_openpgp_get_key_id
+e_source_openpgp_set_key_id
+e_source_openpgp_get_signing_algorithm
+e_source_openpgp_set_signing_algorithm
+e_source_openpgp_get_sign_by_default
+e_source_openpgp_set_sign_by_default
+<SUBSECTION Standard>
+E_SOURCE_OPENPGP
+E_IS_SOURCE_OPENPGP
+E_TYPE_SOURCE_OPENPGP
+E_SOURCE_OPENPGP_CLASS
+E_IS_SOURCE_OPENPGP_CLASS
+E_SOURCE_OPENPGP_GET_CLASS
+ESourceOpenPGPClass
+<SUBSECTION Private>
+ESourceOpenPGPPrivate
+e_source_openpgp_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_enabled
+e_source_refresh_set_enabled
+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_new_sync
+e_source_registry_new
+e_source_registry_new_finish
+e_source_registry_create_source_sync
+e_source_registry_create_source
+e_source_registry_create_source_finish
+e_source_registry_remove_source_sync
+e_source_registry_remove_source
+e_source_registry_remove_source_finish
+e_source_registry_lookup_by_uid
+e_source_registry_list_sources
+e_source_registry_build_display_tree
+e_source_registry_debug_dump
+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_mail_account
+e_source_registry_set_default_mail_account
+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-smime</FILE>
+<TITLE>ESourceSMIME</TITLE>
+ESourceSMIME
+E_SOURCE_EXTENSION_SMIME
+e_source_smime_get_encryption_certificate
+e_source_smime_set_encryption_certificate
+e_source_smime_get_encrypt_by_default
+e_source_smime_set_encrypt_by_default
+e_source_smime_get_encrypt_to_self
+e_source_smime_set_encrypt_to_self
+e_source_smime_get_signing_algorithm
+e_source_smime_set_signing_algorithm
+e_source_smime_get_signing_certificate
+e_source_smime_set_signing_certificate
+e_source_smime_get_sign_by_default
+e_source_smime_set_sign_by_default
+<SUBSECTION Standard>
+E_SOURCE_SMIME
+E_IS_SOURCE_SMIME
+E_TYPE_SOURCE_SMIME
+E_SOURCE_SMIME_CLASS
+E_IS_SOURCE_SMIME_CLASS
+E_SOURCE_SMIME_GET_CLASS
+ESourceSMIMEClass
+<SUBSECTION Private>
+ESourceSMIMEPrivate
+e_source_smime_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 d4678e5..d5cd147 100644
--- a/docs/reference/libedataserver/libedataserver.types
+++ b/docs/reference/libedataserver/libedataserver.types
@@ -4,9 +4,27 @@
 #include <libedataserver/e-list-iterator.h>
 #include <libedataserver/e-proxy.h>
 #include <libedataserver/e-source.h>
+#include <libedataserver/e-source-authentication.h>
+#include <libedataserver/e-source-authenticator.h>
+#include <libedataserver/e-source-extension.h>
+#include <libedataserver/e-source-mail-account.h>
+#include <libedataserver/e-source-mail-composition.h>
+#include <libedataserver/e-source-mail-identity.h>
+#include <libedataserver/e-source-mail-signature.h>
+#include <libedataserver/e-source-mail-submission.h>
+#include <libedataserver/e-source-mail-transport.h>
+#include <libedataserver/e-source-offline.h>
+#include <libedataserver/e-source-openpgp.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>
+#include <libedataserver/e-source-smime.h>
+#include <libedataserver/e-source-webdav.h>
 
 #include <libedataserver/e-dbus-source.h>
 #include <libedataserver/e-dbus-source-manager.h>
+#include <libedataserver/e-dbus-authenticator.h>
 
 e_client_get_type
 e_iterator_get_type
@@ -14,6 +32,23 @@ e_list_get_type
 e_list_iterator_get_type
 e_proxy_get_type
 e_source_get_type
+e_source_authentication_get_type
+e_source_authenticator_get_type
+e_source_extension_get_type
+e_source_mail_account_get_type
+e_source_mail_composition_get_type
+e_source_mail_identity_get_type
+e_source_mail_signature_get_type
+e_source_mail_submission_get_type
+e_source_mail_transport_get_type
+e_source_offline_get_type
+e_source_openpgp_get_type
+e_source_refresh_get_type
+e_source_registry_get_type
+e_source_security_get_type
+e_source_selectable_get_type
+e_source_smime_get_type
+e_source_webdav_get_type
 
 e_dbus_object_get_type
 e_dbus_object_proxy_get_type
@@ -25,3 +60,6 @@ e_dbus_source_skeleton_get_type
 e_dbus_source_manager_get_type
 e_dbus_source_manager_proxy_get_type
 e_dbus_source_manager_skeleton_get_type
+e_dbus_authenticator_get_type
+e_dbus_authenticator_proxy_get_type
+e_dbus_authenticator_skeleton_get_type
diff --git a/docs/reference/libedataserverui/libedataserverui-sections.txt b/docs/reference/libedataserverui/libedataserverui-sections.txt
index af8675c..cbd1a43 100644
--- a/docs/reference/libedataserverui/libedataserverui-sections.txt
+++ b/docs/reference/libedataserverui/libedataserverui-sections.txt
@@ -394,7 +394,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
@@ -407,7 +408,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 e782542..a58b43e 100644
--- a/libedataserver/Makefile.am
+++ b/libedataserver/Makefile.am
@@ -1,5 +1,16 @@
+include $(top_srcdir)/glib-gen.mak
+glib_enum_headers=e-source-enums.h
+glib_enum_define=E
+glib_enum_prefix=e
+
+ENUM_GENERATED = e-source-enumtypes.h e-source-enumtypes.c
+
 # The marshallers
-MARSHAL_GENERATED = e-gdbus-marshallers.c e-gdbus-marshallers.h
+MARSHAL_GENERATED = \
+	e-gdbus-marshallers.c \
+	e-gdbus-marshallers.h \
+	e-marshal.c \
+	e-marshal.h
 @EVO_MARSHAL_RULE@
 
 $(GENERATED_DBUS_SOURCE) : Makefile.am org.gnome.evolution.dataserver.Source.xml
@@ -7,7 +18,7 @@ $(GENERATED_DBUS_SOURCE) : Makefile.am org.gnome.evolution.dataserver.Source.xml
 		--interface-prefix org.gnome.evolution.dataserver.	\
 		--c-namespace E_DBus					\
 		--c-generate-object-manager				\
-		--generate-c-code e-dbus-source			\
+		--generate-c-code e-dbus-source				\
 		org.gnome.evolution.dataserver.Source.xml
 
 $(GENERATED_DBUS_SOURCE_MANAGER) : Makefile.am org.gnome.evolution.dataserver.SourceManager.xml
@@ -17,6 +28,13 @@ $(GENERATED_DBUS_SOURCE_MANAGER) : Makefile.am org.gnome.evolution.dataserver.So
 		--generate-c-code e-dbus-source-manager			\
 		org.gnome.evolution.dataserver.SourceManager.xml
 
+$(GENERATED_DBUS_AUTHENTICATOR) : Makefile.am org.gnome.evolution.dataserver.Authenticator.xml
+	$(AM_V_GEN) gdbus-codegen					\
+		--interface-prefix org.gnome.evolution.dataserver	\
+		--c-namespace E_DBus					\
+		--generate-c-code e-dbus-authenticator			\
+		org.gnome.evolution.dataserver.Authenticator.xml
+
 GENERATED_DBUS_SOURCE = \
 	e-dbus-source.c \
 	e-dbus-source.h
@@ -25,11 +43,16 @@ GENERATED_DBUS_SOURCE_MANAGER = \
 	e-dbus-source-manager.c \
 	e-dbus-source-manager.h
 
+GENERATED_DBUS_AUTHENTICATOR = \
+	e-dbus-authenticator.c \
+	e-dbus-authenticator.h
+
 BUILT_SOURCES = \
 	$(ENUM_GENERATED) \
 	$(MARSHAL_GENERATED) \
 	$(GENERATED_DBUS_SOURCE) \
-	$(GENERATED_DBUS_SOURCE_MANAGER)
+	$(GENERATED_DBUS_SOURCE_MANAGER) \
+	$(GENERATED_DBUS_AUTHENTICATOR)
 
 lib_LTLIBRARIES = libedataserver-1.2.la
 
@@ -41,6 +64,7 @@ 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)						\
@@ -63,6 +87,26 @@ libedataserver_1_2_la_SOURCES =		\
 	e-proxy.c			\
 	e-sexp.c			\
 	e-source.c			\
+	e-source-extension.c		\
+	e-source-alarms.c		\
+	e-source-authentication.c	\
+	e-source-authenticator.c	\
+	e-source-autocomplete.c		\
+	e-source-mail-account.c		\
+	e-source-mail-composition.c	\
+	e-source-mail-identity.c	\
+	e-source-mail-signature.c	\
+	e-source-mail-submission.c	\
+	e-source-mail-transport.c	\
+	e-source-offline.c		\
+	e-source-openpgp.c		\
+	e-source-password.c		\
+	e-source-refresh.c		\
+	e-source-registry.c		\
+	e-source-security.c		\
+	e-source-selectable.c		\
+	e-source-smime.c		\
+	e-source-webdav.c		\
 	e-debug-log.c			\
 	e-time-utils.c			\
 	e-uid.c				\
@@ -90,6 +134,7 @@ libedataserverinclude_HEADERS =		\
 	e-categories.h			\
 	e-client.h			\
 	e-credentials.h			\
+	e-dbus-authenticator.h		\
 	e-dbus-source.h			\
 	e-dbus-source-manager.h		\
 	e-flag.h			\
@@ -103,6 +148,28 @@ libedataserverinclude_HEADERS =		\
 	e-proxy.h			\
 	e-sexp.h			\
 	e-source.h			\
+	e-source-alarms.h		\
+	e-source-authentication.h	\
+	e-source-authenticator.h	\
+	e-source-autocomplete.h		\
+	e-source-enums.h		\
+	e-source-enumtypes.h		\
+	e-source-extension.h		\
+	e-source-mail-account.h		\
+	e-source-mail-composition.h	\
+	e-source-mail-identity.h	\
+	e-source-mail-signature.h	\
+	e-source-mail-submission.h	\
+	e-source-mail-transport.h	\
+	e-source-offline.h		\
+	e-source-openpgp.h		\
+	e-source-password.h		\
+	e-source-refresh.h		\
+	e-source-registry.h		\
+	e-source-security.h		\
+	e-source-selectable.h		\
+	e-source-smime.h		\
+	e-source-webdav.h		\
 	e-debug-log.h			\
 	e-time-utils.h			\
 	e-uid.h				\
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..d0f4ad8
--- /dev/null
+++ b/libedataserver/e-source-alarms.c
@@ -0,0 +1,259 @@
+/*
+ * 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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-alarms
+ * @include: libedataserver/e-source-alarms.h
+ * @short_description: #ESource extension for alarm state
+ *
+ * The #ESourceAlarms extension tracks alarm state for a calendar.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-alarms.h>
+ *
+ *   ESourceAlarms *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_ALARMS);
+ * ]|
+ **/
+
+#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);
+}
+
+/**
+ * e_source_alarms_get_include_me:
+ * @extension: an #ESourceAlarms
+ *
+ * Returns whether the user should be alerted about upcoming appointments
+ * in the calendar described by the #ESource to which @extension belongs.
+ *
+ * Alarm daemons such as evolution-alarm-notify can use this property to
+ * decide which calendars to query for upcoming appointments.
+ *
+ * Returns: whether to show alarms for upcoming appointments
+ *
+ * Since: 3.4
+ **/
+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;
+}
+
+/**
+ * e_source_alarms_set_include_me:
+ * @extension: an #ESourceAlarms
+ * @include_me: whether to show alarms for upcoming appointments
+ *
+ * Sets whether the user should be alerted about upcoming appointments in
+ * the calendar described by the #ESource to which @extension belongs.
+ *
+ * Alarm daemons such as evolution-alarm-notify can use this property to
+ * decide which calendars to query for upcoming appointments.
+ *
+ * Since: 3.4
+ **/
+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");
+}
+
+/**
+ * e_source_alarms_get_last_notified:
+ * @extension: an #ESourceAlarms
+ *
+ * Returns an ISO 8601 formatted timestamp of when the user was last
+ * alerted about an upcoming appointment in the calendar described by
+ * the #ESource to which @extension belongs.  If no valid timestamp
+ * has been set, the function will return %NULL.
+ *
+ * Returns: an ISO 8601 timestamp, or %NULL
+ *
+ * Since: 3.4
+ **/
+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;
+}
+
+/**
+ * e_source_alarms_set_last_notified:
+ * @extension: an #ESourceAlarms
+ * @last_notified: an ISO 8601 timestamp, or %NULL
+ *
+ * Sets an ISO 8601 formatted timestamp of when the user was last
+ * alerted about an upcoming appointment in the calendar described
+ * by the #ESource to which @extension belongs.
+ *
+ * If @last_notified is non-%NULL, the function will validate the
+ * timestamp before setting the #ESourceAlarms:last-notified property.
+ * Invalid timestamps are discarded with a runtime warning.
+ *
+ * Generally, this function should only be called by an alarm daemon
+ * such as evolution-alarm-notify.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_alarms_set_last_notified (ESourceAlarms *extension,
+                                   const gchar *last_notified)
+{
+	g_return_if_fail (E_IS_SOURCE_ALARMS (extension));
+
+	if (last_notified != NULL) {
+		GTimeVal time_val;
+
+		if (!g_time_val_from_iso8601 (last_notified, &time_val)) {
+			g_warning ("Invalid timestamp: %s", last_notified);
+			return;
+		}
+	}
+
+	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..e109b4c
--- /dev/null
+++ b/libedataserver/e-source-alarms.h
@@ -0,0 +1,88 @@
+/*
+ * 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))
+
+/**
+ * E_SOURCE_EXTENSION_ALARMS:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceAlarms.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_ALARMS "Alarms"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceAlarms ESourceAlarms;
+typedef struct _ESourceAlarmsClass ESourceAlarmsClass;
+typedef struct _ESourceAlarmsPrivate ESourceAlarmsPrivate;
+
+/**
+ * ESourceAlarms:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+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..fa429f6
--- /dev/null
+++ b/libedataserver/e-source-authentication.c
@@ -0,0 +1,573 @@
+/*
+ * 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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-authentication
+ * @include: libedataserver/e-source-authentication.h
+ * @short_description: #ESource extension for authentication settings
+ *
+ * The #ESourceAuthentication extension tracks authentication settings
+ * for a user account on a remote server.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-authentication.h>
+ *
+ *   ESourceAuthentication *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
+ * ]|
+ **/
+
+#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);
+}
+
+/**
+ * e_source_authentication_required:
+ * @extension: an #ESourceAuthentication
+ *
+ * This is a convenience function which returns whether authentication
+ * is required at all, regardless of the method used.  This relies on
+ * the convention of setting #ESourceAuthentication:method to "none"
+ * when authentication is <emphasis>not</emphasis> required.
+ *
+ * Returns: whether authentication is required at all
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_authentication_required (ESourceAuthentication *extension)
+{
+	const gchar *method;
+
+	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);
+}
+
+/**
+ * e_source_authentication_get_domain:
+ * @extension: an #ESourceAuthentication
+ *
+ * Returns the domain name used to authenticate to a remote account.  This
+ * refers to backend-specific network domains such as Windows domains, not
+ * Internet domains.  Most backends will probably leave this empty.
+ *
+ * Returns: the backend-specific domain of a remote account
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_authentication_get_domain (ESourceAuthentication *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
+
+	return extension->priv->domain;
+}
+
+/**
+ * e_source_authentication_set_domain:
+ * @extension: an #ESourceAuthentication
+ * @domain: a backend-specific domain, or %NULL
+ *
+ * Sets the domain name used to authenticate to a remote account.  This
+ * referes to backend-specific network domains such as Windows domains,
+ * not Internet domains.  Most backends will probably leave this empty.
+ *
+ * Since: 3.4.
+ **/
+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");
+}
+
+/**
+ * e_source_authentication_get_host:
+ * @extension: an #ESourceAuthentication
+ *
+ * Returns the host name used to authenticate to a remote account.
+ *
+ * Returns: the host name of a remote account
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_authentication_get_host (ESourceAuthentication *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
+
+	return extension->priv->host;
+}
+
+/**
+ * e_source_authentication_set_host:
+ * @extension: an #ESourceAuthentication
+ * @host: a host name, or %NULL
+ *
+ * Sets the host name used to authenticate to a remote account.  The
+ * #ESourceAuthentication:host property is automatically stripped of
+ * leading and trailing whitespace.
+ *
+ * Since: 3.4
+ **/
+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);
+
+	/* Strip leading and trailing whitespace. */
+	if (extension->priv->host != NULL)
+		g_strstrip (extension->priv->host);
+
+	g_object_notify (G_OBJECT (extension), "host");
+}
+
+/**
+ * e_source_authentication_get_method:
+ * @extension: an #ESourceAuthentication
+ *
+ * Returns the authentication method for a remote account.  There are
+ * no pre-defined method names; backends are free to set this however
+ * they wish.  If authentication is not required for a remote account,
+ * the convention is to set #ESourceAuthentication:method to "none".
+ *
+ * Returns: the authentication method for a remote account
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_authentication_get_method (ESourceAuthentication *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
+
+	return extension->priv->method;
+}
+
+/**
+ * e_source_authentication_set_method:
+ * @extension: an #ESourceAuthentication
+ * @method: authentication method, or %NULL
+ *
+ * Sets the authentication method for a remote account.  There are no
+ * pre-defined method names; backends are free to set this however they
+ * wish.  If authentication is not required for a remote account, the
+ * convention is to set the method to "none".  In keeping with that
+ * convention, #ESourceAuthentication:method will be set to "none" if
+ * @method is %NULL or an empty string.
+ *
+ * Since: 3.4
+ **/
+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");
+}
+
+/**
+ * e_source_authentication_get_port:
+ * @extension: an #ESourceAuthentication
+ *
+ * Returns the port number used to authenticate to a remote account.
+ *
+ * Returns: the port number of a remote account
+ *
+ * Since: 3.4
+ **/
+guint16
+e_source_authentication_get_port (ESourceAuthentication *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), 0);
+
+	return extension->priv->port;
+}
+
+/**
+ * e_source_authentication_set_port:
+ * @extension: an #ESourceAuthentication
+ * @port: a port number
+ *
+ * Sets the port number used to authenticate to a remote account.
+ *
+ * Since: 3.4
+ **/
+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");
+}
+
+/**
+ * e_source_authentication_get_remember_password:
+ * @extension: an #ESourceAuthentication
+ *
+ * Returns whether the password for a remote account should be saved
+ * permanently after a successful authentication.
+ *
+ * Returns: whether to save the password
+ *
+ * Since: 3.4
+ **/
+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;
+}
+
+/**
+ * e_source_authentication_set_remember_password:
+ * @extension: an #ESourceAuthentication
+ * @remember_password: whether to save the password
+ *
+ * Sets whether the password for a remote account should be saved
+ * permanently after a successful authentication.
+ *
+ * Since: 3.4
+ **/
+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");
+}
+
+/**
+ * e_source_authentication_get_user:
+ * @extension: an #ESourceAuthentication
+ *
+ * Returns the user name used to authenticate to a remote account.
+ *
+ * Returns: the user name of a remote account
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_authentication_get_user (ESourceAuthentication *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
+
+	return extension->priv->user;
+}
+
+/**
+ * e_source_authentication_set_user:
+ * @extension: an #ESourceAuthentication
+ * @user: a user name, or %NULL
+ *
+ * Sets the user name used to authenticate to a remote account.  The
+ * #ESourceAuthentication:user property is automatically stripped of
+ * leading and trailing whitespace.
+ *
+ * Returns: the user name of a remote account
+ *
+ * Since: 3.4
+ **/
+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..98df438
--- /dev/null
+++ b/libedataserver/e-source-authentication.h
@@ -0,0 +1,112 @@
+/*
+ * 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))
+
+/**
+ * E_SOURCE_EXTENSION_AUTHENTICATION:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceAuthentication.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_AUTHENTICATION "Authentication"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceAuthentication ESourceAuthentication;
+typedef struct _ESourceAuthenticationClass ESourceAuthenticationClass;
+typedef struct _ESourceAuthenticationPrivate ESourceAuthenticationPrivate;
+
+/**
+ * ESourceAuthentication:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+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-authenticator.c b/libedataserver/e-source-authenticator.c
new file mode 100644
index 0000000..a5abf0e
--- /dev/null
+++ b/libedataserver/e-source-authenticator.c
@@ -0,0 +1,235 @@
+/*
+ * e-source-authenticator.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-authenticator.h"
+
+typedef struct _AsyncContext AsyncContext;
+
+struct _AsyncContext {
+	GString *password;
+	ESourceAuthenticationResult result;
+};
+
+G_DEFINE_INTERFACE (
+	ESourceAuthenticator,
+	e_source_authenticator,
+	G_TYPE_OBJECT)
+
+static void
+async_context_free (AsyncContext *async_context)
+{
+	g_string_free (async_context->password, TRUE);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
+static void
+source_authenticator_try_password_thread (GSimpleAsyncResult *simple,
+                                          GObject *object,
+                                          GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	async_context->result =
+		e_source_authenticator_try_password_sync (
+			E_SOURCE_AUTHENTICATOR (object),
+			async_context->password,
+			cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
+}
+
+static void
+source_authenticator_try_password (ESourceAuthenticator *authenticator,
+                                   const GString *password,
+                                   GCancellable *cancellable,
+                                   GAsyncReadyCallback callback,
+                                   gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->password = g_string_new (password->str);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (authenticator), callback,
+		user_data, source_authenticator_try_password);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, source_authenticator_try_password_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
+}
+
+static ESourceAuthenticationResult
+source_authenticator_try_password_finish (ESourceAuthenticator *authenticator,
+                                          GAsyncResult *result,
+                                          GError **error)
+{
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (authenticator),
+		source_authenticator_try_password),
+		E_SOURCE_AUTHENTICATION_REJECTED);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return E_SOURCE_AUTHENTICATION_ERROR;
+
+	return async_context->result;
+}
+
+static void
+e_source_authenticator_default_init (ESourceAuthenticatorInterface *interface)
+{
+	interface->try_password = source_authenticator_try_password;
+	interface->try_password_finish = source_authenticator_try_password_finish;
+}
+
+/**
+ * e_source_authenticator_try_password_sync:
+ * @auth: an #ESourceAuthenticator
+ * @password: a user-provided password
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Attempts to authenticate using @password.
+ *
+ * The password is passed in a #GString container so its content is not
+ * accidentally revealed in a stack trace.
+ *
+ * If an error occurs, the function sets @error and returns
+ * #E_SOURCE_AUTHENTICATION_ERROR.
+ *
+ * Returns: the authentication result
+ *
+ * Since: 3.4
+ **/
+ESourceAuthenticationResult
+e_source_authenticator_try_password_sync (ESourceAuthenticator *auth,
+                                          const GString *password,
+                                          GCancellable *cancellable,
+                                          GError **error)
+{
+	ESourceAuthenticatorInterface *interface;
+
+	g_return_val_if_fail (
+		E_IS_SOURCE_AUTHENTICATOR (auth),
+		E_SOURCE_AUTHENTICATION_REJECTED);
+	g_return_val_if_fail (
+		password != NULL,
+		E_SOURCE_AUTHENTICATION_REJECTED);
+
+	interface = E_SOURCE_AUTHENTICATOR_GET_INTERFACE (auth);
+	g_return_val_if_fail (
+		interface->try_password_sync != NULL,
+		E_SOURCE_AUTHENTICATION_REJECTED);
+
+	return interface->try_password_sync (
+		auth, password, cancellable, error);
+}
+
+/**
+ * e_source_authenticator_try_password:
+ * @auth: an #ESourceAuthenticator
+ * @password: a user-provided password
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asyncrhonously attempts to authenticate using @password.
+ *
+ * The password is passed in a #GString container so its content is not
+ * accidentally revealed in a stack trace.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call e_source_authenticator_try_password_finish() to get the result of the
+ * operation.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_authenticator_try_password (ESourceAuthenticator *auth,
+                                     const GString *password,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
+{
+	ESourceAuthenticatorInterface *interface;
+
+	g_return_if_fail (E_IS_SOURCE_AUTHENTICATOR (auth));
+	g_return_if_fail (password != NULL);
+
+	interface = E_SOURCE_AUTHENTICATOR_GET_INTERFACE (auth);
+	g_return_if_fail (interface->try_password != NULL);
+
+	interface->try_password (
+		auth, password, cancellable, callback, user_data);
+}
+
+/**
+ * e_source_authenticator_try_password_finish:
+ * @auth: an #ESourceAuthenticator
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_authenticator_try_password().
+ *
+ * If an error occurred, the function sets @error and returns
+ * #E_SOURCE_AUTHENTICATION_ERROR.
+ *
+ * Returns: the authentication result
+ *
+ * Since: 3.4
+ **/
+ESourceAuthenticationResult
+e_source_authenticator_try_password_finish (ESourceAuthenticator *auth,
+                                            GAsyncResult *result,
+                                            GError **error)
+{
+	ESourceAuthenticatorInterface *interface;
+
+	g_return_val_if_fail (
+		E_IS_SOURCE_AUTHENTICATOR (auth),
+		E_SOURCE_AUTHENTICATION_REJECTED);
+	g_return_val_if_fail (
+		G_IS_ASYNC_RESULT (result),
+		E_SOURCE_AUTHENTICATION_REJECTED);
+
+	interface = E_SOURCE_AUTHENTICATOR_GET_INTERFACE (auth);
+	g_return_val_if_fail (
+		interface->try_password_finish != NULL,
+		E_SOURCE_AUTHENTICATION_REJECTED);
+
+	return interface->try_password_finish (auth, result, error);
+}
+
diff --git a/libedataserver/e-source-authenticator.h b/libedataserver/e-source-authenticator.h
new file mode 100644
index 0000000..51ff34d
--- /dev/null
+++ b/libedataserver/e-source-authenticator.h
@@ -0,0 +1,91 @@
+/*
+ * e-source-authenticator.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_AUTHENTICATOR_H
+#define E_SOURCE_AUTHENTICATOR_H
+
+#include <gio/gio.h>
+#include <libedataserver/e-source-enums.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_AUTHENTICATOR \
+	(e_source_authenticator_get_type ())
+#define E_SOURCE_AUTHENTICATOR(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_AUTHENTICATOR, ESourceAuthenticator))
+#define E_IS_SOURCE_AUTHENTICATOR(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_AUTHENTICATOR))
+#define E_SOURCE_AUTHENTICATOR_GET_INTERFACE(obj) \
+	(G_TYPE_INSTANCE_GET_INTERFACE \
+	((obj), E_TYPE_SOURCE_AUTHENTICATOR, ESourceAuthenticatorInterface))
+
+G_BEGIN_DECLS
+
+/**
+ * ESourceAuthenticator:
+ *
+ * Since: 3.4
+ **/
+typedef struct _ESourceAuthenticator ESourceAuthenticator;
+typedef struct _ESourceAuthenticatorInterface ESourceAuthenticatorInterface;
+
+struct _ESourceAuthenticatorInterface {
+	GTypeInterface parent_interface;
+
+	/* Synchronous I/O Methods */
+	ESourceAuthenticationResult
+			(*try_password_sync)	(ESourceAuthenticator *auth,
+						 const GString *password,
+						 GCancellable *cancellable,
+						 GError **error);
+
+	/* Asynchronous I/O Methods (all have defaults) */
+	void		(*try_password)		(ESourceAuthenticator *auth,
+						 const GString *password,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+	ESourceAuthenticationResult
+			(*try_password_finish)	(ESourceAuthenticator *auth,
+						 GAsyncResult *result,
+						 GError **error);
+};
+
+GType		e_source_authenticator_get_type	(void) G_GNUC_CONST;
+ESourceAuthenticationResult
+		e_source_authenticator_try_password_sync
+						(ESourceAuthenticator *auth,
+						 const GString *password,
+						 GCancellable *cancellable,
+						 GError **error);
+void		e_source_authenticator_try_password
+						(ESourceAuthenticator *auth,
+						 const GString *password,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+ESourceAuthenticationResult
+		e_source_authenticator_try_password_finish
+						(ESourceAuthenticator *auth,
+						 GAsyncResult *result,
+						 GError **error);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_AUTHENTICATOR_H */
diff --git a/libedataserver/e-source-autocomplete.c b/libedataserver/e-source-autocomplete.c
new file mode 100644
index 0000000..52bbbeb
--- /dev/null
+++ b/libedataserver/e-source-autocomplete.c
@@ -0,0 +1,168 @@
+/*
+ * 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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-autocomplete
+ * @include: libedataserver/e-source-autocomplete.h
+ * @short_description: #ESource extension for autocomplete settings
+ *
+ * The #ESourceAutocomplete extension tracks contact autocompletion
+ * settings for an address book.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-autocomplete.h>
+ *
+ *   ESourceAutocomplete *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTOCOMPLETE);
+ * ]|
+ **/
+
+#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);
+}
+
+/**
+ * e_source_autocomplete_get_include_me:
+ * @extension: an #ESourceAutocomplete
+ *
+ * Returns whether the address book described by the #ESource to which
+ * @extension belongs should be queried when the user inputs a partial
+ * contact name or email address.
+ *
+ * Returns: whether to use the autocomplete feature
+ *
+ * Since: 3.4
+ **/
+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;
+}
+
+/**
+ * e_source_autocomplete_set_include_me:
+ * @extension: an #ESourceAutocomplete
+ * @include_me: whether to use the autocomplete feature
+ *
+ * Sets whether the address book described by the #ESource to which
+ * @extension belongs should be queried when the user inputs a partial
+ * contact name or email address.
+ *
+ * Since: 3.4
+ **/
+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..83b0b8b
--- /dev/null
+++ b/libedataserver/e-source-autocomplete.h
@@ -0,0 +1,85 @@
+/*
+ * 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))
+
+/**
+ * E_SOURCE_EXTENSION_AUTOCOMPLETE:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceAutocomplete.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_AUTOCOMPLETE "Autocomplete"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceAutocomplete ESourceAutocomplete;
+typedef struct _ESourceAutocompleteClass ESourceAutocompleteClass;
+typedef struct _ESourceAutocompletePrivate ESourceAutocompletePrivate;
+
+/**
+ * ESourceAutocomplete:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+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-enums.h b/libedataserver/e-source-enums.h
new file mode 100644
index 0000000..ce0e4f1
--- /dev/null
+++ b/libedataserver/e-source-enums.h
@@ -0,0 +1,62 @@
+/*
+ * e-source-enums.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_ENUMS_H
+#define E_SOURCE_ENUMS_H
+
+/**
+ * EMdnRequestPolicy:
+ * @E_MDN_REQUEST_POLICY_NEVER:
+ *   Never respond to an MDN request.
+ * @E_MDN_REQUEST_POLICY_ALWAYS:
+ *   Always respond to an MDN request.
+ * @E_MDN_REQUEST_POLICY_ASK:
+ *   Ask the user before responding to an MDN request.
+ *
+ * Policy for responding to Message Disposition Notification requests
+ * (i.e. a Disposition-Notification-To header) when receiving messages.
+ * See RFC 2298 for more information about MDN requests.
+ *
+ * Since: 3.4
+ **/
+typedef enum {
+	E_MDN_REQUEST_POLICY_NEVER,
+	E_MDN_REQUEST_POLICY_ALWAYS,
+	E_MDN_REQUEST_POLICY_ASK
+} EMdnRequestPolicy;
+
+/**
+ * ESourceAuthenticationResult:
+ * @E_SOURCE_AUTHENTICATION_ERROR:
+ *   An error occurred while authenticating.
+ * @E_SOURCE_AUTHENTICATION_ACCEPTED:
+ *   Server requesting authentication accepted password.
+ * @E_SOURCE_AUTHENTICATION_REJECTED:
+ *   Server requesting authentication rejected password.
+ *
+ * Status codes used by the #ESourceAuthenticator interface.
+ *
+ * Since: 3.4
+ **/
+typedef enum {
+	E_SOURCE_AUTHENTICATION_ERROR,
+	E_SOURCE_AUTHENTICATION_ACCEPTED,
+	E_SOURCE_AUTHENTICATION_REJECTED
+} ESourceAuthenticationResult;
+
+#endif /* E_SOURCE_ENUMS_H */
diff --git a/libedataserver/e-source-extension.c b/libedataserver/e-source-extension.c
new file mode 100644
index 0000000..8013740
--- /dev/null
+++ b/libedataserver/e-source-extension.c
@@ -0,0 +1,301 @@
+/*
+ * 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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-extension
+ * @include: libedataserver/e-source-extension.h
+ * @short_description: Base class for #ESource extensions
+ *
+ * #ESourceExtension is an abstract base class for #ESource extension
+ * objects.  An #ESourceExtension object basically just maps the keys in
+ * a key file group to a set of #GObject properties.  The name of the key
+ * file group doubles as the name of the #ESourceExtension object.
+ *
+ * #ESourceExtension objects are accessed through e_source_get_extension().
+ **/
+
+#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);
+}
+
+/**
+ * e_source_extension_get_source:
+ * @extension: an #ESourceExtension
+ *
+ * Returns the #ESource instance to which @extension belongs.
+ *
+ * Returns: the #ESource instance
+ **/
+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);
+}
+
+/* Helper for e_source_extension_resolve_reference() */
+static gboolean
+source_extension_traverse_cb (GNode *node,
+                              gpointer user_data)
+{
+	struct {
+		const gchar *target_uid;
+		ESource *target_source;
+	} *traverse_data = user_data;
+
+	if (E_IS_SOURCE (node->data)) {
+		ESource *source;
+		const gchar *uid;
+
+		source = E_SOURCE (node->data);
+		uid = e_source_get_uid (source);
+
+		if (g_strcmp0 (uid, traverse_data->target_uid) == 0) {
+			traverse_data->target_source = source;
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+/**
+ * e_source_extension_resolve_reference:
+ * @extension: an #ESourceExtension
+ * @uid_reference: an #ESource UID to resolve, or %NULL
+ * @extension_name: an extension name to check for, or %NULL
+ *
+ * Tries to locate an #ESource instance with a unique identifier
+ * string equal to @uid_reference by recursing over the hierarchy
+ * to which @extension belongs.  This only works if the #ESource
+ * containing @extension has already been added to a hierarchy by
+ * way of e_source_registry_add_source().
+ *
+ * Applications should usually prefer e_source_registry_lookup_by_uid(),
+ * which is faster than this function.  This function is useful in cases
+ * where an #ESourceRegistry is unavailable and assuming the default
+ * instance would be bad design.  For example, some #ESourceExtension
+ * classes reference other sources by their #ESource:uid string, and this
+ * function allows them to locate those other sources without relying on
+ * an #ESourceRegistry.
+ *
+ * As a special case, if @uid_reference is the string "self" then
+ * the function returns the result of e_source_extension_get_source(),
+ * providing a way for an #ESource to refer to itself without explicitly
+ * using its own UID.
+ *
+ * If @extension_name is non-%NULL, the function will also check whether the
+ * resolved #ESource has an #ESourceExtension with the given @extension_name,
+ * and if not the function will return %NULL.
+ *
+ * Returns: the #ESource instance for @uid_reference, or %NULL
+ *
+ * Since: 3.4
+ **/
+ESource *
+e_source_extension_resolve_reference (ESourceExtension *extension,
+                                      const gchar *uid_reference,
+                                      const gchar *extension_name)
+{
+	ESource *source;
+	GNode *node;
+
+	struct {
+		const gchar *target_uid;
+		ESource *target_source;
+	} traverse_data;
+
+	g_return_val_if_fail (E_IS_SOURCE_EXTENSION (extension), NULL);
+
+	/* Handle NULL references gracefully. */
+	if (uid_reference == NULL)
+		return NULL;
+
+	source = e_source_extension_get_source (extension);
+
+	/* Check for a self-reference before we recurse. */
+	if (g_strcmp0 (uid_reference, e_source_get_uid (source)) == 0)
+		return source;
+
+	/* A UID named "self" is another form of self-reference. */
+	if (g_strcmp0 (uid_reference, "self") == 0)
+		return source;
+
+	node = e_source_get_node (source);
+
+	/* This implies the ESource is not yet part of a heirarchy. */
+	if (node == NULL)
+		return NULL;
+
+	traverse_data.target_uid = uid_reference;
+	traverse_data.target_source = NULL;
+
+	g_node_traverse (
+		g_node_get_root (node),
+		G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+		source_extension_traverse_cb,
+		&traverse_data);
+
+	source = traverse_data.target_source;
+
+	if (source != NULL && extension_name != NULL)
+		if (!e_source_has_extension (source, extension_name))
+			source = NULL;
+
+	return source;
+}
+
diff --git a/libedataserver/e-source-extension.h b/libedataserver/e-source-extension.h
new file mode 100644
index 0000000..d576903
--- /dev/null
+++ b/libedataserver/e-source-extension.h
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+/**
+ * ESourceExtension:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+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);
+ESource *	e_source_extension_resolve_reference
+						(ESourceExtension *extension,
+						 const gchar *uid_reference,
+						 const gchar *extension_name);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_EXTENSION_H */
diff --git a/libedataserver/e-source-mail-account.c b/libedataserver/e-source-mail-account.c
new file mode 100644
index 0000000..63bab4d
--- /dev/null
+++ b/libedataserver/e-source-mail-account.c
@@ -0,0 +1,288 @@
+/*
+ * e-source-mail-account.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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-mail-account
+ * @include: libedataserver/e-source-mail-account.h
+ * @short_description: #ESource extension for an email account
+ *
+ * The #ESourceMailAccount extension identifies the #ESource as a
+ * mail account and also links to a default "mail identity" to use.
+ * See #ESourceMailIdentity for more information about identities.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-mail-account.h>
+ *
+ *   ESourceMailAccount *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
+ * ]|
+ **/
+
+#include "e-source-mail-account.h"
+
+#include <libedataserver/e-source-enumtypes.h>
+#include <libedataserver/e-source-mail-identity.h>
+
+#define E_SOURCE_MAIL_ACCOUNT_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_MAIL_ACCOUNT, ESourceMailAccountPrivate))
+
+struct _ESourceMailAccountPrivate {
+	gchar *identity_uid;
+	EMdnRequestPolicy mdn_request_policy;
+};
+
+enum {
+	PROP_0,
+	PROP_IDENTITY_UID,
+	PROP_MDN_REQUEST_POLICY
+};
+
+G_DEFINE_TYPE (
+	ESourceMailAccount,
+	e_source_mail_account,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_mail_account_set_property (GObject *object,
+                                   guint property_id,
+                                   const GValue *value,
+                                   GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_IDENTITY_UID:
+			e_source_mail_account_set_identity_uid (
+				E_SOURCE_MAIL_ACCOUNT (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_MDN_REQUEST_POLICY:
+			e_source_mail_account_set_mdn_request_policy (
+				E_SOURCE_MAIL_ACCOUNT (object),
+				g_value_get_enum (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_mail_account_get_property (GObject *object,
+                                   guint property_id,
+                                   GValue *value,
+                                   GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_IDENTITY_UID:
+			g_value_set_string (
+				value,
+				e_source_mail_account_get_identity_uid (
+				E_SOURCE_MAIL_ACCOUNT (object)));
+			return;
+
+		case PROP_MDN_REQUEST_POLICY:
+			g_value_set_enum (
+				value,
+				e_source_mail_account_get_mdn_request_policy (
+				E_SOURCE_MAIL_ACCOUNT (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_mail_account_finalize (GObject *object)
+{
+	ESourceMailAccountPrivate *priv;
+
+	priv = E_SOURCE_MAIL_ACCOUNT_GET_PRIVATE (object);
+
+	g_free (priv->identity_uid);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_mail_account_parent_class)->finalize (object);
+}
+
+static void
+e_source_mail_account_class_init (ESourceMailAccountClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceMailAccountPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_mail_account_set_property;
+	object_class->get_property = source_mail_account_get_property;
+	object_class->finalize = source_mail_account_finalize;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_IDENTITY_UID,
+		g_param_spec_string (
+			"identity-uid",
+			"Identity UID",
+			"ESource UID of a Mail Identity",
+			"self",
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MDN_REQUEST_POLICY,
+		g_param_spec_enum (
+			"mdn-request-policy",
+			"MDN Request Policy",
+			"Policy for responding to MDN requests",
+			E_TYPE_MDN_REQUEST_POLICY,
+			E_MDN_REQUEST_POLICY_ASK,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_mail_account_init (ESourceMailAccount *extension)
+{
+	extension->priv = E_SOURCE_MAIL_ACCOUNT_GET_PRIVATE (extension);
+}
+
+/**
+ * e_source_mail_account_get_identity:
+ * @extension: an #ESourceMailAccount
+ *
+ * Convenience function that uses e_source_extension_resolve_reference()
+ * to resolve @extension's #ESourceMailAccount:identity-uid property to
+ * an #ESource instance with a matching #ESource:uid.
+ *
+ * If no matching #ESource is found, or if the matching #ESource does not
+ * have an #ESourceMailIdentity extension, the function returns %NULL.
+ *
+ * Returns: a matching #ESource instance, or %NULL
+ *
+ * Since: 3.4
+ **/
+ESource *
+e_source_mail_account_get_identity (ESourceMailAccount *extension)
+{
+	const gchar *extension_name;
+	const gchar *uid;
+
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_ACCOUNT (extension), NULL);
+
+	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
+	uid = e_source_mail_account_get_identity_uid (extension);
+
+	return e_source_extension_resolve_reference (
+		E_SOURCE_EXTENSION (extension), uid, extension_name);
+}
+
+/**
+ * e_source_mail_account_get_identity_uid:
+ * @extension: an #ESourceMailAccount
+ *
+ * Returns the #ESource:uid of the #ESource that describes the mail
+ * identity to be used for this account.
+ *
+ * Returns: the mail identity #ESource:uid
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_mail_account_get_identity_uid (ESourceMailAccount *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_ACCOUNT (extension), NULL);
+
+	return extension->priv->identity_uid;
+}
+
+/**
+ * e_source_mail_account_set_identity_uid:
+ * @extension: an #ESourceMailAccount
+ * @identity_uid: the mail identity #ESource:uid, or %NULL
+ *
+ * Sets the #ESource:uid of the #ESource that describes the mail
+ * identity to be used for this account.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_account_set_identity_uid (ESourceMailAccount *extension,
+                                        const gchar *identity_uid)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_ACCOUNT (extension));
+
+	g_free (extension->priv->identity_uid);
+	extension->priv->identity_uid = g_strdup (identity_uid);
+
+	g_object_notify (G_OBJECT (extension), "identity-uid");
+}
+
+/**
+ * e_source_mail_account_get_mdn_request_policy:
+ * @extension: an #ESourceMailAccount
+ *
+ * Returns the policy for this mail account on responding to Message
+ * Disposition Notification requests when receiving messages.  See
+ * RFC 2298 for more information about MDN requests.
+ *
+ * Returns: the #EMdnRequestPolicy for this account
+ *
+ * Since: 3.4
+ **/
+EMdnRequestPolicy
+e_source_mail_account_get_mdn_request_policy (ESourceMailAccount *extension)
+{
+	g_return_val_if_fail (
+		E_IS_SOURCE_MAIL_ACCOUNT (extension),
+		E_MDN_REQUEST_POLICY_NEVER);
+
+	return extension->priv->mdn_request_policy;
+}
+
+/**
+ * e_source_mail_account_set_mdn_request_policy:
+ * @extension: an #ESourceMailAccount
+ * @mdn_request_policy: the #EMdnRequestPolicy
+ *
+ * Sets the policy for this mail account on responding to Message
+ * Disposition Notification requests when receiving messages.  See
+ * RFC 2298 for more information about MDN requests.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_account_set_mdn_request_policy (ESourceMailAccount *extension,
+                                              EMdnRequestPolicy mdn_request_policy)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_ACCOUNT (extension));
+
+	extension->priv->mdn_request_policy = mdn_request_policy;
+
+	g_object_notify (G_OBJECT (extension), "mdn-request-policy");
+}
diff --git a/libedataserver/e-source-mail-account.h b/libedataserver/e-source-mail-account.h
new file mode 100644
index 0000000..c818c4c
--- /dev/null
+++ b/libedataserver/e-source-mail-account.h
@@ -0,0 +1,94 @@
+/*
+ * e-source-mail-account.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_MAIL_ACCOUNT_H
+#define E_SOURCE_MAIL_ACCOUNT_H
+
+#include <libedataserver/e-source-enums.h>
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_MAIL_ACCOUNT \
+	(e_source_mail_account_get_type ())
+#define E_SOURCE_MAIL_ACCOUNT(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_MAIL_ACCOUNT, ESourceMailAccount))
+#define E_SOURCE_MAIL_ACCOUNT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_MAIL_ACCOUNT, ESourceMailAccountClass))
+#define E_IS_SOURCE_MAIL_ACCOUNT(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_MAIL_ACCOUNT))
+#define E_IS_SOURCE_MAIL_ACCOUNT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_MAIL_ACCOUNT))
+#define E_SOURCE_MAIL_ACCOUNT_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_MAIL_ACCOUNT, ESourceMailAccountClass))
+
+/**
+ * E_SOURCE_EXTENSION_MAIL_ACCOUNT:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceMailAccount.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_MAIL_ACCOUNT "Mail Account"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceMailAccount ESourceMailAccount;
+typedef struct _ESourceMailAccountClass ESourceMailAccountClass;
+typedef struct _ESourceMailAccountPrivate ESourceMailAccountPrivate;
+
+/**
+ * ESourceMailAccount:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceMailAccount {
+	ESourceExtension parent;
+	ESourceMailAccountPrivate *priv;
+};
+
+struct _ESourceMailAccountClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_mail_account_get_type (void);
+ESource *	e_source_mail_account_get_identity
+					(ESourceMailAccount *extension);
+const gchar *	e_source_mail_account_get_identity_uid
+					(ESourceMailAccount *extension);
+void		e_source_mail_account_set_identity_uid
+					(ESourceMailAccount *extension,
+					 const gchar *identity_uid);
+EMdnRequestPolicy
+		e_source_mail_account_get_mdn_request_policy
+					(ESourceMailAccount *extension);
+void		e_source_mail_account_set_mdn_request_policy
+					(ESourceMailAccount *extension,
+					 EMdnRequestPolicy mdn_request_policy);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_MAIL_ACCOUNT_H */
diff --git a/libedataserver/e-source-mail-composition.c b/libedataserver/e-source-mail-composition.c
new file mode 100644
index 0000000..22b46b9
--- /dev/null
+++ b/libedataserver/e-source-mail-composition.c
@@ -0,0 +1,647 @@
+/*
+ * e-source-mail-composition.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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-mail-composition
+ * @include: libedataserver/e-source-mail-composition.h
+ * @short_description: #ESource extension for mail composition settings
+ *
+ * The #ESourceMailComposition extension tracks settings to be applied
+ * when composing a new mail message.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-mail-composition.h>
+ *
+ *   ESourceMailComposition *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_COMPOSITION);
+ * ]|
+ **/
+
+#include "e-source-mail-composition.h"
+
+#define E_SOURCE_MAIL_COMPOSITION_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_MAIL_COMPOSITION, ESourceMailCompositionPrivate))
+
+struct _ESourceMailCompositionPrivate {
+	gchar **bcc;
+	gchar **cc;
+	gchar *drafts_folder;
+	gchar *templates_folder;
+	gboolean sign_imip;
+	gboolean smime_encrypt;
+	gboolean smime_sign;
+};
+
+enum {
+	PROP_0,
+	PROP_BCC,
+	PROP_CC,
+	PROP_DRAFTS_FOLDER,
+	PROP_SIGN_IMIP,
+	PROP_SMIME_ENCRYPT,
+	PROP_SMIME_SIGN,
+	PROP_TEMPLATES_FOLDER
+};
+
+G_DEFINE_TYPE (
+	ESourceMailComposition,
+	e_source_mail_composition,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_mail_composition_set_property (GObject *object,
+                                      guint property_id,
+                                      const GValue *value,
+                                      GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_BCC:
+			e_source_mail_composition_set_bcc (
+				E_SOURCE_MAIL_COMPOSITION (object),
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_CC:
+			e_source_mail_composition_set_cc (
+				E_SOURCE_MAIL_COMPOSITION (object),
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_DRAFTS_FOLDER:
+			e_source_mail_composition_set_drafts_folder (
+				E_SOURCE_MAIL_COMPOSITION (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_SIGN_IMIP:
+			e_source_mail_composition_set_sign_imip (
+				E_SOURCE_MAIL_COMPOSITION (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_SMIME_ENCRYPT:
+			e_source_mail_composition_set_smime_encrypt (
+				E_SOURCE_MAIL_COMPOSITION (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_SMIME_SIGN:
+			e_source_mail_composition_set_smime_sign (
+				E_SOURCE_MAIL_COMPOSITION (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_TEMPLATES_FOLDER:
+			e_source_mail_composition_set_templates_folder (
+				E_SOURCE_MAIL_COMPOSITION (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_mail_composition_get_property (GObject *object,
+                                      guint property_id,
+                                      GValue *value,
+                                      GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_BCC:
+			g_value_set_boxed (
+				value,
+				e_source_mail_composition_get_bcc (
+				E_SOURCE_MAIL_COMPOSITION (object)));
+			return;
+
+		case PROP_CC:
+			g_value_set_boxed (
+				value,
+				e_source_mail_composition_get_cc (
+				E_SOURCE_MAIL_COMPOSITION (object)));
+			return;
+
+		case PROP_DRAFTS_FOLDER:
+			g_value_set_string (
+				value,
+				e_source_mail_composition_get_drafts_folder (
+				E_SOURCE_MAIL_COMPOSITION (object)));
+			return;
+
+		case PROP_SIGN_IMIP:
+			g_value_set_boolean (
+				value,
+				e_source_mail_composition_get_sign_imip (
+				E_SOURCE_MAIL_COMPOSITION (object)));
+			return;
+
+		case PROP_SMIME_ENCRYPT:
+			g_value_set_boolean (
+				value,
+				e_source_mail_composition_get_smime_encrypt (
+				E_SOURCE_MAIL_COMPOSITION (object)));
+			return;
+
+		case PROP_SMIME_SIGN:
+			g_value_set_boolean (
+				value,
+				e_source_mail_composition_get_smime_sign (
+				E_SOURCE_MAIL_COMPOSITION (object)));
+			return;
+
+		case PROP_TEMPLATES_FOLDER:
+			g_value_set_string (
+				value,
+				e_source_mail_composition_get_templates_folder (
+				E_SOURCE_MAIL_COMPOSITION (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_mail_composition_finalize (GObject *object)
+{
+	ESourceMailCompositionPrivate *priv;
+
+	priv = E_SOURCE_MAIL_COMPOSITION_GET_PRIVATE (object);
+
+	if (priv->bcc != NULL)
+		g_strfreev (priv->bcc);
+
+	if (priv->cc != NULL)
+		g_strfreev (priv->cc);
+
+	g_free (priv->drafts_folder);
+	g_free (priv->templates_folder);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_mail_composition_parent_class)->
+		finalize (object);
+}
+
+static void
+e_source_mail_composition_class_init (ESourceMailCompositionClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (
+		class, sizeof (ESourceMailCompositionPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_mail_composition_set_property;
+	object_class->get_property = source_mail_composition_get_property;
+	object_class->finalize = source_mail_composition_finalize;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_MAIL_COMPOSITION;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_BCC,
+		g_param_spec_boxed (
+			"bcc",
+			"Bcc",
+			"Recipients to blind carbon-copy",
+			G_TYPE_STRV,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CC,
+		g_param_spec_boxed (
+			"cc",
+			"Cc",
+			"Recipients to carbon-copy",
+			G_TYPE_STRV,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DRAFTS_FOLDER,
+		g_param_spec_string (
+			"drafts-folder",
+			"Drafts Folder",
+			"Preferred folder for draft messages",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SIGN_IMIP,
+		g_param_spec_boolean (
+			"sign-imip",
+			"Sign iMIP",
+			"Include iMIP messages when signing",
+			TRUE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SMIME_ENCRYPT,
+		g_param_spec_boolean (
+			"smime-encrypt",
+			"S/MIME Encrypt",
+			"Encrypt outgoing messages using S/MIME",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SMIME_SIGN,
+		g_param_spec_boolean (
+			"smime-sign",
+			"S/MIME Sign",
+			"Sign outgoing messages using S/MIME",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_TEMPLATES_FOLDER,
+		g_param_spec_string (
+			"templates-folder",
+			"Templates Folder",
+			"Preferred folder for message templates",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_mail_composition_init (ESourceMailComposition *extension)
+{
+	extension->priv = E_SOURCE_MAIL_COMPOSITION_GET_PRIVATE (extension);
+}
+
+/**
+ * e_source_mail_composition_get_bcc:
+ * @extension: an #ESourceMailComposition
+ *
+ * Returns a %NULL-terminated string array of recipients which should
+ * automatically be added to the blind carbon-copy (Bcc) list when
+ * composing a new mail message.  The recipient strings should be of
+ * the form "Full Name <email-address>".  The returned array is owned
+ * by @extension and should not be modified or freed.
+ *
+ * Returns: a %NULL-terminated string array of Bcc recipients
+ *
+ * Since: 3.4
+ **/
+const gchar * const *
+e_source_mail_composition_get_bcc (ESourceMailComposition *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension), NULL);
+
+	return (const gchar * const *) extension->priv->bcc;
+}
+
+/**
+ * e_source_mail_composition_set_bcc:
+ * @extension: an #ESource
+ * @bcc: a %NULL-terminated string array of Bcc recipients
+ *
+ * Sets the recipients which should automatically be added to the blind
+ * carbon-copy (Bcc) list when composing a new mail message.  The recipient
+ * strings should be of the form "Full Name <email-address>".
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_composition_set_bcc (ESourceMailComposition *extension,
+                                   const gchar * const *bcc)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension));
+
+	if (extension->priv->bcc != NULL) {
+		g_strfreev (extension->priv->bcc);
+		extension->priv->bcc = NULL;
+	}
+
+	if (bcc != NULL) {
+		gchar **string_array;
+		guint length, ii;
+
+		length = g_strv_length ((gchar **) bcc);
+		string_array = g_new0 (gchar *, length + 1);
+		for (ii = 0; ii < length; ii++)
+			string_array[ii] = g_strdup (bcc[ii]);
+		extension->priv->bcc = string_array;
+	}
+
+	g_object_notify (G_OBJECT (extension), "bcc");
+}
+
+/**
+ * e_source_mail_composition_get_cc:
+ * @extension: an #ESourceMailComposition
+ *
+ * Returns a %NULL-terminated string array of recipients which should
+ * automatically be added to the carbon-copy (Cc) list when composing a
+ * new mail message.  The recipient strings should be of the form "Full
+ * Name <email-address>".  The returned array is owned by @extension and
+ * should not be modified or freed.
+ *
+ * Returns: a %NULL-terminated string array of Cc recipients
+ *
+ * Since: 3.4
+ **/
+const gchar * const *
+e_source_mail_composition_get_cc (ESourceMailComposition *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension), NULL);
+
+	return (const gchar * const *) extension->priv->cc;
+}
+
+/**
+ * e_source_mail_composition_set_cc:
+ * @extension: an #ESourceMailComposition
+ * @cc: a %NULL-terminated string array of Cc recipients
+ *
+ * Sets the recipients which should automatically be added to the carbon
+ * copy (Cc) list when composing a new mail message.  The recipient strings
+ * should be of the form "Full Name <email-address>".
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_composition_set_cc (ESourceMailComposition *extension,
+                                  const gchar * const *cc)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension));
+
+	if (extension->priv->cc != NULL) {
+		g_strfreev (extension->priv->cc);
+		extension->priv->cc = NULL;
+	}
+
+	if (cc != NULL) {
+		gchar **string_array;
+		guint length, ii;
+
+		length = g_strv_length ((gchar **) cc);
+		string_array = g_new0 (gchar *, length + 1);
+		for (ii = 0; ii < length; ii++)
+			string_array[ii] = g_strdup (cc[ii]);
+		extension->priv->cc = string_array;
+	}
+
+	g_object_notify (G_OBJECT (extension), "cc");
+}
+
+/**
+ * e_source_mail_composition_get_drafts_folder:
+ * @extension: an #ESourceMailComposition
+ * 
+ * Returns a string identifying the preferred folder for draft messages.
+ * The format of the identifier string is defined by the client application.
+ *
+ * Returns: an identifier for the preferred drafts folder
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_mail_composition_get_drafts_folder (ESourceMailComposition *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension), NULL);
+
+	return extension->priv->drafts_folder;
+}
+
+/**
+ * e_source_mail_composition_set_drafts_folder:
+ * @extension: an #ESourceMailComposition
+ * @drafts_folder: an identifier for the preferred drafts folder, or %NULL
+ *
+ * Sets the preferred folder for draft messages by an identifier string.
+ * The format of the identifier string is defined by the client application.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_composition_set_drafts_folder (ESourceMailComposition *extension,
+                                             const gchar *drafts_folder)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension));
+
+	g_free (extension->priv->drafts_folder);
+	extension->priv->drafts_folder = g_strdup (drafts_folder);
+
+	g_object_notify (G_OBJECT (extension), "drafts-folder");
+}
+
+/**
+ * e_source_mail_composition_get_sign_imip:
+ * @extension: an #ESourceMailComposition
+ *
+ * Returns whether outgoing iMIP messages such as meeting requests should
+ * also be signed.  This is primarily intended as a workaround for certain
+ * versions of Microsoft Outlook which can't handle signed iMIP messages.
+ *
+ * If neither #ESourceOpenPGP #ESourceOpenPGP:always-sign nor
+ * #ESourceMailComposition:smime-sign properties are enabled then this
+ * property has no effect.
+ *
+ * Returns: whether outgoing iMIP messages should be signed
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_mail_composition_get_sign_imip (ESourceMailComposition *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension), FALSE);
+
+	return extension->priv->sign_imip;
+}
+
+/**
+ * e_source_mail_composition_set_sign_imip:
+ * @extension: an #ESourceMailComposition
+ * @sign_imip: whether outgoing iMIP messages should be signed
+ *
+ * Sets whether outgoing iMIP messages such as meeting requests should
+ * also be signed.  This is primarily intended as a workaround for certain
+ * versions of Microsoft Outlook which can't handle signed iMIP messages.
+ *
+ * If neither #ESourceOpenPGP #ESourceOpenPGP:always-sign nor
+ * #ESourceMailComposition:smime-sign properties are enabled then this
+ * property has no effect.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_composition_set_sign_imip (ESourceMailComposition *extension,
+                                         gboolean sign_imip)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension));
+
+	extension->priv->sign_imip = sign_imip;
+
+	g_object_notify (G_OBJECT (extension), "sign-imip");
+}
+
+/**
+ * e_source_mail_composition_get_smime_encrypt:
+ * @extension: an #ESourceMailComposition
+ *
+ * Returns whether to digitally encrypt outgoing messages by default using
+ * the Secure/Multipurpose Internet Mail Extensions (S/MIME) standard.
+ *
+ * Returns: whether to encrypt outgoing messages with S/MIME
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_mail_composition_get_smime_encrypt (ESourceMailComposition *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension), FALSE);
+
+	return extension->priv->smime_encrypt;
+}
+
+/**
+ * e_source_mail_composition_set_smime_encrypt:
+ * @extension: an #ESourceMailComposition
+ * @smime_encrypt: whether to encrypt outgoing messages with S/MIME
+ *
+ * Sets whether to digitally encrypt outgoing messages by default using
+ * the Secure/Multipurpose Internet Mail Extensions (S/MIME) standard.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_composition_set_smime_encrypt (ESourceMailComposition *extension,
+                                             gboolean smime_encrypt)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension));
+
+	extension->priv->smime_encrypt = smime_encrypt;
+
+	g_object_notify (G_OBJECT (extension), "smime-encrypt");
+}
+
+/**
+ * e_source_mail_composition_get_smime_sign:
+ * @extension: an #ESourceMailComposition
+ *
+ * Returns whether to digitally sign outgoing messages by default using
+ * the Secure/Multipurpose Internet Mail Extensions (S/MIME) standard.
+ *
+ * Returns: whether to sign outgoing messages with S/MIME
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_mail_composition_get_smime_sign (ESourceMailComposition *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension), FALSE);
+
+	return extension->priv->smime_sign;
+}
+
+/**
+ * e_source_mail_composition_set_smime_sign:
+ * @extension: an #ESourceMailComposition
+ * @smime_sign: whether to sign outgoing messages with S/MIME
+ *
+ * Sets whether to digitally sign outgoing messages by default using
+ * the Secure/Multipurpose Internet Mail Extensions (S/MIME) standard.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_composition_set_smime_sign (ESourceMailComposition *extension,
+                                          gboolean smime_sign)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension));
+
+	extension->priv->smime_sign = smime_sign;
+
+	g_object_notify (G_OBJECT (extension), "smime-sign");
+}
+
+/**
+ * e_source_mail_composition_get_templates_folder:
+ * @extension: an #ESourceMailComposition
+ *
+ * Returns a string identifying the preferred folder for message templates.
+ * The format of the identifier string is defined by the client application.
+ *
+ * Returns: an identifier for the preferred templates folder
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_mail_composition_get_templates_folder (ESourceMailComposition *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension), NULL);
+
+	return extension->priv->templates_folder;
+}
+
+/**
+ * e_source_mail_composition_set_templates_folder:
+ * @extension: an #ESourceMailComposition
+ * @templates_folder: an identifier for the preferred templates folder,
+ *                    or %NULL
+ *
+ * Sets the preferred folder for message templates by an identifier string.
+ * The format of the identifier string is defined by the client application.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_composition_set_templates_folder (ESourceMailComposition *extension,
+                                                const gchar *templates_folder)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_COMPOSITION (extension));
+
+	g_free (extension->priv->templates_folder);
+	extension->priv->templates_folder = g_strdup (templates_folder);
+
+	g_object_notify (G_OBJECT (extension), "templates-folder");
+}
+
diff --git a/libedataserver/e-source-mail-composition.h b/libedataserver/e-source-mail-composition.h
new file mode 100644
index 0000000..dd6cc8e
--- /dev/null
+++ b/libedataserver/e-source-mail-composition.h
@@ -0,0 +1,117 @@
+/*
+ * e-source-mail-composition.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_MAIL_COMPOSITION_H
+#define E_SOURCE_MAIL_COMPOSITION_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_MAIL_COMPOSITION \
+	(e_source_mail_composition_get_type ())
+#define E_SOURCE_MAIL_COMPOSITION(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_MAIL_COMPOSITION, ESourceMailComposition))
+#define E_SOURCE_MAIL_COMPOSITION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_MAIL_COMPOSITION, ESourceMailCompositionClass))
+#define E_IS_SOURCE_MAIL_COMPOSITION(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_MAIL_COMPOSITION))
+#define E_IS_SOURCE_MAIL_COMPOSITION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_MAIL_COMPOSITION))
+#define E_SOURCE_MAIL_COMPOSITION_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_MAIL_COMPOSITION, ESourceMailCompositionClass))
+
+/**
+ * E_SOURCE_EXTENSION_MAIL_COMPOSITION:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceMailComposition.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_MAIL_COMPOSITION "Mail Composition"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceMailComposition ESourceMailComposition;
+typedef struct _ESourceMailCompositionClass ESourceMailCompositionClass;
+typedef struct _ESourceMailCompositionPrivate ESourceMailCompositionPrivate;
+
+/**
+ * ESourceMailComposition:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceMailComposition {
+	ESourceExtension parent;
+	ESourceMailCompositionPrivate *priv;
+};
+
+struct _ESourceMailCompositionClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_mail_composition_get_type (void);
+const gchar * const *
+		e_source_mail_composition_get_bcc
+					(ESourceMailComposition *extension);
+void		e_source_mail_composition_set_bcc
+					(ESourceMailComposition *extension,
+					 const gchar * const *bcc);
+const gchar * const *
+		e_source_mail_composition_get_cc
+					(ESourceMailComposition *extension);
+void		e_source_mail_composition_set_cc
+					(ESourceMailComposition *extension,
+					 const gchar * const *cc);
+const gchar *	e_source_mail_composition_get_drafts_folder
+					(ESourceMailComposition *extension);
+void		e_source_mail_composition_set_drafts_folder
+					(ESourceMailComposition *extension,
+					 const gchar *drafts_folder);
+gboolean	e_source_mail_composition_get_sign_imip
+					(ESourceMailComposition *extension);
+void		e_source_mail_composition_set_sign_imip
+					(ESourceMailComposition *extension,
+					 gboolean sign_imip);
+gboolean	e_source_mail_composition_get_smime_encrypt
+					(ESourceMailComposition *extension);
+void		e_source_mail_composition_set_smime_encrypt
+					(ESourceMailComposition *extension,
+					 gboolean smime_encrypt);
+gboolean	e_source_mail_composition_get_smime_sign
+					(ESourceMailComposition *extension);
+void		e_source_mail_composition_set_smime_sign
+					(ESourceMailComposition *extension,
+					 gboolean smime_sign);
+const gchar *	e_source_mail_composition_get_templates_folder
+					(ESourceMailComposition *extension);
+void		e_source_mail_composition_set_templates_folder
+					(ESourceMailComposition *extension,
+					 const gchar *templates_folder);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_MAIL_COMPOSITION_H */
diff --git a/libedataserver/e-source-mail-identity.c b/libedataserver/e-source-mail-identity.c
new file mode 100644
index 0000000..f6afb16
--- /dev/null
+++ b/libedataserver/e-source-mail-identity.c
@@ -0,0 +1,504 @@
+/*
+ * e-source-mail-identity.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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-mail-identity
+ * @include: libedataserver/e-source-mail-identity.h
+ * @short_description: #ESource extension for an email identity
+ *
+ * The #ESourceMailIdentity extension describes an "identity" for a mail
+ * account, which is the information that other people see when they read
+ * your messages.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-mail-identity.h>
+ *
+ *   ESourceMailIdentity *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_IDENTITY);
+ * ]|
+ **/
+
+#include "e-source-mail-identity.h"
+
+#include <libedataserver/e-source-mail-signature.h>
+
+#define E_SOURCE_MAIL_IDENTITY_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_MAIL_IDENTITY, ESourceMailIdentityPrivate))
+
+struct _ESourceMailIdentityPrivate {
+	gchar *address;
+	gchar *name;
+	gchar *organization;
+	gchar *reply_to;
+	gchar *signature_uid;
+};
+
+enum {
+	PROP_0,
+	PROP_ADDRESS,
+	PROP_NAME,
+	PROP_ORGANIZATION,
+	PROP_REPLY_TO,
+	PROP_SIGNATURE_UID
+};
+
+G_DEFINE_TYPE (
+	ESourceMailIdentity,
+	e_source_mail_identity,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_mail_identity_set_property (GObject *object,
+                                   guint property_id,
+                                   const GValue *value,
+                                   GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ADDRESS:
+			e_source_mail_identity_set_address (
+				E_SOURCE_MAIL_IDENTITY (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_NAME:
+			e_source_mail_identity_set_name (
+				E_SOURCE_MAIL_IDENTITY (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_ORGANIZATION:
+			e_source_mail_identity_set_organization (
+				E_SOURCE_MAIL_IDENTITY (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_REPLY_TO:
+			e_source_mail_identity_set_reply_to (
+				E_SOURCE_MAIL_IDENTITY (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_SIGNATURE_UID:
+			e_source_mail_identity_set_signature_uid (
+				E_SOURCE_MAIL_IDENTITY (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_mail_identity_get_property (GObject *object,
+                                   guint property_id,
+                                   GValue *value,
+                                   GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ADDRESS:
+			g_value_set_string (
+				value,
+				e_source_mail_identity_get_address (
+				E_SOURCE_MAIL_IDENTITY (object)));
+			return;
+
+		case PROP_NAME:
+			g_value_set_string (
+				value,
+				e_source_mail_identity_get_name (
+				E_SOURCE_MAIL_IDENTITY (object)));
+			return;
+
+		case PROP_ORGANIZATION:
+			g_value_set_string (
+				value,
+				e_source_mail_identity_get_organization (
+				E_SOURCE_MAIL_IDENTITY (object)));
+			return;
+
+		case PROP_REPLY_TO:
+			g_value_set_string (
+				value,
+				e_source_mail_identity_get_reply_to (
+				E_SOURCE_MAIL_IDENTITY (object)));
+			return;
+
+		case PROP_SIGNATURE_UID:
+			g_value_set_string (
+				value,
+				e_source_mail_identity_get_signature_uid (
+				E_SOURCE_MAIL_IDENTITY (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_mail_identity_finalize (GObject *object)
+{
+	ESourceMailIdentityPrivate *priv;
+
+	priv = E_SOURCE_MAIL_IDENTITY_GET_PRIVATE (object);
+
+	g_free (priv->address);
+	g_free (priv->name);
+	g_free (priv->organization);
+	g_free (priv->reply_to);
+	g_free (priv->signature_uid);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_mail_identity_parent_class)->finalize (object);
+}
+
+static void
+e_source_mail_identity_class_init (ESourceMailIdentityClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceMailIdentityPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_mail_identity_set_property;
+	object_class->get_property = source_mail_identity_get_property;
+	object_class->finalize = source_mail_identity_finalize;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ADDRESS,
+		g_param_spec_string (
+			"address",
+			"Address",
+			"Sender's email address",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_NAME,
+		g_param_spec_string (
+			"name",
+			"Name",
+			"Sender's name",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ORGANIZATION,
+		g_param_spec_string (
+			"organization",
+			"Organization",
+			"Sender's organization",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_REPLY_TO,
+		g_param_spec_string (
+			"reply-to",
+			"Reply-To",
+			"Sender's reply-to address",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SIGNATURE_UID,
+		g_param_spec_string (
+			"signature-uid",
+			"Signature UID",
+			"ESource UID of the sender's signature",
+			"none",
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_mail_identity_init (ESourceMailIdentity *extension)
+{
+	extension->priv = E_SOURCE_MAIL_IDENTITY_GET_PRIVATE (extension);
+}
+
+/**
+ * e_source_mail_identity_get_address:
+ * @extension: an #ESourceMailIdentity
+ *
+ * Returns the email address for this identity from which to send messages.
+ *
+ * Returns: the sender's email address
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_mail_identity_get_address (ESourceMailIdentity *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_IDENTITY (extension), NULL);
+
+	return extension->priv->address;
+}
+
+/**
+ * e_source_mail_identity_set_address:
+ * @extension: an #ESourceMailIdentity
+ * @address: the sender's email address, or %NULL
+ *
+ * Sets the email address for this identity from which to send messages.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_identity_set_address (ESourceMailIdentity *extension,
+                                    const gchar *address)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_IDENTITY (extension));
+
+	g_free (extension->priv->address);
+	extension->priv->address = g_strdup (address);
+
+	g_object_notify (G_OBJECT (extension), "address");
+}
+
+/**
+ * e_source_mail_identity_get_name:
+ * @extension: an #ESourceMailIdentity
+ *
+ * Returns the sender's name for this identity.
+ *
+ * Returns: the sender's name
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_mail_identity_get_name (ESourceMailIdentity *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_IDENTITY (extension), NULL);
+
+	return extension->priv->name;
+}
+
+/**
+ * e_source_mail_identity_set_name:
+ * @extension: an #ESourceMailIdentity
+ * @name: the sender's name, or %NULL
+ *
+ * Sets the sender's name for this identity.  If @name is %NULL or
+ * an empty string, the return value of g_get_real_name() is used.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_identity_set_name (ESourceMailIdentity *extension,
+                                 const gchar *name)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_IDENTITY (extension));
+
+	if (name == NULL || *name == '\0')
+		name = g_get_real_name ();
+
+	g_free (extension->priv->name);
+	extension->priv->name = g_strdup (name);
+
+	g_object_notify (G_OBJECT (extension), "name");
+}
+
+/**
+ * e_source_mail_identity_get_organization:
+ * @extension: an #ESourceMailIdentity
+ *
+ * Returns the sender's organization for this identity.
+ *
+ * Returns: the sender's organization
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_mail_identity_get_organization (ESourceMailIdentity *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_IDENTITY (extension), NULL);
+
+	return extension->priv->organization;
+}
+
+/**
+ * e_source_mail_identity_set_organization:
+ * @extension: an #ESourceMailIdentity
+ * @organization: the sender's organization, or %NULL
+ *
+ * Sets the sender's organization for this identity.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_identity_set_organization (ESourceMailIdentity *extension,
+                                         const gchar *organization)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_IDENTITY (extension));
+
+	g_free (extension->priv->organization);
+	extension->priv->organization = g_strdup (organization);
+
+	g_object_notify (G_OBJECT (extension), "organization");
+}
+
+/**
+ * e_source_mail_identity_get_reply_to:
+ * @extension: an #ESourceMailIdentity
+ *
+ * Returns the email address for this identity to which recipients should
+ * send replies.
+ *
+ * Returns: the sender's reply-to address
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_mail_identity_get_reply_to (ESourceMailIdentity *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_IDENTITY (extension), NULL);
+
+	return extension->priv->reply_to;
+}
+
+/**
+ * e_source_mail_identity_set_reply_to:
+ * @extension: an #ESourceMailIdentity
+ * @reply_to: the sender's reply-to address, or %NULL
+ *
+ * Sets the email address for this identity to which recipients should
+ * send replies.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_identity_set_reply_to (ESourceMailIdentity *extension,
+                                     const gchar *reply_to)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_IDENTITY (extension));
+
+	g_free (extension->priv->reply_to);
+	extension->priv->reply_to = g_strdup (reply_to);
+
+	g_object_notify (G_OBJECT (extension), "reply-to");
+}
+
+/**
+ * e_source_mail_identity_get_signature:
+ * @extension: an #ESourceMailIdentity
+ *
+ * Convenience function that uses e_source_extension_resolve_reference()
+ * to resolve @extension's #ESourceMailIdentity:signature-uid property to
+ * an #ESource instance with a matching #ESource:uid.
+ *
+ * If no matching #ESource is found, or if the matching #ESource does not
+ * have an #ESourceMailSignature extension, the function returns %NULL.
+ *
+ * Returns: a matching #ESource instance, or %NULL
+ *
+ * Since: 3.4
+ **/
+ESource *
+e_source_mail_identity_get_signature (ESourceMailIdentity *extension)
+{
+	const gchar *extension_name;
+	const gchar *uid;
+
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_IDENTITY (extension), NULL);
+
+	extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
+	uid = e_source_mail_identity_get_signature_uid (extension);
+
+	return e_source_extension_resolve_reference (
+		E_SOURCE_EXTENSION (extension), uid, extension_name);
+}
+
+/**
+ * e_source_mail_identity_get_signature_uid:
+ * @extension: an #ESourceMailIdentity
+ *
+ * Returns the #ESource:uid of an #ESource describing a mail signature.
+ *
+ * If the user does not want to use a signature for this identity, the
+ * convention is to set the #ESourceMailIdentity:signature property to
+ * "none".
+ *
+ * Returns: the sender's signature ID, or "none"
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_mail_identity_get_signature_uid (ESourceMailIdentity *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_IDENTITY (extension), NULL);
+
+	return extension->priv->signature_uid;
+}
+
+/**
+ * e_source_mail_identity_set_signature:
+ * @extension: an #ESourceMailIdentity
+ * @signature: the sender's signature ID, or %NULL
+ *
+ * Sets the #ESource:uid of an #ESource describing a mail signature.
+ *
+ * If the user does not want to use a signature for this identity, the
+ * convention is to set the #ESourceMailIdentity:signature property to
+ * "none".  In keeping with that convention, the property will be set
+ * to "none" if @signature is %NULL or an empty string.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_identity_set_signature_uid (ESourceMailIdentity *extension,
+                                          const gchar *signature_uid)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_IDENTITY (extension));
+
+	/* Convert empty strings to "none". */
+	if (signature_uid == NULL || *signature_uid == '\0')
+		signature_uid = "none";
+
+	g_free (extension->priv->signature_uid);
+	extension->priv->signature_uid = g_strdup (signature_uid);
+
+	g_object_notify (G_OBJECT (extension), "signature-uid");
+}
+
diff --git a/libedataserver/e-source-mail-identity.h b/libedataserver/e-source-mail-identity.h
new file mode 100644
index 0000000..b6f44dd
--- /dev/null
+++ b/libedataserver/e-source-mail-identity.h
@@ -0,0 +1,107 @@
+/*
+ * e-source-mail-identity.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_MAIL_IDENTITY_H
+#define E_SOURCE_MAIL_IDENTITY_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_MAIL_IDENTITY \
+	(e_source_mail_identity_get_type ())
+#define E_SOURCE_MAIL_IDENTITY(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_MAIL_IDENTITY, ESourceMailIdentity))
+#define E_SOURCE_MAIL_IDENTITY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_MAIL_IDENTITY, ESourceMailIdentityClass))
+#define E_IS_SOURCE_MAIL_IDENTITY(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_MAIL_IDENTITY))
+#define E_IS_SOURCE_MAIL_IDENTITY_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_MAIL_IDENTITY))
+#define E_SOURCE_MAIL_IDENTITY_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_MAIL_IDENTITY, ESourceMailIdentityClass))
+
+/**
+ * E_SOURCE_EXTENSION_MAIL_IDENTITY:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceMailIdentity.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_MAIL_IDENTITY "Mail Identity"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceMailIdentity ESourceMailIdentity;
+typedef struct _ESourceMailIdentityClass ESourceMailIdentityClass;
+typedef struct _ESourceMailIdentityPrivate ESourceMailIdentityPrivate;
+
+/**
+ * ESourceMailIdentity:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceMailIdentity {
+	ESourceExtension parent;
+	ESourceMailIdentityPrivate *priv;
+};
+
+struct _ESourceMailIdentityClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_mail_identity_get_type (void);
+const gchar *	e_source_mail_identity_get_address
+					(ESourceMailIdentity *extension);
+void		e_source_mail_identity_set_address
+					(ESourceMailIdentity *extension,
+					 const gchar *address);
+const gchar *	e_source_mail_identity_get_name
+					(ESourceMailIdentity *extension);
+void		e_source_mail_identity_set_name
+					(ESourceMailIdentity *extension,
+					 const gchar *name);
+const gchar *	e_source_mail_identity_get_organization
+					(ESourceMailIdentity *extension);
+void		e_source_mail_identity_set_organization
+					(ESourceMailIdentity *extension,
+					 const gchar *organization);
+const gchar *	e_source_mail_identity_get_reply_to
+					(ESourceMailIdentity *extension);
+void		e_source_mail_identity_set_reply_to
+					(ESourceMailIdentity *extension,
+					 const gchar *reply_to);
+ESource *	e_source_mail_identity_get_signature
+					(ESourceMailIdentity *extension);
+const gchar *	e_source_mail_identity_get_signature_uid
+					(ESourceMailIdentity *extension);
+void		e_source_mail_identity_set_signature_uid
+					(ESourceMailIdentity *extension,
+					 const gchar *signature_uid);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_MAIL_IDENTITY_H */
diff --git a/libedataserver/e-source-mail-signature.c b/libedataserver/e-source-mail-signature.c
new file mode 100644
index 0000000..a0c6e94
--- /dev/null
+++ b/libedataserver/e-source-mail-signature.c
@@ -0,0 +1,721 @@
+/*
+ * e-source-mail-signature.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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-mail-signature
+ * @include: libedataserver/e-source-mail-signature.h
+ * @short_description: #ESource extension for email signatures
+ *
+ * The #ESourceMailSignature extension refers to a personalized email
+ * signature.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-mail-signature.h>
+ *
+ *   ESourceMailSignature *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_SIGNATURE);
+ * ]|
+ **/
+
+#include "e-source-mail-signature.h"
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#include <libedataserver/e-data-server-util.h>
+
+#define E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_MAIL_SIGNATURE, ESourceMailSignaturePrivate))
+
+typedef struct _Context Context;
+
+struct _ESourceMailSignaturePrivate {
+	GFile *file;
+	gchar *mime_type;
+};
+
+struct _Context {
+	GFile *file;
+	gint io_priority;
+	GCancellable *cancellable;
+	gchar *contents;
+	gchar *mime_type;
+};
+
+enum {
+	PROP_0,
+	PROP_FILE,
+	PROP_MIME_TYPE
+};
+
+G_DEFINE_TYPE (
+	ESourceMailSignature,
+	e_source_mail_signature,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+context_free (Context *context)
+{
+	if (context->file != NULL)
+		g_object_unref (context->file);
+
+	if (context->cancellable != NULL)
+		g_object_unref (context->cancellable);
+
+	g_free (context->contents);
+	g_free (context->mime_type);
+
+	g_slice_free (Context, context);
+}
+
+static void
+source_mail_signature_set_property (GObject *object,
+                                    guint property_id,
+                                    const GValue *value,
+                                    GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_MIME_TYPE:
+			e_source_mail_signature_set_mime_type (
+				E_SOURCE_MAIL_SIGNATURE (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_mail_signature_get_property (GObject *object,
+                                    guint property_id,
+                                    GValue *value,
+                                    GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_FILE:
+			g_value_set_object (
+				value,
+				e_source_mail_signature_get_file (
+				E_SOURCE_MAIL_SIGNATURE (object)));
+			return;
+
+		case PROP_MIME_TYPE:
+			g_value_set_string (
+				value,
+				e_source_mail_signature_get_mime_type (
+				E_SOURCE_MAIL_SIGNATURE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_mail_signature_dispose (GObject *object)
+{
+	ESourceMailSignaturePrivate *priv;
+
+	priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (object);
+
+	if (priv->file != NULL) {
+		g_object_unref (priv->file);
+		priv->file = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (e_source_mail_signature_parent_class)->
+		dispose (object);
+}
+
+static void
+source_mail_signature_finalize (GObject *object)
+{
+	ESourceMailSignaturePrivate *priv;
+
+	priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (object);
+
+	g_free (priv->mime_type);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_mail_signature_parent_class)->
+		finalize (object);
+}
+
+static void
+source_mail_signature_constructed (GObject *object)
+{
+	ESourceMailSignaturePrivate *priv;
+	ESourceExtension *extension;
+	ESource *source;
+	const gchar *config_dir;
+	const gchar *uid;
+	gchar *path;
+
+	priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (object);
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (e_source_mail_signature_parent_class)->
+		constructed (object);
+
+	extension = E_SOURCE_EXTENSION (object);
+	source = e_source_extension_get_source (extension);
+	uid = e_source_get_uid (source);
+
+	config_dir = e_get_user_config_dir ();
+	path = g_build_filename (config_dir, "signatures", uid, NULL);
+	priv->file = g_file_new_for_path (path);
+	g_free (path);
+}
+
+static void
+e_source_mail_signature_class_init (ESourceMailSignatureClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (
+		class, sizeof (ESourceMailSignaturePrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_mail_signature_set_property;
+	object_class->get_property = source_mail_signature_get_property;
+	object_class->dispose = source_mail_signature_dispose;
+	object_class->finalize = source_mail_signature_finalize;
+	object_class->constructed = source_mail_signature_constructed;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FILE,
+		g_param_spec_object (
+			"file",
+			"File",
+			"File containing signature content",
+			G_TYPE_FILE,
+			G_PARAM_READABLE |
+			G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MIME_TYPE,
+		g_param_spec_string (
+			"mime-type",
+			"MIME Type",
+			"MIME type of the signature content",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_mail_signature_init (ESourceMailSignature *extension)
+{
+	extension->priv = E_SOURCE_MAIL_SIGNATURE_GET_PRIVATE (extension);
+}
+
+/**
+ * e_source_mail_signature_get_file:
+ * @extension: an #ESourceMailSignature
+ *
+ * Returns a #GFile instance pointing to the signature file for @extension.
+ * The signature file may be a regular file containing the static signature
+ * content, or it may be a symbolic link to an executable file that produces
+ * the signature content.
+ *
+ * e_source_mail_signature_load() uses this to load the signature content.
+ *
+ * Returns: a #GFile
+ *
+ * Since: 3.4
+ **/
+GFile *
+e_source_mail_signature_get_file (ESourceMailSignature *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_SIGNATURE (extension), NULL);
+
+	return extension->priv->file;
+}
+
+/**
+ * e_source_mail_signature_get_mime_type:
+ * @extension: an #ESourceMailSignature
+ *
+ * Returns the MIME type of the signature content for @extension, or %NULL
+ * if it has not yet been determined.
+ *
+ * e_source_mail_signature_load() sets this automatically if the MIME type
+ * has not yet been determined.
+ *
+ * Returns: the MIME type of the signature content, or %NULL
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_mail_signature_get_mime_type (ESourceMailSignature *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_SIGNATURE (extension), NULL);
+
+	return extension->priv->mime_type;
+}
+
+/**
+ * e_source_mail_signature_set_mime_type:
+ * @extension: an #ESourceMailSignature
+ * @mime_type: a MIME type, or %NULL
+ *
+ * Sets the MIME type of the signature content for @extension.
+ *
+ * e_source_mail_signature_load() sets this automatically if the MIME type
+ * has not yet been determined.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_signature_set_mime_type (ESourceMailSignature *extension,
+                                       const gchar *mime_type)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_SIGNATURE (extension));
+
+	g_free (extension->priv->mime_type);
+	extension->priv->mime_type = g_strdup (mime_type);
+
+	g_object_notify (G_OBJECT (extension), "mime-type");
+}
+
+/********************** e_source_mail_signature_load() ***********************/
+
+static void
+source_mail_signature_run_script (GSimpleAsyncResult *simple,
+                                  ESource *source,
+                                  GCancellable *cancellable)
+{
+	Context *context;
+	gchar *command_line;
+	gchar *content_type;
+	gchar *path;
+	GError *error = NULL;
+
+	context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	path = g_file_get_path (context->file);
+
+	if (path == NULL) {
+		g_simple_async_result_set_error (
+			simple, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+			_("Signature script must be a local file"));
+		return;
+	}
+
+	/* Enclose the path in single-quotes for compatibility on Windows.
+	 * (See g_spawn_command_line_sync() documentation for rationale.) */
+	command_line = g_strdup_printf ("'%s'", path);
+
+	g_spawn_command_line_sync (
+		command_line, &context->contents, NULL, NULL, &error);
+
+	g_free (command_line);
+	g_free (path);
+
+	/* Check if we failed to spawn the script. */
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+		return;
+	}
+
+	/* Check if we were cancelled while the script was running. */
+	if (g_cancellable_set_error_if_cancelled (cancellable, &error)) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+		return;
+	}
+
+	/* Signature scripts are supposed to generate UTF-8 content, but
+	 * because users are known to never read the manual, we try to do
+	 * our best if the content isn't valid UTF-8 by assuming that the
+	 * content is in the user's locale character set. */
+	if (!g_utf8_validate (context->contents, -1, NULL)) {
+		gchar *utf8;
+
+		utf8 = g_locale_to_utf8 (
+			context->contents, -1, NULL, NULL, &error);
+
+		if (error != NULL) {
+			g_warn_if_fail (utf8 == NULL);
+			g_simple_async_result_set_from_error (simple, error);
+			g_error_free (error);
+			return;
+		}
+
+		g_free (context->contents);
+		context->contents = utf8;
+	}
+
+	g_free (context->mime_type);
+
+	/* Try and guess the content type of the script output
+	 * so it can be applied correctly to the mail message. */
+	content_type = g_content_type_guess (
+		NULL, (guchar *) context->contents,
+		strlen (context->contents), NULL);
+	context->mime_type = g_content_type_get_mime_type (content_type);
+	g_free (content_type);
+}
+
+static void
+source_mail_signature_load_cb (GFile *file,
+                               GAsyncResult *result,
+                               GSimpleAsyncResult *simple)
+{
+	Context *context;
+	gsize length;
+	GError *error = NULL;
+
+	context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	g_file_load_contents_finish (
+		file, result, &context->contents, &length, NULL, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_simple_async_result_complete (simple);
+		g_object_unref (simple);
+		g_error_free (error);
+		return;
+	}
+
+	/* Signatures are saved as UTF-8, but we still need to check that
+	 * the signature is valid UTF-8 because the user may be opening a
+	 * signature file that is in his/her locale character set.  If it
+	 * is not UTF-8 then try converting from the current locale. */
+	if (!g_utf8_validate (context->contents, length, NULL)) {
+		gchar *utf8;
+
+		utf8 = g_locale_to_utf8 (
+			context->contents, length, NULL, NULL, &error);
+
+		if (error != NULL) {
+			g_warn_if_fail (utf8 == NULL);
+			g_simple_async_result_set_from_error (simple, error);
+			g_simple_async_result_complete (simple);
+			g_object_unref (simple);
+			g_error_free (error);
+			return;
+		}
+
+		g_free (context->contents);
+		context->contents = utf8;
+	}
+
+	g_simple_async_result_complete (simple);
+
+	g_object_unref (simple);
+}
+
+static void
+source_mail_signature_query_cb (GFile *file,
+                                GAsyncResult *result,
+                                GSimpleAsyncResult *simple)
+{
+	Context *context;
+	GFileInfo *file_info;
+	const gchar *content_type;
+	gboolean can_execute;
+	GError *error = NULL;
+
+	context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	file_info = g_file_query_info_finish (file, result, &error);
+
+	if (error != NULL) {
+		g_warn_if_fail (file_info == NULL);
+		g_simple_async_result_set_from_error (simple, error);
+		g_simple_async_result_complete (simple);
+		g_object_unref (simple);
+		g_error_free (error);
+		return;
+	}
+
+	g_return_if_fail (G_IS_FILE_INFO (file_info));
+
+	can_execute = g_file_info_get_attribute_boolean (
+		file_info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE);
+
+	content_type = g_file_info_get_content_type (file_info);
+	context->mime_type = g_content_type_get_mime_type (content_type);
+
+	/* If this is a script then do the rest on a thread. */
+	if (can_execute)
+		g_simple_async_result_run_in_thread (
+			simple, (GSimpleAsyncThreadFunc)
+			source_mail_signature_run_script,
+			context->io_priority,
+			context->cancellable);
+	else
+		g_file_load_contents_async (
+			file, context->cancellable,
+			(GAsyncReadyCallback) source_mail_signature_load_cb,
+			g_object_ref (simple));
+
+	g_object_unref (file_info);
+	g_object_unref (simple);
+}
+
+/**
+ * e_source_mail_signature_load:
+ * @source: an #ESource
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously loads a signature from the signature file for @source,
+ * which is given by e_source_mail_signature_get_file().
+ *
+ * If the signature file is executable, it will be executed and its output
+ * captured as the email signature content.  If the signature file is not
+ * executable, the email signature content is read directly from the file.
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call e_source_mail_signature_load_finish() to get the result of
+ * the operation.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_signature_load (ESource *source,
+                              gint io_priority,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+	ESourceMailSignature *extension;
+	GSimpleAsyncResult *simple;
+	Context *context;
+	GFile *file;
+	const gchar *extension_name;
+
+	g_return_if_fail (E_IS_SOURCE (source));
+
+	extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
+	extension = e_source_get_extension (source, extension_name);
+	file = e_source_mail_signature_get_file (extension);
+
+	context = g_slice_new0 (Context);
+	context->file = g_object_ref (file);
+	context->io_priority = io_priority;
+
+	if (G_IS_CANCELLABLE (cancellable))
+		context->cancellable = g_object_ref (cancellable);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (source),
+		callback, user_data,
+		e_source_mail_signature_load);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, context, (GDestroyNotify) context_free);
+
+	/* Query the file's content type and whether it's executable. */
+	g_file_query_info_async (
+		context->file,
+		G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE ","
+		G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+		G_FILE_QUERY_INFO_NONE, context->io_priority,
+		context->cancellable, (GAsyncReadyCallback)
+		source_mail_signature_query_cb, simple);
+}
+
+/**
+ * e_source_mail_signature_load_finish:
+ * @source: an #ESource
+ * @result: a #GAsyncResult obtained from the #GAsyncReadyCallback
+ *          passed to e_source_mail_signature_load()
+ * @contents: return location for the signature content
+ * @length: return location for the length of the signature content,
+ *          or %NULL if the length is not needed
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes an operation started with e_source_mail_signature_load().  The
+ * signature file contents are placed in @contents, and @length is set to
+ * the size of the @contents string.  The @contents string should be freed
+ * with g_free() when no longer needed.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_mail_signature_load_finish (ESource *source,
+                                     GAsyncResult *result,
+                                     gchar **contents,
+                                     gsize *length,
+                                     GError **error)
+{
+	ESourceMailSignature *extension;
+	GSimpleAsyncResult *simple;
+	Context *context;
+	const gchar *extension_name;
+	const gchar *mime_type;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (source),
+		e_source_mail_signature_load), FALSE);
+
+	g_return_val_if_fail (contents != NULL, 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;
+
+	extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
+	extension = e_source_get_extension (source, extension_name);
+	mime_type = e_source_mail_signature_get_mime_type (extension);
+
+	/* Don't override the MIME type if it's already set. */
+	if (mime_type == NULL || *mime_type == '\0')
+		e_source_mail_signature_set_mime_type (
+			extension, context->mime_type);
+
+	g_return_val_if_fail (context->contents != NULL, FALSE);
+
+	if (length != NULL)
+		*length = strlen (context->contents);
+
+	*contents = context->contents;
+	context->contents = NULL;
+
+	return TRUE;
+}
+
+/********************* e_source_mail_signature_replace() *********************/
+
+static void
+source_mail_signature_replace_cb (GFile *file,
+                                  GAsyncResult *result,
+                                  GSimpleAsyncResult *simple)
+{
+	GError *error = NULL;
+
+	g_file_replace_contents_finish (file, result, NULL, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (simple, error);
+		g_error_free (error);
+	}
+
+	g_simple_async_result_complete (simple);
+
+	g_object_unref (simple);
+}
+
+/**
+ * e_source_mail_signature_replace:
+ * @source: an #ESource
+ * @contents: the signature contents
+ * @length: the length of @contents in bytes
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchrously replaces the signature file for @source with the given
+ * @contents of @length bytes.  The signature file for @source is given
+ * by e_source_mail_signature_get_file().
+ *
+ * When the operation is finished, @callback will be called.  You can
+ * then call e_source_mail_signature_replace_finish() to get the result
+ * of the operation.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_signature_replace (ESource *source,
+                                 const gchar *contents,
+                                 gsize length,
+                                 gint io_priority,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+	ESourceMailSignature *extension;
+	GSimpleAsyncResult *simple;
+	GFile *file;
+	const gchar *extension_name;
+
+	g_return_if_fail (E_IS_SOURCE (source));
+	g_return_if_fail (contents != NULL);
+
+	extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
+	extension = e_source_get_extension (source, extension_name);
+	file = e_source_mail_signature_get_file (extension);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (source),
+		callback, user_data,
+		e_source_mail_signature_replace);
+
+	g_file_replace_contents_async (
+		file, contents, length, NULL, FALSE,
+		G_FILE_CREATE_REPLACE_DESTINATION,
+		cancellable, (GAsyncReadyCallback)
+		source_mail_signature_replace_cb, simple);
+}
+
+/**
+ * e_source_mail_signature_replace_finish:
+ * @source: an #ESource
+ * @result: a #GAsyncResult obtained from the #GAsyncReadyCallback
+ *          passed to e_source_mail_signature_replace()
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes an operation started with e_source_mail_signature_replace().
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_mail_signature_replace_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_mail_signature_replace), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
diff --git a/libedataserver/e-source-mail-signature.h b/libedataserver/e-source-mail-signature.h
new file mode 100644
index 0000000..d410cf8
--- /dev/null
+++ b/libedataserver/e-source-mail-signature.h
@@ -0,0 +1,112 @@
+/*
+ * e-source-mail-signature.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_MAIL_SIGNATURE_H
+#define E_SOURCE_MAIL_SIGNATURE_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_MAIL_SIGNATURE \
+	(e_source_mail_signature_get_type ())
+#define E_SOURCE_MAIL_SIGNATURE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_MAIL_SIGNATURE, ESourceMailSignature))
+#define E_SOURCE_MAIL_SIGNATURE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_MAIL_SIGNATURE, ESourceMailSignatureClass))
+#define E_IS_SOURCE_MAIL_SIGNATURE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_MAIL_SIGNATURE))
+#define E_IS_SOURCE_MAIL_SIGNATURE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_MAIL_SIGNATURE))
+#define E_SOURCE_MAIL_SIGNATURE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_MAIL_SIGNATURE, ESourceMailSignatureClass))
+
+/**
+ * E_SOURCE_EXTENSION_MAIL_SIGNATURE:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceMailSignature.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_MAIL_SIGNATURE "Mail Signature"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceMailSignature ESourceMailSignature;
+typedef struct _ESourceMailSignatureClass ESourceMailSignatureClass;
+typedef struct _ESourceMailSignaturePrivate ESourceMailSignaturePrivate;
+
+/**
+ * ESourceMailSignature:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * function below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceMailSignature {
+	ESourceExtension parent;
+	ESourceMailSignaturePrivate *priv;
+};
+
+struct _ESourceMailSignatureClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_mail_signature_get_type (void);
+GFile *		e_source_mail_signature_get_file
+					(ESourceMailSignature *extension);
+const gchar *	e_source_mail_signature_get_mime_type
+					(ESourceMailSignature *extension);
+void		e_source_mail_signature_set_mime_type
+					(ESourceMailSignature *extension,
+					 const gchar *mime_type);
+
+void		e_source_mail_signature_load
+					(ESource *source,
+					 gint io_priority,
+					 GCancellable *cancellable,
+					 GAsyncReadyCallback callback,
+					 gpointer user_data);
+gboolean	e_source_mail_signature_load_finish
+					(ESource *source,
+					 GAsyncResult *result,
+					 gchar **contents,
+					 gsize *length,
+					 GError **error);
+void		e_source_mail_signature_replace
+					(ESource *source,
+					 const gchar *contents,
+					 gsize length,
+					 gint io_priority,
+					 GCancellable *cancellable,
+					 GAsyncReadyCallback callback,
+					 gpointer user_data);
+gboolean	e_source_mail_signature_replace_finish
+					(ESource *source,
+					 GAsyncResult *result,
+					 GError **error);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_MAIL_SIGNATURE_H */
diff --git a/libedataserver/e-source-mail-submission.c b/libedataserver/e-source-mail-submission.c
new file mode 100644
index 0000000..0458da5
--- /dev/null
+++ b/libedataserver/e-source-mail-submission.c
@@ -0,0 +1,285 @@
+/*
+ * e-source-mail-submission.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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-mail-submission
+ * @include: libedataserver/e-source-mail-submission.h
+ * @short_description: #ESource extension for submitting emails
+ *
+ * The #ESourceMailSubmission extension tracks settings to be applied
+ * when submitting a mail message for delivery.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-mail-submission.h>
+ *
+ *   ESourceMailSubmission *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_SUBMISSION);
+ * ]|
+ **/
+
+#include "e-source-mail-submission.h"
+
+#include <libedataserver/e-source-mail-transport.h>
+
+#define E_SOURCE_MAIL_SUBMISSION_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_MAIL_SUBMISSION, ESourceMailSubmissionPrivate))
+
+struct _ESourceMailSubmissionPrivate {
+	gchar *sent_folder;
+	gchar *transport_uid;
+};
+
+enum {
+	PROP_0,
+	PROP_SENT_FOLDER,
+	PROP_TRANSPORT_UID
+};
+
+G_DEFINE_TYPE (
+	ESourceMailSubmission,
+	e_source_mail_submission,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_mail_submission_set_property (GObject *object,
+                                     guint property_id,
+                                     const GValue *value,
+                                     GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SENT_FOLDER:
+			e_source_mail_submission_set_sent_folder (
+				E_SOURCE_MAIL_SUBMISSION (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_TRANSPORT_UID:
+			e_source_mail_submission_set_transport_uid (
+				E_SOURCE_MAIL_SUBMISSION (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_mail_submission_get_property (GObject *object,
+                                     guint property_id,
+                                     GValue *value,
+                                     GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SENT_FOLDER:
+			g_value_set_string (
+				value,
+				e_source_mail_submission_get_sent_folder (
+				E_SOURCE_MAIL_SUBMISSION (object)));
+			return;
+
+		case PROP_TRANSPORT_UID:
+			g_value_set_string (
+				value,
+				e_source_mail_submission_get_transport_uid (
+				E_SOURCE_MAIL_SUBMISSION (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_mail_submission_finalize (GObject *object)
+{
+	ESourceMailSubmissionPrivate *priv;
+
+	priv = E_SOURCE_MAIL_SUBMISSION_GET_PRIVATE (object);
+
+	g_free (priv->sent_folder);
+	g_free (priv->transport_uid);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_mail_submission_parent_class)->
+		finalize (object);
+}
+
+static void
+e_source_mail_submission_class_init (ESourceMailSubmissionClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (
+		class, sizeof (ESourceMailSubmissionPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_mail_submission_set_property;
+	object_class->get_property = source_mail_submission_get_property;
+	object_class->finalize = source_mail_submission_finalize;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_MAIL_SUBMISSION;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SENT_FOLDER,
+		g_param_spec_string (
+			"sent-folder",
+			"Sent Folder",
+			"Preferred folder for sent messages",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_TRANSPORT_UID,
+		g_param_spec_string (
+			"transport-uid",
+			"Transport UID",
+			"ESource UID of a Mail Transport",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_mail_submission_init (ESourceMailSubmission *extension)
+{
+	extension->priv = E_SOURCE_MAIL_SUBMISSION_GET_PRIVATE (extension);
+}
+
+/**
+ * e_source_mail_submission_get_sent_folder:
+ * @extension: an #ESourceMailSubmission
+ *
+ * Returns a string identifying the preferred folder for sent messages.
+ * The format of the identifier string is defined by the client application.
+ *
+ * Returns: an identifier for the preferred sent folder
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_mail_submission_get_sent_folder (ESourceMailSubmission *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_SUBMISSION (extension), NULL);
+
+	return extension->priv->sent_folder;
+}
+
+/**
+ * e_source_mail_submission_set_sent_folder:
+ * @extension: an #ESourceMailIdentity
+ * @sent_folder: an identifier for the preferred sent folder, or %NULL
+ *
+ * Sets the preferred folder for sent messages by an identifier string.
+ * The format of the identifier string is defined by the client application.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_submission_set_sent_folder (ESourceMailSubmission *extension,
+                                          const gchar *sent_folder)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_SUBMISSION (extension));
+
+	g_free (extension->priv->sent_folder);
+	extension->priv->sent_folder = g_strdup (sent_folder);
+
+	g_object_notify (G_OBJECT (extension), "sent-folder");
+}
+
+/**
+ * e_source_mail_submission_get_transport:
+ * @extension: an #ESourceMailSubmission
+ *
+ * Convenience function that uses e_source_extension_resolve_reference()
+ * to resolve @extension's #ESourceMailSubmission:transport-uid property
+ * to an #ESource instance with a matching #ESource:uid.
+ *
+ * If no matching #ESource is found, or if the matching #ESource does not
+ * have an #ESourceMailTransport extension, the function returns %NULL.
+ *
+ * Returns: a matching #ESource instance, or %NULL
+ *
+ * Since: 3.4
+ **/
+ESource *
+e_source_mail_submission_get_transport (ESourceMailSubmission *extension)
+{
+	const gchar *extension_name;
+	const gchar *uid;
+
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_SUBMISSION (extension), NULL);
+
+	extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
+	uid = e_source_mail_submission_get_transport_uid (extension);
+
+	return e_source_extension_resolve_reference (
+		E_SOURCE_EXTENSION (extension), uid, extension_name);
+}
+
+/**
+ * e_source_mail_submission_get_transport_uid:
+ * @extension: an #ESourceMailSubmission
+ *
+ * Returns the #ESource:uid of the #ESource that describes the mail
+ * transport to be used for outgoing messages.
+ *
+ * Returns: the mail transport #ESource:uid
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_mail_submission_get_transport_uid (ESourceMailSubmission *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_MAIL_SUBMISSION (extension), NULL);
+
+	return extension->priv->transport_uid;
+}
+
+/**
+ * e_source_mail_submission_set_transport_uid:
+ * @extension: an #ESourceMailSubmission
+ * @transport_uid: the mail transport #ESource:uid, or %NULL
+ *
+ * Sets the #ESource:uid of the #ESource that describes the mail
+ * transport to be used for outgoing messages.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_mail_submission_set_transport_uid (ESourceMailSubmission *extension,
+                                            const gchar *transport_uid)
+{
+	g_return_if_fail (E_IS_SOURCE_MAIL_SUBMISSION (extension));
+
+	g_free (extension->priv->transport_uid);
+	extension->priv->transport_uid = g_strdup (transport_uid);
+
+	g_object_notify (G_OBJECT (extension), "transport-uid");
+}
diff --git a/libedataserver/e-source-mail-submission.h b/libedataserver/e-source-mail-submission.h
new file mode 100644
index 0000000..019af26
--- /dev/null
+++ b/libedataserver/e-source-mail-submission.h
@@ -0,0 +1,92 @@
+/*
+ * e-source-mail-submission.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_MAIL_SUBMISSION_H
+#define E_SOURCE_MAIL_SUBMISSION_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_MAIL_SUBMISSION \
+	(e_source_mail_submission_get_type ())
+#define E_SOURCE_MAIL_SUBMISSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_MAIL_SUBMISSION, ESourceMailSubmission))
+#define E_SOURCE_MAIL_SUBMISSION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_MAIL_SUBMISSION, ESourceMailSubmissionClass))
+#define E_IS_SOURCE_MAIL_SUBMISSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_MAIL_SUBMISSION))
+#define E_IS_SOURCE_MAIL_SUBMISSION_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_MAIL_SUBMISSION))
+#define E_SOURCE_MAIL_SUBMISSION_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_MAIL_SUBMISSION, ESourceMailSubmissionClass))
+
+/**
+ * E_SOURCE_EXTENSION_MAIL_SUBMISSION:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceMailSubmission.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_MAIL_SUBMISSION "Mail Submission"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceMailSubmission ESourceMailSubmission;
+typedef struct _ESourceMailSubmissionClass ESourceMailSubmissionClass;
+typedef struct _ESourceMailSubmissionPrivate ESourceMailSubmissionPrivate;
+
+/**
+ * ESourceMailSubmission:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * function below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceMailSubmission {
+	ESourceExtension parent;
+	ESourceMailSubmissionPrivate *priv;
+};
+
+struct _ESourceMailSubmissionClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_mail_submission_get_type (void);
+const gchar *	e_source_mail_submission_get_sent_folder
+					(ESourceMailSubmission *extension);
+void		e_source_mail_submission_set_sent_folder
+					(ESourceMailSubmission *extension,
+					 const gchar *sent_folder);
+ESource *	e_source_mail_submission_get_transport
+					(ESourceMailSubmission *extension);
+const gchar *	e_source_mail_submission_get_transport_uid
+					(ESourceMailSubmission *extension);
+void		e_source_mail_submission_set_transport_uid
+					(ESourceMailSubmission *extension,
+					 const gchar *transport_uid);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_MAIL_SUBMISSION_H */
diff --git a/libedataserver/e-source-mail-transport.c b/libedataserver/e-source-mail-transport.c
new file mode 100644
index 0000000..d279a9b
--- /dev/null
+++ b/libedataserver/e-source-mail-transport.c
@@ -0,0 +1,130 @@
+/*
+ * e-source-mail-transport.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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-mail-transport
+ * @include: libedataserver/e-source-mail-transport.h
+ * @short_description: #ESource extension for an email transport
+ *
+ * The #ESourceMailTransport extension identifies the #ESource as a
+ * mail transport which describes where to send outgoing messages.
+ *
+ * The extension has no real settings at present, only a placeholder
+ * key to ensure the corresponding key file group gets written to disk.
+ * The placeholder is an implementation detail; you can safely ignore it.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-mail-transport.h>
+ *
+ *   ESourceMailTransport *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_MAIL_TRANSPORT);
+ * ]|
+ **/
+
+#include "e-source-mail-transport.h"
+
+#define E_SOURCE_MAIL_TRANSPORT_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_MAIL_TRANSPORT, ESourceMailTransportPrivate))
+
+struct _ESourceMailTransportPrivate {
+	gint placeholder;
+};
+
+enum {
+	PROP_0,
+	PROP_PLACEHOLDER
+};
+
+G_DEFINE_TYPE (
+	ESourceMailTransport,
+	e_source_mail_transport,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_mail_transport_set_property (GObject *object,
+                                   guint property_id,
+                                   const GValue *value,
+                                   GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_PLACEHOLDER:
+			/* disregard the value */
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_mail_transport_get_property (GObject *object,
+                                   guint property_id,
+                                   GValue *value,
+                                   GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_PLACEHOLDER:
+			g_value_set_string (value, NULL);
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_source_mail_transport_class_init (ESourceMailTransportClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceMailTransportPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_mail_transport_set_property;
+	object_class->get_property = source_mail_transport_get_property;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
+
+	/* XXX This extension doesn't have any actual settings to remember,
+	 *     but the [Mail Transport] group still needs to appear in the
+	 *     key file.  Problem is key file syntax requires each group
+	 *     have at least one key.  The "Placeholder" key is just that.
+	 *     Remove it if we ever add another E_SOURCE_PARAM_SETTING. */
+	g_object_class_install_property (
+		object_class,
+		PROP_PLACEHOLDER,
+		g_param_spec_string (
+			"placeholder",
+			"Placeholder",
+			"Unused placeholder value",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_mail_transport_init (ESourceMailTransport *extension)
+{
+	extension->priv = E_SOURCE_MAIL_TRANSPORT_GET_PRIVATE (extension);
+}
diff --git a/libedataserver/e-source-mail-transport.h b/libedataserver/e-source-mail-transport.h
new file mode 100644
index 0000000..2539a85
--- /dev/null
+++ b/libedataserver/e-source-mail-transport.h
@@ -0,0 +1,80 @@
+/*
+ * e-source-mail-transport.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_MAIL_TRANSPORT_H
+#define E_SOURCE_MAIL_TRANSPORT_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_MAIL_TRANSPORT \
+	(e_source_mail_transport_get_type ())
+#define E_SOURCE_MAIL_TRANSPORT(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_MAIL_TRANSPORT, ESourceMailTransport))
+#define E_SOURCE_MAIL_TRANSPORT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_MAIL_TRANSPORT, ESourceMailTransportClass))
+#define E_IS_SOURCE_MAIL_TRANSPORT(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_MAIL_TRANSPORT))
+#define E_IS_SOURCE_MAIL_TRANSPORT_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_MAIL_TRANSPORT))
+#define E_SOURCE_MAIL_TRANSPORT_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_MAIL_TRANSPORT, ESourceMailTransportClass))
+
+/**
+ * E_SOURCE_EXTENSION_MAIL_TRANSPORT:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceMailTransport.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_MAIL_TRANSPORT "Mail Transport"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceMailTransport ESourceMailTransport;
+typedef struct _ESourceMailTransportClass ESourceMailTransportClass;
+typedef struct _ESourceMailTransportPrivate ESourceMailTransportPrivate;
+
+/**
+ * ESourceMailTransport:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceMailTransport {
+	ESourceExtension parent;
+	ESourceMailTransportPrivate *priv;
+};
+
+struct _ESourceMailTransportClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_mail_transport_get_type (void);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_MAIL_TRANSPORT_H */
diff --git a/libedataserver/e-source-offline.c b/libedataserver/e-source-offline.c
new file mode 100644
index 0000000..b514a88
--- /dev/null
+++ b/libedataserver/e-source-offline.c
@@ -0,0 +1,168 @@
+/*
+ * 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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-offline
+ * @include: libedataserver/e-source-offline.h
+ * @short_description: #ESource extension for offline settings
+ *
+ * The #ESourceOffline extension tracks whether data from a remote
+ * server should be cached locally for viewing while offline.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-offline.h>
+ *
+ *   ESourceOffline *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_OFFLINE);
+ * ]|
+ **/
+
+#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);
+}
+
+/**
+ * e_source_offline_get_stay_synchronized:
+ * @extension: an #ESourceOffline
+ *
+ * Returns whether data from a remote server should be cached locally
+ * for viewing while offline.  Backends are responsible for implementing
+ * such caching.
+ *
+ * Returns: whether data should be cached for offline
+ *
+ * Since: 3.4
+ **/
+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;
+}
+
+/**
+ * e_source_offline_set_stay_synchronized:
+ * @extension: an #ESourceOffline
+ * @stay_synchronized: whether data should be cached for offline
+ *
+ * Sets whether data from a remote server should be cached locally for
+ * viewing while offline.  Backends are responsible for implementing
+ * such caching.
+ *
+ * Since: 3.4
+ **/
+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..b3fbab5
--- /dev/null
+++ b/libedataserver/e-source-offline.h
@@ -0,0 +1,85 @@
+/*
+ * 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))
+
+/**
+ * E_SOURCE_EXTENSION_OFFLINE:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceOffline.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_OFFLINE "Offline"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceOffline ESourceOffline;
+typedef struct _ESourceOfflineClass ESourceOfflineClass;
+typedef struct _ESourceOfflinePrivate ESourceOfflinePrivate;
+
+/**
+ * ESourceOffline:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+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-openpgp.c b/libedataserver/e-source-openpgp.c
new file mode 100644
index 0000000..338920a
--- /dev/null
+++ b/libedataserver/e-source-openpgp.c
@@ -0,0 +1,453 @@
+/*
+ * e-source-openpgp.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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-openpgp
+ * @include: libedataserver/e-source-openpgp.h
+ * @short_description: #ESource extension for OpenPGP settings
+ *
+ * The #ESourceOpenPGP extension tracks OpenPGP (RFC 4880) settings to be
+ * applied to outgoing mail messages.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-openpgp.h>
+ *
+ *   ESourceOpenPGP *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_OPENPGP);
+ * ]|
+ **/
+
+#include "e-source-openpgp.h"
+
+#define E_SOURCE_OPENPGP_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_OPENPGP, ESourceOpenPGPPrivate))
+
+struct _ESourceOpenPGPPrivate {
+	gchar *key_id;
+	gchar *signing_algorithm;
+
+	gboolean always_trust;
+	gboolean encrypt_to_self;
+	gboolean sign_by_default;
+};
+
+enum {
+	PROP_0,
+	PROP_ALWAYS_TRUST,
+	PROP_ENCRYPT_TO_SELF,
+	PROP_KEY_ID,
+	PROP_SIGNING_ALGORITHM,
+	PROP_SIGN_BY_DEFAULT
+};
+
+G_DEFINE_TYPE (
+	ESourceOpenPGP,
+	e_source_openpgp,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_openpgp_set_property (GObject *object,
+                             guint property_id,
+                             const GValue *value,
+                             GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ALWAYS_TRUST:
+			e_source_openpgp_set_always_trust (
+				E_SOURCE_OPENPGP (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_ENCRYPT_TO_SELF:
+			e_source_openpgp_set_encrypt_to_self (
+				E_SOURCE_OPENPGP (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_KEY_ID:
+			e_source_openpgp_set_key_id (
+				E_SOURCE_OPENPGP (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_SIGNING_ALGORITHM:
+			e_source_openpgp_set_signing_algorithm (
+				E_SOURCE_OPENPGP (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_SIGN_BY_DEFAULT:
+			e_source_openpgp_set_sign_by_default (
+				E_SOURCE_OPENPGP (object),
+				g_value_get_boolean (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_openpgp_get_property (GObject *object,
+                             guint property_id,
+                             GValue *value,
+                             GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ALWAYS_TRUST:
+			g_value_set_boolean (
+				value,
+				e_source_openpgp_get_always_trust (
+				E_SOURCE_OPENPGP (object)));
+			return;
+
+		case PROP_ENCRYPT_TO_SELF:
+			g_value_set_boolean (
+				value,
+				e_source_openpgp_get_encrypt_to_self (
+				E_SOURCE_OPENPGP (object)));
+			return;
+
+		case PROP_KEY_ID:
+			g_value_set_string (
+				value,
+				e_source_openpgp_get_key_id (
+				E_SOURCE_OPENPGP (object)));
+			return;
+
+		case PROP_SIGNING_ALGORITHM:
+			g_value_set_string (
+				value,
+				e_source_openpgp_get_signing_algorithm (
+				E_SOURCE_OPENPGP (object)));
+			return;
+
+		case PROP_SIGN_BY_DEFAULT:
+			g_value_set_boolean (
+				value,
+				e_source_openpgp_get_sign_by_default (
+				E_SOURCE_OPENPGP (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_openpgp_finalize (GObject *object)
+{
+	ESourceOpenPGPPrivate *priv;
+
+	priv = E_SOURCE_OPENPGP_GET_PRIVATE (object);
+
+	g_free (priv->key_id);
+	g_free (priv->signing_algorithm);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_openpgp_parent_class)->finalize (object);
+}
+
+static void
+e_source_openpgp_class_init (ESourceOpenPGPClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceOpenPGPPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_openpgp_set_property;
+	object_class->get_property = source_openpgp_get_property;
+	object_class->finalize = source_openpgp_finalize;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_OPENPGP;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ALWAYS_TRUST,
+		g_param_spec_boolean (
+			"always-trust",
+			"Always Trust",
+			"Always trust keys in my keyring",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ENCRYPT_TO_SELF,
+		g_param_spec_boolean (
+			"encypt-to-self",
+			"Encrypt To Self",
+			"Always encrypt to myself",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_KEY_ID,
+		g_param_spec_string (
+			"key-id",
+			"Key ID",
+			"PGP/GPG Key ID",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SIGNING_ALGORITHM,
+		g_param_spec_string (
+			"signing-algorithm",
+			"Signing Algorithm",
+			"Hash algorithm used to sign messages",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SIGN_BY_DEFAULT,
+		g_param_spec_boolean (
+			"sign-by-default",
+			"Sign By Default",
+			"Sign outgoing messages by default",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_openpgp_init (ESourceOpenPGP *extension)
+{
+	extension->priv = E_SOURCE_OPENPGP_GET_PRIVATE (extension);
+}
+
+/**
+ * e_source_openpgp_get_always_trust:
+ * @extension: an #ESourceOpenPGP
+ *
+ * Returns whether to skip key validation and assume that used keys are
+ * always fully trusted.
+ *
+ * Returns: whether used keys are always fully trusted
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_openpgp_get_always_trust (ESourceOpenPGP *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_OPENPGP (extension), FALSE);
+
+	return extension->priv->always_trust;
+}
+
+/**
+ * e_source_openpgp_set_always_trust:
+ * @extension: an #ESourceOpenPGP
+ * @always_trust: whether used keys are always fully trusted
+ *
+ * Sets whether to skip key validation and assume that used keys are
+ * always fully trusted.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_openpgp_set_always_trust (ESourceOpenPGP *extension,
+                                   gboolean always_trust)
+{
+	g_return_if_fail (E_IS_SOURCE_OPENPGP (extension));
+
+	extension->priv->always_trust = always_trust;
+
+	g_object_notify (G_OBJECT (extension), "always-trust");
+}
+
+/**
+ * e_source_openpgp_get_encrypt_to_self:
+ * @extension: an #ESourceOpenPGP
+ *
+ * Returns whether to "encrypt-to-self" when sending encrypted messages.
+ *
+ * Returns: whether to "encrypt-to-self"
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_openpgp_get_encrypt_to_self (ESourceOpenPGP *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_OPENPGP (extension), FALSE);
+
+	return extension->priv->encrypt_to_self;
+}
+
+/**
+ * e_source_openpgp_set_encrypt_to_self:
+ * @extension: an #ESourceOpenPGP
+ * @encrypt_to_self: whether to "encrypt-to-self"
+ *
+ * Sets whether to "encrypt-to-self" when sending encrypted messages.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_openpgp_set_encrypt_to_self (ESourceOpenPGP *extension,
+                                      gboolean encrypt_to_self)
+{
+	g_return_if_fail (E_IS_SOURCE_OPENPGP (extension));
+
+	extension->priv->encrypt_to_self = encrypt_to_self;
+
+	g_object_notify (G_OBJECT (extension), "encrypt-to-self");
+}
+
+/**
+ * e_source_openpgp_get_key_id:
+ * @extension: an #ESourceOpenPGP
+ *
+ * Returns the OpenPGP key ID used to sign and encrypt messages.
+ *
+ * Returns: the key ID used to sign and encrypt messages
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_openpgp_get_key_id (ESourceOpenPGP *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_OPENPGP (extension), NULL);
+
+	return extension->priv->key_id;
+}
+
+/**
+ * e_source_openpgp_set_key_id:
+ * @extension: an #ESourceOpenPGP
+ * @key_id: the key ID used to sign and encrypt messages
+ *
+ * Sets the OpenPGP key ID used to sign and encrypt messages.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_openpgp_set_key_id (ESourceOpenPGP *extension,
+                             const gchar *key_id)
+{
+	g_return_if_fail (E_IS_SOURCE_OPENPGP (extension));
+
+	g_free (extension->priv->key_id);
+	extension->priv->key_id = g_strdup (key_id);
+
+	g_object_notify (G_OBJECT (extension), "key-id");
+}
+
+/**
+ * e_source_openpgp_get_signing_algorithm:
+ * @extension: an #ESourceOpenPGP
+ *
+ * Returns the name of the hash algorithm used to digitally sign outgoing
+ * messages.
+ *
+ * Returns: the signing algorithm for outgoing messages
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_openpgp_get_signing_algorithm (ESourceOpenPGP *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_OPENPGP (extension), NULL);
+
+	return extension->priv->signing_algorithm;
+}
+
+/**
+ * e_source_openpgp_set_signing_algorithm:
+ * @extension: an #ESourceOpenPGP
+ * @signing_algorithm: the signing algorithm for outgoing messages
+ *
+ * Sets the name of the hash algorithm used to digitally sign outgoing
+ * messages.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_openpgp_set_signing_algorithm (ESourceOpenPGP *extension,
+                                        const gchar *signing_algorithm)
+{
+	g_return_if_fail (E_IS_SOURCE_OPENPGP (extension));
+
+	g_free (extension->priv->signing_algorithm);
+	extension->priv->signing_algorithm = g_strdup (signing_algorithm);
+
+	g_object_notify (G_OBJECT (extension), "signing-algorithm");
+}
+
+/**
+ * e_source_openpgp_get_sign_by_default:
+ * @extension: an #ESourceOpenPGP
+ *
+ * Returns whether to digitally sign outgoing messages by default using
+ * OpenPGP-compliant software such as GNU Privacy Guard (GnuPG).
+ *
+ * Returns: whether to sign outgoing messages by default
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_openpgp_get_sign_by_default (ESourceOpenPGP *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_OPENPGP (extension), FALSE);
+
+	return extension->priv->sign_by_default;
+}
+
+/**
+ * e_source_openpgp_set_sign_by_default:
+ * @extension: an #ESourceOpenPGP
+ * @sign_by_default: whether to sign outgoing messages by default
+ *
+ * Sets whether to digitally sign outgoing messages by default using
+ * OpenPGP-compliant software such as GNU Privacy Guard (GnuPG).
+ *
+ * Since: 3.4
+ **/
+void
+e_source_openpgp_set_sign_by_default (ESourceOpenPGP *extension,
+                                      gboolean sign_by_default)
+{
+	g_return_if_fail (E_IS_SOURCE_OPENPGP (extension));
+
+	extension->priv->sign_by_default = sign_by_default;
+
+	g_object_notify (G_OBJECT (extension), "sign-by-default");
+}
+
diff --git a/libedataserver/e-source-openpgp.h b/libedataserver/e-source-openpgp.h
new file mode 100644
index 0000000..b5aada0
--- /dev/null
+++ b/libedataserver/e-source-openpgp.h
@@ -0,0 +1,104 @@
+/*
+ * e-source-openpgp.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_OPENPGP_H
+#define E_SOURCE_OPENPGP_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_OPENPGP \
+	(e_source_openpgp_get_type ())
+#define E_SOURCE_OPENPGP(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_OPENPGP, ESourceOpenPGP))
+#define E_SOURCE_OPENPGP_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_OPENPGP, ESourceOpenPGPClass))
+#define E_IS_SOURCE_OPENPGP(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_OPENPGP))
+#define E_IS_SOURCE_OPENPGP_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_OPENPGP))
+#define E_SOURCE_OPENPGP_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_OPENPGP, ESourceOpenPGPClass))
+
+/**
+ * E_SOURCE_EXTENSION_OPENPGP:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceOpenPGP.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_OPENPGP "Pretty Good Privacy (OpenPGP)"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceOpenPGP ESourceOpenPGP;
+typedef struct _ESourceOpenPGPClass ESourceOpenPGPClass;
+typedef struct _ESourceOpenPGPPrivate ESourceOpenPGPPrivate;
+
+/**
+ * ESourceOpenPGP:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceOpenPGP {
+	ESourceExtension parent;
+	ESourceOpenPGPPrivate *priv;
+};
+
+struct _ESourceOpenPGPClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_openpgp_get_type	(void);
+gboolean	e_source_openpgp_get_always_trust
+						(ESourceOpenPGP *extension);
+void		e_source_openpgp_set_always_trust
+						(ESourceOpenPGP *extension,
+						 gboolean always_trust);
+gboolean	e_source_openpgp_get_encrypt_to_self
+						(ESourceOpenPGP *extension);
+void		e_source_openpgp_set_encrypt_to_self
+						(ESourceOpenPGP *extension,
+						 gboolean encrypt_to_self);
+const gchar *	e_source_openpgp_get_key_id	(ESourceOpenPGP *extension);
+void		e_source_openpgp_set_key_id	(ESourceOpenPGP *extension,
+						 const gchar *key_id);
+const gchar *	e_source_openpgp_get_signing_algorithm
+						(ESourceOpenPGP *extension);
+void		e_source_openpgp_set_signing_algorithm
+						(ESourceOpenPGP *extension,
+						 const gchar *signing_algorithm);
+gboolean	e_source_openpgp_get_sign_by_default
+						(ESourceOpenPGP *extension);
+void		e_source_openpgp_set_sign_by_default
+						(ESourceOpenPGP *extension,
+						 gboolean sign_by_default);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_OPENPGP_H */
+
diff --git a/libedataserver/e-source-password.c b/libedataserver/e-source-password.c
new file mode 100644
index 0000000..a77254a
--- /dev/null
+++ b/libedataserver/e-source-password.c
@@ -0,0 +1,601 @@
+/*
+ * 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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-password
+ * @include: libedataserver/e-source-password.h
+ * @short_description: #ESource password management
+ *
+ * This section describes functions for managing account passwords.
+ *
+ * Account passwords are stored securely in GNOME Keyring under the
+ * #ESource:uid string of the #ESource instance which describes the
+ * account.  If an account is described by a hierarchy of #ESource
+ * instances (common with groupware accounts), the keyring entry should
+ * be associated with the #ESource holding authentication information
+ * (via the #ESourceAuthentication extension).
+ *
+ * The password operations described here cover storing a password in
+ * the keyring, retrieving a password from the keyring, and deleting a
+ * password from the keyring.  None of these operations interact with
+ * the user.
+ **/
+
+#include "e-source-password.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.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);
+	}
+}
+
+/**
+ * e_source_password_store:
+ * @source: an #ESource
+ * @password: the password to store
+ * @permanently: store permanently or just for the session
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously stores a password for @source.  If @permanently is %TRUE,
+ * the password is stored in the default keyring.  Otherwise the password
+ * is stored in the memory-only session keyring.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call e_source_password_store_finish() to get the result of the operation.
+ *
+ * Since: 3.4.
+ **/
+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);
+}
+
+/**
+ * e_source_password_store_finish:
+ * @source: an #ESource
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_password_store().
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.4
+ **/
+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);
+}
+
+/**
+ * e_source_password_store_sync:
+ * @source: an #ESource
+ * @password: the password to store
+ * @permanently: store permanently or just for the session
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Stores a password for @source.  If @permanently is %TRUE, the password
+ * is stored in the default keyring.  Otherwise the password is stored in
+ * the memory-only session keyring.  If an error occurs, the function sets
+ * @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.4
+ **/
+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);
+	}
+}
+
+/**
+ * e_source_password_lookup:
+ * @source: an #ESource
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously looks up a password for @source in both the default
+ * keyring and session keyring.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call e_source_password_lookup_finish() to get the result of the operation.
+ *
+ * Since: 3.4
+ **/
+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);
+}
+
+/**
+ * e_source_password_lookup_finish:
+ * @source: an #ESource
+ * @result: a #GAsyncResult
+ * @password: return location for the password, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_password_lookup().  The
+ * returned password string is allocated from a secure memory pool, and
+ * must be freed using e_source_password_free(), <emphasis>not</emphasis>
+ * g_free().
+ *
+ * Note the return value indicates whether the lookup operation itself
+ * completed without error, not whether a password for @source was found.
+ * If no password was found, the function will set @password to %NULL but
+ * still return %TRUE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.4
+ **/
+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;
+}
+
+/**
+ * e_source_password_lookup_sync:
+ * @source: an #ESource
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @password: return location for the password, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Looks up a password for @source in both the default keyring and
+ * session keyring.  The returned password string is allocated from a
+ * secure memory pool, and must be free using e_source_password_free(),
+ * <emphasis>not</emphasis> g_free().
+ *
+ * Note the return value indicates whether the lookup operation itself
+ * completed without error, not whether a password for @source was found.
+ * If no password was found, the function will set @password to %NULL but
+ * still return %TRUE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.4
+ **/
+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);
+	}
+}
+
+/**
+ * e_source_password_delete:
+ * @source: an #ESource
+ * @io_priority: the I/O priority of the request
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously deletes the password for @source from either the default
+ * keyring or session keyring.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call e_source_password_delete_finish() to get the result of the operation.
+ *
+ * Since: 3.4
+ **/
+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);
+}
+
+/**
+ * e_source_password_delete_finish:
+ * @source: an #ESource
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_password_delete().
+ *
+ * Note the return value indicates whether the delete operation itself
+ * completed without error, not whether a password for @source was found
+ * and deleted.  If no password was found, the function will still return
+ * %TRUE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.4
+ **/
+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);
+}
+
+/**
+ * e_source_password_delete_sync:
+ * @source: an #ESource
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Deletes the password for @source from either the default keyring or
+ * session keyring.
+ *
+ * Note the return value indicates whether the delete operation itself
+ * completed without error, not whether a password for @source was found
+ * and deleted.  If no password was found, the function will still return
+ * %TRUE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.4
+ **/
+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);
+}
+
+/**
+ * e_source_password_free:
+ * @password: a password string, or %NULL
+ *
+ * Frees the password string returned by e_source_password_lookup_sync()
+ * or e_source_password_lookup_finish() after filling it with zeros.  The
+ * @password string was allocated from a secure memory pool.  This function
+ * returns the string to that memory pool.
+ *
+ * As a convenience, if @password is %NULL the function does nothing.
+ *
+ * Since: 3.4
+ **/
+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..03d4adf
--- /dev/null
+++ b/libedataserver/e-source-password.h
@@ -0,0 +1,85 @@
+/*
+ * 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
+
+/* This needs to be in the public header since we're
+ * reusing the GnomeKeyringResult enum for error codes. */
+#include <gnome-keyring.h>
+
+#include <libedataserver/e-source.h>
+
+/**
+ * E_SOURCE_PASSWORD_ERROR:
+ *
+ * Error domain for password storage and retrieval.  Error codes in this
+ * domain are defined by the #GnomeKeyringResult enumeration.  See #GError
+ * for information on error domains.
+ *
+ * Since: 3.4
+ **/
+#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..2999d83
--- /dev/null
+++ b/libedataserver/e-source-refresh.c
@@ -0,0 +1,242 @@
+/*
+ * 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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-refresh
+ * @include: libedataserver/e-source-refresh.h
+ * @short_description: #ESource extension for refresh settings
+ *
+ * The #ESourceRefresh extension tracks the interval for fetching
+ * updates from a remote server.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-refresh.h>
+ *
+ *   ESourceRefresh *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_REFRESH);
+ * ]|
+ **/
+
+#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 {
+	gboolean enabled;
+	guint interval_minutes;
+};
+
+enum {
+	PROP_0,
+	PROP_ENABLED,
+	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_ENABLED:
+			e_source_refresh_set_enabled (
+				E_SOURCE_REFRESH (object),
+				g_value_get_boolean (value));
+			return;
+
+		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_ENABLED:
+			g_value_set_boolean (
+				value,
+				e_source_refresh_get_enabled (
+				E_SOURCE_REFRESH (object)));
+			return;
+
+		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_ENABLED,
+		g_param_spec_boolean (
+			"enabled",
+			"Enabled",
+			"Whether to periodically refresh",
+			TRUE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	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);
+}
+
+/**
+ * e_source_refresh_get_enabled:
+ * @extension: an #ESourceRefresh
+ *
+ * Returns whether to periodically fetch updates from a remote server.
+ *
+ * The refresh interval is determined by the #ESourceRefresh:interval-minutes
+ * property.
+ *
+ * Returns: whether periodic refresh is enabled
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_refresh_get_enabled (ESourceRefresh *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_REFRESH (extension), FALSE);
+
+	return extension->priv->enabled;
+}
+
+/**
+ * e_source_refresh_set_enabled:
+ * @extension: an #ESourceRefresh
+ * @enabled: whether to enable periodic refresh
+ *
+ * Sets whether to periodically fetch updates from a remote server.
+ *
+ * The refresh interval is determined by the #ESourceRefresh:interval-minutes
+ * property.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_refresh_set_enabled (ESourceRefresh *extension,
+                              gboolean enabled)
+{
+	g_return_if_fail (E_IS_SOURCE_REFRESH (extension));
+
+	extension->priv->enabled = enabled;
+
+	g_object_notify (G_OBJECT (extension), "enabled");
+}
+
+/**
+ * e_source_refresh_get_interval_minutes:
+ * @extension: an #ESourceRefresh
+ *
+ * Returns the interval for fetching updates from a remote server.
+ *
+ * Note this value is only effective when the #ESourceRefresh:enabled
+ * property is %TRUE.
+ *
+ * Returns: the interval in minutes
+ *
+ * Since: 3.4
+ **/
+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;
+}
+
+/**
+ * e_source_refresh_set_interval_minutes:
+ * @extension: an #ESourceRefresh
+ * @interval_minutes: the interval in minutes
+ *
+ * Sets the interval for fetching updates from a remote server.
+ *
+ * Note this value is only effective when the #ESourceRefresh:enabled
+ * property is %TRUE.
+ *
+ * Since: 3.4
+ **/
+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..641aff2
--- /dev/null
+++ b/libedataserver/e-source-refresh.h
@@ -0,0 +1,88 @@
+/*
+ * 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))
+
+/**
+ * E_SOURCE_EXTENSION_REFRESH:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceRefresh.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_REFRESH "Refresh"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceRefresh ESourceRefresh;
+typedef struct _ESourceRefreshClass ESourceRefreshClass;
+typedef struct _ESourceRefreshPrivate ESourceRefreshPrivate;
+
+/**
+ * ESourceRefresh:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceRefresh {
+	ESourceExtension parent;
+	ESourceRefreshPrivate *priv;
+};
+
+struct _ESourceRefreshClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_refresh_get_type	(void);
+gboolean	e_source_refresh_get_enabled	(ESourceRefresh *extension);
+void		e_source_refresh_set_enabled	(ESourceRefresh *extension,
+						 gboolean enabled);
+guint		e_source_refresh_get_interval_minutes
+						(ESourceRefresh *extension);
+void		e_source_refresh_set_interval_minutes
+						(ESourceRefresh *extension,
+						 guint interval_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..870b8f2
--- /dev/null
+++ b/libedataserver/e-source-registry.c
@@ -0,0 +1,1647 @@
+/*
+ * 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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-registry
+ * @include: libedataserver/e-source-registry.h
+ * @short_description: A central repository for data sources
+ *
+ * The #ESourceRegistry is a global singleton store for all #ESource
+ * instances.  It uses file monitors to react to key file creation and
+ * deletion events, either constructing an #ESource instance from the
+ * newly created key file, or removing from the logical #ESource
+ * hierarchy the instance corresponding to the deleted key file.
+ *
+ * The #ESourceRegistry can be queried for individual #ESource instances
+ * by their unique identifier string or key file path, for collections of
+ * #ESource instances having a particular extension, or for all available
+ * #ESource instances.
+ *
+ * The #ESourceRegistry API also provides a front-end for the
+ * "org.gnome.Evolution.DefaultSources" #GSettings schema which tracks
+ * which #ESource instances are designated to be the user's default address
+ * book, calendar, memo list and task list for desktop integration
+ **/
+
+#include "e-source-registry.h"
+
+#include <config.h>
+#include <glib/gstdio.h>
+#include <glib/gi18n-lib.h>
+
+#include <libedataserver/e-marshal.h>
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-dbus-source.h>
+#include <libedataserver/e-dbus-source-manager.h>
+
+#define E_SOURCE_REGISTRY_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_REGISTRY, ESourceRegistryPrivate))
+
+#define DBUS_OBJECT_PATH "/org/gnome/evolution/dataserver/SourceManager"
+#define GSETTINGS_SCHEMA "org.gnome.Evolution.DefaultSources"
+
+struct _ESourceRegistryPrivate {
+	GDBusObjectManager *dbus_object_manager;
+	EDBusSourceManager *dbus_source_manager;
+	GHashTable *object_path_to_source_map;
+
+	GHashTable *sources;  /* sources added to hierarchy */
+	GHashTable *orphans;  /* sources waiting for parent */
+
+	GSettings *settings;
+};
+
+enum {
+	PROP_0,
+	PROP_DEFAULT_ADDRESS_BOOK,
+	PROP_DEFAULT_CALENDAR,
+	PROP_DEFAULT_MAIL_ACCOUNT,
+	PROP_DEFAULT_MEMO_LIST,
+	PROP_DEFAULT_TASK_LIST
+};
+
+enum {
+	SOURCE_ADDED,
+	SOURCE_CHANGED,
+	SOURCE_REMOVED,
+	LAST_SIGNAL
+};
+
+/* Forward Declarations */
+static void	source_registry_add_source	(ESourceRegistry *registry,
+						 ESource *source);
+static void	e_source_registry_initable_init	(GInitableIface *interface);
+
+static guint signals[LAST_SIGNAL];
+
+/* By default, the GAsyncInitable interface calls GInitable.init()
+ * from a separate thread, so we only have to override GInitable. */
+G_DEFINE_TYPE_WITH_CODE (
+	ESourceRegistry,
+	e_source_registry,
+	G_TYPE_OBJECT,
+	G_IMPLEMENT_INTERFACE (
+		G_TYPE_INITABLE, e_source_registry_initable_init)
+	G_IMPLEMENT_INTERFACE (
+		G_TYPE_ASYNC_INITABLE, NULL))
+
+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_traverse_cb (GNode *node,
+                             GQueue *queue)
+{
+	g_queue_push_tail (queue, node->data);
+
+	return FALSE;
+}
+
+static void
+source_registry_queue_subtree (ESource *source,
+                               GQueue *queue)
+{
+	GNode *node;
+
+	node = e_source_get_node (source);
+
+	g_node_traverse (
+		node, G_POST_ORDER, G_TRAVERSE_ALL, -1,
+		(GNodeTraverseFunc) source_registry_traverse_cb, queue);
+}
+
+static void
+source_registry_add_orphan (ESourceRegistry *registry,
+                            ESource *source)
+{
+	GPtrArray *array;
+	GHashTable *orphans;
+	const gchar *parent_uid;
+
+	parent_uid = e_source_get_parent (source);
+
+	/* A top-level ESource has no parent UID, so we
+	 * use a special "empty" key in the hash table. */
+	if (parent_uid == NULL)
+		parent_uid = "";
+
+	orphans = registry->priv->orphans;
+	array = g_hash_table_lookup (orphans, parent_uid);
+
+	if (array == NULL) {
+		array = g_ptr_array_new_with_free_func (
+			(GDestroyNotify) g_object_unref);
+		g_hash_table_insert (
+			orphans, g_strdup (parent_uid), array);
+	}
+
+	g_ptr_array_add (array, g_object_ref (source));
+}
+
+static gboolean
+source_registry_remove_orphan (ESourceRegistry *registry,
+                               ESource *source)
+{
+	GPtrArray *array;
+	GHashTable *orphans;
+	const gchar *parent_uid;
+	gboolean removed = FALSE;
+
+	parent_uid = e_source_get_parent (source);
+
+	/* A top-level ESource has no parent UID, so we
+	 * use a special "empty" key in the hash table. */
+	if (parent_uid == NULL)
+		parent_uid = "";
+
+	orphans = registry->priv->orphans;
+	array = g_hash_table_lookup (orphans, parent_uid);
+
+	if (array != NULL) {
+		/* Array is not ordered, so use "remove_fast". */
+		removed = g_ptr_array_remove_fast (array, source);
+	}
+
+	return removed;
+}
+
+static gboolean
+source_registry_find_parent (ESourceRegistry *registry,
+                             ESource *source)
+{
+	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 table 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;
+	}
+
+	source_registry_add_orphan (registry, 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);
+		source_registry_add_source (registry, orphan);
+	}
+
+	/* This is faster than source_registry_remove_orphan(). */
+	g_ptr_array_set_size (array, 0);
+}
+
+static void
+source_registry_add_source (ESourceRegistry *registry,
+                            ESource *source)
+{
+	const gchar *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);
+}
+
+static void
+source_registry_remove_source (ESourceRegistry *registry,
+                               ESource *source)
+{
+	const gchar *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);
+}
+
+static void
+source_registry_object_added_cb (GDBusObjectManager *manager,
+                                 GDBusObject *dbus_object,
+                                 ESourceRegistry *registry)
+{
+	ESource *source;
+	const gchar *object_path;
+	GError *error = NULL;
+
+	/* The likelihood of an error here is slim, so it's
+	 * sufficient to just print a warning if one occurs. */
+
+	g_return_if_fail (E_DBUS_IS_OBJECT (dbus_object));
+
+	source = e_source_new (E_DBUS_OBJECT (dbus_object), &error);
+	object_path = g_dbus_object_get_object_path (dbus_object);
+
+	if (source != NULL) {
+		g_hash_table_insert (
+			registry->priv->object_path_to_source_map,
+			g_strdup (object_path),
+			g_object_ref (source));
+		source_registry_add_source (registry, source);
+		g_object_unref (source);
+	}
+
+	if (error != NULL) {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
+}
+
+static void
+source_registry_object_removed_cb (GDBusObjectManager *manager,
+                                   GDBusObject *dbus_object,
+                                   ESourceRegistry *registry)
+{
+	GHashTable *hash_table;
+	GQueue queue = G_QUEUE_INIT;
+	ESource *child;
+	ESource *source;
+	const gchar *object_path;
+	const gchar *uid;
+
+	hash_table = registry->priv->object_path_to_source_map;
+	object_path = g_dbus_object_get_object_path (dbus_object);
+	source = g_hash_table_lookup (hash_table, object_path);
+	g_return_if_fail (E_IS_SOURCE (source));
+
+	uid = e_source_get_uid (source);
+
+	/* If the removed ESource is in the registry hierarchy,
+	 * gather it and all of its descendants into a queue in
+	 * "post-order", so we're always processing leaf nodes
+	 * as we pop elements off the head of the queue. */
+	if (e_source_registry_lookup_by_uid (registry, uid) != NULL)
+		source_registry_queue_subtree (source, &queue);
+
+	/* Move the queued descendants to the orphan table, and emit a
+	 * "source-removed" signal for each element.  This will include
+	 * the removed ESource unless the ESource was already an orphan,
+	 * in which case the queue will be empty. */
+	while ((child = g_queue_pop_head (&queue)) != NULL) {
+		source_registry_remove_source (registry, child);
+		source_registry_add_orphan (registry, child);
+	}
+
+	/* The removed ESource should be in the orphan table now. */
+	source_registry_remove_orphan (registry, source);
+
+	g_hash_table_remove (hash_table, dbus_object);
+}
+
+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_MAIL_ACCOUNT:
+			e_source_registry_set_default_mail_account (
+				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_MAIL_ACCOUNT:
+			g_value_set_object (
+				value,
+				e_source_registry_get_default_mail_account (
+				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);
+
+	if (priv->dbus_object_manager != NULL) {
+		g_signal_handlers_disconnect_matched (
+			priv->dbus_object_manager,
+			G_SIGNAL_MATCH_DATA, 0, 0,
+			NULL, NULL, object);
+		g_object_unref (priv->dbus_object_manager);
+		priv->dbus_object_manager = NULL;
+	}
+
+	if (priv->dbus_source_manager != NULL) {
+		g_object_unref (priv->dbus_source_manager);
+		priv->dbus_source_manager = NULL;
+	}
+
+	g_hash_table_remove_all (priv->object_path_to_source_map);
+
+	g_hash_table_remove_all (priv->sources);
+	g_hash_table_remove_all (priv->orphans);
+
+	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->object_path_to_source_map);
+
+	g_hash_table_destroy (priv->sources);
+	g_hash_table_destroy (priv->orphans);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_registry_parent_class)->finalize (object);
+}
+
+static gboolean
+source_registry_initable_init (GInitable *initable,
+                               GCancellable *cancellable,
+                               GError **error)
+{
+	ESourceRegistry *registry;
+	GList *list, *link;
+	gboolean success = TRUE;
+
+	registry = E_SOURCE_REGISTRY (initable);
+
+	registry->priv->dbus_object_manager =
+		e_dbus_object_manager_client_new_for_bus_sync (
+			G_BUS_TYPE_SESSION,
+			G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+			SOURCES_DBUS_SERVICE_NAME,
+			DBUS_OBJECT_PATH,
+			cancellable, error);
+
+	if (registry->priv->dbus_object_manager == NULL)
+		return FALSE;
+
+	registry->priv->dbus_source_manager =
+		e_dbus_source_manager_proxy_new_for_bus_sync (
+			G_BUS_TYPE_SESSION,
+			G_DBUS_PROXY_FLAGS_NONE,
+			SOURCES_DBUS_SERVICE_NAME,
+			DBUS_OBJECT_PATH,
+			cancellable, error);
+
+	if (registry->priv->dbus_source_manager == NULL)
+		return FALSE;
+
+	list = g_dbus_object_manager_get_objects (
+		registry->priv->dbus_object_manager);
+
+	for (link = list; link != NULL; link = g_list_next (link)) {
+		GDBusObject *dbus_object;
+		const gchar *object_path;
+		ESource *source;
+
+		dbus_object = G_DBUS_OBJECT (link->data);
+		object_path = g_dbus_object_get_object_path (dbus_object);
+
+		source = e_source_new (E_DBUS_OBJECT (dbus_object), error);
+
+		if (source == NULL) {
+			success = FALSE;
+			break;
+		}
+
+		g_hash_table_insert (
+			registry->priv->object_path_to_source_map,
+			g_strdup (object_path),
+			g_object_ref (source));
+		source_registry_add_source (registry, source);
+		g_object_unref (source);
+	}
+
+	g_list_free_full (list, (GDestroyNotify) g_object_unref);
+
+	g_signal_connect (
+		registry->priv->dbus_object_manager, "object-added",
+		G_CALLBACK (source_registry_object_added_cb), registry);
+
+	g_signal_connect (
+		registry->priv->dbus_object_manager, "object-removed",
+		G_CALLBACK (source_registry_object_removed_cb), registry);
+
+	return success;
+}
+
+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-mail-account
+	 *
+	 * The default mail account #ESource.
+	 **/
+	g_object_class_install_property (
+		object_class,
+		PROP_DEFAULT_MAIL_ACCOUNT,
+		g_param_spec_object (
+			"default-mail-account",
+			"Default Mail Account",
+			"The default mail account 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::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);
+}
+
+static void
+e_source_registry_initable_init (GInitableIface *interface)
+{
+	interface->init = source_registry_initable_init;
+}
+
+static void
+e_source_registry_init (ESourceRegistry *registry)
+{
+	registry->priv = E_SOURCE_REGISTRY_GET_PRIVATE (registry);
+
+	/* D-Bus object path -> ESource */
+	registry->priv->object_path_to_source_map =
+		g_hash_table_new_full (
+			(GHashFunc) g_str_hash,
+			(GEqualFunc) g_str_equal,
+			(GDestroyNotify) g_free,
+			(GDestroyNotify) g_object_unref);
+
+	/* 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 -> GPtrArray 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);
+
+	registry->priv->settings = g_settings_new (GSETTINGS_SCHEMA);
+
+	g_signal_connect (
+		registry->priv->settings, "changed",
+		G_CALLBACK (source_registry_settings_changed_cb), registry);
+}
+
+ESourceRegistry *
+e_source_registry_new_sync (GCancellable *cancellable,
+                            GError **error)
+{
+	return g_initable_new (
+		E_TYPE_SOURCE_REGISTRY,
+		cancellable, error, NULL);
+}
+
+void
+e_source_registry_new (GCancellable *cancellable,
+                       GAsyncReadyCallback callback,
+                       gpointer user_data)
+{
+	g_async_initable_new_async (
+		E_TYPE_SOURCE_REGISTRY,
+		G_PRIORITY_DEFAULT, cancellable,
+		callback, user_data, NULL);
+}
+
+ESourceRegistry *
+e_source_registry_new_finish (GAsyncResult *result,
+                              GError **error)
+{
+	GObject *source_object;
+	GObject *object;
+
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+
+	source_object = g_async_result_get_source_object (result);
+	g_return_val_if_fail (source_object != NULL, NULL);
+
+	object = g_async_initable_new_finish (
+		G_ASYNC_INITABLE (source_object), result, error);
+
+	g_object_unref (source_object);
+
+	return (object != NULL) ? E_SOURCE_REGISTRY (object) : NULL;
+}
+
+gboolean
+e_source_registry_create_source_sync (ESourceRegistry *registry,
+                                      const gchar *source_data,
+                                      GCancellable *cancellable,
+                                      GError **error)
+{
+	/* Note that we don't alter any local data structures here.
+	 * If the D-Bus service honors the request, the object manager
+	 * will emit an "object-added" signal, and our signal handler
+	 * will then update local data structures accordingly. */
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
+	g_return_val_if_fail (source_data != NULL, FALSE);
+
+	return e_dbus_source_manager_call_create_source_sync (
+		registry->priv->dbus_source_manager,
+		source_data, cancellable, error);
+}
+
+/* Helper for e_source_registry_create_source() */
+static void
+source_registry_create_source_thread (GSimpleAsyncResult *simple,
+                                      GObject *object,
+                                      GCancellable *cancellable)
+{
+	const gchar *source_data;
+	GError *error = NULL;
+
+	source_data = g_simple_async_result_get_op_res_gpointer (simple);
+
+	e_source_registry_create_source_sync (
+		E_SOURCE_REGISTRY (object),
+		source_data, cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
+}
+
+void
+e_source_registry_create_source (ESourceRegistry *registry,
+                                 const gchar *source_data,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+	g_return_if_fail (source_data != NULL);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (registry), callback, user_data,
+		e_source_registry_create_source);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, g_strdup (source_data),
+		(GDestroyNotify) g_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, source_registry_create_source_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
+}
+
+gboolean
+e_source_registry_create_source_finish (ESourceRegistry *registry,
+                                        GAsyncResult *result,
+                                        GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (registry),
+		e_source_registry_create_source), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+/**
+ * e_source_registry_remove_source_sync:
+ * @registry: an #ESourceRegistry
+ * @source: the #ESource to be removed
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Requests the D-Bus service to delete the key files for @source and all of
+ * its descendants and broadcast their removal to all clients.  If successful,
+ * @registry will emit a #ESourceRegistry:source-removed signal for each
+ * #ESource removed.  If an error occurs, the functon will set @error and
+ * return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_registry_remove_source_sync (ESourceRegistry *registry,
+                                      ESource *source,
+                                      GCancellable *cancellable,
+                                      GError **error)
+{
+	GQueue queue = G_QUEUE_INIT;
+	const gchar **uids;
+	gboolean success = TRUE;
+	guint ii = 0;
+
+	/* Note that we don't alter any local data structures here.
+	 * If the D-Bus service honors the request, the object manager
+	 * will emit "object-removed" signals, and our signal handler
+	 * will then update local data structures accordingly. */
+
+	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+	source_registry_queue_subtree (source, &queue);
+	uids = g_new0 (const gchar *, queue.length + 1);
+
+	while ((source = g_queue_pop_head (&queue)) != NULL)
+		uids[ii++] = e_source_get_uid (source);
+
+	success = e_dbus_source_manager_call_remove_sources_sync (
+		registry->priv->dbus_source_manager,
+		uids, cancellable, error);
+
+	g_free (uids);
+
+	return success;
+}
+
+/* Helper for e_source_registry_remove_source() */
+static void
+source_registry_remove_source_cb (EDBusSourceManager *proxy,
+                                  GAsyncResult *result,
+                                  GSimpleAsyncResult *simple)
+{
+	GError *error = NULL;
+
+	e_dbus_source_manager_call_remove_sources_finish (
+		proxy, result, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
+
+	g_simple_async_result_complete (simple);
+	g_object_unref (simple);
+}
+
+/**
+ * e_source_registry_remove_source:
+ * @registry: an #ESourceRegistry
+ * @source: the #ESource to be removed
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously requests the D-Bus service to delete the key files for
+ * @source all of its descendants and broadcast their removal to all clients.
+ * If successful, @registry will emit a #ESourceRegistry:source-removed signal
+ * for each #ESource removed.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call e_source_registry_remove_source_finish() to get the result of the
+ * operation.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_registry_remove_source (ESourceRegistry *registry,
+                                 ESource *source,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+	GQueue queue = G_QUEUE_INIT;
+	const gchar **uids;
+	guint ii = 0;
+
+	/* Note that we don't alter any local data structures here.
+	 * If the D-Bus service honors the request, the object manager
+	 * will emit "object-removed" signals, and our signal handler
+	 * will then update local data structures accordingly. */
+
+	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+	g_return_if_fail (E_IS_SOURCE (source));
+
+	source_registry_queue_subtree (source, &queue);
+	uids = g_new0 (const gchar *, queue.length + 1);
+
+	while ((source = g_queue_pop_head (&queue)) != NULL)
+		uids[ii++] = e_source_get_uid (source);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (registry), callback, user_data,
+		e_source_registry_remove_source);
+
+	e_dbus_source_manager_call_remove_sources (
+		registry->priv->dbus_source_manager,
+		uids, cancellable, (GAsyncReadyCallback)
+		source_registry_remove_source_cb, simple);
+
+	g_free (uids);
+}
+
+/**
+ * e_source_registry_remove_source_finish:
+ * @registry: an #ESourceRegistry
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_registry_remove_source().
+ * If an error occured, the function will set @error and return %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE of failure
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_registry_remove_source_finish (ESourceRegistry *registry,
+                                        GAsyncResult *result,
+                                        GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (registry),
+		e_source_registry_remove_source), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+/**
+ * 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: 3.4
+ **/
+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, sorted by display name.  If
+ * @extension_name is given, restrict the list to sources having that
+ * extension name.  Free the returned list with g_list_free().
+ *
+ * Returns: a sorted list of sources
+ *
+ * Since: 3.4
+ **/
+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 g_list_sort (
+		list, (GCompareFunc)
+		e_source_compare_by_display_name);
+}
+
+/* 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)
+			if (e_source_get_enabled (source))
+				g_node_append (node, child);
+			else
+				g_node_destroy (child);
+
+		else if (e_source_has_extension (source, extension_name))
+			if (e_source_get_enabled (source))
+				g_node_append (node, child);
+			else
+				g_node_destroy (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.
+ *
+ * Disabled leaf nodes are automatically excluded from the #GNode tree.
+ *
+ * Free the returned #GNode tree with g_node_destroy().
+ *
+ * Returns: a tree of sources, arranged for display
+ *
+ * Since: 3.4
+ **/
+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;
+}
+
+/* Helper for e_source_registry_debug_dump() */
+static gboolean
+source_registry_debug_dump_cb (GNode *node)
+{
+	guint ii, depth;
+
+	/* Root node is an empty placeholder. */
+	if (G_NODE_IS_ROOT (node))
+		return FALSE;
+
+	depth = g_node_depth (node);
+	for (ii = 2; ii < depth; ii++)
+		g_print ("    ");
+
+	if (E_IS_SOURCE (node->data)) {
+		ESource *source = E_SOURCE (node->data);
+		g_print ("\"%s\" ", e_source_get_display_name (source));
+		g_print ("(%s)", e_source_get_uid (source));
+	}
+
+	g_print ("\n");
+
+	return FALSE;
+}
+
+/**
+ * e_source_registry_debug_dump:
+ * @registry: an #ESourceRegistry
+ * @extension_name: an extension name, or %NULL
+ *
+ * Handy debugging function that uses e_source_registry_build_display_tree()
+ * to print a tree of registered sources to standard output.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_registry_debug_dump (ESourceRegistry *registry,
+                              const gchar *extension_name)
+{
+	GNode *root;
+
+	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+
+	root = e_source_registry_build_display_tree (registry, extension_name);
+
+	g_node_traverse (
+		root, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+		(GNodeTraverseFunc) source_registry_debug_dump_cb, NULL);
+
+	g_node_destroy (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: 3.4
+ **/
+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: 3.4
+ **/
+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: 3.4
+ **/
+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: 3.4
+ **/
+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_mail_account:
+ * @registry: an #ESourceRegistry
+ *
+ * Returns the #ESource most recently passed to
+ * e_source_registry_set_default_mail_account() 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 result value is a valid #ESource.
+ *
+ * Returns: the default mail account #ESource
+ *
+ * Since: 3.4
+ **/
+ESource *
+e_source_registry_get_default_mail_account (ESourceRegistry *registry)
+{
+	const gchar *key = "default-mail-account";
+	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_mail_account:
+ * @registry: an #ESourceRegistry
+ * @default_source: a mail account #ESource, or %NULL
+ *
+ * Sets @default_source as the default mail account.  If @default_source
+ * is %NULL, the default mail account is reset to the "system" #ESource.
+ * This setting will persist across sessions until changed.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_registry_set_default_mail_account (ESourceRegistry *registry,
+                                            ESource *default_source)
+{
+	const gchar *key = "default-mail-account";
+	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 value is a valid #ESource.
+ *
+ * Returns: the default memo list #ESource
+ *
+ * Since: 3.4
+ **/
+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: 3.4
+ **/
+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: 3.4
+ **/
+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: 3.4
+ **/
+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..7e0bdea
--- /dev/null
+++ b/libedataserver/e-source-registry.h
@@ -0,0 +1,154 @@
+/*
+ * 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;
+
+/**
+ * ESourceRegistry:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceRegistry {
+	GObject parent;
+	ESourceRegistryPrivate *priv;
+};
+
+struct _ESourceRegistryClass {
+	GObjectClass parent_class;
+
+	/* Signals */
+	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_new_sync	(GCancellable *cancellable,
+						 GError **error);
+void		e_source_registry_new		(GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+ESourceRegistry *
+		e_source_registry_new_finish	(GAsyncResult *result,
+						 GError **error);
+gboolean	e_source_registry_create_source_sync
+						(ESourceRegistry *registry,
+						 const gchar *source_data,
+						 GCancellable *cancellable,
+						 GError **error);
+void		e_source_registry_create_source	(ESourceRegistry *registry,
+						 const gchar *source_data,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_source_registry_create_source_finish
+						(ESourceRegistry *registry,
+						 GAsyncResult *result,
+						 GError **error);
+gboolean	e_source_registry_remove_source_sync
+						(ESourceRegistry *registry,
+						 ESource *source,
+						 GCancellable *cancellable,
+						 GError **error);
+void		e_source_registry_remove_source	(ESourceRegistry *registry,
+						 ESource *source,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_source_registry_remove_source_finish
+						(ESourceRegistry *registry,
+						 GAsyncResult *result,
+						 GError **error);
+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);
+void		e_source_registry_debug_dump	(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_mail_account
+						(ESourceRegistry *registry);
+void		e_source_registry_set_default_mail_account
+						(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..48e2e52
--- /dev/null
+++ b/libedataserver/e-source-security.c
@@ -0,0 +1,276 @@
+/*
+ * 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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-security
+ * @include: libedataserver/e-source-security.h
+ * @short_description: #ESource extension for security settings
+ *
+ * The #ESourceSecurity extension tracks settings for establishing a
+ * secure connection with a remote server.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-security.h>
+ *
+ *   ESourceSecurity *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_SECURITY);
+ * ]|
+ **/
+
+#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);
+}
+
+/**
+ * e_source_security_get_method:
+ * @extension: an #ESourceSecurity
+ *
+ * Returns the method used to establish a secure network connection to a
+ * remote account.  There are no pre-defined method names; backends are
+ * free to set this however they wish.  If a secure connection is not
+ * desired, the convention is to set #ESourceSecurity:method to "none".
+ *
+ * Returns: the method used to establish a secure network connection
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_security_get_method (ESourceSecurity *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SECURITY (extension), FALSE);
+
+	return extension->priv->method;
+}
+
+/**
+ * e_source_security_set_method:
+ * @extension: an #ESourceSecurity
+ * @method: security method, or %NULL
+ *
+ * Sets the method used to establish a secure network connection to a
+ * remote account.  There are no pre-defined method names; backends are
+ * free to set this however they wish.  If a secure connection is not
+ * desired, the convention is to set #ESourceSecurity:method to "none".
+ * In keeping with that convention, #ESourceSecurity:method will be set
+ * to "none" if @method is %NULL or an empty string.
+ *
+ * Since: 3.4
+ **/
+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);
+}
+
+/**
+ * e_source_security_get_secure:
+ * @extension: an #ESourceSecurity
+ *
+ * This is a convenience function which returns whether a secure network
+ * connection is desired, regardless of the method used.  This relies on
+ * the convention of setting #ESourceSecurity:method to "none" when a
+ * secure network connection is <emphasis>not</emphasis> desired.
+ *
+ * Returns: whether a secure network connection is desired
+ *
+ * Since: 3.4
+ **/
+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);
+}
+
+/**
+ * e_source_security_set_secure:
+ * @extension: an #ESourceSecurity
+ * @secure: whether a secure network connection is desired
+ *
+ * This function provides a simpler way to set #ESourceSecurity:method
+ * when using a secure network connection is a yes or no option and the
+ * exact method name is unimportant.  If @secure is %FALSE, the
+ * #ESourceSecurity:method property is set to "none".  If @secure is
+ * %TRUE, the function assumes the backend will use Transport Layer
+ * Security and sets the #ESourceSecurity:method property to "tls".
+ *
+ * Since: 3.4
+ **/
+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..b490017
--- /dev/null
+++ b/libedataserver/e-source-security.h
@@ -0,0 +1,86 @@
+/*
+ * 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))
+
+/**
+ * E_SOURCE_EXTENSION_SECURITY:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceSecurity.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_SECURITY "Security"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceSecurity ESourceSecurity;
+typedef struct _ESourceSecurityClass ESourceSecurityClass;
+typedef struct _ESourceSecurityPrivate ESourceSecurityPrivate;
+
+/**
+ * ESourceSecurity:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+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..3adadfe
--- /dev/null
+++ b/libedataserver/e-source-selectable.c
@@ -0,0 +1,321 @@
+/*
+ * 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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-selectable
+ * @include: libedataserver/e-source-selectable.h
+ * @short_description: Base class for selectable data sources
+ * @see_also: #ESourceAddressBook, #ESourceCalendar, #ESourceMemoList,
+ *            #ESourceTaskList
+ *
+ * #ESourceSelectable is an abstract base class for data sources
+ * that can be selected in an #ESourceSelector or similar widget.
+ **/
+
+#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);
+}
+
+/**
+ * e_source_selectable_get_color:
+ * @extension: an #ESourceSelectable
+ *
+ * Returns the color specification for the #ESource to which @extension
+ * belongs.  A colored block is often displayed next to the data source's
+ * display name in user interfaces.
+ *
+ * Returns: the color specification for the #ESource
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_selectable_get_color (ESourceSelectable *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SELECTABLE (extension), NULL);
+
+	return extension->priv->color;
+}
+
+/**
+ * e_source_selectable_set_color:
+ * @extension: an #ESourceSelectable
+ * @color: a color specification
+ *
+ * Sets the color specification for the #ESource to which @extension
+ * belongs.  A colored block is often displayed next to the data source's
+ * display name in user interfaces.
+ *
+ * Since: 3.4
+ **/
+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");
+}
+
+/**
+ * e_source_selectable_get_enabled:
+ * @extension: an #ESourceSelectable
+ *
+ * Returns the enabled state of the #ESource to which @extension belongs.
+ * The enabled state is often represented as a checkbox next to the data
+ * source's display name in user interfaces.
+ *
+ * Returns: the enabled state for the #ESource
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_selectable_get_enabled (ESourceSelectable *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SELECTABLE (extension), FALSE);
+
+	return extension->priv->enabled;
+}
+
+/**
+ * e_source_selectable_set_enabled:
+ * @extension: an #ESourceSelectable
+ * @enabled: enabled state
+ *
+ * Sets the enabled state for the #ESource to which @extension belongs.
+ * The enabled state is often represented as a checkbox next to the data
+ * source's display name in user interfaces.
+ *
+ * Since: 3.4
+ **/
+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");
+}
+
+/**
+ * e_source_selectable_get_writable_hint:
+ * @extension: an #ESourceSelectable
+ *
+ * Returns the cached writable state of the #ESource to which @extension
+ * belongs.  This function does not query the data source's backend for
+ * its true writable state, and is therefore not authoritative.  It is
+ * merely a hint to user interfaces to disable actions that require write
+ * access to the data source so as to avoid permission errors that would
+ * otherwise occur were those actions to be activated.
+ *
+ * Returns: the cached writable state for the #ESource
+ *
+ * Since: 3.4
+ **/
+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;
+}
+
+/**
+ * e_source_selectable_set_writable_hint:
+ * @extension: an #ESourceSelectable
+ * @writable_hint: writable state
+ *
+ * Caches the writable state of the #ESource to which @extension belongs.
+ * Setting this property does not change the writable state of the data
+ * source's backend.  It is merely a hint to user interfaces to disable
+ * actions that require write access to the data source so as to avoid
+ * permission errors that would otherwise occur were those actions to be
+ * activated.
+ *
+ * Since: 3.4
+ **/
+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..79d094e
--- /dev/null
+++ b/libedataserver/e-source-selectable.h
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+/**
+ * ESourceSelectable:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+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-smime.c b/libedataserver/e-source-smime.c
new file mode 100644
index 0000000..d575d76
--- /dev/null
+++ b/libedataserver/e-source-smime.c
@@ -0,0 +1,522 @@
+/*
+ * e-source-smime.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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-smime
+ * @include: libedataserver/e-source-smime.h
+ * @short_description: #ESource extension for S/MIME settings
+ *
+ * The #ESourceSMIME extension tracks Secure/Multipurpose Internet Mail
+ * Extensions (S/MIME) settings to be applied to outgoing mail messages.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-smime.h>
+ *
+ *   ESourceSMIME *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_SMIME);
+ * ]|
+ **/
+
+#include "e-source-smime.h"
+
+#define E_SOURCE_SMIME_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE_SMIME, ESourceSMIMEPrivate))
+
+struct _ESourceSMIMEPrivate {
+	gchar *encryption_certificate;
+	gchar *signing_algorithm;
+	gchar *signing_certificate;
+
+	gboolean encrypt_by_default;
+	gboolean encrypt_to_self;
+	gboolean sign_by_default;
+};
+
+enum {
+	PROP_0,
+	PROP_ENCRYPTION_CERTIFICATE,
+	PROP_ENCRYPT_BY_DEFAULT,
+	PROP_ENCRYPT_TO_SELF,
+	PROP_SIGNING_ALGORITHM,
+	PROP_SIGNING_CERTIFICATE,
+	PROP_SIGN_BY_DEFAULT
+};
+
+G_DEFINE_TYPE (
+	ESourceSMIME,
+	e_source_smime,
+	E_TYPE_SOURCE_EXTENSION)
+
+static void
+source_smime_set_property (GObject *object,
+                           guint property_id,
+                           const GValue *value,
+                           GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ENCRYPTION_CERTIFICATE:
+			e_source_smime_set_encryption_certificate (
+				E_SOURCE_SMIME (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_ENCRYPT_BY_DEFAULT:
+			e_source_smime_set_encrypt_by_default (
+				E_SOURCE_SMIME (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_ENCRYPT_TO_SELF:
+			e_source_smime_set_encrypt_to_self (
+				E_SOURCE_SMIME (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_SIGNING_ALGORITHM:
+			e_source_smime_set_signing_algorithm (
+				E_SOURCE_SMIME (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_SIGNING_CERTIFICATE:
+			e_source_smime_set_signing_certificate (
+				E_SOURCE_SMIME (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_SIGN_BY_DEFAULT:
+			e_source_smime_set_sign_by_default (
+				E_SOURCE_SMIME (object),
+				g_value_get_boolean (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_smime_get_property (GObject *object,
+                           guint property_id,
+                           GValue *value,
+                           GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ENCRYPTION_CERTIFICATE:
+			g_value_set_string (
+				value,
+				e_source_smime_get_encryption_certificate (
+				E_SOURCE_SMIME (object)));
+			return;
+
+		case PROP_ENCRYPT_BY_DEFAULT:
+			g_value_set_boolean (
+				value,
+				e_source_smime_get_encrypt_by_default (
+				E_SOURCE_SMIME (object)));
+			return;
+
+		case PROP_ENCRYPT_TO_SELF:
+			g_value_set_boolean (
+				value,
+				e_source_smime_get_encrypt_to_self (
+				E_SOURCE_SMIME (object)));
+			return;
+
+		case PROP_SIGNING_ALGORITHM:
+			g_value_set_string (
+				value,
+				e_source_smime_get_signing_algorithm (
+				E_SOURCE_SMIME (object)));
+			return;
+
+		case PROP_SIGNING_CERTIFICATE:
+			g_value_set_string (
+				value,
+				e_source_smime_get_signing_certificate (
+				E_SOURCE_SMIME (object)));
+			return;
+
+		case PROP_SIGN_BY_DEFAULT:
+			g_value_set_boolean (
+				value,
+				e_source_smime_get_sign_by_default (
+				E_SOURCE_SMIME (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_smime_finalize (GObject *object)
+{
+	ESourceSMIMEPrivate *priv;
+
+	priv = E_SOURCE_SMIME_GET_PRIVATE (object);
+
+	g_free (priv->encryption_certificate);
+	g_free (priv->signing_algorithm);
+	g_free (priv->signing_certificate);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_smime_parent_class)->finalize (object);
+}
+
+static void
+e_source_smime_class_init (ESourceSMIMEClass *class)
+{
+	GObjectClass *object_class;
+	ESourceExtensionClass *extension_class;
+
+	g_type_class_add_private (class, sizeof (ESourceSMIMEPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = source_smime_set_property;
+	object_class->get_property = source_smime_get_property;
+	object_class->finalize = source_smime_finalize;
+
+	extension_class = E_SOURCE_EXTENSION_CLASS (class);
+	extension_class->name = E_SOURCE_EXTENSION_SMIME;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ENCRYPTION_CERTIFICATE,
+		g_param_spec_string (
+			"encryption-certificate",
+			"Encryption Certificate",
+			"S/MIME certificate for encrypting messages",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ENCRYPT_BY_DEFAULT,
+		g_param_spec_boolean (
+			"encrypt-by-default",
+			"Encrypt By Default",
+			"Encrypt outgoing messages by default",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ENCRYPT_TO_SELF,
+		g_param_spec_boolean (
+			"encrypt-to-self",
+			"Encrypt To Self",
+			"Always encrypt to myself",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SIGNING_ALGORITHM,
+		g_param_spec_string (
+			"signing-algorithm",
+			"Signing Algorithm",
+			"Hash algorithm used to sign messages",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SIGNING_CERTIFICATE,
+		g_param_spec_string (
+			"signing-certificate",
+			"Signing Certificate",
+			"S/MIME certificate for signing messages",
+			NULL,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SIGN_BY_DEFAULT,
+		g_param_spec_boolean (
+			"sign-by-default",
+			"Sign By Default",
+			"Sign outgoing messages by default",
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT |
+			G_PARAM_STATIC_STRINGS |
+			E_SOURCE_PARAM_SETTING));
+}
+
+static void
+e_source_smime_init (ESourceSMIME *extension)
+{
+	extension->priv = E_SOURCE_SMIME_GET_PRIVATE (extension);
+}
+
+/**
+ * e_source_smime_get_encryption_certificate:
+ * @extension: an #ESourceExtension
+ *
+ * Returns the S/MIME certificate name used to encrypt messages.
+ *
+ * Returns: the certificate name used to encrypt messages
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_smime_get_encryption_certificate (ESourceSMIME *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SMIME (extension), NULL);
+
+	return extension->priv->encryption_certificate;
+}
+
+/**
+ * e_source_smime_set_encryption_certificate:
+ * @extension: an #ESourceSMIME
+ * @encryption_certificate: the certificate name used to encrypt messages
+ *
+ * Sets the certificate name used to encrypt messages.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_smime_set_encryption_certificate (ESourceSMIME *extension,
+                                           const gchar *encryption_certificate)
+{
+	g_return_if_fail (E_IS_SOURCE_SMIME (extension));
+
+	g_free (extension->priv->encryption_certificate);
+	extension->priv->encryption_certificate =
+		g_strdup (encryption_certificate);
+
+	g_object_notify (G_OBJECT (extension), "encryption-certificate");
+}
+
+/**
+ * e_source_smime_get_encrypt_by_default:
+ * @extension: an #ESourceSMIME
+ *
+ * Returns whether to encrypt outgoing messages by default using S/MIME
+ * software such as Mozilla Network Security Services (NSS).
+ *
+ * Returns: whether to encrypt outgoing messages by default
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_smime_get_encrypt_by_default (ESourceSMIME *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SMIME (extension), FALSE);
+
+	return extension->priv->encrypt_by_default;
+}
+
+/**
+ * e_source_smime_set_encrypt_by_default:
+ * @extension: an #ESourceSMIME
+ * @encrypt_by_default: whether to encrypt outgoing messages by default
+ *
+ * Sets whether to encrypt outgoing messages by default using S/MIME
+ * software such as Mozilla Network Security Services (NSS).
+ *
+ * Since: 3.4
+ **/
+void
+e_source_smime_set_encrypt_by_default (ESourceSMIME *extension,
+                                       gboolean encrypt_by_default)
+{
+	g_return_if_fail (E_IS_SOURCE_SMIME (extension));
+
+	extension->priv->encrypt_by_default = encrypt_by_default;
+
+	g_object_notify (G_OBJECT (extension), "encrypt-by-default");
+}
+
+/**
+ * e_source_smime_get_encrypt_to_self:
+ * @extension: an #ESourceSMIME
+ *
+ * Returns whether to "encrypt-to-self" when sending encrypted messages.
+ *
+ * Returns: whether to "encrypt-to-self"
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_smime_get_encrypt_to_self (ESourceSMIME *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SMIME (extension), FALSE);
+
+	return extension->priv->encrypt_to_self;
+}
+
+/**
+ * e_source_smime_set_encrypt_to_self:
+ * @extension: an #ESourceSMIME
+ * @encrypt_to_self: whether to "encrypt-to-self"
+ *
+ * Sets whether to "encrypt-to-self" when sending encrypted messages.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_smime_set_encrypt_to_self (ESourceSMIME *extension,
+                                    gboolean encrypt_to_self)
+{
+	g_return_if_fail (E_IS_SOURCE_SMIME (extension));
+
+	extension->priv->encrypt_to_self = encrypt_to_self;
+
+	g_object_notify (G_OBJECT (extension), "encrypt-to-self");
+}
+
+/**
+ * e_source_smime_get_signing_algorithm:
+ * @extension: an #ESourceSMIME
+ *
+ * Returns the name of the hash algorithm used to digitally sign outgoing
+ * messages.
+ *
+ * Returns: the signing algorithm for outgoing messages
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_smime_get_signing_algorithm (ESourceSMIME *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SMIME (extension), NULL);
+
+	return extension->priv->signing_algorithm;
+}
+
+/**
+ * e_source_smime_set_signing_algorithm:
+ * @extension: an #ESourceSMIME
+ * @signing_algorithm: the signing algorithm for outgoing messages
+ *
+ * Sets the name of the hash algorithm used to digitally sign outgoing
+ * messages.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_smime_set_signing_algorithm (ESourceSMIME *extension,
+                                      const gchar *signing_algorithm)
+{
+	g_return_if_fail (E_IS_SOURCE_SMIME (extension));
+
+	g_free (extension->priv->signing_algorithm);
+	extension->priv->signing_algorithm = g_strdup (signing_algorithm);
+
+	g_object_notify (G_OBJECT (extension), "signing-algorithm");
+}
+
+/**
+ * e_source_smime_get_signing_certificate:
+ * @extension: an #ESourceSMIME
+ *
+ * Returns the S/MIME certificate name used to sign messages.
+ *
+ * Returns: the certificate name used to sign messages
+ *
+ * Since: 3.4
+ **/
+const gchar *
+e_source_smime_get_signing_certificate (ESourceSMIME *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SMIME (extension), NULL);
+
+	return extension->priv->signing_certificate;
+}
+
+/**
+ * e_source_smime_set_signing_certificate:
+ * @extension: an #ESourceSMIME
+ * @signing_certificate: the certificate name used to sign messages
+ *
+ * Sets the S/MIME certificate name used to sign messages.
+ *
+ * Since: 3.4
+ **/
+void
+e_source_smime_set_signing_certificate (ESourceSMIME *extension,
+                                        const gchar *signing_certificate)
+{
+	g_return_if_fail (E_IS_SOURCE_SMIME (extension));
+
+	g_free (extension->priv->signing_certificate);
+	extension->priv->signing_certificate = g_strdup (signing_certificate);
+
+	g_object_notify (G_OBJECT (extension), "signing-certificate");
+}
+
+/**
+ * e_source_smime_get_sign_by_default:
+ * @extension: an #ESourceSMIME
+ *
+ * Returns whether to digitally sign outgoing messages by default using
+ * S/MIME software such as Mozilla Network Security Services (NSS).
+ *
+ * Returns: whether to sign outgoing messages by default
+ *
+ * Since: 3.4
+ **/
+gboolean
+e_source_smime_get_sign_by_default (ESourceSMIME *extension)
+{
+	g_return_val_if_fail (E_IS_SOURCE_SMIME (extension), FALSE);
+
+	return extension->priv->sign_by_default;
+}
+
+/**
+ * e_source_smime_set_sign_by_default:
+ * @extension: an #ESourceSMIME
+ * @sign_by_default: whether to sign outgoing messages by default
+ *
+ * Sets whether to digitally sign outgoing messages by default using
+ * S/MIME software such as Mozilla Network Security Services (NSS).
+ *
+ * Since: 3.4
+ **/
+void
+e_source_smime_set_sign_by_default (ESourceSMIME *extension,
+                                    gboolean sign_by_default)
+{
+	g_return_if_fail (E_IS_SOURCE_SMIME (extension));
+
+	extension->priv->sign_by_default = sign_by_default;
+
+	g_object_notify (G_OBJECT (extension), "sign-by-default");
+}
+
diff --git a/libedataserver/e-source-smime.h b/libedataserver/e-source-smime.h
new file mode 100644
index 0000000..a6d55d8
--- /dev/null
+++ b/libedataserver/e-source-smime.h
@@ -0,0 +1,111 @@
+/*
+ * e-source-smime.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_SMIME_H
+#define E_SOURCE_SMIME_H
+
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_SMIME \
+	(e_source_smime_get_type ())
+#define E_SOURCE_SMIME(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_SOURCE_SMIME, ESourceSMIME))
+#define E_SOURCE_SMIME_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_SOURCE_SMIME, ESourceSMIMEClass))
+#define E_IS_SOURCE_SMIME(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_SOURCE_SMIME))
+#define E_IS_SOURCE_SMIME_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_SOURCE_SMIME))
+#define E_SOURCE_SMIME_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_SOURCE_SMIME, ESourceSMIMEClass))
+
+/**
+ * E_SOURCE_EXTENSION_SMIME:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceSMIME.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_SMIME "Secure MIME (S/MIME)"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceSMIME ESourceSMIME;
+typedef struct _ESourceSMIMEClass ESourceSMIMEClass;
+typedef struct _ESourceSMIMEPrivate ESourceSMIMEPrivate;
+
+/**
+ * ESourceSMIME:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceSMIME {
+	ESourceExtension parent;
+	ESourceSMIMEPrivate *priv;
+};
+
+struct _ESourceSMIMEClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_smime_get_type		(void);
+const gchar *	e_source_smime_get_encryption_certificate
+						(ESourceSMIME *extension);
+void		e_source_smime_set_encryption_certificate
+						(ESourceSMIME *extension,
+						 const gchar *encryption_certificate);
+gboolean	e_source_smime_get_encrypt_by_default
+						(ESourceSMIME *extension);
+void		e_source_smime_set_encrypt_by_default
+						(ESourceSMIME *extension,
+						 gboolean encrypt_by_default);
+gboolean	e_source_smime_get_encrypt_to_self
+						(ESourceSMIME *extension);
+void		e_source_smime_set_encrypt_to_self
+						(ESourceSMIME *extension,
+						 gboolean encrypt_to_self);
+const gchar *	e_source_smime_get_signing_algorithm
+						(ESourceSMIME *extension);
+void		e_source_smime_set_signing_algorithm
+						(ESourceSMIME *extension,
+						 const gchar *signing_algorithm);
+const gchar *	e_source_smime_get_signing_certificate
+						(ESourceSMIME *extension);
+void		e_source_smime_set_signing_certificate
+						(ESourceSMIME *extension,
+						 const gchar *signing_certificate);
+gboolean	e_source_smime_get_sign_by_default
+						(ESourceSMIME *extension);
+void		e_source_smime_set_sign_by_default
+						(ESourceSMIME *extension,
+						 gboolean sign_by_default);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_SMIME_H */
+
diff --git a/libedataserver/e-source-webdav.c b/libedataserver/e-source-webdav.c
new file mode 100644
index 0000000..cc74812
--- /dev/null
+++ b/libedataserver/e-source-webdav.c
@@ -0,0 +1,667 @@
+/*
+ * 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/>
+ *
+ */
+
+/**
+ * SECTION: e-source-webdav
+ * @include: libedataserver/e-source-webdav.h
+ * @short_description: #ESource extension for WebDAV settings
+ *
+ * The #ESourceWebdav extension tracks settings for accessing resources
+ * on a remote WebDAV server.
+ *
+ * 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 #ESourceAuthentication
+ * and #ESourceSecurity.
+ *
+ * Access the extension as follows:
+ *
+ * |[
+ *   #include <libedataserver/e-source-webdav.h>
+ *
+ *   ESourceWebdav *extension;
+ *
+ *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
+ * ]|
+ **/
+
+#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);
+}
+
+/**
+ * e_source_webdav_get_avoid_ifmatch:
+ * @extension: an #ESourceWebdav
+ *
+ * This setting works around a
+ * <ulink url="https://issues.apache.org/bugzilla/show_bug.cgi?id=38034";>
+ * bug</ulink> in older Apache mod_dav versions.
+ *
+ * <note>
+ *   <para>
+ *     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.
+ *   </para>
+ * </note>
+ *
+ * Returns: whether the WebDAV server is known to exhibit the bug
+ *
+ * Since: 3.4
+ **/
+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;
+}
+
+/**
+ * e_source_webdav_set_avoid_ifmatch:
+ * @extension: an #ESourceWebdav
+ * @avoid_ifmatch: whether the WebDAV server is known to exhibit the bug
+ *
+ * This setting works around a
+ * <ulink url="https://issues.apache.org/bugzilla/show_bug.cgi?id=38034";>
+ * bug</ulink> in older Apache mod_dav versions.
+ *
+ * <note>
+ *   <para>
+ *     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.
+ *   </para>
+ * </note>
+ *
+ * Since: 3.4
+ **/
+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");
+}
+
+/**
+ * e_source_webdav_get_display_name:
+ * @extension: an #ESourceWebdav
+ *
+ * Returns the last known display name of a WebDAV resource, which may
+ * differ from the #ESource:display-name property of the #ESource to which
+ * @extension belongs.
+ *
+ * Returns: the display name of the WebDAV resource
+ *
+ * Since: 3.4
+ **/
+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;
+}
+
+/**
+ * e_source_webdav_set_display_name:
+ * @extension: an #ESourceWebdav
+ * @display_name: the display name of the WebDAV resource
+ *
+ * Updates the last known display name of a WebDAV resource, which may
+ * differ from the #ESource:display-name property of the #ESource to which
+ * @extension belongs.
+ *
+ * Since: 3.4
+ **/
+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");
+}
+
+/**
+ * e_source_webdav_get_soup_uri:
+ * @extension: an #ESourceWebdav
+ *
+ * This is a convenience function which returns a newly-allocated
+ * #SoupURI, its contents assembled from the #ESourceAuthentication
+ * extension, the #ESourceSecurity extension, and @extension itself.
+ * Free the returned #SoupURI with soup_uri_free().
+ *
+ * Returns: a newly-allocated #SoupURI
+ *
+ * Since: 3.4
+ **/
+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);
+}
+
+/**
+ * e_source_webdav_set_soup_uri:
+ * @extension: an #ESourceWebdav
+ * @uri: a #SoupURI
+ *
+ * This is a convenience function which propagates the components of
+ * @uri to the #ESourceAuthentication extension, the #ESourceSecurity
+ * extension, and @extension itself.  (The "query" and "fragment"
+ * components of @uri are ignored.)
+ *
+ * Since: 3.4
+ **/
+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..3bf984e
--- /dev/null
+++ b/libedataserver/e-source-webdav.h
@@ -0,0 +1,94 @@
+/*
+ * 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
+
+#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))
+
+/**
+ * E_SOURCE_EXTENSION_WEBDAV_BACKEND:
+ *
+ * Pass this extension name to e_source_get_extension() to access
+ * #ESourceWebdav.  This is also used as a group name in key files.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_EXTENSION_WEBDAV_BACKEND "WebDAV Backend"
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceWebdav ESourceWebdav;
+typedef struct _ESourceWebdavClass ESourceWebdavClass;
+typedef struct _ESourceWebdavPrivate ESourceWebdavPrivate;
+
+/**
+ * ESourceWebdav:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.4
+ **/
+struct _ESourceWebdav {
+	ESourceExtension parent;
+	ESourceWebdavPrivate *priv;
+};
+
+struct _ESourceWebdavClass {
+	ESourceExtensionClass parent_class;
+};
+
+GType		e_source_webdav_get_type	(void);
+gboolean	e_source_webdav_get_avoid_ifmatch
+						(ESourceWebdav *extension);
+void		e_source_webdav_set_avoid_ifmatch
+						(ESourceWebdav *extension,
+						 gboolean avoid_ifmatch);
+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);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_WEBDAV_H */
diff --git a/libedataserver/e-source.c b/libedataserver/e-source.c
index 4754615..f20893f 100644
--- a/libedataserver/e-source.c
+++ b/libedataserver/e-source.c
@@ -1,46 +1,145 @@
-/* -*- 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>
  */
 
+/**
+ * SECTION: e-source
+ * @include: libedataserver/e-source.h
+ * @short_description: Hierarchical data sources
+ *
+ * An #ESource (or "data source") is a description of a file or network
+ * location where data can be obtained (such as a mail account), or a
+ * description of a resource at that location (such as a mail folder).
+ *
+ * In more concrete terms, it's an interface for a key file.  All such
+ * key files have a main group named [Data Source].  The keys in a
+ * [Data Source] group map to #GObject properties in an #ESource.
+ *
+ * Additional groups in the key file are referred to as "extensions".
+ * #ESourceExtension serves as the base class for writing interfaces
+ * for these additional key file groups.  The keys in one of these
+ * key file groups map to #GObject properties in some custom subclass
+ * of #ESourceExtension which was written specifically for that key
+ * file group.  For example, a key file might include a group named
+ * [Calendar], whose keys map to #GObject properties in an extension
+ * class named #ESourceCalendar.
+ *
+ * Each #ESource contains an internal dictionary of extension objects,
+ * accessible by their key file group name.  e_source_get_extension()
+ * can look up extension objects by name.
+ *
+ * An #ESource is identified by a unique identifier string, or "UID",
+ * which is also the basename of the corresponding key file.  Additional
+ * files related to the #ESource, such as cache files, are usually kept
+ * in a directory named after the UID of the #ESource.  Similarly, the
+ * password for an account described by an #ESource is kept in GNOME
+ * Keyring under the UID of the #ESource.  This makes finding these
+ * additional resources simple.
+ *
+ * Several extensions for common information such as authentication
+ * details are built into libedataserver (#ESourceAuthentication, for
+ * example).  Backend modules may also define their own extensions for
+ * information and settings unique to the backend.  #ESourceExtension
+ * subclasses written for specific backends are generally not available
+ * to applications and shared libraries.  This is by design, to try and
+ * keep backend-specific knowledge from creeping into places it doesn't
+ * belong.
+ **/
+
 #include "e-source.h"
 
 #include <config.h>
 #include <string.h>
 
-#include <libedataserver/e-uid.h>
-#include <libedataserver/e-source-group.h>
+#include <glib/gi18n-lib.h>
+
+#include "e-dbus-authenticator.h"
+#include "e-dbus-source.h"
+#include "e-data-server-util.h"
+#include "e-source-extension.h"
+#include "e-uid.h"
+
+/* built-in extension types */
+#include "e-source-alarms.h"
+#include "e-source-authentication.h"
+#include "e-source-autocomplete.h"
+#include "e-source-mail-account.h"
+#include "e-source-mail-composition.h"
+#include "e-source-mail-identity.h"
+#include "e-source-mail-signature.h"
+#include "e-source-mail-submission.h"
+#include "e-source-offline.h"
+#include "e-source-openpgp.h"
+#include "e-source-refresh.h"
+#include "e-source-security.h"
+#include "e-source-selectable.h"
+#include "e-source-smime.h"
+#include "e-source-webdav.h"
+
+#define E_SOURCE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_SOURCE, ESourcePrivate))
+
+#define E_SOURCE_GROUP_NAME	"Data Source"
+
+typedef struct _AuthContext AuthContext;
 
 struct _ESourcePrivate {
-	ESourceGroup *group;
+	EDBusObject *dbus_object;
 
+	gchar *backend_name;
+	gchar *display_name;
+	gchar *parent;
 	gchar *uid;
-	gchar *name;
-	gchar *relative_uri;
-	gchar *absolute_uri;
 
-	gboolean readonly;
+	/* The lock guards the key file and hash table.
+	 * XXX The GNode is not currently thread-safe. */
 
-	gchar *color_spec;
+	GNode node;
+	GKeyFile *key_file;
+	GStaticRecMutex lock;
+	GHashTable *extensions;
+	GMainContext *main_context;
 
-	GHashTable *properties;
+	gboolean enabled;
+	guint changed_idle_id;
+};
+
+/* Used in e_source_authenticate_sync() */
+struct _AuthContext {
+	ESource *source;
+	ESourceAuthenticator *auth;
+	EDBusAuthenticator *dbus_auth;
+	GCancellable *cancellable;
+	GMainLoop *main_loop;
+	ESourceAuthenticationResult auth_result;
+	gboolean authenticating;
+	gboolean success;
+	GError **error;
+};
+
+enum {
+	PROP_0,
+	PROP_BACKEND_NAME,
+	PROP_DBUS_OBJECT,
+	PROP_DISPLAY_NAME,
+	PROP_ENABLED,
+	PROP_PARENT,
+	PROP_UID
 };
 
 enum {
@@ -48,1183 +147,1870 @@ enum {
 	LAST_SIGNAL
 };
 
-static guint signals[LAST_SIGNAL] = { 0 };
+static guint signals[LAST_SIGNAL];
 
-/* Callbacks.  */
+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)
+auth_context_free (AuthContext *auth_context)
 {
-	source->priv->group = NULL;
+	if (auth_context->source != NULL)
+		g_object_unref (auth_context->source);
 
-	g_signal_emit (source, signals[CHANGED], 0);
+	if (auth_context->auth != NULL)
+		g_object_unref (auth_context->auth);
+
+	if (auth_context->dbus_auth != NULL)
+		g_object_unref (auth_context->dbus_auth);
+
+	if (auth_context->cancellable != NULL)
+		g_object_unref (auth_context->cancellable);
+
+	if (auth_context->main_loop != NULL)
+		g_main_loop_unref (auth_context->main_loop);
+
+	g_slice_free (AuthContext, auth_context);
 }
 
-/* GObject methods.  */
+static gboolean
+source_changed_idle_cb (ESource *source)
+{
+	g_static_rec_mutex_lock (&source->priv->lock);
+	source->priv->changed_idle_id = 0;
+	g_static_rec_mutex_unlock (&source->priv->lock);
 
-G_DEFINE_TYPE (ESource, e_source, G_TYPE_OBJECT)
+	g_signal_emit (source, signals[CHANGED], 0);
+
+	return FALSE;
+}
 
 static void
-impl_finalize (GObject *object)
+source_find_extension_classes_rec (GType parent_type,
+                                   GHashTable *hash_table)
 {
-	ESourcePrivate *priv = E_SOURCE (object)->priv;
+	GType *children;
+	guint n_children, ii;
 
-	g_free (priv->uid);
-	g_free (priv->name);
-	g_free (priv->relative_uri);
-	g_free (priv->absolute_uri);
-	g_free (priv->color_spec);
+	children = g_type_children (parent_type, &n_children);
+
+	for (ii = 0; ii < n_children; ii++) {
+		GType type = children[ii];
+		ESourceExtensionClass *class;
+		gpointer key;
 
-	g_hash_table_destroy (priv->properties);
+		/* Recurse over the child's children. */
+		source_find_extension_classes_rec (type, hash_table);
 
-	g_free (priv);
+		/* Skip abstract types. */
+		if (G_TYPE_IS_ABSTRACT (type))
+			continue;
+
+		class = g_type_class_ref (type);
+		key = (gpointer) class->name;
 
-	(* G_OBJECT_CLASS (e_source_parent_class)->finalize) (object);
+		if (key != NULL)
+			g_hash_table_insert (hash_table, key, class);
+		else
+			g_type_class_unref (class);
+	}
+
+	g_free (children);
+}
+
+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)
+source_set_key_file_from_property (GObject *object,
+                                   GParamSpec *pspec,
+                                   GKeyFile *key_file,
+                                   const gchar *group_name)
 {
-	ESourcePrivate *priv = E_SOURCE (object)->priv;
+	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 = e_source_parameter_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);
+		}
 
-	if (priv->group != NULL) {
-		g_object_weak_unref (G_OBJECT (priv->group), (GWeakNotify) group_weak_notify, object);
-		priv->group = NULL;
+		if (enum_value != NULL)
+			g_key_file_set_string (
+				key_file, group_name, key,
+				enum_value->value_nick);
+
+	} else if (G_VALUE_HOLDS (pvalue, G_TYPE_STRV)) {
+		const gchar **strv = g_value_get_boxed (pvalue);
+		guint length = 0;
+
+		if (strv != NULL)
+			length = g_strv_length ((gchar **) strv);
+		g_key_file_set_string_list (
+			key_file, group_name, key, strv, length);
+
+	/* 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);
 	}
 
-	(* G_OBJECT_CLASS (e_source_parent_class)->dispose) (object);
+	g_free (key);
+	g_value_unset (pvalue);
+	g_value_unset (svalue);
+	g_slice_free (GValue, pvalue);
+	g_slice_free (GValue, svalue);
 }
 
-/* Initialization.  */
-
 static void
-e_source_class_init (ESourceClass *class)
+source_set_property_from_key_file (GObject *object,
+                                   GParamSpec *pspec,
+                                   GKeyFile *key_file,
+                                   const gchar *group_name)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (class);
-
-	object_class->dispose  = impl_dispose;
-	object_class->finalize = impl_finalize;
-
-	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);
+	gchar *key;
+	GValue *value;
+	GError *error = NULL;
+
+	value = g_slice_new0 (GValue);
+	key = e_source_parameter_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);
+		}
+
+	} else if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) {
+		gboolean v_boolean;
+
+		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);
+		}
+
+	} 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);
+		}
+
+	} else if (G_IS_PARAM_SPEC_FLOAT (pspec) ||
+		   G_IS_PARAM_SPEC_DOUBLE (pspec)) {
+		gdouble v_double;
+
+		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);
+		}
+
+	} else if (G_IS_PARAM_SPEC_STRING (pspec)) {
+		gchar *v_string;
+
+		/* 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_take_string (value, v_string);
+		}
+
+	} else if (g_type_is_a (pspec->value_type, G_TYPE_STRV)) {
+		gchar **strv;
+
+		strv = g_key_file_get_string_list (
+			key_file, group_name, key, NULL, &error);
+		if (error == NULL) {
+			g_value_init (value, G_TYPE_STRV);
+			g_value_take_boxed (value, strv);
+		}
+
+	} 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);
+		}
+
+	} else {
+		g_warning (
+			"No GKeyFile-to-GValue converter defined "
+			"for type '%s'", G_VALUE_TYPE_NAME (value));
+	}
+
+	/* 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
-e_source_init (ESource *source)
+source_load_from_key_file (GObject *object,
+                           GKeyFile *key_file,
+                           const gchar *group_name)
 {
-	ESourcePrivate *priv;
+	GObjectClass *class;
+	GParamSpec **properties;
+	guint n_properties, ii;
 
-	priv = g_new0 (ESourcePrivate, 1);
-	source->priv = priv;
+	class = G_OBJECT_GET_CLASS (object);
+	properties = g_object_class_list_properties (class, &n_properties);
 
-	priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal,
-						  g_free, g_free);
+	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);
+		}
+	}
+
+	g_object_thaw_notify (object);
+
+	g_free (properties);
 }
 
-/* Private methods. */
+static void
+source_save_to_key_file (GObject *object,
+                         GKeyFile *key_file,
+                         const gchar *group_name)
+{
+	GObjectClass *class;
+	GParamSpec **properties;
+	guint n_properties, ii;
+
+	class = G_OBJECT_GET_CLASS (object);
+	properties = g_object_class_list_properties (class, &n_properties);
+
+	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);
+		}
+	}
+
+	g_free (properties);
+}
 
 static gboolean
-set_color_spec (ESource *source,
-                const gchar *color_spec)
+source_parse_dbus_data (ESource *source,
+                        GError **error)
 {
-	ESourcePrivate *priv = source->priv;
-	gboolean do_cmp;
+	EDBusObject *dbus_object;
+	EDBusSource *dbus_source;
+	GKeyFile *key_file;
+	gchar *data;
+	gboolean success;
 
-	if (color_spec == priv->color_spec)
+	dbus_object = e_source_get_dbus_object (source);
+	dbus_source = e_dbus_object_get_source (dbus_object);
+	data = e_dbus_source_dup_data (dbus_source);
+	g_object_unref (dbus_source);
+
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	key_file = source->priv->key_file;
+
+	success = g_key_file_load_from_data (
+		key_file, data, strlen (data),
+		G_KEY_FILE_KEEP_COMMENTS |
+		G_KEY_FILE_KEEP_TRANSLATIONS,
+		error);
+
+	g_free (data);
+	data = NULL;
+
+	if (!success)
 		return FALSE;
 
-	do_cmp = (color_spec != NULL && priv->color_spec != NULL);
-	if (do_cmp && g_ascii_strcasecmp (color_spec, priv->color_spec) == 0)
+	/* Make sure the key file has a [Data Source] 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);
 		return FALSE;
+	}
 
-	g_free (priv->color_spec);
-	priv->color_spec = g_strdup (color_spec);
+	/* Populate ESource properties from the [Data Source] group.
+	 * The other key file groups will be fed to extension objects
+	 * as needed.  This is better than trying to create extension
+	 * objects from the key file groups up front, because not all
+	 * the extension classes may be registered at this point. */
+	source_load_from_key_file (
+		G_OBJECT (source), key_file, E_SOURCE_GROUP_NAME);
 
 	return TRUE;
 }
 
-/**
- * e_source_new:
- * @name: a display name for the source
- * @relative_uri: a relative URI for the source
- *
- * Creates a new #ESource instance, and gives it a display name specified
- * by @name and a relative URI specified by @relative_uri.
- *
- * Returns: a new #ESource
- **/
-ESource *
-e_source_new (const gchar *name,
-              const gchar *relative_uri)
+static void
+source_notify_dbus_data_cb (EDBusSource *dbus_source,
+                            GParamSpec *pspec,
+                            ESource *source)
 {
-	ESource *source;
+	GError *error = NULL;
 
-	g_return_val_if_fail (name != NULL, NULL);
-	g_return_val_if_fail (relative_uri != NULL, NULL);
+	g_static_rec_mutex_lock (&source->priv->lock);
 
-	source = g_object_new (E_TYPE_SOURCE, NULL);
-	source->priv->uid = e_uid_new ();
-
-	e_source_set_name (source, name);
-	e_source_set_relative_uri (source, relative_uri);
+	/* Since the source data came from a GKeyFile structure on the
+	 * server-side, this should never fail.  But we'll print error
+	 * messages to the terminal just in case. */
+	if (!source_parse_dbus_data (source, &error)) {
+		g_return_if_fail (error != NULL);
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
 
-	return source;
+	g_static_rec_mutex_unlock (&source->priv->lock);
 }
 
-/**
- * e_source_new_with_absolute_uri:
- * @name: a display name for the source
- * @absolute_uri: a custom absolute URI for the source
- *
- * Creates a new #ESource instance, and gives it a display name specified
- * by @name and a custom absolute URI specified by @abolute_uri.
- *
- * Returns: a new #ESource
- **/
-ESource *
-e_source_new_with_absolute_uri (const gchar *name,
-                                const gchar *absolute_uri)
+static void
+source_set_dbus_object (ESource *source,
+                        EDBusObject *dbus_object)
 {
-	ESource *source;
+	/* D-Bus object will be NULL when configuring a new source. */
+	if (dbus_object == NULL)
+		return;
 
-	g_return_val_if_fail (name != NULL, NULL);
-	g_return_val_if_fail (absolute_uri != NULL, NULL);
+	g_return_if_fail (E_DBUS_IS_OBJECT (dbus_object));
+	g_return_if_fail (source->priv->dbus_object == NULL);
 
-	source = g_object_new (E_TYPE_SOURCE, NULL);
-	source->priv->uid = e_uid_new ();
+	source->priv->dbus_object = g_object_ref (dbus_object);
+}
 
-	e_source_set_name (source, name);
-	e_source_set_absolute_uri (source, absolute_uri);
+static void
+source_set_property (GObject *object,
+                     guint property_id,
+                     const GValue *value,
+                     GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_BACKEND_NAME:
+			e_source_set_backend_name (
+				E_SOURCE (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_DBUS_OBJECT:
+			source_set_dbus_object (
+				E_SOURCE (object),
+				g_value_get_object (value));
+			return;
+
+		case PROP_DISPLAY_NAME:
+			e_source_set_display_name (
+				E_SOURCE (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_ENABLED:
+			e_source_set_enabled (
+				E_SOURCE (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_PARENT:
+			e_source_set_parent (
+				E_SOURCE (object),
+				g_value_get_string (value));
+			return;
+	}
 
-	return source;
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
-/**
- * e_source_new_from_xml_node:
- * @node: a pointer to the XML node to parse
- *
- * Creates a new #ESource instance from the XML specification in @node.
- * If the XML specification is invalid, the function returns %NULL.
- *
- * Returns: a new #ESource, or %NULL
- **/
-ESource *
-e_source_new_from_xml_node (xmlNodePtr node)
+static void
+source_get_property (GObject *object,
+                     guint property_id,
+                     GValue *value,
+                     GParamSpec *pspec)
 {
-	ESource *source;
-	xmlChar *uid;
+	switch (property_id) {
+		case PROP_BACKEND_NAME:
+			g_value_set_string (
+				value, e_source_get_backend_name (
+				E_SOURCE (object)));
+			return;
+
+		case PROP_DBUS_OBJECT:
+			g_value_set_object (
+				value, e_source_get_dbus_object (
+				E_SOURCE (object)));
+			return;
+
+		case PROP_DISPLAY_NAME:
+			g_value_set_string (
+				value, e_source_get_display_name (
+				E_SOURCE (object)));
+			return;
+
+		case PROP_ENABLED:
+			g_value_set_boolean (
+				value, e_source_get_enabled (
+				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 void
+source_dispose (GObject *object)
+{
+	ESourcePrivate *priv;
 
-	uid = xmlGetProp (node, (xmlChar *)"uid");
-	if (uid == NULL)
-		return NULL;
+	priv = E_SOURCE_GET_PRIVATE (object);
 
-	source = g_object_new (E_TYPE_SOURCE, NULL);
+	if (priv->dbus_object != NULL) {
+		EDBusSource *dbus_source;
 
-	source->priv->uid = g_strdup ((gchar *) uid);
-	xmlFree (uid);
+		dbus_source = e_dbus_object_get_source (priv->dbus_object);
+		g_signal_handlers_disconnect_matched (
+			dbus_source, G_SIGNAL_MATCH_DATA,
+			0, 0, NULL, NULL, object);
+		g_object_unref (dbus_source);
 
-	if (e_source_update_from_xml_node (source, node, NULL))
-		return source;
+		g_object_unref (priv->dbus_object);
+		priv->dbus_object = NULL;
+	}
 
-	g_object_unref (source);
-	return NULL;
+	g_hash_table_remove_all (priv->extensions);
+
+	if (priv->main_context != NULL) {
+		g_main_context_unref (priv->main_context);
+		priv->main_context = NULL;
+	}
+
+	if (priv->changed_idle_id != 0) {
+		g_source_remove (priv->changed_idle_id);
+		priv->changed_idle_id = 0;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (e_source_parent_class)->dispose (object);
 }
 
 static void
-import_properties (ESource *source,
-                   xmlNodePtr prop_root)
+source_finalize (GObject *object)
 {
-	ESourcePrivate *priv = source->priv;
-	xmlNodePtr prop_node;
+	ESourcePrivate *priv;
 
-	for (prop_node = prop_root->children; prop_node; prop_node = prop_node->next) {
-		xmlChar *name, *value;
+	priv = E_SOURCE_GET_PRIVATE (object);
 
-		if (!prop_node->name || strcmp ((gchar *)prop_node->name, "property"))
-			continue;
+	g_node_unlink (&priv->node);
 
-		name = xmlGetProp (prop_node, (xmlChar *)"name");
-		value = xmlGetProp (prop_node, (xmlChar *)"value");
+	g_free (priv->backend_name);
+	g_free (priv->display_name);
+	g_free (priv->parent);
+	g_free (priv->uid);
 
-		if (name && value)
-			g_hash_table_insert (priv->properties, g_strdup ((gchar *) name), g_strdup ((gchar *) value));
+	g_key_file_free (priv->key_file);
+	g_static_rec_mutex_free (&priv->lock);
+	g_hash_table_destroy (priv->extensions);
 
-		if (name)
-			xmlFree (name);
-		if (value)
-			xmlFree (value);
-	}
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_source_parent_class)->finalize (object);
 }
 
-typedef struct
-{
-	gboolean equal;
-	GHashTable *table2;
-} hash_compare_data;
-
 static void
-compare_str_hash (gpointer key,
-                  gpointer value,
-                  hash_compare_data *cd)
+source_notify (GObject *object,
+               GParamSpec *pspec)
 {
-	gpointer value2 = g_hash_table_lookup (cd->table2, key);
-	if (value2 == NULL || g_str_equal (value, value2) == FALSE)
-		cd->equal = FALSE;
+	e_source_changed (E_SOURCE (object));
 }
 
 static gboolean
-compare_str_hashes (GHashTable *table1,
-                    GHashTable *table2)
+source_initable_init (GInitable *initable,
+                      GCancellable *cancellable,
+                      GError **error)
 {
-	hash_compare_data cd;
+	ESource *source;
+	EDBusObject *dbus_object;
+	static guint scratch_source_uid = 0;
+	gboolean success = TRUE;
 
-	if (g_hash_table_size (table1) != g_hash_table_size (table2))
-		return FALSE;
+	source = E_SOURCE (initable);
+	dbus_object = e_source_get_dbus_object (source);
 
-	cd.equal = TRUE;
-	cd.table2 = table2;
-	g_hash_table_foreach (table1, (GHFunc) compare_str_hash, &cd);
-	return cd.equal;
-}
+	/* The D-Bus object has our server-assigned UID. */
+	if (dbus_object != NULL) {
+		EDBusSource *dbus_source;
 
-/**
- * e_source_update_from_xml_node:
- * @source: an #ESource.
- * @node: a pointer to the XML node to parse
- * @changed_return: return location for change confirmation, or %NULL
- *
- * Update the #ESource attributes from @node.  If @changed_return is
- * non-%NULL, it will be set to %TRUE if any attributes were actually
- * changed in the course of the update.  This will also emit the
- * #ESource::changed signal if any attributes were actually changed.
- *
- * 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);
-		}
-
-		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;
+		dbus_source = e_dbus_object_get_source (dbus_object);
 
-			tmp[strlen (tmp) - strlen (source->priv->relative_uri)] = 0;
-			source->priv->absolute_uri = g_strconcat (tmp, (gchar *) relative_uri, NULL);
+		/* The UID never changes, so we can cache a copy. */
+		source->priv->uid = e_dbus_source_dup_uid (dbus_source);
 
-			g_free (tmp);
-		}
+		g_signal_connect (
+			dbus_source, "notify::data",
+			G_CALLBACK (source_notify_dbus_data_cb), source);
 
-		g_free (abs_uri);
+		success = source_parse_dbus_data (source, error);
 
-		g_free (source->priv->relative_uri);
-		source->priv->relative_uri = g_strdup ((gchar *) relative_uri);
+		g_object_unref (dbus_source);
 
-		changed = TRUE;
+	/* No D-Bus object implies we're configuring a new source, and
+	 * that this ESource instance is just an offline container to be
+	 * discarded after its data is submitted to the registry server.
+	 *
+	 * Still, functions such as e_source_equal() depend on all
+	 * ESource instances having some sort of UID.  So we assign
+	 * our own UID for it; one that clear distinguishes it from
+	 * server-assigned UIDs. */
+	} else {
+		source->priv->uid = g_strdup_printf (
+			"scratch-source-%d", scratch_source_uid++);
 	}
 
-	if (absolute_uri != NULL) {
-		g_free (source->priv->absolute_uri);
+	return success;
+}
 
-		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 = g_strdup ("local:system");
-		else
-			source->priv->absolute_uri = g_strdup ((gchar *) absolute_uri);
-		changed = TRUE;
-	}
+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_DBUS_OBJECT,
+		g_param_spec_object (
+			"dbus-object",
+			"D-Bus Object",
+			"The D-Bus object for the data source",
+			E_DBUS_TYPE_OBJECT,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY |
+			G_PARAM_STATIC_STRINGS));
+
+	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",
+			_("Unnamed"),
+			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_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));
+
+	/**
+	 * ESource::changed:
+	 * @source: the #ESource that received the signal
+	 *
+	 * The ::changed signal is emitted when a property in @source or
+	 * one of its extension objects changes.  A common use for this
+	 * signal is to notify a #GtkTreeModel containing data collected
+	 * from #ESource<!-- -->s that it needs to update a row.
+	 **/
+	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);
+
+	/* Register built-in ESourceExtension types. */
+	E_TYPE_SOURCE_ALARMS;
+	E_TYPE_SOURCE_AUTHENTICATION;
+	E_TYPE_SOURCE_AUTOCOMPLETE;
+	E_TYPE_SOURCE_MAIL_ACCOUNT;
+	E_TYPE_SOURCE_MAIL_COMPOSITION;
+	E_TYPE_SOURCE_MAIL_IDENTITY;
+	E_TYPE_SOURCE_MAIL_SIGNATURE;
+	E_TYPE_SOURCE_MAIL_SUBMISSION;
+	E_TYPE_SOURCE_OFFLINE;
+	E_TYPE_SOURCE_OPENPGP;
+	E_TYPE_SOURCE_REFRESH;
+	E_TYPE_SOURCE_SECURITY;
+	E_TYPE_SOURCE_SELECTABLE;
+	E_TYPE_SOURCE_SMIME;
+	E_TYPE_SOURCE_WEBDAV;
+}
 
-	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);
-	}
+static void
+e_source_initable_init (GInitableIface *interface)
+{
+	interface->init = source_initable_init;
+}
 
-	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;
-	}
+static void
+e_source_init (ESource *source)
+{
+	GHashTable *extensions;
+	GMainContext *main_context;
 
-	for (node = node->children; node; node = node->next) {
-		if (!node->name)
-			continue;
+	extensions = g_hash_table_new_full (
+		(GHashFunc) g_str_hash,
+		(GEqualFunc) g_str_equal,
+		(GDestroyNotify) g_free,
+		(GDestroyNotify) g_object_unref);
 
-		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;
-		}
-	}
+	source->priv = E_SOURCE_GET_PRIVATE (source);
+	source->priv->key_file = g_key_file_new ();
+	source->priv->extensions = extensions;
+
+	g_static_rec_mutex_init (&source->priv->lock);
 
-	retval = TRUE;
+	memset (&source->priv->node, 0, sizeof (GNode));
+	source->priv->node.data = source;
 
-done:
-	if (changed)
-		g_signal_emit (source, signals[CHANGED], 0);
+	main_context = g_main_context_get_thread_default ();
+	source->priv->main_context = main_context;
 
-	if (changed_return != NULL)
-		*changed_return = changed;
+	if (main_context != NULL)
+		g_main_context_ref (main_context);
+}
 
-	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);
+ESource *
+e_source_new (EDBusObject *dbus_object,
+              GError **error)
+{
+	if (dbus_object != NULL)
+		g_return_val_if_fail (E_DBUS_IS_OBJECT (dbus_object), NULL);
 
-	return retval;
+	return g_initable_new (
+		E_TYPE_SOURCE, NULL, error,
+		"dbus-object", dbus_object, NULL);
 }
 
 /**
- * e_source_uid_from_xml_node:
- * @node: a pointer to an XML node
+ * 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.
  *
- * Assuming that @node is a valid #ESource specification, retrieve the
- * source's unique identifier string from it.  Free the returned string
- * with g_free().
+ * Returns: a hash value for @source.
  *
- * Returns: the unique ID of the source specified by @node,
- *          or %NULL if @node is not a valid specification
+ * Since: 3.4
  **/
-gchar *
-e_source_uid_from_xml_node (xmlNodePtr node)
+guint
+e_source_hash (ESource *source)
 {
-	xmlChar *prop;
-	gchar *uid = NULL;
+	const gchar *uid;
 
-	prop = xmlGetProp (node, (xmlChar *) "uid");
+	g_return_val_if_fail (E_IS_SOURCE (source), 0);
 
-	if (prop != NULL) {
-		uid = g_strdup ((gchar *) prop);
-		xmlFree (prop);
-	}
+	uid = e_source_get_uid (source);
 
-	return uid;
+	return g_str_hash (uid);
 }
 
 /**
- * e_source_build_absolute_uri:
- * @source: an #ESource
+ * e_source_equal:
+ * @source1: the first #ESource
+ * @source2: the second #ESource
  *
- * Builds an absolute URI string using the base URI of the #ESourceGroup
- * to which @source belongs, and its own relative URI.  This function
- * ignores any custom absolute URIs set with e_source_set_absolute_uri().
- * Free the returned string with g_free().
+ * 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
  *
- * Returns: a newly-allocated absolute URI string
+ * Since: 3.4
  **/
-gchar *
-e_source_build_absolute_uri (ESource *source)
+gboolean
+e_source_equal (ESource *source1,
+                ESource *source2)
 {
-	const gchar *base_uri_str;
-	gchar *uri_str;
-
-	g_return_val_if_fail (source->priv->group != NULL, NULL);
-
-	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);
-	}
+	const gchar *uid1, *uid2;
 
-	return uri_str;
+	g_return_val_if_fail (E_IS_SOURCE (source1), FALSE);
+	g_return_val_if_fail (E_IS_SOURCE (source2), FALSE);
+
+	if (source1 == source2)
+		return TRUE;
+
+	uid1 = e_source_get_uid (source1);
+	uid2 = e_source_get_uid (source2);
+
+	return g_str_equal (uid1, uid2);
 }
 
 /**
- * e_source_set_group:
+ * e_source_changed:
  * @source: an #ESource
- * @group: an #ESourceGroup
- *
- * If the read-only flag for @source is set, the function does nothing.
  *
- * Otherwise, sets the group membership for @source.
+ * Emits the #ESource::changed signal from an idle callback in the
+ * #GMainContext in which @source was created.
  *
- * <note>
- *   <para>
- *     If you want to add an #ESource to an #ESourceGroup, use
- *     e_source_group_add_source().  This function only notifies
- *     @source of its group membership, but makes no effort to
- *     verify that membership with @group.
- *   </para>
- * </note>
+ * This function is primarily intended for use by #ESourceExtension
+ * when emitting a #GObject::notify signal on one of its properties.
  *
- * This will emit the #ESource::changed signal if the group membership
- * actually changed.
+ * Since: 3.4
  **/
 void
-e_source_set_group (ESource *source,
-                    ESourceGroup *group)
+e_source_changed (ESource *source)
 {
 	g_return_if_fail (E_IS_SOURCE (source));
-	g_return_if_fail (group == NULL || E_IS_SOURCE_GROUP (group));
 
-	if (source->priv->readonly)
-		return;
+	g_static_rec_mutex_lock (&source->priv->lock);
 
-	if (source->priv->group == group)
-		return;
+	if (source->priv->changed_idle_id == 0) {
+		GMainContext *main_context;
+		GSource *idle_source;
+		guint source_id;
 
-	if (source->priv->group != NULL)
-		g_object_weak_unref (
-			G_OBJECT (source->priv->group),
-			(GWeakNotify) group_weak_notify, source);
+		idle_source = g_idle_source_new ();
 
-	source->priv->group = group;
-	if (group != NULL)
-		g_object_weak_ref (
-			G_OBJECT (group), (GWeakNotify)
-			group_weak_notify, source);
+		g_source_set_callback (
+			idle_source,
+			(GSourceFunc) source_changed_idle_cb,
+			source,
+			(GDestroyNotify) NULL);
 
-	g_signal_emit (source, signals[CHANGED], 0);
+		main_context = source->priv->main_context;
+		source_id = g_source_attach (idle_source, main_context);
+		source->priv->changed_idle_id = source_id;
+
+		g_source_unref (idle_source);
+	}
+
+	g_static_rec_mutex_unlock (&source->priv->lock);
 }
 
 /**
- * e_source_set_name:
+ * e_source_get_uid:
  * @source: an #ESource
- * @name: a display name
  *
- * If the read-only flag for @source is set, the function does nothing.
+ * Returns the unique identifier string for @source.
  *
- * Otherwise, sets the display name for @source.
+ * Returns: the UID for @source
  *
- * This will emit the #ESource::changed signal if the display name
- * actually changed.
+ * Since: 3.4
  **/
-void
-e_source_set_name (ESource *source,
-                   const gchar *name)
+const gchar *
+e_source_get_uid (ESource *source)
 {
-	g_return_if_fail (E_IS_SOURCE (source));
-	g_return_if_fail (name != NULL);
-
-	if (source->priv->readonly)
-		return;
-
-	if (source->priv->name != NULL &&
-	    strcmp (source->priv->name, name) == 0)
-		return;
-
-	g_free (source->priv->name);
-	source->priv->name = g_strdup (name);
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	g_signal_emit (source, signals[CHANGED], 0);
+	return source->priv->uid;
 }
 
 /**
- * e_source_set_relative_uri:
+ * e_source_get_node:
  * @source: an #ESource
- * @relative_uri: a relative URI string
  *
- * If the read-only flag for @source is set, the function does nothing.
+ * Returns a #GNode representing the source's position within a hierarchy
+ * of sources.  The #GNode<!-- -->'s data value points back to @source.
  *
- * Otherwise, sets the relative URI for @source.  If @source is a member
- * of an #ESourceGroup and has not been given a custom absolute URI, the
- * function also generates a new absolute URI for @source.
+ * Often data such as the backend name must be fetched from a parent
+ * #ESource.  This is the mechanism for accessing a parent #ESource.
  *
- * This will emit the #ESource::changed signal if the relative URI
- * actually changed.
+ * Returns: the #GNode for @source
+ *
+ * Since: 3.4
  **/
-void
-e_source_set_relative_uri (ESource *source,
-                           const gchar *relative_uri)
+GNode *
+e_source_get_node (ESource *source)
 {
-	gchar *absolute_uri, *old_abs_uri = NULL;
-
-	g_return_if_fail (E_IS_SOURCE (source));
-
-	if (source->priv->readonly)
-		return;
-
-	if (source->priv->relative_uri == relative_uri ||
-	    (source->priv->relative_uri && relative_uri && g_str_equal (source->priv->relative_uri, relative_uri)))
-		return;
-
-	if (source->priv->group)
-		old_abs_uri = e_source_build_absolute_uri (source);
-
-	g_free (source->priv->relative_uri);
-	source->priv->relative_uri = g_strdup (relative_uri);
-
-	/* 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;
-	}
-
-	g_free (old_abs_uri);
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	g_signal_emit (source, signals[CHANGED], 0);
+	return &source->priv->node;
 }
 
 /**
- * e_source_set_absolute_uri:
+ * e_source_get_parent:
  * @source: an #ESource
- * @absolute_uri: an absolute URI string, or %NULL
  *
- * Sets a custom absolute URI for @source.  If @absolute_uri is %NULL, the
- * custom absolute URI is cleared and @source will fall back to its relative
- * URI plus the base URI of its containing #ESourceGroup.
+ * Returns the unique identifier string of the parent #ESource.
+ *
+ * Returns: the UID of the parent #ESource
  *
- * This will emit the #ESource::changed signal if the custom absolute URI
- * actually changed.
+ * Since: 3.4
  **/
-void
-e_source_set_absolute_uri (ESource *source,
-                           const gchar *absolute_uri)
+const gchar *
+e_source_get_parent (ESource *source)
 {
-	g_return_if_fail (E_IS_SOURCE (source));
-
-	if ((absolute_uri == source->priv->absolute_uri && absolute_uri == NULL)
-	    || (absolute_uri && source->priv->absolute_uri && !strcmp (source->priv->absolute_uri, absolute_uri)))
-		return;
-
-	g_free (source->priv->absolute_uri);
-	source->priv->absolute_uri = g_strdup (absolute_uri);
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	g_signal_emit (source, signals[CHANGED], 0);
+	return source->priv->parent;
 }
 
 /**
- * e_source_set_readonly:
+ * e_source_set_parent:
  * @source: an #ESource
- * @readonly: a read-only flag
+ * @parent: the UID of the parent #ESource
  *
- * Sets @source as being read-only (%TRUE) or writable (%FALSE).
- * A read-only #ESource ignores attempts to change its display name,
- * #ESourceGroup, relative URI or color.
+ * Identifies the parent of @source by its unique identifier string.
+ * This can only be set prior to adding @source to an #ESourceRegistry.
  *
- * This will emit the #ESource::changed signal if the read-only state
- * actually changed.
+ * Since: 3.4
  **/
 void
-e_source_set_readonly (ESource *source,
-                       gboolean readonly)
+e_source_set_parent (ESource *source,
+                     const gchar *parent)
 {
+	GNode *node;
+
 	g_return_if_fail (E_IS_SOURCE (source));
 
-	if (source->priv->readonly == readonly)
+	node = e_source_get_node (source);
+	if (node->parent != NULL)
 		return;
 
-	source->priv->readonly = readonly;
-
-	g_signal_emit (source, signals[CHANGED], 0);
+	g_free (source->priv->parent);
+	source->priv->parent = g_strdup (parent);
 
+	g_object_notify (G_OBJECT (source), "parent");
 }
 
 /**
- * e_source_set_color_spec:
+ * e_source_get_enabled:
  * @source: an #ESource
- * @color_spec: a string specifying the color
  *
- * 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.
+ * Returns %TRUE if @source is enabled.
+ *
+ * An application should try to honor this setting if at all possible,
+ * even if it does not provide a way to change the setting through its
+ * user interface.  Disabled data sources should generally be hidden.
  *
- * This will emit the #ESource::changed signal if the color representation
- * actually changed.
+ * Returns: whether @source is enabled
  *
- * Since: 1.10
+ * Since: 3.4
  **/
-void
-e_source_set_color_spec (ESource *source,
-                         const gchar *color_spec)
+gboolean
+e_source_get_enabled (ESource *source)
 {
-	g_return_if_fail (E_IS_SOURCE (source));
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
 
-	if (!source->priv->readonly && set_color_spec (source, color_spec))
-		g_signal_emit (source, signals[CHANGED], 0);
+	return source->priv->enabled;
 }
 
 /**
- * e_source_peek_group:
+ * e_source_set_enabled:
  * @source: an #ESource
+ * @enabled: whether to enable @source
+ *
+ * Enables or disables @source.
  *
- * Returns the #ESourceGroup to which @source belongs, or %NULL if it
- * does not belong to a group.
+ * An application should try to honor this setting if at all possible,
+ * even if it does not provide a way to change the setting through its
+ * user interface.  Disabled data sources should generally be hidden.
  *
- * Returns: (transfer none): the #ESourceGroup to which the source belongs
+ * Since: 3.4
  **/
-ESourceGroup *
-e_source_peek_group (ESource *source)
+void
+e_source_set_enabled (ESource *source,
+                      gboolean enabled)
 {
-	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+	g_return_if_fail (E_IS_SOURCE (source));
 
-	return source->priv->group;
+	source->priv->enabled = enabled;
+
+	g_object_notify (G_OBJECT (source), "enabled");
 }
 
 /**
- * e_source_peek_uid:
+ * e_source_get_extension:
  * @source: an #ESource
+ * @extension_name: an extension name
  *
- * Returns the unique identifier string for @source.
+ * Returns an instance of some #ESourceExtension subclass which registered
+ * itself under @extension_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().
  *
- * Returns: the source's unique ID
+ * 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: 3.4
  **/
-const gchar *
-e_source_peek_uid (ESource *source)
+gpointer
+e_source_get_extension (ESource *source,
+                        const gchar *extension_name)
 {
+	ESourceExtension *extension;
+	GHashTable *hash_table;
+	GTypeClass *class;
+
 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+	g_return_val_if_fail (extension_name != NULL, NULL);
+
+	g_static_rec_mutex_lock (&source->priv->lock);
+
+	/* Check if we already have the extension. */
+	extension = g_hash_table_lookup (
+		source->priv->extensions, extension_name);
+	if (extension != NULL)
+		goto exit;
+
+	/* Find all subclasses of ESourceExtensionClass. */
+	hash_table = source_find_extension_classes ();
+	class = g_hash_table_lookup (hash_table, extension_name);
+
+	/* Create a new instance of the appropriate GType. */
+	if (class != NULL) {
+		extension = g_object_new (
+			G_TYPE_FROM_CLASS (class),
+			"source", source, NULL);
+		source_load_from_key_file (
+			G_OBJECT (extension),
+			source->priv->key_file,
+			extension_name);
+		g_hash_table_insert (
+			source->priv->extensions,
+			g_strdup (extension_name), extension);
+	} else {
+		/* XXX Tie this into a debug setting for ESources. */
+#ifdef DEBUG
+		g_critical (
+			"No registered GType for ESource "
+			"extension '%s'", extension_name);
+#endif
+	}
 
-	return source->priv->uid;
+	g_hash_table_destroy (hash_table);
+
+exit:
+	g_static_rec_mutex_unlock (&source->priv->lock);
+
+	return extension;
 }
 
 /**
- * e_source_peek_name:
+ * e_source_has_extension:
  * @source: an #ESource
+ * @extension_name: an extension name
  *
- * Returns the display name for @source.
+ * Checks whether @source has an #ESourceExtension with the given name.
  *
- * Returns: the source's display name
+ * Returns: %TRUE if @source has such an extension, %FALSE if not
+ *
+ * Since: 3.4
  **/
-const gchar *
-e_source_peek_name (ESource *source)
+gboolean
+e_source_has_extension (ESource *source,
+                        const gchar *extension_name)
 {
-	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+	ESourceExtension *extension = NULL;
+
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+	g_return_val_if_fail (extension_name != NULL, FALSE);
 
-	return source->priv->name;
+	g_static_rec_mutex_lock (&source->priv->lock);
+
+	/* First check if the key file even has a group with this name,
+	 * then check if an ESourceExtensionClass is registered for it. */
+	if (g_key_file_has_group (source->priv->key_file, extension_name))
+		extension = e_source_get_extension (source, extension_name);
+
+	g_static_rec_mutex_unlock (&source->priv->lock);
+
+	return (extension != NULL);
 }
 
 /**
- * e_source_peek_relative_uri:
+ * e_source_get_dbus_object:
  * @source: an #ESource
  *
- * Returns the relative URI for @source.
+ * Returns the #EDBusObject that was passed to e_source_new().
+ *
+ * Returns: the #EDBusObject for @source, or %NULL
  *
- * Returns: the source's relative URI
+ * Since: 3.4
  **/
-const gchar *
-e_source_peek_relative_uri (ESource *source)
+EDBusObject *
+e_source_get_dbus_object (ESource *source)
 {
 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	return source->priv->relative_uri;
+	return source->priv->dbus_object;
 }
 
 /**
- * e_source_peek_absolute_uri:
+ * e_source_get_backend_name:
  * @source: an #ESource
  *
- * Returns the absolute URI for @source if it has one, or else %NULL if
- * it has only a relative URI.  e_source_get_uri() may be more convenient.
+ * Returns the backend name for @source.
+ *
+ * Returns: the backend name for @source
  *
- * Returns: the source's own absolute URI, or %NULL
+ * Since: 3.4
  **/
 const gchar *
-e_source_peek_absolute_uri (ESource *source)
+e_source_get_backend_name (ESource *source)
 {
 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	return source->priv->absolute_uri;
+	/* Check the given ESource and its parents
+	 * until we find a non-empty backend string. */
+
+	while (E_IS_SOURCE (source)) {
+		GNode *node;
+		const gchar *backend_name;
+
+		backend_name = source->priv->backend_name;
+		if (backend_name != NULL && *backend_name != '\0')
+			return backend_name;
+
+		node = e_source_get_node (source);
+		g_return_val_if_fail (node != NULL, NULL);
+		source = (node->parent != NULL) ? node->parent->data : NULL;
+	}
+
+	return NULL;
 }
 
 /**
- * e_source_peek_color_spec:
+ * e_source_set_backend_name:
  * @source: an #ESource
+ * @backend_name: a backend name
  *
- * 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: a string specifying the color
+ * Sets the backend name for @source.
  *
- * Since: 1.10
+ * Since: 3.4
  **/
-const gchar *
-e_source_peek_color_spec (ESource *source)
+void
+e_source_set_backend_name (ESource *source,
+                           const gchar *backend_name)
 {
-	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+	g_return_if_fail (E_IS_SOURCE (source));
+
+	g_free (source->priv->backend_name);
+	source->priv->backend_name = g_strdup (backend_name);
 
-	return source->priv->color_spec;
+	g_object_notify (G_OBJECT (source), "backend-name");
 }
 
 /**
- * e_source_get_readonly:
+ * e_source_get_display_name:
  * @source: an #ESource
  *
- * Returns the read-only flag for @source.
+ * Returns the display name for @source.  Use the display name to
+ * represent the #ESource in a user interface.
+ *
+ * Returns: the display name for @source
  *
- * Returns: %TRUE if the source is read-only, %FALSE if it's writable
+ * Since: 3.4
  **/
-gboolean
-e_source_get_readonly (ESource *source)
+const gchar *
+e_source_get_display_name (ESource *source)
 {
-	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	return source->priv->readonly;
+	return source->priv->display_name;
 }
 
 /**
- * e_source_get_uri:
+ * e_source_set_display_name:
  * @source: an #ESource
+ * @display_name: a display name
  *
- * Returns a newly-allocated copy of an absolute URI for @source.  If
- * @source has no absolute URI of its own, the URI is constructed from
- * the base URI of its #ESourceGroup and its relative URI.  Free the
- * returned string with g_free().
+ * Sets the display name for @source to a valid UTF-8 string.  Use the
+ * display name to represent the #ESource in a user interface.
  *
- * Returns: a newly-allocated absolute URI string
+ * Since: 3.4
  **/
-gchar *
-e_source_get_uri (ESource *source)
-{
-	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);
-
-		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)
+void
+e_source_set_display_name (ESource *source,
+                           const gchar *display_name)
 {
-	xmlNodePtr node;
+	g_return_if_fail (E_IS_SOURCE (source));
+	g_return_if_fail (display_name != NULL);
+	g_return_if_fail (g_utf8_validate (display_name, -1, NULL));
 
-	node = xmlNewChild (root, NULL, (xmlChar *)"property", NULL);
-	xmlSetProp (node, (xmlChar *)"name", key);
-	xmlSetProp (node, (xmlChar *)"value", value);
-}
+	g_free (source->priv->display_name);
+	source->priv->display_name = g_strdup (display_name);
 
-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);
-	}
+	/* Strip leading and trailing whitespace. */
+	g_strstrip (source->priv->display_name);
 
-	return node;
+	g_object_notify (G_OBJECT (source), "display-name");
 }
 
 /**
- * e_source_dump_to_xml_node:
- * @source: an #ESource
- * @parent_node: location to add XML data
+ * 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
  *
- * Converts @source to an <structname>xmlNode</structname> structure
- * and adds it as a child of @parent_node.
+ * Since: 3.4
  **/
-void
-e_source_dump_to_xml_node (ESource *source,
-                           xmlNodePtr parent_node)
+gint
+e_source_compare_by_display_name (ESource *source1,
+                                  ESource *source2)
 {
-	g_return_if_fail (E_IS_SOURCE (source));
+	const gchar *display_name1;
+	const gchar *display_name2;
+
+	display_name1 = e_source_get_display_name (source1);
+	display_name2 = e_source_get_display_name (source2);
 
-	dump_common_to_xml_node (source, parent_node);
+	return g_utf8_collate (display_name1, display_name2);
 }
 
 /**
- * e_source_to_standalone_xml:
+ * e_source_to_string:
  * @source: an #ESource
+ * @length: return location for the length of the returned string, or %NULL
  *
- * Converts @source to an XML string for permanent storage.
+ * Outputs the current contents of @source as a key file string.
  * Free the returned string with g_free().
  *
- * Returns: a newly-allocated XML string
+ * Returns: a newly-allocated string
+ *
+ * Since: 3.4
  **/
 gchar *
-e_source_to_standalone_xml (ESource *source)
+e_source_to_string (ESource *source,
+                    gsize *length)
 {
-	xmlDocPtr doc;
-	xmlNodePtr node;
-	xmlChar *xml_buffer;
-	gchar *returned_buffer;
-	gint xml_buffer_size;
-	gchar *uri;
+	GHashTableIter iter;
+	GKeyFile *key_file;
+	gpointer group_name;
+	gpointer extension;
+	gchar *data;
 
 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	doc = xmlNewDoc ((xmlChar *)"1.0");
-	node = dump_common_to_xml_node (source, NULL);
+	g_static_rec_mutex_lock (&source->priv->lock);
+
+	key_file = source->priv->key_file;
 
-	xmlDocSetRootElement (doc, node);
+	source_save_to_key_file (
+		G_OBJECT (source), key_file, E_SOURCE_GROUP_NAME);
 
-	uri = e_source_get_uri (source);
-	xmlSetProp (node, (xmlChar *)"uri", (xmlChar *)uri);
-	g_free (uri);
+	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);
 
-	xmlDocDumpMemory (doc, &xml_buffer, &xml_buffer_size);
-	xmlFreeDoc (doc);
+	data = g_key_file_to_data (key_file, length, NULL);
 
-	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_static_rec_mutex_unlock (&source->priv->lock);
 
-	return returned_buffer;
+	return data;
 }
 
 /**
- * e_source_equal:
- * @a: an #ESource
- * @b: another #ESource
+ * e_source_parameter_to_key:
+ * @param_name: a #GParamSpec name
  *
- * Compares if @a is equivalent to @b.
+ * Converts a #GParamSpec name (e.g. "foo-bar" or "foo_bar")
+ * to "CamelCase" for use as a #GKeyFile key (e.g. "FooBar").
  *
- * Returns: %TRUE if @a is equivalent to @b, %FALSE otherwise
+ * This function is made public only to aid in account migration.
+ * Applications should not need to use this.
  *
- * Since: 2.24
+ * Since: 3.4
  **/
-gboolean
-e_source_equal (ESource *a,
-                ESource *b)
+gchar *
+e_source_parameter_to_key (const gchar *param_name)
 {
-	g_return_val_if_fail (E_IS_SOURCE (a), FALSE);
-	g_return_val_if_fail (E_IS_SOURCE (b), FALSE);
+	gboolean uppercase = TRUE;
+	gchar *key, *cp;
+	gint ii;
 
-	#define ONLY_ONE_NULL(aa, bb) (((aa) == NULL && (bb) != NULL) || ((aa) != NULL && (bb) == NULL))
+	g_return_val_if_fail (param_name != NULL, NULL);
 
-	/* Compare source stuff */
-	if (a->priv->uid
-	 && b->priv->uid
-	 && g_ascii_strcasecmp (a->priv->uid, b->priv->uid))
-		return FALSE;
+	key = cp = g_malloc0 (strlen (param_name) + 1);
 
-	if (a->priv->name
-	 && b->priv->name
-	 && g_ascii_strcasecmp (a->priv->name, b->priv->name))
-		return FALSE;
+	for (ii = 0; param_name[ii] != '\0'; ii++) {
+		if (g_ascii_isalnum (param_name[ii]) && uppercase) {
+			*cp++ = g_ascii_toupper (param_name[ii]);
+			uppercase = FALSE;
+		} else if (param_name[ii] == '-' || param_name[ii] == '_')
+			uppercase = TRUE;
+		else
+			*cp++ = param_name[ii];
+	}
 
-	if (a->priv->relative_uri
-	 && b->priv->relative_uri
-	 && g_ascii_strcasecmp (a->priv->relative_uri, b->priv->relative_uri))
-		return FALSE;
+	return key;
+}
 
-	if (a->priv->absolute_uri
-	 && b->priv->absolute_uri
-	 && g_ascii_strcasecmp (a->priv->absolute_uri, b->priv->absolute_uri))
-		return FALSE;
+/* Helper for e_source_authenticate() */
+static void
+source_authenticate_thread (GSimpleAsyncResult *simple,
+                            GObject *object,
+                            GCancellable *cancellable)
+{
+	ESourceAuthenticator *auth;
+	GError *error = NULL;
 
-	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;
+	auth = g_simple_async_result_get_op_res_gpointer (simple);
 
-	if (a->priv->readonly != b->priv->readonly)
-		return FALSE;
+	e_source_authenticate_sync (
+		E_SOURCE (object), auth, cancellable, &error);
 
-	if (!compare_str_hashes (a->priv->properties, b->priv->properties))
-		return FALSE;
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
+}
+
+/* Helper for e_source_authenticate_sync() */
+static gboolean
+source_authenticate_respond_cb (AuthContext *auth_context)
+{
+	ESourceAuthenticationResult auth_result;
+	GError *non_fatal_error = NULL;
 
-	#undef ONLY_ONE_NULL
+	g_return_val_if_fail (auth_context->authenticating, FALSE);
 
-	return TRUE;
+	auth_result = auth_context->auth_result;
+
+	switch (auth_result) {
+		case E_SOURCE_AUTHENTICATION_ERROR:
+			g_print ("Authentication result for '%s': ERROR: %s\n",
+				e_source_get_display_name (
+				auth_context->source),
+				(*auth_context->error)->message);
+			break;
+		case E_SOURCE_AUTHENTICATION_ACCEPTED:
+			g_print ("Authentication result for '%s': ACCEPTED\n",
+				e_source_get_display_name (
+				auth_context->source));
+			break;
+		case E_SOURCE_AUTHENTICATION_REJECTED:
+			g_print ("Authentication result for '%s': REJECTED\n",
+				e_source_get_display_name (
+				auth_context->source));
+			break;
+		default:
+			g_warn_if_reached ();
+	}
+
+	/* Allow the next authentication attempt to proceed. */
+	auth_context->authenticating = FALSE;
+
+	/* Send the server a status update based on the authentication
+	 * result.  Note, we don't really care if the D-Bus message gets
+	 * through to the server at this point.  If it doesn't, the auth
+	 * session will either time out on its own or the authentication
+	 * dialog will eventually be dismissed by the user. */
+
+	/* If an error occurred while attempting to authenticate,
+	 * tell the server to cancel the authentication session. */
+	if (auth_result == E_SOURCE_AUTHENTICATION_ERROR) {
+		e_dbus_authenticator_call_cancel_sync (
+			auth_context->dbus_auth,
+			auth_context->cancellable,
+			&non_fatal_error);
+		g_main_loop_quit (auth_context->main_loop);
+		auth_context->success = FALSE;
+
+	/* If the password was accepted, let the server know so it
+	 * can close any authentication dialogs and save the user
+	 * provided password to the keyring. */
+	} else if (auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
+		e_dbus_authenticator_call_accepted_sync (
+			auth_context->dbus_auth,
+			auth_context->cancellable,
+			&non_fatal_error);
+		g_main_loop_quit (auth_context->main_loop);
+		auth_context->success = TRUE;
+
+	/* If the password was rejected, let the server know so it can
+	 * indicate failure and request a different password, and then
+	 * wait for the next "response" signal. */
+	} else {
+		e_dbus_authenticator_call_rejected_sync (
+			auth_context->dbus_auth,
+			auth_context->cancellable,
+			&non_fatal_error);
+	}
+
+	/* Leave breadcrumbs if something went wrong,
+	 * but don't fail the whole operation over it. */
+	if (non_fatal_error != NULL) {
+		g_warning ("%s: %s", G_STRFUNC, non_fatal_error->message);
+		g_error_free (non_fatal_error);
+	}
+
+	return FALSE;
+}
+
+/* Helper for e_source_authenticate_sync() */
+static void
+source_authenticate_authenticate_cb (EDBusAuthenticator *dbus_auth,
+                                     const gchar *password,
+                                     AuthContext *auth_context)
+{
+	GSource *idle_source;
+	GMainContext *main_context;
+	GString *cloaked_password;
+
+	/* We should only get one password at a time. */
+	g_return_if_fail (!auth_context->authenticating);
+
+	auth_context->authenticating = TRUE;
+
+	g_print ("Attempting authentication for '%s'\n",
+		e_source_get_display_name (auth_context->source));
+
+	/* This avoids revealing the password in a stack trace. */
+	cloaked_password = g_string_new (password);
+
+	/* Try authenticating with the given password.  We have to
+	 * call this synchronously because some authenticators use
+	 * mutexes to serialize I/O operations and are not prepared
+	 * to make authentication attempts from a different thread.
+	 *
+	 * Unfortunately this means we won't notice server-side
+	 * dismissals while the main loop is blocked.  We respond
+	 * to the server from a low-priority idle callback so that
+	 * any pending "dismissed" signals get handled first. */
+
+	auth_context->auth_result =
+		e_source_authenticator_try_password_sync (
+			auth_context->auth,
+			cloaked_password,
+			auth_context->cancellable,
+			auth_context->error);
+
+	idle_source = g_idle_source_new ();
+	main_context = g_main_context_get_thread_default ();
+	g_source_set_callback (
+		idle_source, (GSourceFunc)
+		source_authenticate_respond_cb,
+		auth_context, NULL);
+	g_source_attach (idle_source, main_context);
+	g_source_unref (idle_source);
+
+	g_string_free (cloaked_password, TRUE);
+}
+
+/* Helper for e_source_authenticate_sync() */
+static void
+source_authenticate_dismissed_cb (EDBusAuthenticator *dbus_auth,
+                                  AuthContext *auth_context)
+{
+	g_print ("Authentication dismissed for '%s'\n",
+		e_source_get_display_name (auth_context->source));
+
+	/* Be careful not to overwrite an existing error in case this
+	 * is called after e_source_authenticator_try_password_sync()
+	 * but prior to the idle callback. */
+	if (auth_context->auth_result != E_SOURCE_AUTHENTICATION_ERROR) {
+		/* XXX Use a separate error code for dismissals? */
+		g_set_error_literal (
+			auth_context->error,
+			G_IO_ERROR, G_IO_ERROR_CANCELLED,
+			_("The user declined to authenticate"));
+		auth_context->auth_result = E_SOURCE_AUTHENTICATION_ERROR;
+	}
+
+	g_main_loop_quit (auth_context->main_loop);
+	auth_context->success = FALSE;
 }
 
 /**
- * e_source_xmlstr_equal:
- * @a: an XML representation of an #ESource
- * @b: an XML representation of another #ESource
+ * e_source_authenticate_sync:
+ * @source: an #ESource
+ * @auth: an #ESourceAuthenticator
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Authenticates @source, using @auth to handle the authentication
+ * attempts.  The operation loops until authentication is successful or
+ * the user aborts further authentication attempts.  If an error occurs,
+ * the function will set @error and return %FALSE.
  *
- * Compares if @a is equivalent to @b.
+ * Only backend implementations should call this function.  The intent is
+ * for client applications to not have to deal with authentication at all.
  *
- * Returns: %TRUE if @a is equivalent to @b, %FALSE otherwise
+ * Returns: %TRUE on success, %FALSE on failure
  *
- * Since: 2.24
+ * Since: 3.4
  **/
 gboolean
-e_source_xmlstr_equal (const gchar *a,
-                       const gchar *b)
+e_source_authenticate_sync (ESource *source,
+                            ESourceAuthenticator *auth,
+                            GCancellable *cancellable,
+                            GError **error)
 {
-	ESource *srca, *srcb;
-	gboolean retval;
+	AuthContext *auth_context;
+	GMainContext *main_context;
+	EDBusAuthenticator *dbus_auth;
+	EDBusObject *dbus_object;
+	EDBusSource *dbus_source;
+	gchar *object_path = NULL;
+	gboolean success;
 
-	srca = e_source_new_from_standalone_xml (a);
-	srcb = e_source_new_from_standalone_xml (b);
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+	g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATOR (auth), FALSE);
 
-	retval = e_source_equal (srca, srcb);
+	dbus_object = e_source_get_dbus_object (source);
+	dbus_source = e_dbus_object_get_source (dbus_object);
 
-	g_object_unref (srca);
-	g_object_unref (srcb);
+	success = e_dbus_source_call_authenticate_sync (
+		dbus_source, &object_path, cancellable, error);
 
-	return retval;
-}
+	g_object_unref (dbus_source);
 
-/**
- * e_source_new_from_standalone_xml:
- * @xml: an XML representation of an #ESource
- *
- * Constructs an #ESource instance from an XML string representation,
- * probably generated by e_source_to_standalone_xml().
- *
- * Returns: a new #ESource
- **/
-ESource *
-e_source_new_from_standalone_xml (const gchar *xml)
-{
-	xmlDocPtr doc;
-	xmlNodePtr root;
-	ESource *source;
+	if (!success) {
+		g_warn_if_fail (object_path == NULL);
+		return FALSE;
+	}
+
+	g_return_val_if_fail (object_path != NULL, FALSE);
 
-	doc = xmlParseDoc ((xmlChar *) xml);
-	if (doc == NULL)
-		return NULL;
+	main_context = g_main_context_new ();
+	g_main_context_push_thread_default (main_context);
 
-	root = doc->children;
-	if (strcmp ((gchar *)root->name, "source") != 0)
-		return NULL;
+	dbus_auth = e_dbus_authenticator_proxy_new_for_bus_sync (
+		G_BUS_TYPE_SESSION,
+		G_DBUS_PROXY_FLAGS_NONE,
+		SOURCES_DBUS_SERVICE_NAME,
+		object_path, cancellable, error);
 
-	source = e_source_new_from_xml_node (root);
-	xmlFreeDoc (doc);
+	g_print ("Opening authentication session for '%s'... %s\n",
+		e_source_get_display_name (source),
+		(dbus_auth != NULL) ? "OK" : "ERROR");
 
-	return source;
+	g_free (object_path);
+
+	if (dbus_auth == NULL) {
+		success = FALSE;
+		goto exit;
+	}
+
+	auth_context = g_slice_new0 (AuthContext);
+	auth_context->source = g_object_ref (source);
+	auth_context->auth = g_object_ref (auth);
+	auth_context->dbus_auth = dbus_auth;  /* takes ownership */
+	auth_context->main_loop = g_main_loop_new (main_context, FALSE);
+	auth_context->error = error;
+
+	/* This just needs to be something other
+	 * than E_SOURCE_AUTHENTICATION_ERROR. */
+	auth_context->auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
+
+	if (G_IS_CANCELLABLE (cancellable))
+		auth_context->cancellable = g_object_ref (cancellable);
+
+	g_signal_connect (
+		dbus_auth, "authenticate",
+		G_CALLBACK (source_authenticate_authenticate_cb),
+		auth_context);
+
+	g_signal_connect (
+		dbus_auth, "dismissed",
+		G_CALLBACK (source_authenticate_dismissed_cb),
+		auth_context);
+
+	/* Signal the D-Bus server that we're ready to begin the
+	 * authentication session.  This must happen AFTER we've
+	 * connected to the response signal since the server may
+	 * already have a response ready and waiting for us. */
+	success = e_dbus_authenticator_call_ready_sync (
+		dbus_auth, cancellable, error);
+
+	if (success) {
+		g_main_loop_run (auth_context->main_loop);
+		success = auth_context->success;
+	}
+
+	auth_context_free (auth_context);
+
+	g_print ("Authentication session for '%s' complete.\n",
+		e_source_get_display_name (source));
+
+exit:
+	g_main_context_pop_thread_default (main_context);
+	g_main_context_unref (main_context);
+
+	return success;
 }
 
 /**
- * e_source_get_property:
+ * e_source_authenticate:
  * @source: an #ESource
- * @property_name: a custom property name
+ * @auth: an #ESourceAuthenticator
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously authenticates @source, using @auth to handle the
+ * authentication attempts.  The operation loops until authentication
+ * is successful or the user aborts further authentication attempts.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call e_source_authenticate_finish() to get the result of the operation.
  *
- * Looks up the value of a custom #ESource property.  If no such
- * property name exists in @source, the function returns %NULL.
+ * Only backend implementations should call this function.  The intent is
+ * for client applications to not have to deal with authentication at all.
  *
- * Returns: the property value, or %NULL
+ * Since: 3.4
  **/
-const gchar *
-e_source_get_property (ESource *source,
-                       const gchar *property_name)
+void
+e_source_authenticate (ESource *source,
+                       ESourceAuthenticator *auth,
+                       GCancellable *cancellable,
+                       GAsyncReadyCallback callback,
+                       gpointer user_data)
 {
-	const gchar *property_value;
+	GSimpleAsyncResult *simple;
 
-	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
-	g_return_val_if_fail (property_name != NULL, NULL);
+	g_return_if_fail (E_IS_SOURCE (source));
+	g_return_if_fail (E_IS_SOURCE_AUTHENTICATOR (auth));
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (source), callback,
+		user_data, e_source_authenticate);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, g_object_ref (auth),
+		(GDestroyNotify) g_object_unref);
 
-	property_value = g_hash_table_lookup (
-		source->priv->properties, property_name);
+	g_simple_async_result_run_in_thread (
+		simple, source_authenticate_thread,
+		G_PRIORITY_DEFAULT, cancellable);
 
-	return property_value;
+	g_object_unref (simple);
 }
 
 /**
- * e_source_get_duped_property:
+ * e_source_authenticate_finish:
  * @source: an #ESource
- * @property_name: a custom property name
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
  *
- * Looks up the value of a custom #ESource property and returns a
- * newly-allocated copy of the value.  If no such property name exists
- * in @source, the function returns %NULL.  Free the returned value
- * with g_free().
+ * Finishes the operation started with e_source_authenticate().  If
+ * an error occurred, the function will set @error and return %FALSE.
  *
- * Returns: a newly-allocated copy of the property value, or %NULL
+ * Returns: %TRUE on success, %FALSE on failure
  *
- * Since: 1.12
+ * Since: 3.4
  **/
-gchar *
-e_source_get_duped_property (ESource *source,
-                             const gchar *property_name)
+gboolean
+e_source_authenticate_finish (ESource *source,
+                              GAsyncResult *result,
+                              GError **error)
 {
-	const gchar *property_value;
+	GSimpleAsyncResult *simple;
 
-	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
-	g_return_val_if_fail (property_name != NULL, NULL);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (source), e_source_authenticate), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
+}
+
+/* Helper for e_source_submit() */
+static void
+source_submit_thread (GSimpleAsyncResult *simple,
+                      GObject *object,
+                      GCancellable *cancellable)
+{
+	GError *error = NULL;
 
-	property_value = e_source_get_property (source, property_name);
+	e_source_submit_sync (E_SOURCE (object), cancellable, &error);
 
-	return g_strdup (property_value);
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
- * e_source_set_property:
+ * e_source_submit_sync:
  * @source: an #ESource
- * @property_name: a custom property name
- * @property_value: (allow-none): a new value for the property, or %NULL
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
  *
- * Create a new custom #ESource property or replaces an existing one.  If
- * @property_value is %NULL, the property is removed from @source.  This
- * will also emit a #ESource::changed signal.
+ * Submits the current contents of @source to the D-Bus service to be saved
+ * to disk and broadcast to other clients.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ *
+ * Since: 3.4
  **/
-void
-e_source_set_property (ESource *source,
-                       const gchar *property_name,
-                       const gchar *property_value)
+gboolean
+e_source_submit_sync (ESource *source,
+                      GCancellable *cancellable,
+                      GError **error)
 {
-	g_return_if_fail (E_IS_SOURCE (source));
-	g_return_if_fail (property_name != NULL);
+	EDBusObject *dbus_object;
+	EDBusSource *dbus_source;
+	gboolean success;
+	gchar *data;
 
-	if (property_value != NULL)
-		g_hash_table_replace (
-			source->priv->properties,
-			g_strdup (property_name),
-			g_strdup (property_value));
-	else
-		g_hash_table_remove (
-			source->priv->properties, property_name);
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
 
-	g_signal_emit (source, signals[CHANGED], 0);
+	dbus_object = e_source_get_dbus_object (source);
+	g_return_val_if_fail (E_DBUS_IS_OBJECT (dbus_object), FALSE);
+
+	data = e_source_to_string (source, NULL);
+	dbus_source = e_dbus_object_get_source (dbus_object);
+
+	success = e_dbus_source_call_submit_data_sync (
+		dbus_source, data, cancellable, error);
+
+	g_object_unref (dbus_source);
+	g_free (data);
+
+	return success;
 }
 
 /**
- * e_source_foreach_property:
+ * e_source_submit:
  * @source: an #ESource
- * @func: (scope call): the function to call for each property
- * @user_data: user data to pass to the function
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously submits the current contents of @source to the D-Bus
+ * service to be saved to disk and broadcast to other clients.
+ *
+ * When the operation is finished, @callback will be called.  You can then
+ * call e_source_submit_finish() to get the result of the operation.
  *
- * Calls the given function for each property in @source.  The function
- * is passed the name and value of each property, and the given @user_data
- * argument.  The properties may not be modified while iterating over them.
+ * Since: 3.4
  **/
 void
-e_source_foreach_property (ESource *source,
-                           GHFunc func,
-                           gpointer user_data)
+e_source_submit (ESource *source,
+                 GCancellable *cancellable,
+                 GAsyncReadyCallback callback,
+                 gpointer user_data)
 {
+	GSimpleAsyncResult *simple;
+
 	g_return_if_fail (E_IS_SOURCE (source));
-	g_return_if_fail (func != NULL);
 
-	g_hash_table_foreach (source->priv->properties, func, user_data);
-}
+	simple = g_simple_async_result_new (
+		G_OBJECT (source), callback,
+		user_data, e_source_submit);
 
-static void
-copy_property (const gchar *key,
-               const gchar *value,
-               ESource *new_source)
-{
-	e_source_set_property (new_source, key, value);
+	g_simple_async_result_run_in_thread (
+		simple, source_submit_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
- * e_source_copy:
+ * e_source_submit_finish:
  * @source: an #ESource
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_submit().  If an
+ * error occurred, the function will set @error and return %FALSE.
  *
- * Creates a new #ESource instance from @source, such that passing @source
- * and the newly created instance to e_source_equal() would return %TRUE.
+ * Returns: %TRUE on success, %FALSE on failure
  *
- * Returns: (transfer full): a newly-created #ESource
+ * Since: 3.4
  **/
-ESource *
-e_source_copy (ESource *source)
+gboolean
+e_source_submit_finish (ESource *source,
+                        GAsyncResult *result,
+                        GError **error)
 {
-	ESource *new_source;
-
-	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
-
-	new_source = g_object_new (E_TYPE_SOURCE, NULL);
-	new_source->priv->uid = g_strdup (e_source_peek_uid (source));
-
-	e_source_set_name (new_source, e_source_peek_name (source));
+	GSimpleAsyncResult *simple;
 
-	new_source->priv->color_spec =
-		g_strdup (source->priv->color_spec);
-	new_source->priv->absolute_uri =
-		g_strdup (e_source_peek_absolute_uri (source));
-	new_source->priv->relative_uri =
-		g_strdup (e_source_peek_relative_uri (source));
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (source), e_source_submit), FALSE);
 
-	e_source_foreach_property (source, (GHFunc) copy_property, new_source);
+	simple = G_SIMPLE_ASYNC_RESULT (result);
 
-	return new_source;
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
diff --git a/libedataserver/e-source.h b/libedataserver/e-source.h
index bcfea16..c9b9492 100644
--- a/libedataserver/e-source.h
+++ b/libedataserver/e-source.h
@@ -1,30 +1,26 @@
-/* -*- 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>
+#include <libedataserver/e-dbus-source.h>
+#include <libedataserver/e-source-authenticator.h>
 
 /* Standard GObject macros */
 #define E_TYPE_SOURCE \
@@ -45,20 +41,47 @@
 	(G_TYPE_INSTANCE_GET_CLASS \
 	((obj), E_TYPE_SOURCE, ESourceClass))
 
-G_BEGIN_DECLS
+/**
+ * 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.
+ *
+ * Since: 3.4
+ **/
+#define E_SOURCE_PARAM_SETTING (1 << G_PARAM_USER_SHIFT)
+
+/* 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))
 
 typedef struct _ESource ESource;
 typedef struct _ESourceClass ESourceClass;
 typedef struct _ESourcePrivate ESourcePrivate;
 
-/* Avoids a cyclic dependency. */
-struct _ESourceGroup;
-
 /**
  * ESource:
  *
  * Contains only private data that should be read and manipulated using the
  * functions below.
+ *
+ * Since: 3.4
  **/
 struct _ESource {
 	GObject parent;
@@ -73,57 +96,59 @@ struct _ESourceClass {
 };
 
 GType		e_source_get_type		(void) G_GNUC_CONST;
-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,
-						 struct _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);
-struct _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_name);
-void		e_source_set_property		(ESource *source,
-						 const gchar *property_name,
-						 const gchar *property_value);
-void		e_source_foreach_property	(ESource *source,
-						 GHFunc func,
+ESource *	e_source_new			(EDBusObject *dbus_object,
+						 GError **error);
+guint		e_source_hash			(ESource *source);
+gboolean	e_source_equal			(ESource *source1,
+						 ESource *source2);
+void		e_source_changed		(ESource *source);
+const gchar *	e_source_get_uid		(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);
+gboolean	e_source_get_enabled		(ESource *source);
+void		e_source_set_enabled		(ESource *source,
+						 gboolean enabled);
+gpointer	e_source_get_extension		(ESource *source,
+						 const gchar *extension_name);
+gboolean	e_source_has_extension		(ESource *source,
+						 const gchar *extension_name);
+EDBusObject *	e_source_get_dbus_object	(ESource *source);
+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);
+gchar *		e_source_to_string		(ESource *source,
+						 gsize *length);
+gchar *		e_source_parameter_to_key	(const gchar *param_name);
+gboolean	e_source_authenticate_sync	(ESource *source,
+						 ESourceAuthenticator *auth,
+						 GCancellable *cancellable,
+						 GError **error);
+void		e_source_authenticate		(ESource *source,
+						 ESourceAuthenticator *auth,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
+						 gpointer user_data);
+gboolean	e_source_authenticate_finish	(ESource *source,
+						 GAsyncResult *result,
+						 GError **error);
+gboolean	e_source_submit_sync		(ESource *source,
+						 GCancellable *cancellable,
+						 GError **error);
+void		e_source_submit			(ESource *source,
+						 GCancellable *cancellable,
+						 GAsyncReadyCallback callback,
 						 gpointer user_data);
-gchar *		e_source_get_duped_property	(ESource *source,
-						 const gchar *property_name);
-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);
+gboolean	e_source_submit_finish		(ESource *source,
+						 GAsyncResult *result,
+						 GError **error);
 
 G_END_DECLS
 
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]