/*
* e-source-camel-provider.c
*
* 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 .
*
*/
/**
* SECTION: e-source-camel
* @include: libedataserver/libedataserver.h
* @short_description: #ESource extension for #CamelSettings
*
* #ESourceCamel itself is abstract. Its sole function is to
* bridge #GObject properties from the #CamelSettings framework to the
* #ESource framework. It does this by procedurally registering an
* #ESourceCamel subtype for each available #CamelService subtype,
* and then registering #GObject properties to proxy the properties in the
* corresponding #CamelSettings subtype. The #ESourceCamel owns an
* instance of the appropriate #CamelSettings subtype, and redirects all
* get/set operations on its own #GObject properties to its #CamelSettings
* instance. The #CamelSettings instance, now fully initialized from a key
* file, can then be inserted into a new #CamelService instance using
* camel_service_set_settings().
*
* Ultimately, this is all just implementation detail for glueing two
* unrelated class hierarchies together. If you need to access provider
* specific settings, use the #CamelSettings API, not this.
**/
#include "e-source-camel.h"
#include
#include
#include
#include
#include
#include
#define E_SOURCE_CAMEL_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_SOURCE_CAMEL, ESourceCamelPrivate))
struct _ESourceCamelPrivate {
CamelSettings *settings;
GArray *value_array;
};
enum {
PROP_0,
PROP_SETTINGS
};
typedef struct {
const gchar *extension_name;
const gchar *extension_property_name;
const gchar *settings_property_name;
GBindingTransformFunc extension_to_settings;
GBindingTransformFunc settings_to_extension;
} BindingData;
typedef struct {
GType settings_type;
const gchar *extension_name;
} SubclassData;
static gboolean
transform_none_to_null (GBinding *binding,
const GValue *source_value,
GValue *target_value,
gpointer not_used)
{
const gchar *v_string;
/* XXX Camel doesn't understand ESource's convention of using
* "none" to represent no value, instead of NULL or empty
* strings. So convert "none" to NULL for Camel. */
v_string = g_value_get_string (source_value);
if (g_strcmp0 (v_string, "none") == 0)
v_string = NULL;
g_value_set_string (target_value, v_string);
return TRUE;
}
static BindingData bindings[] = {
{ E_SOURCE_EXTENSION_AUTHENTICATION,
"host", "host" },
{ E_SOURCE_EXTENSION_AUTHENTICATION,
"method", "auth-mechanism",
transform_none_to_null,
NULL },
{ E_SOURCE_EXTENSION_AUTHENTICATION,
"port", "port" },
{ E_SOURCE_EXTENSION_AUTHENTICATION,
"user", "user" },
{ E_SOURCE_EXTENSION_OFFLINE,
"stay-synchronized", "stay-synchronized" },
{ E_SOURCE_EXTENSION_SECURITY,
"method", "security-method",
e_binding_transform_enum_nick_to_value,
e_binding_transform_enum_value_to_nick }
};
G_DEFINE_ABSTRACT_TYPE (
ESourceCamel,
e_source_camel,
E_TYPE_SOURCE_EXTENSION)
/* XXX Historical note, originally I tried (ab)using override properties
* in ESourceCamel, which redirected to the equivalent CamelSettings
* property. Seemed to work at first, and I was proud of my clever
* hack, but it turns out g_object_class_list_properties() excludes
* override properties. So the ESourceCamel properties were being
* skipped in source_load_from_key_file() (e-source.c). */
static GParamSpec *
param_spec_clone (GParamSpec *pspec)
{
GParamSpec *clone;
GParamFlags flags;
const gchar *name, *nick, *blurb;
name = g_param_spec_get_name (pspec);
nick = g_param_spec_get_nick (pspec);
blurb = g_param_spec_get_blurb (pspec);
flags = (pspec->flags & ~(G_PARAM_STATIC_STRINGS));
if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) {
GParamSpecBoolean *pspec_boolean = G_PARAM_SPEC_BOOLEAN (pspec);
clone = g_param_spec_boolean (name, nick, blurb,
pspec_boolean->default_value,
flags);
} else if (G_IS_PARAM_SPEC_CHAR (pspec)) {
GParamSpecChar *pspec_char = G_PARAM_SPEC_CHAR (pspec);
clone = g_param_spec_char (name, nick, blurb,
pspec_char->minimum,
pspec_char->maximum,
pspec_char->default_value,
flags);
} else if (G_IS_PARAM_SPEC_UCHAR (pspec)) {
GParamSpecUChar *pspec_uchar = G_PARAM_SPEC_UCHAR (pspec);
clone = g_param_spec_uchar (name, nick, blurb,
pspec_uchar->minimum,
pspec_uchar->maximum,
pspec_uchar->default_value,
flags);
} else if (G_IS_PARAM_SPEC_INT (pspec)) {
GParamSpecInt *pspec_int = G_PARAM_SPEC_INT (pspec);
clone = g_param_spec_int (name, nick, blurb,
pspec_int->minimum,
pspec_int->maximum,
pspec_int->default_value,
flags);
} else if (G_IS_PARAM_SPEC_UINT (pspec)) {
GParamSpecUInt *pspec_uint = G_PARAM_SPEC_UINT (pspec);
clone = g_param_spec_uint (name, nick, blurb,
pspec_uint->minimum,
pspec_uint->maximum,
pspec_uint->default_value,
flags);
} else if (G_IS_PARAM_SPEC_LONG (pspec)) {
GParamSpecLong *pspec_long = G_PARAM_SPEC_LONG (pspec);
clone = g_param_spec_long (name, nick, blurb,
pspec_long->minimum,
pspec_long->maximum,
pspec_long->default_value,
flags);
} else if (G_IS_PARAM_SPEC_ULONG (pspec)) {
GParamSpecULong *pspec_ulong = G_PARAM_SPEC_ULONG (pspec);
clone = g_param_spec_ulong (name, nick, blurb,
pspec_ulong->minimum,
pspec_ulong->maximum,
pspec_ulong->default_value,
flags);
} else if (G_IS_PARAM_SPEC_INT64 (pspec)) {
GParamSpecInt64 *pspec_int64 = G_PARAM_SPEC_INT64 (pspec);
clone = g_param_spec_int64 (name, nick, blurb,
pspec_int64->minimum,
pspec_int64->maximum,
pspec_int64->default_value,
flags);
} else if (G_IS_PARAM_SPEC_UINT64 (pspec)) {
GParamSpecUInt64 *pspec_uint64 = G_PARAM_SPEC_UINT64 (pspec);
clone = g_param_spec_uint64 (name, nick, blurb,
pspec_uint64->minimum,
pspec_uint64->maximum,
pspec_uint64->default_value,
flags);
} else if (G_IS_PARAM_SPEC_FLOAT (pspec)) {
GParamSpecFloat *pspec_float = G_PARAM_SPEC_FLOAT (pspec);
clone = g_param_spec_float (name, nick, blurb,
pspec_float->minimum,
pspec_float->maximum,
pspec_float->default_value,
flags);
} else if (G_IS_PARAM_SPEC_DOUBLE (pspec)) {
GParamSpecDouble *pspec_double = G_PARAM_SPEC_DOUBLE (pspec);
clone = g_param_spec_double (name, nick, blurb,
pspec_double->minimum,
pspec_double->maximum,
pspec_double->default_value,
flags);
} else if (G_IS_PARAM_SPEC_ENUM (pspec)) {
GParamSpecEnum *pspec_enum = G_PARAM_SPEC_ENUM (pspec);
clone = g_param_spec_enum (name, nick, blurb,
pspec->value_type,
pspec_enum->default_value,
flags);
} else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
GParamSpecFlags *pspec_flags = G_PARAM_SPEC_FLAGS (pspec);
clone = g_param_spec_flags (name, nick, blurb,
pspec->value_type,
pspec_flags->default_value,
flags);
} else if (G_IS_PARAM_SPEC_STRING (pspec)) {
GParamSpecString *pspec_string = G_PARAM_SPEC_STRING (pspec);
clone = g_param_spec_string (name, nick, blurb,
pspec_string->default_value,
flags);
} else if (G_IS_PARAM_SPEC_PARAM (pspec)) {
clone = g_param_spec_param (name, nick, blurb,
pspec->value_type,
flags);
} else if (G_IS_PARAM_SPEC_BOXED (pspec)) {
clone = g_param_spec_boxed (name, nick, blurb,
pspec->value_type,
flags);
} else if (G_IS_PARAM_SPEC_POINTER (pspec)) {
clone = g_param_spec_pointer (name, nick, blurb, flags);
} else if (G_IS_PARAM_SPEC_OBJECT (pspec)) {
clone = g_param_spec_object (name, nick, blurb,
pspec->value_type,
flags);
} else if (G_IS_PARAM_SPEC_UNICHAR (pspec)) {
GParamSpecUnichar *pspec_unichar = G_PARAM_SPEC_UNICHAR (pspec);
clone = g_param_spec_unichar (name, nick, blurb,
pspec_unichar->default_value,
flags);
} else if (G_IS_PARAM_SPEC_GTYPE (pspec)) {
GParamSpecGType *pspec_gtype = G_PARAM_SPEC_GTYPE (pspec);
clone = g_param_spec_gtype (name, nick, blurb,
pspec_gtype->is_a_type,
flags);
} else if (G_IS_PARAM_SPEC_VARIANT (pspec)) {
GParamSpecVariant *pspec_variant = G_PARAM_SPEC_VARIANT (pspec);
clone = g_param_spec_variant (name, nick, blurb,
pspec_variant->type,
pspec_variant->default_value,
flags);
} else {
g_warn_if_reached ();
}
return clone;
}
static gint
subclass_get_binding_index (GParamSpec *settings_property)
{
gint ii;
/* Return the index in the bindings list for the given
* CamelSettings property specification, or else -1. */
for (ii = 0; ii < G_N_ELEMENTS (bindings); ii++) {
const gchar *property_name;
property_name = bindings[ii].settings_property_name;
if (g_strcmp0 (settings_property->name, property_name) == 0)
return ii;
}
return -1;
}
static void
subclass_set_property (GObject *object,
guint property_id,
const GValue *src_value,
GParamSpec *pspec)
{
ESourceCamel *extension;
GArray *value_array;
GValue *dst_value;
extension = E_SOURCE_CAMEL (object);
value_array = extension->priv->value_array;
dst_value = &g_array_index (value_array, GValue, property_id - 1);
g_value_copy (src_value, dst_value);
}
static void
subclass_get_property (GObject *object,
guint property_id,
GValue *dst_value,
GParamSpec *pspec)
{
ESourceCamel *extension;
GArray *value_array;
GValue *src_value;
extension = E_SOURCE_CAMEL (object);
value_array = extension->priv->value_array;
src_value = &g_array_index (value_array, GValue, property_id - 1);
g_value_copy (src_value, dst_value);
}
static void
subclass_class_init (gpointer g_class,
gpointer class_data)
{
ESourceCamelClass *class;
GObjectClass *settings_class;
GObjectClass *object_class;
SubclassData *data = class_data;
GParamSpec **properties;
guint ii, n_properties;
guint prop_id = 1;
class = E_SOURCE_CAMEL_CLASS (g_class);
settings_class = g_type_class_ref (data->settings_type);
object_class = G_OBJECT_CLASS (g_class);
object_class->set_property = subclass_set_property;
object_class->get_property = subclass_get_property;
/* For each property in the CamelSettings class, register
* an equivalent GObject property in this class and add an
* E_SOURCE_PARAM_SETTING flag so the value gets written to
* the ESource's key file. */
properties = g_object_class_list_properties (
settings_class, &n_properties);
for (ii = 0; ii < n_properties; ii++) {
GParamSpec *pspec;
/* Some properties in CamelSettings may be covered
* by other ESourceExtensions. Skip them here. */
if (subclass_get_binding_index (properties[ii]) >= 0)
continue;
pspec = param_spec_clone (properties[ii]);
pspec->flags |= E_SOURCE_PARAM_SETTING;
/* Clear the G_PARAM_CONSTRUCT flag. We apply default
* property values to our GValue array during instance
* initialization. */
pspec->flags &= ~G_PARAM_CONSTRUCT;
g_object_class_install_property (
G_OBJECT_CLASS (class), prop_id++, pspec);
}
g_free (properties);
/* Initialize more class members. */
class->settings_type = G_OBJECT_CLASS_TYPE (settings_class);
class->parent_class.name = data->extension_name;
g_type_class_unref (settings_class);
}
static void
subclass_instance_init (GTypeInstance *instance,
gpointer g_class)
{
/* Nothing to do here, just makes a handy breakpoint. */
}
static void
source_camel_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_SETTINGS:
g_value_set_object (
value,
e_source_camel_get_settings (
E_SOURCE_CAMEL (object)));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
source_camel_dispose (GObject *object)
{
ESourceCamelPrivate *priv;
priv = E_SOURCE_CAMEL_GET_PRIVATE (object);
if (priv->settings != NULL) {
g_object_unref (priv->settings);
priv->settings = NULL;
}
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_source_camel_parent_class)->dispose (object);
}
static void
source_camel_finalize (GObject *object)
{
ESourceCamelPrivate *priv;
guint ii;
priv = E_SOURCE_CAMEL_GET_PRIVATE (object);
for (ii = 0; ii < priv->value_array->len; ii++)
g_value_unset (&g_array_index (priv->value_array, GValue, ii));
g_array_free (priv->value_array, TRUE);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_source_camel_parent_class)->finalize (object);
}
static void
source_camel_constructed (GObject *object)
{
ESource *source;
ESourceCamelClass *class;
ESourceCamelPrivate *priv;
GObjectClass *settings_class;
GParamSpec **properties;
guint ii, n_properties;
guint array_index = 0;
/* Chain up to parent's constructed() method. */
G_OBJECT_CLASS (e_source_camel_parent_class)->constructed (object);
class = E_SOURCE_CAMEL_GET_CLASS (object);
priv = E_SOURCE_CAMEL_GET_PRIVATE (object);
source = e_source_extension_ref_source (E_SOURCE_EXTENSION (object));
priv->settings = g_object_new (class->settings_type, NULL);
/* Here we bind all the GObject properties in the newly-created
* CamelSettings instance to either our own identical properties
* or properties in another ESourceExtensions. The bindings list
* at the top of the file maps out bindings to other extensions. */
settings_class = G_OBJECT_GET_CLASS (priv->settings);
properties = g_object_class_list_properties (
settings_class, &n_properties);
/* Allocate more elements than we need, since some CamelSettings
* properties get bound to properties of other ESourceExtensions.
* We'll trim off the extra elements later. */
g_array_set_size (priv->value_array, n_properties);
for (ii = 0; ii < n_properties; ii++) {
GParamSpec *pspec = properties[ii];
GBindingTransformFunc transform_to = NULL;
GBindingTransformFunc transform_from = NULL;
ESourceExtension *extension;
const gchar *source_property;
const gchar *target_property;
gint binding_index;
binding_index = subclass_get_binding_index (pspec);
/* Bind the CamelSettings property to
* one in a different ESourceExtension. */
if (binding_index >= 0) {
BindingData *binding;
binding = &bindings[binding_index];
extension = e_source_get_extension (
source, binding->extension_name);
source_property = binding->extension_property_name;
target_property = binding->settings_property_name;
transform_to = binding->extension_to_settings;
transform_from = binding->settings_to_extension;
/* Bind the CamelSettings property to our own
* equivalent E_SOURCE_PARAM_SETTING property. */
} else {
GValue *value;
extension = E_SOURCE_EXTENSION (object);
source_property = pspec->name;
target_property = pspec->name;
/* Initialize the array element to
* hold the GParamSpec's value type. */
value = &g_array_index (
priv->value_array, GValue, array_index++);
g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
/* Set the array element to the GParamSpec's default
* value. This allows us to avoid declaring our own
* properties with a G_PARAM_CONSTRUCT flag. */
g_param_value_set_default (pspec, value);
}
e_binding_bind_property_full (
extension, source_property,
priv->settings, target_property,
G_BINDING_BIDIRECTIONAL |
G_BINDING_SYNC_CREATE,
transform_to, transform_from,
NULL, (GDestroyNotify) NULL);
}
/* Trim off any extra array elements. */
g_array_set_size (priv->value_array, array_index);
g_free (properties);
g_object_unref (source);
}
static void
e_source_camel_class_init (ESourceCamelClass *class)
{
GObjectClass *object_class;
g_type_class_add_private (class, sizeof (ESourceCamelPrivate));
object_class = G_OBJECT_CLASS (class);
object_class->get_property = source_camel_get_property;
object_class->dispose = source_camel_dispose;
object_class->finalize = source_camel_finalize;
object_class->constructed = source_camel_constructed;
/* CamelSettings itself has no properties. */
class->settings_type = CAMEL_TYPE_SETTINGS;
/* XXX This kind of stomps on CamelSettings' namespace, but it's
* unlikely a CamelSettings subclass would define a property
* named "settings". */
g_object_class_install_property (
object_class,
PROP_SETTINGS,
g_param_spec_object (
"settings",
"Settings",
"The CamelSettings instance being proxied",
CAMEL_TYPE_SETTINGS,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
}
static void
e_source_camel_init (ESourceCamel *extension)
{
GArray *value_array;
/* Zero-fill array elements when they are allocated. */
value_array = g_array_new (FALSE, TRUE, sizeof (GValue));
extension->priv = E_SOURCE_CAMEL_GET_PRIVATE (extension);
extension->priv->value_array = value_array;
}
/* Helper for e_source_camel_register_types() */
static gpointer
source_camel_register_types_once (gpointer unused)
{
GList *list, *link;
/* This implicitly takes care of provider initialization. */
list = camel_provider_list (TRUE);
for (link = list; link != NULL; link = g_list_next (link)) {
CamelProvider *provider;
gint ii;
provider = (CamelProvider *) link->data;
/* This is the novel part: generate and register
* a new ESourceCamel subclass on-the-fly for each
* object type listed in the provider. */
for (ii = 0; ii < CAMEL_NUM_PROVIDER_TYPES; ii++) {
CamelServiceClass *service_class = NULL;
GType service_type;
service_type = provider->object_types[ii];
if (g_type_is_a (service_type, CAMEL_TYPE_SERVICE))
service_class = g_type_class_ref (service_type);
if (service_class != NULL) {
e_source_camel_generate_subtype (
provider->protocol,
service_class->settings_type);
g_type_class_unref (service_class);
}
}
}
g_list_free (list);
return NULL;
}
/**
* e_source_camel_register_types:
*
* Creates and registers subclasses of #ESourceCamel for each available
* #CamelProvider. This function should be called once during application
* or library initialization.
*
* Since: 3.6
**/
void
e_source_camel_register_types (void)
{
static GOnce register_types_once = G_ONCE_INIT;
g_once (®ister_types_once, source_camel_register_types_once, NULL);
}
/**
* e_source_camel_generate_subtype:
* @protocol: a #CamelProvider protocol
* @settings_type: a subtype of #CamelSettings
*
* Generates a custom #ESourceCamel subtype for @protocol. Instances of the
* new subtype will contain a #CamelSettings instance of type @settings_type.
*
* This function is called as part of e_source_camel_register_types() and
* should not be called explicitly, except by some groupware packages that
* need to share package-specific settings across their mail, calendar and
* address book components. In that case the groupware package may choose
* to subclass #CamelSettings rather than #ESourceExtension since libcamel
* is the lowest common denominator across all components. This function
* provides a way for the calendar and address book components of such a
* package to generate an #ESourceCamel subtype for its #CamelSettings
* subtype without having to load all available #CamelProvider modules.
*
* Returns: the #GType of the generated #ESourceCamel subtype
*
* Since: 3.6
**/
GType
e_source_camel_generate_subtype (const gchar *protocol,
GType settings_type)
{
GTypeInfo type_info;
GType type;
SubclassData *subclass_data;
const gchar *type_name;
const gchar *extension_name;
g_return_val_if_fail (protocol != NULL, G_TYPE_INVALID);
type_name = e_source_camel_get_type_name (protocol);
extension_name = e_source_camel_get_extension_name (protocol);
/* Check if the type name is already registered. */
type = g_type_from_name (type_name);
if (type != G_TYPE_INVALID)
return type;
/* The settings type must be derived from CAMEL_TYPE_SETTINGS. */
if (!g_type_is_a (settings_type, CAMEL_TYPE_SETTINGS)) {
g_warning (
"%s: Invalid settings type '%s' for protocol '%s'",
G_STRFUNC, g_type_name (settings_type), protocol);
return G_TYPE_INVALID;
}
subclass_data = g_slice_new0 (SubclassData);
subclass_data->settings_type = settings_type;
subclass_data->extension_name = g_intern_string (extension_name);
memset (&type_info, 0, sizeof (GTypeInfo));
type_info.class_size = sizeof (ESourceCamelClass);
type_info.class_init = subclass_class_init;
type_info.class_data = subclass_data;
type_info.instance_size = sizeof (ESourceCamel);
type_info.instance_init = subclass_instance_init;
type = g_type_register_static (
E_TYPE_SOURCE_CAMEL, type_name, &type_info, 0);
return type;
}
/**
* e_source_camel_get_settings:
* @extension: an #ESourceCamel
*
* Returns @extension's #ESourceCamel:settings instance, pre-configured
* from the #ESource to which @extension belongs. Changes to the #ESource
* will automatically propagate to the #ESourceCamel:settings instance and
* vice versa.
*
* This is essentially the glue that binds #ESource to #CamelService.
* See e_source_camel_configure_service().
*
* Returns: a configured #CamelSettings instance
*
* Since: 3.6
**/
CamelSettings *
e_source_camel_get_settings (ESourceCamel *extension)
{
g_return_val_if_fail (E_IS_SOURCE_CAMEL (extension), NULL);
return extension->priv->settings;
}
/**
* e_source_camel_get_type_name:
* @protocol: a #CamelProvider protocol
*
* Returns the #GType name of the registered #ESourceCamel subtype for
* @protocol.
*
* For example, given a protocol named "imap" the function would return
* "ESourceCamelImap".
*
* Returns: the #ESourceCamel type name for @protocol
*
* Since: 3.6
**/
const gchar *
e_source_camel_get_type_name (const gchar *protocol)
{
gchar *buffer;
gsize buffer_len;
g_return_val_if_fail (protocol != NULL, NULL);
buffer_len = strlen (protocol) + 16;
buffer = g_alloca (buffer_len);
g_snprintf (buffer, buffer_len, "ESourceCamel%s", protocol);
buffer[12] = g_ascii_toupper (buffer[12]);
return g_intern_string (buffer);
}
/**
* e_source_camel_get_extension_name:
* @protocol: a #CamelProvider protocol
*
* Returns the extension name for the #ESourceCamel subtype for @protocol.
* The extension name can then be passed to e_source_get_extension() to
* obtain an instance of the #ESourceCamel subtype.
*
* For example, given a protocol named "imap" the function would return
* "Imap Backend".
*
* Returns: the #ESourceCamel extension name for @protocol
*
* Since: 3.6
**/
const gchar *
e_source_camel_get_extension_name (const gchar *protocol)
{
gchar *buffer;
gsize buffer_len;
g_return_val_if_fail (protocol != NULL, NULL);
/* Use the term "backend" for consistency with other
* calendar and address book backend extension names. */
buffer_len = strlen (protocol) + 16;
buffer = g_alloca (buffer_len);
g_snprintf (buffer, buffer_len, "%s Backend", protocol);
buffer[0] = g_ascii_toupper (buffer[0]);
return g_intern_string (buffer);
}
/**
* e_source_camel_configure_service:
* @source: an #ESource
* @service: a #CamelService
*
* This function essentially glues together @source and @serivce so their
* configuration settings stay synchronized. The glue itself is a shared
* #CamelSettings instance.
*
* Call this function immediately after creating a new #CamelService with
* camel_session_add_service().
*
* Since: 3.6
**/
void
e_source_camel_configure_service (ESource *source,
CamelService *service)
{
ESourceCamel *extension;
CamelProvider *provider;
CamelSettings *settings;
const gchar *extension_name;
g_return_if_fail (E_IS_SOURCE (source));
g_return_if_fail (CAMEL_IS_SERVICE (service));
provider = camel_service_get_provider (service);
g_return_if_fail (provider != NULL);
extension_name =
e_source_camel_get_extension_name (provider->protocol);
extension = e_source_get_extension (source, extension_name);
settings = e_source_camel_get_settings (extension);
camel_service_set_settings (service, settings);
}