[evolution-data-server/account-mgmt: 7/38] Add new ESource classes.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/account-mgmt: 7/38] Add new ESource classes.
- Date: Fri, 11 Nov 2011 01:24:56 +0000 (UTC)
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]