[evolution] Bug 750564 - Make server settings lookup extensible



commit 62e5d0cd16f835dadef68e13014c14616b27cb50
Author: Milan Crha <mcrha redhat com>
Date:   Thu Aug 3 12:24:25 2017 +0200

    Bug 750564 - Make server settings lookup extensible

 src/e-util/CMakeLists.txt                          |    6 +
 src/e-util/e-config-lookup-result-simple.c         |  782 ++++++++++++++++++++
 src/e-util/e-config-lookup-result-simple.h         |  123 +++
 src/e-util/e-config-lookup-result.c                |  235 ++++++
 src/e-util/e-config-lookup-result.h                |   84 +++
 src/e-util/e-config-lookup.c                       |  565 ++++++++++++++
 src/e-util/e-config-lookup.h                       |  130 ++++
 src/e-util/e-simple-async-result.c                 |   21 +
 src/e-util/e-simple-async-result.h                 |    3 +
 src/e-util/e-util-enums.h                          |   61 ++-
 src/e-util/e-util.h                                |    3 +
 src/mail/CMakeLists.txt                            |    5 +
 src/mail/e-mail-autoconfig.c                       |  209 +++++-
 src/mail/e-mail-autoconfig.h                       |    4 +
 src/mail/e-mail-config-assistant.c                 |  141 +++--
 src/mail/e-mail-config-service-backend.c           |   70 ++-
 src/mail/e-mail-config-service-backend.h           |   15 +-
 src/mail/e-mail-config-service-page.c              |   55 +-
 src/mail/e-mail-config-service-page.h              |    6 +-
 src/modules/CMakeLists.txt                         |    1 +
 src/modules/config-lookup/CMakeLists.txt           |   22 +
 src/modules/config-lookup/config-lookup.c          |   38 +
 src/modules/config-lookup/e-gnome-config-lookup.c  |  145 ++++
 src/modules/config-lookup/e-gnome-config-lookup.h  |   29 +
 .../mail-config/e-mail-config-remote-accounts.c    |   20 +-
 .../mail-config/e-mail-config-smtp-backend.c       |    9 +-
 26 files changed, 2659 insertions(+), 123 deletions(-)
---
diff --git a/src/e-util/CMakeLists.txt b/src/e-util/CMakeLists.txt
index 4b2b939..260191b 100644
--- a/src/e-util/CMakeLists.txt
+++ b/src/e-util/CMakeLists.txt
@@ -99,6 +99,9 @@ set(SOURCES
        e-color-chooser-widget.c
        e-color-combo.c
        e-config.c
+       e-config-lookup.c
+       e-config-lookup-result.c
+       e-config-lookup-result-simple.c
        e-conflict-search-selector.c
        e-contact-store.c
        e-content-editor.c
@@ -365,6 +368,9 @@ set(HEADERS
        e-color-chooser-widget.h
        e-color-combo.h
        e-config.h
+       e-config-lookup.h
+       e-config-lookup-result.h
+       e-config-lookup-result-simple.h
        e-conflict-search-selector.h
        e-contact-store.h
        e-content-editor.h
diff --git a/src/e-util/e-config-lookup-result-simple.c b/src/e-util/e-config-lookup-result-simple.c
new file mode 100644
index 0000000..4c49129
--- /dev/null
+++ b/src/e-util/e-config-lookup-result-simple.c
@@ -0,0 +1,782 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION: e-config-lookup-result-simple
+ * @include: e-util/e-util.h
+ * @short_description: An implementation of configuration lookup result interface
+ *
+ * #EConfigLookupResultSimple is a simple implementation of
+ * the #EConfigLookupResult interface.
+ *
+ * Respective configuration changes are added with e_config_lookup_result_simple_add_value(),
+ * then they are saved into the #ESource in #EConfigLookupResultInterface.configure_sources()
+ * call. This does the default implementation of #EConfigLookupResultSimpleClass.configure_sources(),
+ * which any descendants can override, if needed.
+ **/
+
+#include "evolution-config.h"
+
+#include <string.h>
+#include <libedataserver/libedataserver.h>
+
+#include "e-util-enumtypes.h"
+#include "e-config-lookup-result.h"
+
+#include "e-config-lookup-result-simple.h"
+
+struct _EConfigLookupResultSimplePrivate {
+       EConfigLookupResultKind kind;
+       gint priority;
+       gchar *protocol;
+       gchar *display_name;
+       gchar *description;
+       GSList *values; /* ValueData * */
+};
+
+enum {
+       PROP_0,
+       PROP_KIND,
+       PROP_PRIORITY,
+       PROP_PROTOCOL,
+       PROP_DISPLAY_NAME,
+       PROP_DESCRIPTION
+};
+
+static void e_config_lookup_result_simple_result_init (EConfigLookupResultInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EConfigLookupResultSimple, e_config_lookup_result_simple, G_TYPE_OBJECT,
+       G_IMPLEMENT_INTERFACE (E_TYPE_CONFIG_LOOKUP_RESULT, e_config_lookup_result_simple_result_init))
+
+typedef struct _ValueData {
+       gchar *extension_name;
+       gchar *property_name;
+       GValue value;
+} ValueData;
+
+static ValueData *
+value_data_new (const gchar *extension_name,
+               const gchar *property_name,
+               const GValue *value)
+{
+       ValueData *vd;
+
+       vd = g_new0 (ValueData, 1);
+       vd->extension_name = g_strdup (extension_name);
+       vd->property_name = g_strdup (property_name);
+
+       g_value_init (&vd->value, G_VALUE_TYPE (value));
+       g_value_copy (value, &vd->value);
+
+       return vd;
+}
+
+static void
+value_data_free (gpointer ptr)
+{
+       ValueData *vd = ptr;
+
+       if (vd) {
+               g_free (vd->extension_name);
+               g_free (vd->property_name);
+               g_value_reset (&vd->value);
+               g_free (vd);
+       }
+}
+
+static EConfigLookupResultKind
+config_lookup_result_simple_get_kind (EConfigLookupResult *lookup_result)
+{
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result), 
E_CONFIG_LOOKUP_RESULT_UNKNOWN);
+
+       return E_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result)->priv->kind;
+}
+
+static gint
+config_lookup_result_simple_get_priority (EConfigLookupResult *lookup_result)
+{
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result), ~0);
+
+       return E_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result)->priv->priority;
+}
+
+static const gchar *
+config_lookup_result_simple_get_protocol (EConfigLookupResult *lookup_result)
+{
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result), NULL);
+
+       return E_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result)->priv->protocol;
+}
+
+static const gchar *
+config_lookup_result_simple_get_display_name (EConfigLookupResult *lookup_result)
+{
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result), NULL);
+
+       return E_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result)->priv->display_name;
+}
+
+static const gchar *
+config_lookup_result_simple_get_description (EConfigLookupResult *lookup_result)
+{
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result), NULL);
+
+       return E_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result)->priv->description;
+}
+
+static gboolean
+config_lookup_result_simple_configure_source (EConfigLookupResult *lookup_result,
+                                             ESource *source)
+{
+       EConfigLookupResultSimple *result_simple;
+       GSList *link;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       result_simple = E_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result);
+
+       if (!result_simple->priv->values)
+               return FALSE;
+
+       for (link = result_simple->priv->values; link; link = g_slist_next (link)) {
+               ValueData *vd = link->data;
+               gpointer extension;
+
+               if (!vd)
+                       return FALSE;
+
+               extension = e_source_get_extension (source, vd->extension_name);
+               g_warn_if_fail (extension != NULL);
+
+               if (extension)
+                       g_object_set_property (extension, vd->property_name, &vd->value);
+       }
+
+       return TRUE;
+}
+
+static gboolean
+config_lookup_result_simple_configure_source_wrapper (EConfigLookupResult *lookup_result,
+                                                     ESource *source)
+{
+       EConfigLookupResultSimpleClass *klass;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       klass = E_CONFIG_LOOKUP_RESULT_SIMPLE_GET_CLASS (lookup_result);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->configure_source != NULL, FALSE);
+
+       return klass->configure_source (lookup_result, source);
+}
+
+static void
+config_lookup_result_simple_set_kind (EConfigLookupResultSimple *result_simple,
+                                     EConfigLookupResultKind kind)
+{
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (result_simple));
+       g_return_if_fail (kind != E_CONFIG_LOOKUP_RESULT_UNKNOWN);
+
+       result_simple->priv->kind = kind;
+}
+
+static void
+config_lookup_result_simple_set_priority (EConfigLookupResultSimple *result_simple,
+                                         gint priority)
+{
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (result_simple));
+
+       result_simple->priv->priority = priority;
+}
+
+static void
+config_lookup_result_simple_set_string (EConfigLookupResultSimple *result_simple,
+                                       const gchar *value,
+                                       gchar **destination)
+{
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (result_simple));
+       g_return_if_fail (destination != NULL);
+       g_return_if_fail (*destination == NULL);
+
+       *destination = g_strdup (value);
+}
+
+static void
+config_lookup_result_simple_set_property (GObject *object,
+                                         guint property_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec)
+{
+       EConfigLookupResultSimple *result_simple = E_CONFIG_LOOKUP_RESULT_SIMPLE (object);
+
+       switch (property_id) {
+               case PROP_KIND:
+                       config_lookup_result_simple_set_kind (
+                               result_simple, g_value_get_enum (value));
+                       return;
+
+               case PROP_PRIORITY:
+                       config_lookup_result_simple_set_priority (
+                               result_simple, g_value_get_int (value));
+                       return;
+
+               case PROP_PROTOCOL:
+                       config_lookup_result_simple_set_string (
+                               result_simple, g_value_get_string (value),
+                               &result_simple->priv->protocol);
+                       return;
+
+               case PROP_DISPLAY_NAME:
+                       config_lookup_result_simple_set_string (
+                               result_simple, g_value_get_string (value),
+                               &result_simple->priv->display_name);
+                       return;
+
+               case PROP_DESCRIPTION:
+                       config_lookup_result_simple_set_string (
+                               result_simple, g_value_get_string (value),
+                               &result_simple->priv->description);
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+config_lookup_result_simple_get_property (GObject *object,
+                                         guint property_id,
+                                         GValue *value,
+                                         GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_KIND:
+                       g_value_set_enum (
+                               value,
+                               config_lookup_result_simple_get_kind (
+                               E_CONFIG_LOOKUP_RESULT (object)));
+                       return;
+
+               case PROP_PRIORITY:
+                       g_value_set_int (
+                               value,
+                               config_lookup_result_simple_get_priority (
+                               E_CONFIG_LOOKUP_RESULT (object)));
+                       return;
+
+               case PROP_PROTOCOL:
+                       g_value_set_string (
+                               value,
+                               config_lookup_result_simple_get_protocol (
+                               E_CONFIG_LOOKUP_RESULT (object)));
+                       return;
+
+               case PROP_DISPLAY_NAME:
+                       g_value_set_string (
+                               value,
+                               config_lookup_result_simple_get_display_name (
+                               E_CONFIG_LOOKUP_RESULT (object)));
+                       return;
+
+               case PROP_DESCRIPTION:
+                       g_value_set_string (
+                               value,
+                               config_lookup_result_simple_get_description (
+                               E_CONFIG_LOOKUP_RESULT (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+config_lookup_result_simple_finalize (GObject *object)
+{
+       EConfigLookupResultSimple *result_simple = E_CONFIG_LOOKUP_RESULT_SIMPLE (object);
+
+       g_free (result_simple->priv->protocol);
+       g_free (result_simple->priv->display_name);
+       g_free (result_simple->priv->description);
+       g_slist_free_full (result_simple->priv->values, value_data_free);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_config_lookup_result_simple_parent_class)->finalize (object);
+}
+
+static void
+e_config_lookup_result_simple_class_init (EConfigLookupResultSimpleClass *klass)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (klass, sizeof (EConfigLookupResultSimplePrivate));
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->set_property = config_lookup_result_simple_set_property;
+       object_class->get_property = config_lookup_result_simple_get_property;
+       object_class->finalize = config_lookup_result_simple_finalize;
+
+       klass->configure_source = config_lookup_result_simple_configure_source;
+
+       /**
+        * EConfigLookupResultSimple:kind:
+        *
+        * The kind for the #EConfigLookupResult.
+        *
+        * Since: 3.26
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_KIND,
+               g_param_spec_enum (
+                       "kind",
+                       "Kind",
+                       NULL,
+                       E_TYPE_CONFIG_LOOKUP_RESULT_KIND,
+                       E_CONFIG_LOOKUP_RESULT_UNKNOWN,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+
+       /**
+        * EConfigLookupResultSimple:priority:
+        *
+        * The priority for the #EConfigLookupResult. Lower value means higher priority.
+        *
+        * Since: 3.26
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_PRIORITY,
+               g_param_spec_int (
+                       "priority",
+                       "Priority",
+                       NULL,
+                       G_MININT, G_MAXINT, ~0,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+
+       /**
+        * EConfigLookupResultSimple:protocol:
+        *
+        * The protocol name for the #EConfigLookupResult.
+        *
+        * Since: 3.26
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_PROTOCOL,
+               g_param_spec_string (
+                       "protocol",
+                       "Protocol",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+
+       /**
+        * EConfigLookupResultSimple:display_name:
+        *
+        * The display name for the #EConfigLookupResult.
+        *
+        * Since: 3.26
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_DISPLAY_NAME,
+               g_param_spec_string (
+                       "display-name",
+                       "Display Name",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+
+       /**
+        * EConfigLookupResultSimple:description:
+        *
+        * The description for the #EConfigLookupResult.
+        *
+        * Since: 3.26
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_DESCRIPTION,
+               g_param_spec_string (
+                       "description",
+                       "Description",
+                       NULL,
+                       NULL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_config_lookup_result_simple_result_init (EConfigLookupResultInterface *iface)
+{
+       iface->get_kind = config_lookup_result_simple_get_kind;
+       iface->get_priority = config_lookup_result_simple_get_priority;
+       iface->get_protocol = config_lookup_result_simple_get_protocol;
+       iface->get_display_name = config_lookup_result_simple_get_display_name;
+       iface->get_description = config_lookup_result_simple_get_description;
+       iface->configure_source = config_lookup_result_simple_configure_source_wrapper;
+}
+
+static void
+e_config_lookup_result_simple_init (EConfigLookupResultSimple *result_simple)
+{
+       result_simple->priv = G_TYPE_INSTANCE_GET_PRIVATE (result_simple, E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE, 
EConfigLookupResultSimplePrivate);
+}
+
+/**
+ * e_config_lookup_result_simple_new:
+ * @kind: a kind of the result, one of #EConfigLookupResultKind
+ * @priority: a priority of the result
+ * @protocol: (nullable): protocol name of the result, or %NULL
+ * @display_name: display name of the result
+ * @description: description of the result
+ *
+ * Creates a new #EConfigLookupResultSimple instance with prefilled values.
+ *
+ * Returns: (transfer full): an #EConfigLookupResultSimple
+ *
+ * Since: 3.26
+ **/
+EConfigLookupResult *
+e_config_lookup_result_simple_new (EConfigLookupResultKind kind,
+                                  gint priority,
+                                  const gchar *protocol,
+                                  const gchar *display_name,
+                                  const gchar *description)
+{
+       g_return_val_if_fail (kind != E_CONFIG_LOOKUP_RESULT_UNKNOWN, NULL);
+       g_return_val_if_fail (display_name != NULL, NULL);
+       g_return_val_if_fail (description != NULL, NULL);
+
+       return g_object_new (E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE,
+               "kind", kind,
+               "priority", priority,
+               "protocol", protocol,
+               "display-name", display_name,
+               "description", description,
+               NULL);
+}
+
+/**
+ * e_config_lookup_result_simple_add_value:
+ * @lookup_result: an #EConfigLookupResultSimple
+ * @extension_name: extension name
+ * @property_name: property name within the extension
+ * @value: value to be set
+ *
+ * Adds a value to be stored into an #ESource when e_config_lookup_result_configure_source().
+ * is called. The @value is identified as a property named @property_name in an extension
+ * named @extension_name.
+ *
+ * In case multiple values are stored for the same extension and property,
+ * then the first is saved.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_result_simple_add_value (EConfigLookupResult *lookup_result,
+                                        const gchar *extension_name,
+                                        const gchar *property_name,
+                                        const GValue *value)
+{
+       EConfigLookupResultSimple *result_simple;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result));
+       g_return_if_fail (extension_name != NULL);
+       g_return_if_fail (property_name != NULL);
+       g_return_if_fail (value != NULL);
+
+       result_simple = E_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result);
+
+       result_simple->priv->values = g_slist_prepend (result_simple->priv->values,
+               value_data_new (extension_name, property_name, value));
+}
+
+/**
+ * e_config_lookup_result_simple_add_boolean:
+ * @lookup_result: an #EConfigLookupResultSimple
+ * @extension_name: extension name
+ * @property_name: property name within the extension
+ * @value: value to set
+ *
+ * Calls e_config_lookup_result_simple_add_value() with a #GValue initialized
+ * to @value.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_result_simple_add_boolean (EConfigLookupResult *lookup_result,
+                                          const gchar *extension_name,
+                                          const gchar *property_name,
+                                          gboolean value)
+{
+       GValue gvalue;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result));
+       g_return_if_fail (extension_name != NULL);
+       g_return_if_fail (property_name != NULL);
+
+       memset (&gvalue, 0, sizeof (GValue));
+       g_value_init (&gvalue, G_TYPE_BOOLEAN);
+       g_value_set_boolean (&gvalue, value);
+
+       e_config_lookup_result_simple_add_value (lookup_result, extension_name, property_name, &gvalue);
+
+       g_value_reset (&gvalue);
+}
+
+/**
+ * e_config_lookup_result_simple_add_int:
+ * @lookup_result: an #EConfigLookupResultSimple
+ * @extension_name: extension name
+ * @property_name: property name within the extension
+ * @value: value to set
+ *
+ * Calls e_config_lookup_result_simple_add_value() with a #GValue initialized
+ * to @value.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_result_simple_add_int (EConfigLookupResult *lookup_result,
+                                      const gchar *extension_name,
+                                      const gchar *property_name,
+                                      gint value)
+{
+       GValue gvalue;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result));
+       g_return_if_fail (extension_name != NULL);
+       g_return_if_fail (property_name != NULL);
+
+       memset (&gvalue, 0, sizeof (GValue));
+       g_value_init (&gvalue, G_TYPE_INT);
+       g_value_set_int (&gvalue, value);
+
+       e_config_lookup_result_simple_add_value (lookup_result, extension_name, property_name, &gvalue);
+
+       g_value_reset (&gvalue);
+}
+
+/**
+ * e_config_lookup_result_simple_add_uint:
+ * @lookup_result: an #EConfigLookupResultSimple
+ * @extension_name: extension name
+ * @property_name: property name within the extension
+ * @value: value to set
+ *
+ * Calls e_config_lookup_result_simple_add_value() with a #GValue initialized
+ * to @value.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_result_simple_add_uint (EConfigLookupResult *lookup_result,
+                                       const gchar *extension_name,
+                                       const gchar *property_name,
+                                       guint value)
+{
+       GValue gvalue;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result));
+       g_return_if_fail (extension_name != NULL);
+       g_return_if_fail (property_name != NULL);
+
+       memset (&gvalue, 0, sizeof (GValue));
+       g_value_init (&gvalue, G_TYPE_UINT);
+       g_value_set_uint (&gvalue, value);
+
+       e_config_lookup_result_simple_add_value (lookup_result, extension_name, property_name, &gvalue);
+
+       g_value_reset (&gvalue);
+}
+
+/**
+ * e_config_lookup_result_simple_add_int64:
+ * @lookup_result: an #EConfigLookupResultSimple
+ * @extension_name: extension name
+ * @property_name: property name within the extension
+ * @value: value to set
+ *
+ * Calls e_config_lookup_result_simple_add_value() with a #GValue initialized
+ * to @value.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_result_simple_add_int64 (EConfigLookupResult *lookup_result,
+                                        const gchar *extension_name,
+                                        const gchar *property_name,
+                                        gint64 value)
+{
+       GValue gvalue;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result));
+       g_return_if_fail (extension_name != NULL);
+       g_return_if_fail (property_name != NULL);
+
+       memset (&gvalue, 0, sizeof (GValue));
+       g_value_init (&gvalue, G_TYPE_INT64);
+       g_value_set_int64 (&gvalue, value);
+
+       e_config_lookup_result_simple_add_value (lookup_result, extension_name, property_name, &gvalue);
+
+       g_value_reset (&gvalue);
+}
+
+/**
+ * e_config_lookup_result_simple_add_uint64:
+ * @lookup_result: an #EConfigLookupResultSimple
+ * @extension_name: extension name
+ * @property_name: property name within the extension
+ * @value: value to set
+ *
+ * Calls e_config_lookup_result_simple_add_value() with a #GValue initialized
+ * to @value.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_result_simple_add_uint64 (EConfigLookupResult *lookup_result,
+                                         const gchar *extension_name,
+                                         const gchar *property_name,
+                                         guint64 value)
+{
+       GValue gvalue;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result));
+       g_return_if_fail (extension_name != NULL);
+       g_return_if_fail (property_name != NULL);
+
+       memset (&gvalue, 0, sizeof (GValue));
+       g_value_init (&gvalue, G_TYPE_UINT64);
+       g_value_set_uint64 (&gvalue, value);
+
+       e_config_lookup_result_simple_add_value (lookup_result, extension_name, property_name, &gvalue);
+
+       g_value_reset (&gvalue);
+}
+
+/**
+ * e_config_lookup_result_simple_add_double:
+ * @lookup_result: an #EConfigLookupResultSimple
+ * @extension_name: extension name
+ * @property_name: property name within the extension
+ * @value: value to set
+ *
+ * Calls e_config_lookup_result_simple_add_value() with a #GValue initialized
+ * to @value.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_result_simple_add_double (EConfigLookupResult *lookup_result,
+                                         const gchar *extension_name,
+                                         const gchar *property_name,
+                                         gdouble value)
+{
+       GValue gvalue;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result));
+       g_return_if_fail (extension_name != NULL);
+       g_return_if_fail (property_name != NULL);
+
+       memset (&gvalue, 0, sizeof (GValue));
+       g_value_init (&gvalue, G_TYPE_DOUBLE);
+       g_value_set_double (&gvalue, value);
+
+       e_config_lookup_result_simple_add_value (lookup_result, extension_name, property_name, &gvalue);
+
+       g_value_reset (&gvalue);
+}
+
+/**
+ * e_config_lookup_result_simple_add_string:
+ * @lookup_result: an #EConfigLookupResultSimple
+ * @extension_name: extension name
+ * @property_name: property name within the extension
+ * @value: value to set
+ *
+ * Calls e_config_lookup_result_simple_add_value() with a #GValue initialized
+ * to @value.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_result_simple_add_string (EConfigLookupResult *lookup_result,
+                                         const gchar *extension_name,
+                                         const gchar *property_name,
+                                         const gchar *value)
+{
+       GValue gvalue;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result));
+       g_return_if_fail (extension_name != NULL);
+       g_return_if_fail (property_name != NULL);
+
+       memset (&gvalue, 0, sizeof (GValue));
+       g_value_init (&gvalue, G_TYPE_STRING);
+       g_value_set_string (&gvalue, value);
+
+       e_config_lookup_result_simple_add_value (lookup_result, extension_name, property_name, &gvalue);
+
+       g_value_reset (&gvalue);
+}
+
+/**
+ * e_config_lookup_result_simple_add_enum:
+ * @lookup_result: an #EConfigLookupResultSimple
+ * @extension_name: extension name
+ * @property_name: property name within the extension
+ * @enum_type: a #GType of the enum
+ * @value: value to set
+ *
+ * Calls e_config_lookup_result_simple_add_value() with a #GValue initialized
+ * to @value.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_result_simple_add_enum (EConfigLookupResult *lookup_result,
+                                       const gchar *extension_name,
+                                       const gchar *property_name,
+                                       GType enum_type,
+                                       gint value)
+{
+       GValue gvalue;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT_SIMPLE (lookup_result));
+       g_return_if_fail (extension_name != NULL);
+       g_return_if_fail (property_name != NULL);
+
+       memset (&gvalue, 0, sizeof (GValue));
+       g_value_init (&gvalue, enum_type);
+       g_value_set_enum (&gvalue, value);
+
+       e_config_lookup_result_simple_add_value (lookup_result, extension_name, property_name, &gvalue);
+
+       g_value_reset (&gvalue);
+}
diff --git a/src/e-util/e-config-lookup-result-simple.h b/src/e-util/e-config-lookup-result-simple.h
new file mode 100644
index 0000000..3eaf0de
--- /dev/null
+++ b/src/e-util/e-config-lookup-result-simple.h
@@ -0,0 +1,123 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_CONFIG_LOOKUP_RESULT_SIMPLE_H
+#define E_CONFIG_LOOKUP_RESULT_SIMPLE_H
+
+#include <libedataserver/libedataserver.h>
+#include <e-util/e-config-lookup-result.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE \
+       (e_config_lookup_result_simple_get_type ())
+#define E_CONFIG_LOOKUP_RESULT_SIMPLE(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE, EConfigLookupResultSimple))
+#define E_CONFIG_LOOKUP_RESULT_SIMPLE_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE, EConfigLookupResultSimpleClass))
+#define E_IS_CONFIG_LOOKUP_RESULT_SIMPLE(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE))
+#define E_IS_CONFIG_LOOKUP_RESULT_SIMPLE_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE))
+#define E_CONFIG_LOOKUP_RESULT_SIMPLE_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE, EConfigLookupResultSimpleClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EConfigLookupResultSimple EConfigLookupResultSimple;
+typedef struct _EConfigLookupResultSimpleClass EConfigLookupResultSimpleClass;
+typedef struct _EConfigLookupResultSimplePrivate EConfigLookupResultSimplePrivate;
+
+/**
+ * EConfigLookupResultSimple:
+ *
+ * Contains only private data that should be read and manipulated using
+ * the functions below.
+ *
+ * Since: 3.26
+ **/
+struct _EConfigLookupResultSimple {
+       /*< private >*/
+       GObject parent;
+       EConfigLookupResultSimplePrivate *priv;
+};
+
+struct _EConfigLookupResultSimpleClass {
+       /*< private >*/
+       GObjectClass parent_class;
+
+       gboolean        (* configure_source)            (EConfigLookupResult *lookup_result,
+                                                        ESource *source);
+};
+
+GType          e_config_lookup_result_simple_get_type  (void) G_GNUC_CONST;
+EConfigLookupResult *
+               e_config_lookup_result_simple_new       (EConfigLookupResultKind kind,
+                                                        gint priority,
+                                                        const gchar *protocol,
+                                                        const gchar *display_name,
+                                                        const gchar *description);
+void           e_config_lookup_result_simple_add_value (EConfigLookupResult *lookup_result,
+                                                        const gchar *extension_name,
+                                                        const gchar *property_name,
+                                                        const GValue *value);
+void           e_config_lookup_result_simple_add_boolean
+                                                       (EConfigLookupResult *lookup_result,
+                                                        const gchar *extension_name,
+                                                        const gchar *property_name,
+                                                        gboolean value);
+void           e_config_lookup_result_simple_add_int   (EConfigLookupResult *lookup_result,
+                                                        const gchar *extension_name,
+                                                        const gchar *property_name,
+                                                        gint value);
+void           e_config_lookup_result_simple_add_uint  (EConfigLookupResult *lookup_result,
+                                                        const gchar *extension_name,
+                                                        const gchar *property_name,
+                                                        guint value);
+void           e_config_lookup_result_simple_add_int64 (EConfigLookupResult *lookup_result,
+                                                        const gchar *extension_name,
+                                                        const gchar *property_name,
+                                                        gint64 value);
+void           e_config_lookup_result_simple_add_uint64(EConfigLookupResult *lookup_result,
+                                                        const gchar *extension_name,
+                                                        const gchar *property_name,
+                                                        guint64 value);
+void           e_config_lookup_result_simple_add_double(EConfigLookupResult *lookup_result,
+                                                        const gchar *extension_name,
+                                                        const gchar *property_name,
+                                                        gdouble value);
+void           e_config_lookup_result_simple_add_string(EConfigLookupResult *lookup_result,
+                                                        const gchar *extension_name,
+                                                        const gchar *property_name,
+                                                        const gchar *value);
+void           e_config_lookup_result_simple_add_enum  (EConfigLookupResult *lookup_result,
+                                                        const gchar *extension_name,
+                                                        const gchar *property_name,
+                                                        GType enum_type,
+                                                        gint value);
+
+G_END_DECLS
+
+#endif /* E_CONFIG_LOOKUP_RESULT_SIMPLE_H */
diff --git a/src/e-util/e-config-lookup-result.c b/src/e-util/e-config-lookup-result.c
new file mode 100644
index 0000000..2c8b6db
--- /dev/null
+++ b/src/e-util/e-config-lookup-result.c
@@ -0,0 +1,235 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION: e-config-lookup-result
+ * @include: e-util/e-util.h
+ * @short_description: Configuration lookup result interface
+ *
+ * #EConfigLookupResult is an interface which actual results need to implement.
+ * Such result holds information about one kind and knows how to setup
+ * an #ESource with the looked up values.
+ *
+ * Simple changes can be saved using #EConfigLookupResultSimple object.
+ **/
+
+#include "evolution-config.h"
+
+#include <libedataserver/libedataserver.h>
+
+#include "e-util-enums.h"
+
+#include "e-config-lookup-result.h"
+
+G_DEFINE_INTERFACE (EConfigLookupResult, e_config_lookup_result, G_TYPE_OBJECT)
+
+static void
+e_config_lookup_result_default_init (EConfigLookupResultInterface *iface)
+{
+       iface->get_kind = NULL;
+       iface->get_priority = NULL;
+       iface->get_protocol = NULL;
+       iface->get_display_name = NULL;
+       iface->get_description = NULL;
+       iface->configure_source = NULL;
+}
+
+/**
+ * e_config_lookup_result_get_kind:
+ * @lookup_result: an #EConfigLookupResult
+ *
+ * Returns: the result kind, one of #EConfigLookupResultKind, this lookup result corresponds to
+ *
+ * Since: 3.26
+ **/
+EConfigLookupResultKind
+e_config_lookup_result_get_kind (EConfigLookupResult *lookup_result)
+{
+       EConfigLookupResultInterface *iface;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT (lookup_result), E_CONFIG_LOOKUP_RESULT_UNKNOWN);
+
+       iface = E_CONFIG_LOOKUP_RESULT_GET_INTERFACE (lookup_result);
+       g_return_val_if_fail (iface != NULL, E_CONFIG_LOOKUP_RESULT_UNKNOWN);
+       g_return_val_if_fail (iface->get_kind != NULL, E_CONFIG_LOOKUP_RESULT_UNKNOWN);
+
+       return iface->get_kind (lookup_result);
+}
+
+/**
+ * e_config_lookup_result_get_priority:
+ * @lookup_result: an #EConfigLookupResult
+ *
+ * Returns: the result priority; lower value means higher priority
+ *
+ * Since: 3.26
+ **/
+gint
+e_config_lookup_result_get_priority (EConfigLookupResult *lookup_result)
+{
+       EConfigLookupResultInterface *iface;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT (lookup_result), ~0);
+
+       iface = E_CONFIG_LOOKUP_RESULT_GET_INTERFACE (lookup_result);
+       g_return_val_if_fail (iface != NULL, ~0);
+       g_return_val_if_fail (iface->get_priority != NULL, ~0);
+
+       return iface->get_priority (lookup_result);
+}
+
+/**
+ * e_config_lookup_result_get_protocol:
+ * @lookup_result: an #EConfigLookupResult
+ *
+ * Returns: (nullable): if applicable, returns the protocol of this @lookup_result,
+ *    or %NULL if not set, or not known, or not applicable
+ *
+ * Since: 3.26
+ **/
+const gchar *
+e_config_lookup_result_get_protocol (EConfigLookupResult *lookup_result)
+{
+       EConfigLookupResultInterface *iface;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT (lookup_result), NULL);
+
+       iface = E_CONFIG_LOOKUP_RESULT_GET_INTERFACE (lookup_result);
+       g_return_val_if_fail (iface != NULL, NULL);
+       g_return_val_if_fail (iface->get_protocol != NULL, NULL);
+
+       return iface->get_protocol (lookup_result);
+}
+
+/**
+ * e_config_lookup_result_get_display_name:
+ * @lookup_result: an #EConfigLookupResult
+ *
+ * Returns: human readable display name of this @lookup_result
+ *
+ * Since: 3.26
+ **/
+const gchar *
+e_config_lookup_result_get_display_name (EConfigLookupResult *lookup_result)
+{
+       EConfigLookupResultInterface *iface;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT (lookup_result), NULL);
+
+       iface = E_CONFIG_LOOKUP_RESULT_GET_INTERFACE (lookup_result);
+       g_return_val_if_fail (iface != NULL, NULL);
+       g_return_val_if_fail (iface->get_display_name != NULL, NULL);
+
+       return iface->get_display_name (lookup_result);
+}
+
+/**
+ * e_config_lookup_result_get_description:
+ * @lookup_result: an #EConfigLookupResult
+ *
+ * Returns: human readable description of this @lookup_result
+ *
+ * Since: 3.26
+ **/
+const gchar *
+e_config_lookup_result_get_description (EConfigLookupResult *lookup_result)
+{
+       EConfigLookupResultInterface *iface;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT (lookup_result), NULL);
+
+       iface = E_CONFIG_LOOKUP_RESULT_GET_INTERFACE (lookup_result);
+       g_return_val_if_fail (iface != NULL, NULL);
+       g_return_val_if_fail (iface->get_description != NULL, NULL);
+
+       return iface->get_description (lookup_result);
+}
+
+/**
+ * e_config_lookup_result_configure_source:
+ * @lookup_result: an #EConfigLookupResult
+ * @source: an #ESource to configure
+ *
+ * Configures the @source with the looked up configuration.
+ *
+ * Returns: %TRUE when made any changes to the @source, %FALSE otherwise
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_config_lookup_result_configure_source (EConfigLookupResult *lookup_result,
+                                        ESource *source)
+{
+       EConfigLookupResultInterface *iface;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT (lookup_result), FALSE);
+
+       iface = E_CONFIG_LOOKUP_RESULT_GET_INTERFACE (lookup_result);
+       g_return_val_if_fail (iface != NULL, FALSE);
+       g_return_val_if_fail (iface->configure_source != NULL, FALSE);
+
+       return iface->configure_source (lookup_result, source);
+}
+
+/**
+ * e_config_lookup_result_compare:
+ * @lookup_result_a: the first #EConfigLookupResult
+ * @lookup_result_b: the second #EConfigLookupResult
+ *
+ * Compares two #EConfigLookupResult objects, and returns value less than 0,
+ * when @lookup_result_a is before @lookup_result_b, 0 when they are the same
+ * and value greater than 0, when @lookup_result_a is after @lookup_result_b.
+ *
+ * The comparison is done on kind, priority and display name values, in this order.
+ *
+ * Returns: strcmp()-like value, what the position between @lookup_result_a and
+ *    @lookup_result_b is.
+ *
+ * Since: 3.26
+ **/
+gint
+e_config_lookup_result_compare (gconstpointer lookup_result_a,
+                               gconstpointer lookup_result_b)
+{
+       EConfigLookupResult *lra, *lrb;
+       gint res;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT (lookup_result_a), 0);
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP_RESULT (lookup_result_b), 0);
+
+       lra = E_CONFIG_LOOKUP_RESULT (lookup_result_a);
+       lrb = E_CONFIG_LOOKUP_RESULT (lookup_result_b);
+
+       res = e_config_lookup_result_get_kind (lra) - e_config_lookup_result_get_kind (lrb);
+
+       if (!res)
+               res = e_config_lookup_result_get_priority (lra) - e_config_lookup_result_get_priority (lrb);
+
+       if (!res) {
+               const gchar *display_name_a, *display_name_b;
+
+               display_name_a = e_config_lookup_result_get_display_name (lra);
+               display_name_b = e_config_lookup_result_get_display_name (lrb);
+
+               if (!display_name_a || !display_name_b)
+                       res = g_strcmp0 (display_name_a, display_name_b);
+               else
+                       res = g_utf8_collate (display_name_a, display_name_b);
+       }
+
+       return res;
+}
diff --git a/src/e-util/e-config-lookup-result.h b/src/e-util/e-config-lookup-result.h
new file mode 100644
index 0000000..56b8c82
--- /dev/null
+++ b/src/e-util/e-config-lookup-result.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_CONFIG_LOOKUP_RESULT_H
+#define E_CONFIG_LOOKUP_RESULT_H
+
+#include <libedataserver/libedataserver.h>
+
+#include <e-util/e-util-enums.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CONFIG_LOOKUP_RESULT \
+       (e_config_lookup_result_get_type ())
+#define E_CONFIG_LOOKUP_RESULT(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CONFIG_LOOKUP_RESULT, EConfigLookupResult))
+#define E_CONFIG_LOOKUP_RESULT_INTERFACE(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CONFIG_LOOKUP_RESULT, EConfigLookupResultInterface))
+#define E_IS_CONFIG_LOOKUP_RESULT(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CONFIG_LOOKUP_RESULT))
+#define E_IS_CONFIG_LOOKUP_RESULT_INTERFACE(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CONFIG_LOOKUP_RESULT))
+#define E_CONFIG_LOOKUP_RESULT_GET_INTERFACE(obj) \
+       (G_TYPE_INSTANCE_GET_INTERFACE \
+       ((obj), E_TYPE_CONFIG_LOOKUP_RESULT, EConfigLookupResultInterface))
+
+#define E_CONFIG_LOOKUP_RESULT_PRIORITY_IMAP   1000
+#define E_CONFIG_LOOKUP_RESULT_PRIORITY_POP3   2000
+#define E_CONFIG_LOOKUP_RESULT_PRIORITY_SMTP   1000
+
+G_BEGIN_DECLS
+
+typedef struct _EConfigLookupResult EConfigLookupResult;
+typedef struct _EConfigLookupResultInterface EConfigLookupResultInterface;
+
+struct _EConfigLookupResultInterface {
+       GTypeInterface parent_interface;
+
+       EConfigLookupResultKind
+                       (* get_kind)                    (EConfigLookupResult *lookup_result);
+       gint            (* get_priority)                (EConfigLookupResult *lookup_result);
+       const gchar *   (* get_protocol)                (EConfigLookupResult *lookup_result);
+       const gchar *   (* get_display_name)            (EConfigLookupResult *lookup_result);
+       const gchar *   (* get_description)             (EConfigLookupResult *lookup_result);
+       gboolean        (* configure_source)            (EConfigLookupResult *lookup_result,
+                                                        ESource *source);
+};
+
+GType          e_config_lookup_result_get_type         (void);
+EConfigLookupResultKind
+               e_config_lookup_result_get_kind         (EConfigLookupResult *lookup_result);
+gint           e_config_lookup_result_get_priority     (EConfigLookupResult *lookup_result);
+const gchar *  e_config_lookup_result_get_protocol     (EConfigLookupResult *lookup_result);
+const gchar *  e_config_lookup_result_get_display_name (EConfigLookupResult *lookup_result);
+const gchar *  e_config_lookup_result_get_description  (EConfigLookupResult *lookup_result);
+gboolean       e_config_lookup_result_configure_source (EConfigLookupResult *lookup_result,
+                                                        ESource *source);
+gint           e_config_lookup_result_compare          (gconstpointer lookup_result_a,
+                                                        gconstpointer lookup_result_b);
+
+G_END_DECLS
+
+#endif /* E_CONFIG_LOOKUP_RESULT_H */
diff --git a/src/e-util/e-config-lookup.c b/src/e-util/e-config-lookup.c
new file mode 100644
index 0000000..fb9ccdc
--- /dev/null
+++ b/src/e-util/e-config-lookup.c
@@ -0,0 +1,565 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION: e-config-lookup
+ * @include: e-util/e-util.h
+ * @short_description: Configuration lookup
+ *
+ * #EConfigLookup is used to search for configuration of an account,
+ * which is identified by an e-mail address, server address or such.
+ * It is an #EExtensible object, where the extensions connect to
+ * the #EConfigLookup::run signal to run the configuration lookup.
+ **/
+
+#include "evolution-config.h"
+
+#include <libedataserver/libedataserver.h>
+
+#include "e-activity.h"
+#include "e-config-lookup-result.h"
+#include "e-simple-async-result.h"
+#include "e-util-enumtypes.h"
+
+#include "e-config-lookup.h"
+
+struct _EConfigLookupPrivate {
+       ESourceRegistry *registry;
+
+       GMutex property_lock;
+       GSList *results; /* EConfigLookupResult * */
+
+       ESimpleAsyncResult *run_result;
+       GCancellable *run_cancellable;
+
+       GThreadPool *pool;
+};
+
+enum {
+       PROP_0,
+       PROP_REGISTRY
+};
+
+enum {
+       RUN,
+       GET_SOURCE,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE_WITH_CODE (EConfigLookup, e_config_lookup, G_TYPE_OBJECT,
+       G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
+
+typedef struct _ThreadData {
+       ENamedParameters *params;
+       EActivity *activity;
+       EConfigLookupThreadFunc thread_func;
+       gpointer user_data;
+       GDestroyNotify user_data_free;
+} ThreadData;
+
+static void
+config_lookup_thread (gpointer data,
+                     gpointer user_data)
+{
+       ThreadData *td = data;
+       EConfigLookup *config_lookup = user_data;
+
+       g_return_if_fail (td != NULL);
+       g_return_if_fail (td->params != NULL);
+       g_return_if_fail (E_IS_ACTIVITY (td->activity));
+       g_return_if_fail (td->thread_func != NULL);
+       g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
+
+       td->thread_func (config_lookup, td->params, td->user_data, e_activity_get_cancellable (td->activity));
+
+       if (td->user_data_free)
+               td->user_data_free (td->user_data);
+
+       e_named_parameters_free (td->params);
+       g_object_unref (td->activity);
+       g_free (td);
+}
+
+static void
+config_lookup_set_registry (EConfigLookup *config_lookup,
+                           ESourceRegistry *registry)
+{
+       g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+       g_return_if_fail (config_lookup->priv->registry == NULL);
+
+       config_lookup->priv->registry = g_object_ref (registry);
+}
+
+static void
+config_lookup_set_property (GObject *object,
+                           guint property_id,
+                           const GValue *value,
+                           GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_REGISTRY:
+                       config_lookup_set_registry (
+                               E_CONFIG_LOOKUP (object),
+                               g_value_get_object (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+config_lookup_get_property (GObject *object,
+                           guint property_id,
+                           GValue *value,
+                           GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_REGISTRY:
+                       g_value_set_object (
+                               value,
+                               e_config_lookup_get_registry (
+                               E_CONFIG_LOOKUP (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+config_lookup_constructed (GObject *object)
+{
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_config_lookup_parent_class)->constructed (object);
+
+       e_extensible_load_extensions (E_EXTENSIBLE (object));
+}
+
+static void
+config_lookup_dispose (GObject *object)
+{
+       EConfigLookup *config_lookup = E_CONFIG_LOOKUP (object);
+
+       g_mutex_lock (&config_lookup->priv->property_lock);
+
+       if (config_lookup->priv->run_cancellable) {
+               g_cancellable_cancel (config_lookup->priv->run_cancellable);
+               g_clear_object (&config_lookup->priv->run_cancellable);
+       }
+
+       g_mutex_unlock (&config_lookup->priv->property_lock);
+
+       g_clear_object (&config_lookup->priv->registry);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_config_lookup_parent_class)->dispose (object);
+}
+
+static void
+config_lookup_finalize (GObject *object)
+{
+       EConfigLookup *config_lookup = E_CONFIG_LOOKUP (object);
+
+       g_slist_free_full (config_lookup->priv->results, g_object_unref);
+       g_thread_pool_free (config_lookup->priv->pool, TRUE, FALSE);
+       g_mutex_clear (&config_lookup->priv->property_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_config_lookup_parent_class)->finalize (object);
+}
+
+static void
+e_config_lookup_class_init (EConfigLookupClass *klass)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (klass, sizeof (EConfigLookupPrivate));
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->set_property = config_lookup_set_property;
+       object_class->get_property = config_lookup_get_property;
+       object_class->constructed = config_lookup_constructed;
+       object_class->dispose = config_lookup_dispose;
+       object_class->finalize = config_lookup_finalize;
+
+       /**
+        * EConfigLookup:registry:
+        *
+        * The #ESourceRegistry manages #ESource instances.
+        *
+        * Since: 3.26
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_REGISTRY,
+               g_param_spec_object (
+                       "registry",
+                       "Registry",
+                       "Data source registry",
+                       E_TYPE_SOURCE_REGISTRY,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+
+       /**
+        * EConfigLookup::run:
+        * @params: an #ENamedParameters with additional parameters
+        * @activity: an #EActivity
+        *
+        * Emitted to run config lookup by each extension. The extensions
+        * run their code asynchronously and claim the result by
+        * e_config_lookup_add_result(). The extension also references the @activity
+        * for the whole run, because it's used to know when all extensions
+        * are finished with searching. Extensions can use e_config_lookup_create_thread(),
+        * which does necessary things for it.
+        *
+        * The signal is emitted from the main/GUI thread, but the @activity can be
+        * unreffed in another thread too.
+        *
+        * Since: 3.26
+        **/
+       signals[RUN] = g_signal_new (
+               "run",
+               G_TYPE_FROM_CLASS (klass),
+               G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+               G_STRUCT_OFFSET (EConfigLookupClass, run),
+               NULL, NULL,
+               NULL,
+               G_TYPE_NONE, 2,
+               E_TYPE_NAMED_PARAMETERS,
+               E_TYPE_ACTIVITY);
+
+       /**
+        * EConfigLookup::get-source:
+        * @kind: an #EConfigLookupSourceKind
+        *
+        * Emitted to get an #ESource of the given @kind. Return %NULL, when not available.
+        *
+        * Since: 3.26
+        **/
+       signals[GET_SOURCE] = g_signal_new (
+               "get-source",
+               G_TYPE_FROM_CLASS (klass),
+               G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+               G_STRUCT_OFFSET (EConfigLookupClass, get_source),
+               NULL, NULL,
+               NULL,
+               G_TYPE_POINTER, 1,
+               E_TYPE_CONFIG_LOOKUP_SOURCE_KIND);
+}
+
+static void
+e_config_lookup_init (EConfigLookup *config_lookup)
+{
+       config_lookup->priv = G_TYPE_INSTANCE_GET_PRIVATE (config_lookup, E_TYPE_CONFIG_LOOKUP, 
EConfigLookupPrivate);
+
+       g_mutex_init (&config_lookup->priv->property_lock);
+       config_lookup->priv->pool = g_thread_pool_new (config_lookup_thread, config_lookup, 10, FALSE, NULL);
+}
+
+/**
+ * e_config_lookup_new:
+ * @registry: an #ESourceRegistry
+ *
+ * Creates a new #EConfigLookup instance.
+ *
+ * Returns: (transfer full): a new #EConfigLookup
+ *
+ * Since: 3.26
+ **/
+EConfigLookup *
+e_config_lookup_new (ESourceRegistry *registry)
+{
+       g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+       return g_object_new (E_TYPE_CONFIG_LOOKUP,
+               "registry", registry,
+               NULL);
+}
+
+/**
+ * e_config_lookup_get_registry:
+ * @config_lookup: an #EConfigLookup
+ *
+ * Returns the #ESourceRegistry passed to e_config_lookup_new().
+ *
+ * Returns: (transfer none): an #ESourceRegistry
+ *
+ * Since: 3.26
+ **/
+ESourceRegistry *
+e_config_lookup_get_registry (EConfigLookup *config_lookup)
+{
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), NULL);
+
+       return config_lookup->priv->registry;
+}
+
+/**
+ * e_config_lookup_get_source:
+ * @config_lookup: an #EConfigLookup
+ * @kind: one of #EConfigLookupSourceKind, except of the %E_CONFIG_LOOKUP_SOURCE_UNKNOWN
+ *
+ * Emits the #EConfigLookup::get-source signal and any listener can provide
+ * the source. The function can return %NULL, when there are no listeners
+ * or when such source is not available.
+ *
+ * Returns: (transfer none) (nullable): an #ESource of the given @kind, or %NULL, if not found
+ *
+ * Since: 3.26
+ **/
+ESource *
+e_config_lookup_get_source (EConfigLookup *config_lookup,
+                           EConfigLookupSourceKind kind)
+{
+       ESource *source = NULL;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), NULL);
+
+       g_signal_emit (config_lookup, signals[GET_SOURCE], 0, kind, &source);
+
+       return source;
+}
+
+static void
+config_lookup_activity_gone (gpointer user_data,
+                            GObject *object)
+{
+       EConfigLookup *config_lookup = user_data;
+       ESimpleAsyncResult *run_result;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
+
+       g_mutex_lock (&config_lookup->priv->property_lock);
+
+       run_result = config_lookup->priv->run_result;
+       config_lookup->priv->run_result = NULL;
+
+       g_mutex_unlock (&config_lookup->priv->property_lock);
+
+       if (run_result) {
+               e_simple_async_result_complete_idle (run_result);
+               g_object_unref (run_result);
+       }
+
+       g_object_unref (config_lookup);
+}
+
+/**
+ * e_config_lookup_run:
+ * @config_lookup: an #EConfigLookup
+ * @params: an #ENamedParameters with lookup parameters
+ * @cancellable: an optional #GCancellable, or %NULL
+ * @callback: a callback to call, when the run is finished
+ * @user_data: user data for the @callback
+ *
+ * Runs configuration lookup asynchronously, by emitting the #EConfigLookup::run signal.
+ * Once the run is done, the @callback is called, and the call can be finished with
+ * e_config_lookup_run_finish(). The @callback is always called from the main thread.
+ *
+ * Note that there cannot be run two lookups at the same time, thus if it
+ * happens, then the @callback is called immediately with a %NULL result.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_run (EConfigLookup *config_lookup,
+                    const ENamedParameters *params,
+                    GCancellable *cancellable,
+                    GAsyncReadyCallback callback,
+                    gpointer user_data)
+{
+       EActivity *activity;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
+       g_return_if_fail (params != NULL);
+       g_return_if_fail (callback != NULL);
+
+       g_mutex_lock (&config_lookup->priv->property_lock);
+
+       if (config_lookup->priv->run_result) {
+               g_mutex_unlock (&config_lookup->priv->property_lock);
+
+               callback (G_OBJECT (config_lookup), NULL, user_data);
+               return;
+       }
+
+       g_slist_free_full (config_lookup->priv->results, g_object_unref);
+       config_lookup->priv->results = NULL;
+
+       if (cancellable)
+               g_object_ref (cancellable);
+       else
+               cancellable = g_cancellable_new ();
+
+       config_lookup->priv->run_result = e_simple_async_result_new (G_OBJECT (config_lookup), callback, 
user_data, e_config_lookup_run);
+       config_lookup->priv->run_cancellable = cancellable;
+
+       activity = e_activity_new ();
+       e_activity_set_cancellable (activity, cancellable);
+
+       g_object_weak_ref (G_OBJECT (activity), config_lookup_activity_gone, g_object_ref (config_lookup));
+
+       g_mutex_unlock (&config_lookup->priv->property_lock);
+
+       g_signal_emit (config_lookup, signals[RUN], 0, params, activity);
+
+       g_object_unref (activity);
+}
+
+/**
+ * e_config_lookup_run_finish:
+ * @config_lookup: an #EConfigLookup
+ * @result: result of the operation
+ *
+ * Finishes the configuration lookup previously run by e_config_lookup_run().
+ * It's expected that the extensions may fail, thus it doesn't return
+ * anything and is provided mainly for consistency with asynchronous API.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_run_finish (EConfigLookup *config_lookup,
+                           GAsyncResult *result)
+{
+       g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
+       g_return_if_fail (G_IS_ASYNC_RESULT (result));
+       g_return_if_fail (g_async_result_is_tagged (result, e_config_lookup_run));
+}
+
+/**
+ * e_config_lookup_create_thread:
+ * @config_lookup: an #EConfigLookup
+ * @params: an #ENamedParameters with lookup parameters
+ * @activity: an #EActivity
+ * @thread_func: function to call in a new thread
+ * @user_data: (nullable): optional user data for @thread_func, or %NULL
+ * @user_data_free: (nullable): optional free function for @user_data, or %NULL
+ *
+ * Creates a new thread and calls @thread_func in it. It also references @activity
+ * and unreferences it once the @thread_func is done.
+ *
+ * This function might be usually called by extensions in a signal handler
+ * for the #EConfigLookup::run signal.
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_create_thread (EConfigLookup *config_lookup,
+                              const ENamedParameters *params,
+                              EActivity *activity,
+                              EConfigLookupThreadFunc thread_func,
+                              gpointer user_data,
+                              GDestroyNotify user_data_free)
+{
+       ThreadData *td;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
+       g_return_if_fail (params != NULL);
+       g_return_if_fail (E_IS_ACTIVITY (activity));
+       g_return_if_fail (thread_func != NULL);
+
+       td = g_new0 (ThreadData, 1);
+       td->params = e_named_parameters_new_clone (params);
+       td->activity = g_object_ref (activity);
+       td->thread_func = thread_func;
+       td->user_data = user_data;
+       td->user_data_free = user_data_free;
+
+       g_thread_pool_push (config_lookup->priv->pool, td, NULL);
+}
+
+/**
+ * e_config_lookup_add_result:
+ * @config_lookup: an #EConfigLookup
+ * @result: (transfer full): an #EConfigLookupResult
+ *
+ * Adds a new @result in a list of known configuration lookup results.
+ * The @config_lookup assumes ownership of the @result and frees it
+ * when no longer needed.
+ *
+ * The list of results can be obtained with e_config_lookup_get_results().
+ *
+ * Since: 3.26
+ **/
+void
+e_config_lookup_add_result (EConfigLookup *config_lookup,
+                           EConfigLookupResult *result)
+{
+       g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
+       g_return_if_fail (E_IS_CONFIG_LOOKUP_RESULT (result));
+
+       g_mutex_lock (&config_lookup->priv->property_lock);
+
+       config_lookup->priv->results = g_slist_prepend (config_lookup->priv->results, result);
+
+       g_mutex_unlock (&config_lookup->priv->property_lock);
+}
+
+/**
+ * e_config_lookup_get_results:
+ * @config_lookup: an #EConfigLookup
+ * @kind: an #EConfigLookupResultKind to filter the results with
+ * @protocol: (nullable): optional protocol to filter the results with, or %NULL
+ *
+ * Returns a #GSList with #EConfigLookupResult objects satisfying
+ * the @kind and @protocol filtering conditions. To receive all
+ * gathered results use %E_CONFIG_LOOKUP_RESULT_UNKNOWN for @kind
+ * and %NULL for the @protocol.
+ *
+ * Free the returned #GSList with
+ * g_slist_free_full (results, g_object_unref);
+ * when no longer needed.
+ *
+ * Returns: (element-type EConfigLookupResult) (transfer full): a #GSList
+ *    with results satisfying the @kind and @protocol filtering conditions.
+ *
+ * Since: 3.26
+ **/
+GSList *
+e_config_lookup_get_results (EConfigLookup *config_lookup,
+                            EConfigLookupResultKind kind,
+                            const gchar *protocol)
+{
+       GSList *results = NULL, *link;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), NULL);
+
+       g_mutex_lock (&config_lookup->priv->property_lock);
+
+       for (link = config_lookup->priv->results; link; link = g_slist_next (link)) {
+               EConfigLookupResult *result = link->data;
+
+               if (!E_IS_CONFIG_LOOKUP_RESULT (result))
+                       continue;
+
+               if (kind != E_CONFIG_LOOKUP_RESULT_UNKNOWN &&
+                   kind != e_config_lookup_result_get_kind (result))
+                       continue;
+
+               if (protocol &&
+                   g_strcmp0 (protocol, e_config_lookup_result_get_protocol (result)) != 0)
+                       continue;
+
+               results = g_slist_prepend (results, g_object_ref (result));
+       }
+
+       g_mutex_unlock (&config_lookup->priv->property_lock);
+
+       return results;
+}
diff --git a/src/e-util/e-config-lookup.h b/src/e-util/e-config-lookup.h
new file mode 100644
index 0000000..92e27e3
--- /dev/null
+++ b/src/e-util/e-config-lookup.h
@@ -0,0 +1,130 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_CONFIG_LOOKUP_H
+#define E_CONFIG_LOOKUP_H
+
+#include <libedataserver/libedataserver.h>
+
+#include <e-util/e-activity.h>
+#include <e-util/e-util-enums.h>
+#include <e-util/e-config-lookup-result.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CONFIG_LOOKUP \
+       (e_config_lookup_get_type ())
+#define E_CONFIG_LOOKUP(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CONFIG_LOOKUP, EConfigLookup))
+#define E_CONFIG_LOOKUP_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CONFIG_LOOKUP, EConfigLookupClass))
+#define E_IS_CONFIG_LOOKUP(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CONFIG_LOOKUP))
+#define E_IS_CONFIG_LOOKUP_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CONFIG_LOOKUP))
+#define E_CONFIG_LOOKUP_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_CONFIG_LOOKUP, EConfigLookupClass))
+
+#define E_CONFIG_LOOKUP_PARAM_USER             "user"
+#define E_CONFIG_LOOKUP_PARAM_PASSWORD         "password"
+#define E_CONFIG_LOOKUP_PARAM_EMAIL_ADDRESS    "email-address"
+#define E_CONFIG_LOOKUP_PARAM_SERVERS          "servers"
+
+G_BEGIN_DECLS
+
+typedef struct _EConfigLookup EConfigLookup;
+typedef struct _EConfigLookupClass EConfigLookupClass;
+typedef struct _EConfigLookupPrivate EConfigLookupPrivate;
+
+/**
+ * EConfigLookupThreadFunc:
+ * @config_lookup: an #EConfigLookup
+ * @params: an #ENamedParameters with additional parameters
+ * @user_data: user data passed to e_config_lookup_create_thread()
+ * @cancellable: a #GCancellable
+ *
+ * A function executed in a dedicated thread.
+ *
+ * Since: 3.26
+ **/
+typedef void (* EConfigLookupThreadFunc) (EConfigLookup *config_lookup,
+                                         const ENamedParameters *params,
+                                         gpointer user_data,
+                                         GCancellable *cancellable);
+
+/**
+ * EConfigLookup:
+ *
+ * Contains only private data that should be read and manipulated using
+ * the functions below.
+ *
+ * Since: 3.26
+ **/
+struct _EConfigLookup {
+       /*< private >*/
+       GObject parent;
+       EConfigLookupPrivate *priv;
+};
+
+struct _EConfigLookupClass {
+       /*< private >*/
+       GObjectClass parent_class;
+
+       /* Signals */
+       void            (* run)         (EConfigLookup *config_lookup,
+                                        const ENamedParameters *params,
+                                        EActivity *activity);
+       ESource *       (* get_source)  (EConfigLookup *config_lookup,
+                                        EConfigLookupSourceKind kind);
+};
+
+GType          e_config_lookup_get_type                (void) G_GNUC_CONST;
+EConfigLookup *        e_config_lookup_new                     (ESourceRegistry *registry);
+ESourceRegistry *
+               e_config_lookup_get_registry            (EConfigLookup *config_lookup);
+ESource *      e_config_lookup_get_source              (EConfigLookup *config_lookup,
+                                                        EConfigLookupSourceKind kind);
+void           e_config_lookup_run                     (EConfigLookup *config_lookup,
+                                                        const ENamedParameters *params,
+                                                        GCancellable *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer user_data);
+void           e_config_lookup_run_finish              (EConfigLookup *config_lookup,
+                                                        GAsyncResult *result);
+void           e_config_lookup_create_thread           (EConfigLookup *config_lookup,
+                                                        const ENamedParameters *params,
+                                                        EActivity *activity,
+                                                        EConfigLookupThreadFunc thread_func,
+                                                        gpointer user_data,
+                                                        GDestroyNotify user_data_free);
+void           e_config_lookup_add_result              (EConfigLookup *config_lookup,
+                                                        EConfigLookupResult *result);
+GSList *       e_config_lookup_get_results             (EConfigLookup *config_lookup,
+                                                        EConfigLookupResultKind kind,
+                                                        const gchar *protocol);
+
+G_END_DECLS
+
+#endif /* E_CONFIG_LOOKUP_H */
diff --git a/src/e-util/e-simple-async-result.c b/src/e-util/e-simple-async-result.c
index dcec35b..bb9e87f 100644
--- a/src/e-util/e-simple-async-result.c
+++ b/src/e-util/e-simple-async-result.c
@@ -217,3 +217,24 @@ e_simple_async_result_complete (ESimpleAsyncResult *result)
 
        g_object_unref (result);
 }
+
+static gboolean
+result_complete_idle_cb (gpointer user_data)
+{
+       ESimpleAsyncResult *result = user_data;
+
+       g_return_val_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+       e_simple_async_result_complete (result);
+       g_object_unref (result);
+
+       return FALSE;
+}
+
+void
+e_simple_async_result_complete_idle (ESimpleAsyncResult *result)
+{
+       g_return_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result));
+
+       g_idle_add (result_complete_idle_cb, g_object_ref (result));
+}
diff --git a/src/e-util/e-simple-async-result.h b/src/e-util/e-simple-async-result.h
index 3800de1..d2a5699 100644
--- a/src/e-util/e-simple-async-result.h
+++ b/src/e-util/e-simple-async-result.h
@@ -84,6 +84,9 @@ void          e_simple_async_result_set_op_pointer
 gpointer       e_simple_async_result_get_op_pointer
                                                (ESimpleAsyncResult *result);
 void           e_simple_async_result_complete  (ESimpleAsyncResult *result);
+void           e_simple_async_result_complete_idle
+                                               (ESimpleAsyncResult *result);
+
 
 G_END_DECLS
 
diff --git a/src/e-util/e-util-enums.h b/src/e-util/e-util-enums.h
index 75eeeee..5b6bef2 100644
--- a/src/e-util/e-util-enums.h
+++ b/src/e-util/e-util-enums.h
@@ -550,13 +550,13 @@ typedef enum {
 
 /**
  * EDnDTargetType:
- * DND_TARGET_TYPE_TEXT_URI_LIST: text/uri-list
- * DND_TARGET_TYPE_MOZILLA_URL: _NETSCAPE_URL
- * DND_TARGET_TYPE_TEXT_HTML: text/html
- * DND_TARGET_TYPE_UTF8_STRING: UTF8_STRING
- * DND_TARGET_TYPE_TEXT_PLAIN: text/plain
- * DND_TARGET_TYPE_STRING: STRING
- * DND_TARGET_TYPE_TEXT_PLAIN_UTF8: text/plain;charser=utf-8
+ * @DND_TARGET_TYPE_TEXT_URI_LIST: text/uri-list
+ * @DND_TARGET_TYPE_MOZILLA_URL: _NETSCAPE_URL
+ * @DND_TARGET_TYPE_TEXT_HTML: text/html
+ * @DND_TARGET_TYPE_UTF8_STRING: UTF8_STRING
+ * @DND_TARGET_TYPE_TEXT_PLAIN: text/plain
+ * @DND_TARGET_TYPE_STRING: STRING
+ * @DND_TARGET_TYPE_TEXT_PLAIN_UTF8: text/plain;charser=utf-8
  *
  * Drag and drop targets supported by EContentEditor.
  *
@@ -572,6 +572,53 @@ typedef enum {
        E_DND_TARGET_TYPE_TEXT_PLAIN_UTF8
 } EDnDTargetType;
 
+/**
+ * EConfigLookupSourceKind:
+ * @E_CONFIG_LOOKUP_SOURCE_UNKNOWN: unknown source kind
+ * @E_CONFIG_LOOKUP_SOURCE_COLLECTION: collection source
+ * @E_CONFIG_LOOKUP_SOURCE_MAIL_ACCOUNT: mail account source
+ * @E_CONFIG_LOOKUP_SOURCE_MAIL_IDENTITY: mail identity source
+ * @E_CONFIG_LOOKUP_SOURCE_MAIL_TRANSPORT: mail transport source
+ *
+ * Defines what source kind to get in call of e_config_lookup_get_source().
+ *
+ * Since: 3.26
+ **/
+typedef enum {
+       E_CONFIG_LOOKUP_SOURCE_UNKNOWN,
+       E_CONFIG_LOOKUP_SOURCE_COLLECTION,
+       E_CONFIG_LOOKUP_SOURCE_MAIL_ACCOUNT,
+       E_CONFIG_LOOKUP_SOURCE_MAIL_IDENTITY,
+       E_CONFIG_LOOKUP_SOURCE_MAIL_TRANSPORT
+} EConfigLookupSourceKind;
+
+/**
+ * EConfigLookupResultKind:
+ * @E_CONFIG_LOOKUP_RESULT_UNKNOWN: unknown kind
+ * @E_CONFIG_LOOKUP_RESULT_COLLECTION: collection kind, which can serve one or more of the other kinds
+ * @E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE: configures mail receive
+ * @E_CONFIG_LOOKUP_RESULT_MAIL_SEND: configures mail send
+ * @E_CONFIG_LOOKUP_RESULT_ADDRESS_BOOK: configures address book
+ * @E_CONFIG_LOOKUP_RESULT_CALENDAR: configures calendar
+ * @E_CONFIG_LOOKUP_RESULT_MEMO_LIST: configures memo list
+ * @E_CONFIG_LOOKUP_RESULT_TASK_LIST: configures task list
+ *
+ * Defines config lookup result kind, which is used to distinguish
+ * which part the result configures.
+ *
+ * Since: 3.26
+ **/
+typedef enum {
+       E_CONFIG_LOOKUP_RESULT_UNKNOWN,
+       E_CONFIG_LOOKUP_RESULT_COLLECTION,
+       E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE,
+       E_CONFIG_LOOKUP_RESULT_MAIL_SEND,
+       E_CONFIG_LOOKUP_RESULT_ADDRESS_BOOK,
+       E_CONFIG_LOOKUP_RESULT_CALENDAR,
+       E_CONFIG_LOOKUP_RESULT_MEMO_LIST,
+       E_CONFIG_LOOKUP_RESULT_TASK_LIST
+} EConfigLookupResultKind;
+
 G_END_DECLS
 
 #endif /* E_UTIL_ENUMS_H */
diff --git a/src/e-util/e-util.h b/src/e-util/e-util.h
index 6d95cf3..51e049b 100644
--- a/src/e-util/e-util.h
+++ b/src/e-util/e-util.h
@@ -84,6 +84,9 @@
 #include <e-util/e-color-chooser-widget.h>
 #include <e-util/e-color-combo.h>
 #include <e-util/e-config.h>
+#include <e-util/e-config-lookup.h>
+#include <e-util/e-config-lookup-result.h>
+#include <e-util/e-config-lookup-result-simple.h>
 #include <e-util/e-conflict-search-selector.h>
 #include <e-util/e-contact-store.h>
 #include <e-util/e-content-editor.h>
diff --git a/src/mail/CMakeLists.txt b/src/mail/CMakeLists.txt
index 8520008..279099f 100644
--- a/src/mail/CMakeLists.txt
+++ b/src/mail/CMakeLists.txt
@@ -274,6 +274,10 @@ add_executable(test-mail-autoconfig
        test-mail-autoconfig.c
 )
 
+add_dependencies(test-mail-autoconfig
+       evolution-util
+)
+
 target_compile_definitions(test-mail-autoconfig PRIVATE
        -DG_LOG_DOMAIN=\"test-mail-autoconfig\"
 )
@@ -293,6 +297,7 @@ target_include_directories(test-mail-autoconfig PUBLIC
 )
 
 target_link_libraries(test-mail-autoconfig
+       evolution-util
        ${EVOLUTION_DATA_SERVER_LDFLAGS}
        ${GNOME_PLATFORM_LDFLAGS}
 )
diff --git a/src/mail/e-mail-autoconfig.c b/src/mail/e-mail-autoconfig.c
index 841a428..62cee6b 100644
--- a/src/mail/e-mail-autoconfig.c
+++ b/src/mail/e-mail-autoconfig.c
@@ -453,8 +453,7 @@ exit:
 }
 
 static gboolean
-mail_autoconfig_set_details (EMailAutoconfig *autoconfig,
-                             EMailAutoconfigResult *result,
+mail_autoconfig_set_details (EMailAutoconfigResult *result,
                              ESource *source,
                              const gchar *extension_name)
 {
@@ -491,6 +490,169 @@ mail_autoconfig_set_details (EMailAutoconfig *autoconfig,
        return TRUE;
 }
 
+#define E_TYPE_MAIL_CONFIG_LOOKUP_RESULT \
+       (e_mail_config_lookup_result_get_type ())
+#define E_MAIL_CONFIG_LOOKUP_RESULT(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_MAIL_CONFIG_LOOKUP_RESULT, EMailConfigLookupResult))
+#define E_IS_MAIL_CONFIG_LOOKUP_RESULT(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_MAIL_CONFIG_LOOKUP_RESULT))
+
+typedef struct _EMailConfigLookupResult EMailConfigLookupResult;
+typedef struct _EMailConfigLookupResultClass EMailConfigLookupResultClass;
+
+struct _EMailConfigLookupResult {
+       /*< private >*/
+       EConfigLookupResultSimple parent;
+
+       EMailAutoconfigResult result;
+       gchar *extension_name;
+};
+
+struct _EMailConfigLookupResultClass {
+       /*< private >*/
+       EConfigLookupResultSimpleClass parent_class;
+};
+
+GType e_mail_config_lookup_result_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE (EMailConfigLookupResult, e_mail_config_lookup_result, E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE)
+
+static gboolean
+mail_config_lookup_result_configure_source (EConfigLookupResult *lookup_result,
+                                           ESource *source)
+{
+       EMailConfigLookupResult *mail_result;
+
+       g_return_val_if_fail (E_IS_MAIL_CONFIG_LOOKUP_RESULT (lookup_result), FALSE);
+
+       mail_result = E_MAIL_CONFIG_LOOKUP_RESULT (lookup_result);
+
+       /* No chain up to parent method, not needed here, because not used */
+       return mail_autoconfig_set_details (&mail_result->result, source, mail_result->extension_name);
+}
+
+static void
+mail_config_lookup_result_finalize (GObject *object)
+{
+       EMailConfigLookupResult *mail_result = E_MAIL_CONFIG_LOOKUP_RESULT (object);
+
+       g_free (mail_result->result.user);
+       g_free (mail_result->result.host);
+       g_free (mail_result->result.auth_mechanism);
+       g_free (mail_result->extension_name);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_mail_config_lookup_result_parent_class)->finalize (object);
+}
+
+static void
+e_mail_config_lookup_result_class_init (EMailConfigLookupResultClass *klass)
+{
+       EConfigLookupResultSimpleClass *simple_result_class;
+       GObjectClass *object_class;
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->finalize = mail_config_lookup_result_finalize;
+
+       simple_result_class = E_CONFIG_LOOKUP_RESULT_SIMPLE_CLASS (klass);
+       simple_result_class->configure_source = mail_config_lookup_result_configure_source;
+}
+
+static void
+e_mail_config_lookup_result_init (EMailConfigLookupResult *mail_result)
+{
+}
+
+static EConfigLookupResult *
+e_mail_config_lookup_result_new (EConfigLookupResultKind kind,
+                                gint priority,
+                                const gchar *protocol,
+                                const gchar *display_name,
+                                const gchar *description,
+                                const EMailAutoconfigResult *result,
+                                const gchar *extension_name)
+{
+       EMailConfigLookupResult *mail_result;
+
+       g_return_val_if_fail (protocol != NULL, NULL);
+       g_return_val_if_fail (display_name != NULL, NULL);
+       g_return_val_if_fail (description != NULL, NULL);
+       g_return_val_if_fail (result != NULL, NULL);
+       g_return_val_if_fail (extension_name != NULL, NULL);
+
+       mail_result = g_object_new (E_TYPE_MAIL_CONFIG_LOOKUP_RESULT,
+               "kind", kind,
+               "priority", priority,
+               "protocol", protocol,
+               "display-name", display_name,
+               "description", description,
+               NULL);
+
+       mail_result->result.set = result->set;
+       mail_result->result.user = g_strdup (result->user);
+       mail_result->result.host = g_strdup (result->host);
+       mail_result->result.port = result->port;
+       mail_result->result.auth_mechanism = g_strdup (result->auth_mechanism);
+       mail_result->result.security_method = result->security_method;
+       mail_result->extension_name = g_strdup (extension_name);
+
+       return E_CONFIG_LOOKUP_RESULT (mail_result);
+}
+
+static void
+mail_autoconfig_result_to_config_lookup (EMailAutoconfig *mail_autoconfig,
+                                        EConfigLookup *config_lookup,
+                                        EMailAutoconfigResult *result,
+                                        gint priority,
+                                        const gchar *protocol,
+                                        const gchar *display_name,
+                                        const gchar *extension_name)
+{
+       EConfigLookupResult *lookup_result;
+       EConfigLookupResultKind kind;
+       GString *description;
+
+       g_return_if_fail (E_IS_MAIL_AUTOCONFIG (mail_autoconfig));
+       g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
+       g_return_if_fail (result != NULL);
+       g_return_if_fail (protocol != NULL);
+       g_return_if_fail (display_name != NULL);
+       g_return_if_fail (extension_name != NULL);
+
+       if (!result->set)
+               return;
+
+       kind = E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE;
+       if (g_strcmp0 (extension_name, E_SOURCE_EXTENSION_MAIL_TRANSPORT) == 0)
+               kind = E_CONFIG_LOOKUP_RESULT_MAIL_SEND;
+
+       description = g_string_new ("");
+
+       g_string_append_printf (description, _("Host: %s:%d"), result->host, result->port);
+
+       if (result->user && *result->user) {
+               g_string_append_c (description, '\n');
+               g_string_append_printf (description, _("User: %s"), result->user);
+       }
+
+       g_string_append_c (description, '\n');
+       g_string_append_printf (description, _("Security method: %s"),
+               result->security_method == CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT ?  _("TLS") :
+               result->security_method == CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT ? 
_("STARTTLS") : _("None"));
+
+       if (result->auth_mechanism && *result->auth_mechanism) {
+               g_string_append_c (description, '\n');
+               g_string_append_printf (description, _("Authentication mechanism: %s"), 
result->auth_mechanism);
+       }
+
+       lookup_result = e_mail_config_lookup_result_new (kind, priority, protocol, display_name, 
description->str, result, extension_name);
+       e_config_lookup_add_result (config_lookup, lookup_result);
+
+       g_string_free (description, TRUE);
+}
+
 static void
 mail_autoconfig_set_email_address (EMailAutoconfig *autoconfig,
                                    const gchar *email_address)
@@ -836,7 +998,7 @@ e_mail_autoconfig_set_imap_details (EMailAutoconfig *autoconfig,
        g_return_val_if_fail (E_IS_SOURCE (imap_source), FALSE);
 
        return mail_autoconfig_set_details (
-               autoconfig, &autoconfig->priv->imap_result,
+               &autoconfig->priv->imap_result,
                imap_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
 }
 
@@ -848,7 +1010,7 @@ e_mail_autoconfig_set_pop3_details (EMailAutoconfig *autoconfig,
        g_return_val_if_fail (E_IS_SOURCE (pop3_source), FALSE);
 
        return mail_autoconfig_set_details (
-               autoconfig, &autoconfig->priv->pop3_result,
+               &autoconfig->priv->pop3_result,
                pop3_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
 }
 
@@ -860,7 +1022,7 @@ e_mail_autoconfig_set_smtp_details (EMailAutoconfig *autoconfig,
        g_return_val_if_fail (E_IS_SOURCE (smtp_source), FALSE);
 
        return mail_autoconfig_set_details (
-               autoconfig, &autoconfig->priv->smtp_result,
+               &autoconfig->priv->smtp_result,
                smtp_source, E_SOURCE_EXTENSION_MAIL_TRANSPORT);
 }
 
@@ -911,3 +1073,40 @@ e_mail_autoconfig_dump_results (EMailAutoconfig *autoconfig)
        }
 }
 
+/**
+ * e_mail_autoconfig_copy_results_to_config_lookup:
+ * @mail_autoconfig: an #EMailAutoconfig
+ * @config_lookup: an #EConfigLookup
+ *
+ * Copies any valid result from @mail_autoconfig to @config_lookup.
+ *
+ * Since: 3.26
+ **/
+void
+e_mail_autoconfig_copy_results_to_config_lookup (EMailAutoconfig *mail_autoconfig,
+                                                EConfigLookup *config_lookup)
+{
+       g_return_if_fail (E_IS_MAIL_AUTOCONFIG (mail_autoconfig));
+       g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
+
+       mail_autoconfig_result_to_config_lookup (mail_autoconfig, config_lookup,
+               &mail_autoconfig->priv->imap_result,
+               E_CONFIG_LOOKUP_RESULT_PRIORITY_IMAP,
+               "imapx",
+               _("IMAP server"),
+               E_SOURCE_EXTENSION_MAIL_ACCOUNT);
+
+       mail_autoconfig_result_to_config_lookup (mail_autoconfig, config_lookup,
+               &mail_autoconfig->priv->pop3_result,
+               E_CONFIG_LOOKUP_RESULT_PRIORITY_POP3,
+               "pop",
+               _("POP3 server"),
+               E_SOURCE_EXTENSION_MAIL_ACCOUNT);
+
+       mail_autoconfig_result_to_config_lookup (mail_autoconfig, config_lookup,
+               &mail_autoconfig->priv->smtp_result,
+               E_CONFIG_LOOKUP_RESULT_PRIORITY_SMTP,
+               "smtp",
+               _("SMTP server"),
+               E_SOURCE_EXTENSION_MAIL_TRANSPORT);
+}
diff --git a/src/mail/e-mail-autoconfig.h b/src/mail/e-mail-autoconfig.h
index bc2958f..2ef717c 100644
--- a/src/mail/e-mail-autoconfig.h
+++ b/src/mail/e-mail-autoconfig.h
@@ -19,6 +19,7 @@
 #define E_MAIL_AUTOCONFIG_H
 
 #include <libedataserver/libedataserver.h>
+#include <e-util/e-util.h>
 
 /* Standard GObject macros */
 #define E_TYPE_MAIL_AUTOCONFIG \
@@ -83,6 +84,9 @@ gboolean      e_mail_autoconfig_set_smtp_details
                                                (EMailAutoconfig *autoconfig,
                                                 ESource *smtp_source);
 void           e_mail_autoconfig_dump_results  (EMailAutoconfig *autoconfig);
+void           e_mail_autoconfig_copy_results_to_config_lookup
+                                               (EMailAutoconfig *mail_autoconfig,
+                                                EConfigLookup *config_lookup);
 
 G_END_DECLS
 
diff --git a/src/mail/e-mail-config-assistant.c b/src/mail/e-mail-config-assistant.c
index 7b3f456..35c049e 100644
--- a/src/mail/e-mail-config-assistant.c
+++ b/src/mail/e-mail-config-assistant.c
@@ -21,6 +21,7 @@
 
 #include <libebackend/libebackend.h>
 
+#include <e-util/e-util.h>
 #include <shell/e-shell.h>
 #include <shell/e-shell-window.h>
 #include <shell/e-shell-view.h>
@@ -46,7 +47,7 @@
 /* GtkAssistant's back button label. */
 #define BACK_BUTTON_LABEL N_("Go _Back")
 
-typedef struct _AutoconfigContext AutoconfigContext;
+typedef struct _ConfigLookupContext ConfigLookupContext;
 
 struct _EMailConfigAssistantPrivate {
        EMailSession *session;
@@ -65,10 +66,12 @@ struct _EMailConfigAssistantPrivate {
        GtkButton *back_button;  /* not referenced */
 };
 
-struct _AutoconfigContext {
+struct _ConfigLookupContext {
        GtkAssistant *assistant;
        GCancellable *cancellable;
        GtkWidget *skip_button;  /* not referenced */
+       EConfigLookup *config_lookup;
+       gchar *email_address;
 };
 
 enum {
@@ -96,21 +99,25 @@ G_DEFINE_TYPE_WITH_CODE (
                E_TYPE_EXTENSIBLE, NULL))
 
 static void
-autoconfig_skip_button_clicked_cb (GtkButton *button,
-                                   GCancellable *cancellable)
+config_lookup_skip_button_clicked_cb (GtkButton *button,
+                                     GCancellable *cancellable)
 {
        g_cancellable_cancel (cancellable);
 }
 
-static AutoconfigContext *
-autoconfig_context_new (GtkAssistant *assistant)
+static ConfigLookupContext *
+config_lookup_context_new (GtkAssistant *assistant,
+                          ESourceRegistry *registry,
+                          const gchar *email_address)
 {
-       AutoconfigContext *context;
+       ConfigLookupContext *context;
        const gchar *text;
 
-       context = g_slice_new0 (AutoconfigContext);
+       context = g_slice_new0 (ConfigLookupContext);
        context->assistant = g_object_ref (assistant);
        context->cancellable = g_cancellable_new ();
+       context->config_lookup = e_config_lookup_new (registry);
+       context->email_address = g_strdup (email_address);
 
        /* GtkAssistant sinks the floating button reference. */
        text = _("_Skip Lookup");
@@ -121,22 +128,24 @@ autoconfig_context_new (GtkAssistant *assistant)
 
        g_signal_connect_object (
                context->skip_button, "clicked",
-               G_CALLBACK (autoconfig_skip_button_clicked_cb),
+               G_CALLBACK (config_lookup_skip_button_clicked_cb),
                context->cancellable, 0);
 
        return context;
 }
 
 static void
-autoconfig_context_free (AutoconfigContext *context)
+config_lookup_context_free (ConfigLookupContext *context)
 {
        gtk_assistant_remove_action_widget (
                context->assistant, context->skip_button);
 
        g_object_unref (context->assistant);
        g_object_unref (context->cancellable);
+       g_object_unref (context->config_lookup);
+       g_free (context->email_address);
 
-       g_slice_free (AutoconfigContext, context);
+       g_slice_free (ConfigLookupContext, context);
 }
 
 static gint
@@ -275,55 +284,49 @@ mail_config_assistant_page_changed (EMailConfigPage *page,
 }
 
 static void
-mail_config_assistant_autoconfigure_cb (GObject *source_object,
-                                        GAsyncResult *result,
-                                        gpointer user_data)
+mail_config_assistant_config_lookup_run_cb (GObject *source_object,
+                                           GAsyncResult *result,
+                                           gpointer user_data)
 {
        EMailConfigAssistantPrivate *priv;
-       AutoconfigContext *context;
-       EMailAutoconfig *autoconfig;
-       const gchar *email_address;
+       ConfigLookupContext *context;
        gint n_pages, ii;
-       GError *error = NULL;
+       gboolean any_configured = FALSE;
+
+       context = (ConfigLookupContext *) user_data;
 
-       context = (AutoconfigContext *) user_data;
        priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (context->assistant);
 
-       autoconfig = e_mail_autoconfig_finish (result, &error);
+       e_config_lookup_run_finish (E_CONFIG_LOOKUP (source_object), result);
+
+       if (e_mail_config_service_page_auto_configure (priv->receiving_page, context->config_lookup)) {
+               any_configured = TRUE;
+               /* Add the page to the visited pages hash table to
+                * prevent calling e_mail_config_page_setup_defaults(). */
+               g_hash_table_add (priv->visited_pages, priv->receiving_page);
+       }
 
-       /* We don't really care about errors, we only capture the GError
-        * as a debugging aid.  If this doesn't work we simply proceed to
-        * the Receiving Email page. */
-       if (error != NULL) {
+       if (e_mail_config_service_page_auto_configure (priv->sending_page, context->config_lookup)) {
+               any_configured = TRUE;
+               /* Add the page to the visited pages hash table to
+                * prevent calling e_mail_config_page_setup_defaults(). */
+               g_hash_table_add (priv->visited_pages, priv->sending_page);
+       }
+
+       if (!any_configured) {
                gtk_assistant_next_page (context->assistant);
-               g_error_free (error);
                goto exit;
        }
 
-       g_return_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig));
-
        /* Autoconfiguration worked!  Feed the results to the
         * service pages and then skip to the Summary page. */
 
        /* For the summary page... */
        priv->auto_configured = TRUE;
 
-       e_mail_config_service_page_auto_configure (
-               priv->receiving_page, autoconfig);
-
-       e_mail_config_service_page_auto_configure (
-               priv->sending_page, autoconfig);
-
-       /* Add these pages to the visited pages hash table to
-        * prevent calling e_mail_config_page_setup_defaults(). */
-
-       g_hash_table_add (priv->visited_pages, priv->receiving_page);
-       g_hash_table_add (priv->visited_pages, priv->sending_page);
-
        /* Also set the initial display name to the email address
         * given so the user can just click past the Summary page. */
-       email_address = e_mail_autoconfig_get_email_address (autoconfig);
-       e_source_set_display_name (priv->identity_source, email_address);
+       e_source_set_display_name (priv->identity_source, context->email_address);
 
        /* Go to the next page (Receiving Email) before skipping to the
         * Summary Page to get it into GtkAssistant visited page history.
@@ -348,7 +351,40 @@ exit:
        /* Set the page invisible so we never revisit it. */
        gtk_widget_set_visible (GTK_WIDGET (priv->lookup_page), FALSE);
 
-       autoconfig_context_free (context);
+       config_lookup_context_free (context);
+}
+
+static ESource *
+mail_config_assistant_get_source_cb (EConfigLookup *config_lookup,
+                                    EConfigLookupSourceKind kind,
+                                    gpointer user_data)
+{
+       EMailConfigAssistant *assistant = user_data;
+       EMailConfigServiceBackend *backend;
+       ESource *source = NULL;
+
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), NULL);
+       g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
+
+       switch (kind) {
+       case E_CONFIG_LOOKUP_SOURCE_UNKNOWN:
+               break;
+       case E_CONFIG_LOOKUP_SOURCE_COLLECTION:
+               backend = e_mail_config_assistant_get_account_backend (assistant);
+               source = e_mail_config_service_backend_get_collection (backend);
+               break;
+       case E_CONFIG_LOOKUP_SOURCE_MAIL_ACCOUNT:
+               source = e_mail_config_assistant_get_account_source (assistant);
+               break;
+       case E_CONFIG_LOOKUP_SOURCE_MAIL_IDENTITY:
+               source = e_mail_config_assistant_get_identity_source (assistant);
+               break;
+       case E_CONFIG_LOOKUP_SOURCE_MAIL_TRANSPORT:
+               source = e_mail_config_assistant_get_transport_source (assistant);
+               break;
+       }
+
+       return source;
 }
 
 static gboolean
@@ -977,10 +1013,11 @@ mail_config_assistant_prepare (GtkAssistant *assistant,
        }
 
        if (E_IS_MAIL_CONFIG_LOOKUP_PAGE (page)) {
-               AutoconfigContext *context;
+               ConfigLookupContext *context;
                ESource *source;
                ESourceRegistry *registry;
                ESourceMailIdentity *extension;
+               ENamedParameters *params;
                const gchar *email_address;
                const gchar *extension_name;
 
@@ -991,15 +1028,21 @@ mail_config_assistant_prepare (GtkAssistant *assistant,
                extension = e_source_get_extension (source, extension_name);
                email_address = e_source_mail_identity_get_address (extension);
 
-               context = autoconfig_context_new (assistant);
+               context = config_lookup_context_new (assistant, registry, email_address);
 
-               e_mail_autoconfig_new (
-                       registry,
-                       email_address,
-                       G_PRIORITY_DEFAULT,
+               g_signal_connect (context->config_lookup, "get-source",
+                       G_CALLBACK (mail_config_assistant_get_source_cb), assistant);
+
+               params = e_named_parameters_new ();
+               e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_EMAIL_ADDRESS, email_address);
+
+               e_config_lookup_run (context->config_lookup,
+                       params,
                        context->cancellable,
-                       mail_config_assistant_autoconfigure_cb,
+                       mail_config_assistant_config_lookup_run_cb,
                        context);
+
+               e_named_parameters_free (params);
        }
 
        if (E_IS_MAIL_CONFIG_RECEIVING_PAGE (page) && first_visit) {
diff --git a/src/mail/e-mail-config-service-backend.c b/src/mail/e-mail-config-service-backend.c
index a5b9021..1508784 100644
--- a/src/mail/e-mail-config-service-backend.c
+++ b/src/mail/e-mail-config-service-backend.c
@@ -186,7 +186,8 @@ mail_config_service_backend_setup_defaults (EMailConfigServiceBackend *backend)
 
 static gboolean
 mail_config_service_backend_auto_configure (EMailConfigServiceBackend *backend,
-                                            EMailAutoconfig *autoconfig)
+                                           EConfigLookup *config_lookup,
+                                           gint *out_priority)
 {
        return FALSE;
 }
@@ -478,17 +479,18 @@ e_mail_config_service_backend_setup_defaults (EMailConfigServiceBackend *backend
 
 gboolean
 e_mail_config_service_backend_auto_configure (EMailConfigServiceBackend *backend,
-                                              EMailAutoconfig *autoconfig)
+                                             EConfigLookup *config_lookup,
+                                             gint *out_priority)
 {
        EMailConfigServiceBackendClass *class;
 
        g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend), FALSE);
-       g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), FALSE);
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), FALSE);
 
        class = E_MAIL_CONFIG_SERVICE_BACKEND_GET_CLASS (backend);
        g_return_val_if_fail (class->auto_configure != NULL, FALSE);
 
-       return class->auto_configure (backend, autoconfig);
+       return class->auto_configure (backend, config_lookup, out_priority);
 }
 
 gboolean
@@ -517,3 +519,63 @@ e_mail_config_service_backend_commit_changes (EMailConfigServiceBackend *backend
        class->commit_changes (backend);
 }
 
+/*
+ * e_mail_config_service_backend_auto_configure_for_kind:
+ * @backend: an #EMailConfigServiceBackend
+ * @config_lookup: an #EConfigLookup
+ * @kind: an #EConfigLookupResultKind
+ * @protocol: (nullable): optional protocol name, or %NULL
+ * @source: (nullable): optioanl #ESource to configure, or %NULL
+ * @out_priority: (out) (nullable): priority of the chosen lookup result
+ *
+ * Finds a config lookup result for the given @kind and @protocol and
+ * configures the @source with it. The @out_priority is set to the priority
+ * of that lookup result.
+ *
+ * If no @protocol is given, then the backend name of the @backend it used.
+ * If no @source is given, then gets it with e_mail_config_service_backend_get_source().
+ *
+ * Returns: whether applied any changes
+ *
+ * Since: 3.26
+ */
+gboolean
+e_mail_config_service_backend_auto_configure_for_kind (EMailConfigServiceBackend *backend,
+                                                      EConfigLookup *config_lookup,
+                                                      EConfigLookupResultKind kind,
+                                                      const gchar *protocol,
+                                                      ESource *source,
+                                                      gint *out_priority)
+{
+       EMailConfigServiceBackendClass *klass;
+       GSList *results;
+       gboolean changed = FALSE;
+
+       g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend), FALSE);
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), FALSE);
+       g_return_val_if_fail (kind != E_CONFIG_LOOKUP_RESULT_UNKNOWN, FALSE);
+
+       klass = E_MAIL_CONFIG_SERVICE_BACKEND_GET_CLASS (backend);
+       g_return_val_if_fail (klass->backend_name != NULL, FALSE);
+
+       if (!source)
+               source = e_mail_config_service_backend_get_source (backend);
+       if (!protocol)
+               protocol = klass->backend_name;
+
+       results = e_config_lookup_get_results (config_lookup, kind, protocol);
+       results = g_slist_sort (results, e_config_lookup_result_compare);
+
+       if (results && results->data) {
+               EConfigLookupResult *lookup_result = results->data;
+
+               changed = e_config_lookup_result_configure_source (lookup_result, source);
+
+               if (changed && out_priority)
+                       *out_priority = e_config_lookup_result_get_priority (lookup_result);
+       }
+
+       g_slist_free_full (results, g_object_unref);
+
+       return changed;
+}
diff --git a/src/mail/e-mail-config-service-backend.h b/src/mail/e-mail-config-service-backend.h
index 1f400e8..f869c76 100644
--- a/src/mail/e-mail-config-service-backend.h
+++ b/src/mail/e-mail-config-service-backend.h
@@ -22,7 +22,7 @@
 #include <camel/camel.h>
 #include <libebackend/libebackend.h>
 
-#include <mail/e-mail-autoconfig.h>
+#include <e-util/e-util.h>
 
 /* Standard GObject macros */
 #define E_TYPE_MAIL_CONFIG_SERVICE_BACKEND \
@@ -72,7 +72,8 @@ struct _EMailConfigServiceBackendClass {
                                        (EMailConfigServiceBackend *backend);
        gboolean        (*auto_configure)
                                        (EMailConfigServiceBackend *backend,
-                                        EMailAutoconfig *autoconfig);
+                                        EConfigLookup *config_lookup,
+                                        gint *out_priority);
        gboolean        (*check_complete)
                                        (EMailConfigServiceBackend *backend);
        void            (*commit_changes)
@@ -107,11 +108,19 @@ void              e_mail_config_service_backend_setup_defaults
                                        (EMailConfigServiceBackend *backend);
 gboolean       e_mail_config_service_backend_auto_configure
                                        (EMailConfigServiceBackend *backend,
-                                        EMailAutoconfig *autoconfig);
+                                        EConfigLookup *config_lookup,
+                                        gint *out_priority);
 gboolean       e_mail_config_service_backend_check_complete
                                        (EMailConfigServiceBackend *backend);
 void           e_mail_config_service_backend_commit_changes
                                        (EMailConfigServiceBackend *backend);
+gboolean       e_mail_config_service_backend_auto_configure_for_kind
+                                       (EMailConfigServiceBackend *backend,
+                                        EConfigLookup *config_lookup,
+                                        EConfigLookupResultKind kind,
+                                        const gchar *protocol,
+                                        ESource *source,
+                                        gint *out_priority);
 
 G_END_DECLS
 
diff --git a/src/mail/e-mail-config-service-page.c b/src/mail/e-mail-config-service-page.c
index 8338a8b..6eaf401 100644
--- a/src/mail/e-mail-config-service-page.c
+++ b/src/mail/e-mail-config-service-page.c
@@ -31,11 +31,6 @@
        (G_TYPE_INSTANCE_GET_PRIVATE \
        ((obj), E_TYPE_MAIL_CONFIG_SERVICE_PAGE, EMailConfigServicePagePrivate))
 
-/* Used for autoconfiguration. */
-#define POP3_BACKEND_NAME "pop"
-#define IMAP_BACKEND_NAME "imapx"
-#define SMTP_BACKEND_NAME "smtp"
-
 typedef struct _Candidate Candidate;
 
 struct _EMailConfigServicePagePrivate {
@@ -897,50 +892,40 @@ e_mail_config_service_page_lookup_backend (EMailConfigServicePage *page,
        return NULL;
 }
 
-void
+gboolean
 e_mail_config_service_page_auto_configure (EMailConfigServicePage *page,
-                                           EMailAutoconfig *autoconfig)
+                                           EConfigLookup *config_lookup)
 {
-       EMailConfigServiceBackend *pop3 = NULL;
-       EMailConfigServiceBackend *imap = NULL;
-       EMailConfigServiceBackend *smtp = NULL;
+       EMailConfigServiceBackend *select_backend = NULL;
+       gint selected_priority = G_MAXINT;
+       gboolean any_configured = FALSE;
        guint ii;
 
-       g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page));
-       g_return_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig));
+       g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), FALSE);
+       g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), FALSE);
 
        for (ii = 0; ii < page->priv->candidates->len; ii++) {
-               EMailConfigServiceBackendClass *class;
                EMailConfigServiceBackend *backend;
                Candidate *candidate;
                gboolean configured;
+               gint priority = G_MAXINT;
 
                candidate = page->priv->candidates->pdata[ii];
-
                backend = candidate->backend;
-               class = E_MAIL_CONFIG_SERVICE_BACKEND_GET_CLASS (backend);
 
-               configured = e_mail_config_service_backend_auto_configure (
-                       backend, autoconfig);
-
-               /* XXX There's a few specific backends to check for.
-                *     It requires that we know about these backends,
-                *     which violates the abstraction, but we need to
-                *     break our own rule to be practical here. */
-               if (g_strcmp0 (class->backend_name, POP3_BACKEND_NAME) == 0)
-                       pop3 = configured ? backend : NULL;
-               if (g_strcmp0 (class->backend_name, IMAP_BACKEND_NAME) == 0)
-                       imap = configured ? backend : NULL;
-               if (g_strcmp0 (class->backend_name, SMTP_BACKEND_NAME) == 0)
-                       smtp = configured ? backend : NULL;
+               configured = e_mail_config_service_backend_auto_configure (backend, config_lookup, &priority);
+
+               if (configured && priority < selected_priority) {
+                       selected_priority = priority;
+                       select_backend = backend;
+               }
+
+               any_configured = any_configured || configured;
        }
 
-       /* Select POP3 before IMAP.  If both are present we want IMAP. */
-       if (pop3 != NULL)
-               e_mail_config_service_page_set_active_backend (page, pop3);
-       if (imap != NULL)
-               e_mail_config_service_page_set_active_backend (page, imap);
-       if (smtp != NULL)
-               e_mail_config_service_page_set_active_backend (page, smtp);
+       if (select_backend)
+               e_mail_config_service_page_set_active_backend (page, select_backend);
+
+       return any_configured;
 }
 
diff --git a/src/mail/e-mail-config-service-page.h b/src/mail/e-mail-config-service-page.h
index f648c09..2603331 100644
--- a/src/mail/e-mail-config-service-page.h
+++ b/src/mail/e-mail-config-service-page.h
@@ -24,7 +24,7 @@
 
 #include <camel/camel.h>
 
-#include <mail/e-mail-autoconfig.h>
+#include <e-util/e-util.h>
 #include <mail/e-mail-config-activity-page.h>
 #include <mail/e-mail-config-service-backend.h>
 
@@ -91,9 +91,9 @@ EMailConfigServiceBackend *
                e_mail_config_service_page_lookup_backend
                                                (EMailConfigServicePage *page,
                                                 const gchar *backend_name);
-void           e_mail_config_service_page_auto_configure
+gboolean       e_mail_config_service_page_auto_configure
                                                (EMailConfigServicePage *page,
-                                                EMailAutoconfig *autoconfig);
+                                                EConfigLookup *config_lookup);
 
 G_END_DECLS
 
diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt
index 070a898..dc88551 100644
--- a/src/modules/CMakeLists.txt
+++ b/src/modules/CMakeLists.txt
@@ -102,6 +102,7 @@ add_subdirectory(cal-config-local)
 add_subdirectory(cal-config-webcal)
 add_subdirectory(composer-autosave)
 add_subdirectory(composer-to-meeting)
+add_subdirectory(config-lookup)
 add_subdirectory(contact-photos)
 add_subdirectory(gravatar)
 add_subdirectory(itip-formatter)
diff --git a/src/modules/config-lookup/CMakeLists.txt b/src/modules/config-lookup/CMakeLists.txt
new file mode 100644
index 0000000..37261ee
--- /dev/null
+++ b/src/modules/config-lookup/CMakeLists.txt
@@ -0,0 +1,22 @@
+set(extra_deps
+       evolution-mail
+       evolution-util
+)
+set(sources
+       config-lookup.c
+       e-gnome-config-lookup.c
+       e-gnome-config-lookup.h
+)
+set(extra_defines)
+set(extra_cflags)
+set(extra_incdirs)
+set(extra_ldflags)
+
+add_evolution_module(module-config-lookup
+       sources
+       extra_deps
+       extra_defines
+       extra_cflags
+       extra_incdirs
+       extra_ldflags
+)
diff --git a/src/modules/config-lookup/config-lookup.c b/src/modules/config-lookup/config-lookup.c
new file mode 100644
index 0000000..96ec875
--- /dev/null
+++ b/src/modules/config-lookup/config-lookup.c
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "evolution-config.h"
+
+#include <gmodule.h>
+#include <glib-object.h>
+
+#include "e-gnome-config-lookup.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+       e_gnome_config_lookup_type_register (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
diff --git a/src/modules/config-lookup/e-gnome-config-lookup.c 
b/src/modules/config-lookup/e-gnome-config-lookup.c
new file mode 100644
index 0000000..ed0d11f
--- /dev/null
+++ b/src/modules/config-lookup/e-gnome-config-lookup.c
@@ -0,0 +1,145 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "evolution-config.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "mail/e-mail-autoconfig.h"
+#include "e-util/e-util.h"
+
+#include "e-gnome-config-lookup.h"
+
+/* Standard GObject macros */
+#define E_TYPE_GNOME_CONFIG_LOOKUP \
+       (e_gnome_config_lookup_get_type ())
+#define E_GNOME_CONFIG_LOOKUP(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_GNOME_CONFIG_LOOKUP, EGnomeConfigLookup))
+#define E_GNOME_CONFIG_LOOKUP_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_GNOME_CONFIG_LOOKUP, EGnomeConfigLookupClass))
+#define E_IS_GNOME_CONFIG_LOOKUP(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_GNOME_CONFIG_LOOKUP))
+#define E_IS_GNOME_CONFIG_LOOKUP_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_GNOME_CONFIG_LOOKUP))
+#define E_GNOME_CONFIG_LOOKUP_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_GNOME_CONFIG_LOOKUP, EGnomeConfigLookupClass))
+
+typedef struct _EGnomeConfigLookup EGnomeConfigLookup;
+typedef struct _EGnomeConfigLookupClass EGnomeConfigLookupClass;
+
+struct _EGnomeConfigLookup {
+       EExtension parent;
+};
+
+struct _EGnomeConfigLookupClass {
+       EExtensionClass parent_class;
+};
+
+GType e_gnome_config_lookup_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_DYNAMIC_TYPE (EGnomeConfigLookup, e_gnome_config_lookup, E_TYPE_EXTENSION)
+
+static void
+gnome_config_lookup_thread (EConfigLookup *config_lookup,
+                           const ENamedParameters *params,
+                           gpointer user_data,
+                           GCancellable *cancellable)
+{
+       EMailAutoconfig *mail_autoconfig;
+       ESourceRegistry *registry;
+       const gchar *email_address;
+
+       g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
+       g_return_if_fail (params != NULL);
+
+       registry = e_config_lookup_get_registry (config_lookup);
+       email_address = e_named_parameters_get (params, E_CONFIG_LOOKUP_PARAM_EMAIL_ADDRESS);
+
+       if (!email_address || !*email_address)
+               return;
+
+       mail_autoconfig = e_mail_autoconfig_new_sync (registry, email_address, cancellable, NULL);
+       if (mail_autoconfig)
+               e_mail_autoconfig_copy_results_to_config_lookup (mail_autoconfig, config_lookup);
+
+       g_clear_object (&mail_autoconfig);
+}
+
+static void
+gnome_config_lookup_run_cb (EConfigLookup *config_lookup,
+                           const ENamedParameters *params,
+                           EActivity *activity,
+                           gpointer user_data)
+{
+       g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
+       g_return_if_fail (E_IS_GNOME_CONFIG_LOOKUP (user_data));
+       g_return_if_fail (E_IS_ACTIVITY (activity));
+
+       e_config_lookup_create_thread (config_lookup, params, activity,
+               gnome_config_lookup_thread, NULL, NULL);
+}
+
+static void
+gnome_config_lookup_constructed (GObject *object)
+{
+       EConfigLookup *config_lookup;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_gnome_config_lookup_parent_class)->constructed (object);
+
+       config_lookup = E_CONFIG_LOOKUP (e_extension_get_extensible (E_EXTENSION (object)));
+
+       g_signal_connect (config_lookup, "run",
+               G_CALLBACK (gnome_config_lookup_run_cb), object);
+}
+
+static void
+e_gnome_config_lookup_class_init (EGnomeConfigLookupClass *class)
+{
+       GObjectClass *object_class;
+       EExtensionClass *extension_class;
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->constructed = gnome_config_lookup_constructed;
+
+       extension_class = E_EXTENSION_CLASS (class);
+       extension_class->extensible_type = E_TYPE_CONFIG_LOOKUP;
+}
+
+static void
+e_gnome_config_lookup_class_finalize (EGnomeConfigLookupClass *class)
+{
+}
+
+static void
+e_gnome_config_lookup_init (EGnomeConfigLookup *extension)
+{
+}
+
+void
+e_gnome_config_lookup_type_register (GTypeModule *type_module)
+{
+       /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+        *     function, so we have to wrap it with a public function in
+        *     order to register types from a separate compilation unit. */
+       e_gnome_config_lookup_register_type (type_module);
+}
diff --git a/src/modules/config-lookup/e-gnome-config-lookup.h 
b/src/modules/config-lookup/e-gnome-config-lookup.h
new file mode 100644
index 0000000..dfe8719
--- /dev/null
+++ b/src/modules/config-lookup/e-gnome-config-lookup.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_GNOME_CONFIG_LOOKUP_H
+#define E_GNOME_CONFIG_LOOKUP_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void e_gnome_config_lookup_type_register (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_GNOME_CONFIG_LOOKUP_H */
diff --git a/src/modules/mail-config/e-mail-config-remote-accounts.c 
b/src/modules/mail-config/e-mail-config-remote-accounts.c
index 21c39e9..faeb5c3 100644
--- a/src/modules/mail-config/e-mail-config-remote-accounts.c
+++ b/src/modules/mail-config/e-mail-config-remote-accounts.c
@@ -486,13 +486,11 @@ e_mail_config_remote_backend_init (EMailConfigRemoteBackend *backend)
 
 static gboolean
 mail_config_pop_backend_auto_configure (EMailConfigServiceBackend *backend,
-                                        EMailAutoconfig *autoconfig)
+                                       EConfigLookup *config_lookup,
+                                       gint *out_priority)
 {
-       ESource *source;
-
-       source = e_mail_config_service_backend_get_source (backend);
-
-       return e_mail_autoconfig_set_pop3_details (autoconfig, source);
+       return e_mail_config_service_backend_auto_configure_for_kind (backend, config_lookup,
+               E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE, NULL, NULL, out_priority);
 }
 
 static void
@@ -536,13 +534,11 @@ e_mail_config_nntp_backend_init (EMailConfigRemoteBackend *backend)
 
 static gboolean
 mail_config_imapx_backend_auto_configure (EMailConfigServiceBackend *backend,
-                                          EMailAutoconfig *autoconfig)
+                                         EConfigLookup *config_lookup,
+                                         gint *out_priority)
 {
-       ESource *source;
-
-       source = e_mail_config_service_backend_get_source (backend);
-
-       return e_mail_autoconfig_set_imap_details (autoconfig, source);
+       return e_mail_config_service_backend_auto_configure_for_kind (backend, config_lookup,
+               E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE, NULL, NULL, out_priority);
 }
 
 static void
diff --git a/src/modules/mail-config/e-mail-config-smtp-backend.c 
b/src/modules/mail-config/e-mail-config-smtp-backend.c
index 68a8982..a96d76d 100644
--- a/src/modules/mail-config/e-mail-config-smtp-backend.c
+++ b/src/modules/mail-config/e-mail-config-smtp-backend.c
@@ -385,16 +385,15 @@ mail_config_smtp_backend_insert_widgets (EMailConfigServiceBackend *backend,
 
 static gboolean
 mail_config_smtp_backend_auto_configure (EMailConfigServiceBackend *backend,
-                                         EMailAutoconfig *autoconfig)
+                                        EConfigLookup *config_lookup,
+                                        gint *out_priority)
 {
        EMailConfigSmtpBackendPrivate *priv;
-       ESource *source;
        CamelSettings *settings;
        const gchar *mechanism;
 
-       source = e_mail_config_service_backend_get_source (backend);
-
-       if (!e_mail_autoconfig_set_smtp_details (autoconfig, source))
+       if (!e_mail_config_service_backend_auto_configure_for_kind (backend, config_lookup,
+               E_CONFIG_LOOKUP_RESULT_MAIL_SEND, NULL, NULL, out_priority))
                return FALSE;
 
        /* XXX Need to set the authentication widgets to match the


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