Add new ESource classes.
[platform/upstream/evolution-data-server.git] / libedataserver / e-source-camel.c
1 /*
2  * e-source-camel-provider.c
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
16  *
17  */
18
19 /**
20  * SECTION: e-source-camel
21  * @include: libedataserver/e-source-camel.h
22  * @short_description: #ESource extension for #CamelSettings
23  *
24  * #ESourceCamel itself is abstract.  Its sole function is to
25  * bridge #GObject properties from the #CamelSettings framework to the
26  * #ESource framework.  It does this by procedurally registering an
27  * #ESourceCamel subtype for each available #CamelService subtype,
28  * and then registering #GObject properties to proxy the properties in the
29  * corresponding #CamelSettings subtype.  The #ESourceCamel owns an
30  * instance of the appropriate #CamelSettings subtype, and redirects all
31  * get/set operations on its own #GObject properties to its #CamelSettings
32  * instance.  The #CamelSettings instance, now fully initialized from a key
33  * file, can then be inserted into a new #CamelService instance using
34  * camel_service_set_settings().
35  *
36  * Ultimately, this is all just implementation detail for glueing two
37  * unrelated class hierarchies together.  If you need to access provider
38  * specific settings, use the #CamelSettings API, not this.
39  **/
40
41 #include "e-source-camel.h"
42
43 #include <string.h>
44 #include <glib/gprintf.h>
45
46 #include <libedataserver/e-data-server-util.h>
47 #include <libedataserver/e-source-authentication.h>
48 #include <libedataserver/e-source-offline.h>
49 #include <libedataserver/e-source-security.h>
50
51 #define E_SOURCE_CAMEL_GET_PRIVATE(obj) \
52         (G_TYPE_INSTANCE_GET_PRIVATE \
53         ((obj), E_TYPE_SOURCE_CAMEL, ESourceCamelPrivate))
54
55 struct _ESourceCamelPrivate {
56         CamelSettings *settings;
57         GArray *value_array;
58 };
59
60 enum {
61         PROP_0,
62         PROP_SETTINGS
63 };
64
65 typedef struct {
66         const gchar *extension_name;
67         const gchar *extension_property_name;
68         const gchar *settings_property_name;
69         GBindingTransformFunc extension_to_settings;
70         GBindingTransformFunc settings_to_extension;
71 } BindingData;
72
73 static gboolean
74 transform_none_to_null (GBinding *binding,
75                         const GValue *source_value,
76                         GValue *target_value,
77                         gpointer not_used)
78 {
79         const gchar *v_string;
80
81         /* XXX Camel doesn't understand ESource's convention of using
82          *     "none" to represent no value, instead of NULL or empty
83          *     strings.  So convert "none" to NULL for Camel. */
84
85         v_string = g_value_get_string (source_value);
86
87         if (g_strcmp0 (v_string, "none") == 0)
88                 v_string = NULL;
89
90         g_value_set_string (target_value, v_string);
91
92         return TRUE;
93 }
94
95 static BindingData bindings[] = {
96
97         { E_SOURCE_EXTENSION_AUTHENTICATION,
98           "host", "host" },
99
100         { E_SOURCE_EXTENSION_AUTHENTICATION,
101           "method", "auth-mechanism",
102           transform_none_to_null,
103           NULL },
104
105         { E_SOURCE_EXTENSION_AUTHENTICATION,
106           "port", "port" },
107
108         { E_SOURCE_EXTENSION_AUTHENTICATION,
109           "user", "user" },
110
111         { E_SOURCE_EXTENSION_OFFLINE,
112           "stay-synchronized", "stay-synchronized" },
113
114         { E_SOURCE_EXTENSION_SECURITY,
115           "method", "security-method",
116           e_binding_transform_enum_nick_to_value,
117           e_binding_transform_enum_value_to_nick }
118 };
119
120 G_DEFINE_ABSTRACT_TYPE (
121         ESourceCamel,
122         e_source_camel,
123         E_TYPE_SOURCE_EXTENSION)
124
125 /* XXX A function like this belongs in GObject.  I may yet propose it,
126  *     GParamSpecClass still has some reserved slots.  This fiddles with
127  *     GParamSpec fields that are supposed to be private to GObject, but
128  *     I have no other choice.
129  *
130  * XXX Historical note, originally I tried (ab)using override properties
131  *     in ESourceCamel, which redirected to the equivalent CamelSettings
132  *     property.  Seemed to work at first, and I was proud of my clever
133  *     hack, but it turns out g_object_class_list_properties() excludes
134  *     override properties.  So the ESourceCamel properties were being
135  *     skipped in source_load_from_key_file() (e-source.c). */
136 static GParamSpec *
137 param_spec_clone (GParamSpec *pspec)
138 {
139         GParamSpec *clone;
140         GTypeQuery query;
141
142         /* Query the instance size. */
143         g_type_query (G_PARAM_SPEC_TYPE (pspec), &query);
144
145         /* Start with a memcpy()'d buffer. */
146         clone = g_slice_alloc0 (query.instance_size);
147         memcpy (clone, pspec, query.instance_size);
148
149         /* This sort of mimics g_param_spec_init(). */
150
151 #define PARAM_FLOATING_FLAG 0x2  /* from gparam.c */
152         g_datalist_set_flags (&clone->qdata, PARAM_FLOATING_FLAG);
153         clone->ref_count = 1;
154
155         /* Clear the owner_type. */
156         clone->owner_type = G_TYPE_INVALID;
157
158         /* Clear the param_id. */
159         clone->param_id = 0;
160
161         /* This sort of mimics g_param_spec_internal(). */
162
163         /* Param name should already be canonicalized and interned. */
164
165         /* Always copy the nickname. */
166         clone->flags &= ~G_PARAM_STATIC_NICK;
167         clone->_nick = g_strdup (g_param_spec_get_nick (pspec));
168
169         /* Always copy the blurb. */
170         clone->flags &= ~G_PARAM_STATIC_BLURB;
171         clone->_blurb = g_strdup (g_param_spec_get_blurb (pspec));
172
173         /* Handle special cases. */
174
175         if (G_IS_PARAM_SPEC_STRING (clone)) {
176                 GParamSpecString *clone_s;
177
178                 clone_s = (GParamSpecString *) clone;
179                 clone_s->default_value = g_strdup (clone_s->default_value);
180         }
181
182         /* Some types we don't handle but shouldn't need to. */
183         g_warn_if_fail (!G_IS_PARAM_SPEC_VALUE_ARRAY (clone));
184         g_warn_if_fail (!G_IS_PARAM_SPEC_OVERRIDE (clone));
185         g_warn_if_fail (!G_IS_PARAM_SPEC_VARIANT (clone));
186
187         return clone;
188 }
189
190 static gint
191 subclass_get_binding_index (GParamSpec *settings_property)
192 {
193         gint ii;
194
195         /* Return the index in the bindings list for the given
196          * CamelSettings property specification, or else -1. */
197
198         for (ii = 0; ii < G_N_ELEMENTS (bindings); ii++) {
199                 const gchar *property_name;
200
201                 property_name = bindings[ii].settings_property_name;
202                 if (g_strcmp0 (settings_property->name, property_name) == 0)
203                         return ii;
204         }
205
206         return -1;
207 }
208
209 static void
210 subclass_set_property (GObject *object,
211                        guint property_id,
212                        const GValue *src_value,
213                        GParamSpec *pspec)
214 {
215         ESourceCamel *extension;
216         GArray *value_array;
217         GValue *dst_value;
218
219         extension = E_SOURCE_CAMEL (object);
220         value_array = extension->priv->value_array;
221
222         dst_value = &g_array_index (value_array, GValue, property_id - 1);
223         g_value_copy (src_value, dst_value);
224 }
225
226 static void
227 subclass_get_property (GObject *object,
228                        guint property_id,
229                        GValue *dst_value,
230                        GParamSpec *pspec)
231 {
232         ESourceCamel *extension;
233         GArray *value_array;
234         GValue *src_value;
235
236         extension = E_SOURCE_CAMEL (object);
237         value_array = extension->priv->value_array;
238
239         src_value = &g_array_index (value_array, GValue, property_id - 1);
240         g_value_copy (src_value, dst_value);
241 }
242
243 static void
244 subclass_class_init (gpointer g_class,
245                      gpointer class_data)
246 {
247         GObjectClass *object_class;
248
249         /* e_source_camel_generate_subtype() does all the
250          * dynamic class initialization.  We just do what static
251          * initialization we can here. */
252
253         object_class = G_OBJECT_CLASS (g_class);
254         object_class->set_property = subclass_set_property;
255         object_class->get_property = subclass_get_property;
256 }
257
258 static void
259 subclass_instance_init (GTypeInstance *instance,
260                         gpointer g_class)
261 {
262         /* Nothing to do here, just makes a handy breakpoint. */
263 }
264
265 static void
266 source_camel_get_property (GObject *object,
267                            guint property_id,
268                            GValue *value,
269                            GParamSpec *pspec)
270 {
271         switch (property_id) {
272                 case PROP_SETTINGS:
273                         g_value_set_object (
274                                 value,
275                                 e_source_camel_get_settings (
276                                 E_SOURCE_CAMEL (object)));
277                         return;
278         }
279
280         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
281 }
282
283 static void
284 source_camel_dispose (GObject *object)
285 {
286         ESourceCamelPrivate *priv;
287
288         priv = E_SOURCE_CAMEL_GET_PRIVATE (object);
289
290         if (priv->settings != NULL) {
291                 g_object_unref (priv->settings);
292                 priv->settings = NULL;
293         }
294
295         /* Chain up to parent's dispose() method. */
296         G_OBJECT_CLASS (e_source_camel_parent_class)->dispose (object);
297 }
298
299 static void
300 source_camel_finalize (GObject *object)
301 {
302         ESourceCamelPrivate *priv;
303         guint ii;
304
305         priv = E_SOURCE_CAMEL_GET_PRIVATE (object);
306
307         for (ii = 0; ii < priv->value_array->len; ii++)
308                 g_value_unset (&g_array_index (priv->value_array, GValue, ii));
309
310         g_array_free (priv->value_array, TRUE);
311
312         /* Chain up to parent's finalize() method. */
313         G_OBJECT_CLASS (e_source_camel_parent_class)->finalize (object);
314 }
315
316 static void
317 source_camel_constructed (GObject *object)
318 {
319         ESource *source;
320         ESourceCamelClass *class;
321         ESourceCamelPrivate *priv;
322         GObjectClass *settings_class;
323         GParamSpec **properties;
324         guint ii, n_properties;
325         guint array_index = 0;
326
327         /* Chain up to parent's constructed() method. */
328         G_OBJECT_CLASS (e_source_camel_parent_class)->
329                 constructed (object);
330
331         class = E_SOURCE_CAMEL_GET_CLASS (object);
332         priv = E_SOURCE_CAMEL_GET_PRIVATE (object);
333
334         source = e_source_extension_get_source (E_SOURCE_EXTENSION (object));
335
336         priv->settings = g_object_new (class->settings_type, NULL);
337
338         /* Here we bind all the GObject properties in the newly-created
339          * CamelSettings instance to either our own identical properties
340          * or properties in another ESourceExtensions.  The bindings list
341          * at the top of the file maps out bindings to other extensions. */
342
343         settings_class = G_OBJECT_GET_CLASS (priv->settings);
344
345         properties = g_object_class_list_properties (
346                 settings_class, &n_properties);
347
348         /* Allocate more elements than we need, since some CamelSettings
349          * properties get bound to properties of other ESourceExtensions.
350          * We'll trim off the extra elements later. */
351         g_array_set_size (priv->value_array, n_properties);
352
353         for (ii = 0; ii < n_properties; ii++) {
354                 GParamSpec *pspec = properties[ii];
355                 GBindingTransformFunc transform_to = NULL;
356                 GBindingTransformFunc transform_from = NULL;
357                 ESourceExtension *extension;
358                 const gchar *source_property;
359                 const gchar *target_property;
360                 gint binding_index;
361
362                 binding_index = subclass_get_binding_index (pspec);
363
364                 /* Bind the CamelSettings property to
365                  * one in a different ESourceExtension. */
366                 if (binding_index >= 0) {
367                         BindingData *binding;
368
369                         binding = &bindings[binding_index];
370
371                         extension = e_source_get_extension (
372                                 source, binding->extension_name);
373
374                         source_property = binding->extension_property_name;
375                         target_property = binding->settings_property_name;
376
377                         transform_to = binding->extension_to_settings;
378                         transform_from = binding->settings_to_extension;
379
380                 /* Bind the CamelSettings property to our own
381                  * equivalent E_SOURCE_PARAM_SETTING property. */
382                 } else {
383                         GValue *value;
384
385                         extension = E_SOURCE_EXTENSION (object);
386
387                         source_property = pspec->name;
388                         target_property = pspec->name;
389
390                         /* Initialize the array element to
391                          * hold the GParamSpec's value type. */
392                         value = &g_array_index (
393                                 priv->value_array, GValue, array_index++);
394                         g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
395
396                         /* Set the array element to the GParamSpec's default
397                          * value.  This allows us to avoid declaring our own
398                          * properties with a G_PARAM_CONSTRUCT flag. */
399                         g_param_value_set_default (pspec, value);
400                 }
401
402                 g_object_bind_property_full (
403                         extension, source_property,
404                         priv->settings, target_property,
405                         G_BINDING_BIDIRECTIONAL |
406                         G_BINDING_SYNC_CREATE,
407                         transform_to, transform_from,
408                         NULL, (GDestroyNotify) NULL);
409         }
410
411         /* Trim off any extra array elements. */
412         g_array_set_size (priv->value_array, array_index);
413
414         g_free (properties);
415 }
416
417 static void
418 e_source_camel_class_init (ESourceCamelClass *class)
419 {
420         GObjectClass *object_class;
421
422         g_type_class_add_private (class, sizeof (ESourceCamelPrivate));
423
424         object_class = G_OBJECT_CLASS (class);
425         object_class->get_property = source_camel_get_property;
426         object_class->dispose = source_camel_dispose;
427         object_class->finalize = source_camel_finalize;
428         object_class->constructed = source_camel_constructed;
429
430         /* CamelSettings itself has no properties. */
431         class->settings_type = CAMEL_TYPE_SETTINGS;
432
433         /* XXX This kind of stomps on CamelSettings' namespace, but it's
434          *     unlikely a CamelSettings subclass would define a property
435          *     named "settings". */
436         g_object_class_install_property (
437                 object_class,
438                 PROP_SETTINGS,
439                 g_param_spec_object (
440                         "settings",
441                         "Settings",
442                         "The CamelSettings instance being proxied",
443                         CAMEL_TYPE_SETTINGS,
444                         G_PARAM_READABLE |
445                         G_PARAM_STATIC_STRINGS));
446 }
447
448 static void
449 e_source_camel_init (ESourceCamel *extension)
450 {
451         GArray *value_array;
452
453         /* Zero-fill array elements when they are allocated. */
454         value_array = g_array_new (FALSE, TRUE, sizeof (GValue));
455
456         extension->priv = E_SOURCE_CAMEL_GET_PRIVATE (extension);
457         extension->priv->value_array = value_array;
458 }
459
460 /**
461  * e_source_camel_register_types:
462  *
463  * Creates and registers subclasses of #ESourceCamel for each available
464  * #CamelProvider.  This function should be called once during application
465  * or library initialization.
466  *
467  * Since: 3.6
468  **/
469 void
470 e_source_camel_register_types (void)
471 {
472         GList *list, *link;
473
474         /* This implicitly takes care of provider initialization. */
475         list = camel_provider_list (TRUE);
476
477         for (link = list; link != NULL; link = g_list_next (link)) {
478                 CamelProvider *provider;
479                 gint ii;
480
481                 provider = (CamelProvider *) link->data;
482
483                 /* This is the novel part: generate and register
484                  * a new ESourceCamel subclass on-the-fly for each
485                  * object type listed in the provider. */
486                 for (ii = 0; ii < CAMEL_NUM_PROVIDER_TYPES; ii++) {
487                         CamelServiceClass *service_class = NULL;
488                         GType service_type;
489
490                         service_type = provider->object_types[ii];
491
492                         if (g_type_is_a (service_type, CAMEL_TYPE_SERVICE))
493                                 service_class = g_type_class_ref (service_type);
494
495                         if (service_class != NULL) {
496                                 e_source_camel_generate_subtype (
497                                         provider->protocol,
498                                         service_class->settings_type);
499                                 g_type_class_unref (service_class);
500                         }
501                 }
502         }
503
504         g_list_free (list);
505 }
506
507 /**
508  * e_source_camel_generate_subtype:
509  * @protocol: a #CamelProvider protocol
510  * @settings_type: a subtype of #CamelSettings
511  *
512  * Generates a custom #ESourceCamel subtype for @protocol.  Instances of the
513  * new subtype will contain a #CamelSettings instance of type @settings_type.
514  *
515  * This function is called as part of e_source_camel_register_types() and
516  * should not be called explicitly, except by some groupware packages that
517  * need to share package-specific settings across their mail, calendar and
518  * address book components.  In that case the groupware package may choose
519  * to subclass #CamelSettings rather than #ESourceExtension since libcamel
520  * is the lowest common denominator across all components.  This function
521  * provides a way for the calendar and address book components of such a
522  * package to generate an #ESourceCamel subtype for its #CamelSettings
523  * subtype without having to load all available #CamelProvider modules.
524  *
525  * Returns: the #GType of the generated #ESourceCamel subtype
526  *
527  * Since: 3.6
528  **/
529 GType
530 e_source_camel_generate_subtype (const gchar *protocol,
531                                  GType settings_type)
532 {
533         ESourceCamelClass *class;
534         GObjectClass *settings_class;
535         GParamSpec **properties;
536         guint ii, n_properties;
537         guint prop_id = 1;
538         GTypeInfo type_info;
539         GType parent_type;
540         GType type;
541         const gchar *type_name;
542         const gchar *extension_name;
543
544         g_return_val_if_fail (protocol != NULL, G_TYPE_INVALID);
545
546         type_name = e_source_camel_get_type_name (protocol);
547         extension_name = e_source_camel_get_extension_name (protocol);
548
549         /* Check if the type name is already registered. */
550         type = g_type_from_name (type_name);
551         if (type != G_TYPE_INVALID)
552                 return type;
553
554         /* The settings type must be derived from CAMEL_TYPE_SETTINGS. */
555         if (!g_type_is_a (settings_type, CAMEL_TYPE_SETTINGS)) {
556                 g_warning (
557                         "%s: Invalid settings type '%s' for protocol '%s'",
558                         G_STRFUNC, g_type_name (settings_type), protocol);
559                 return G_TYPE_INVALID;
560         }
561
562         memset (&type_info, 0, sizeof (GTypeInfo));
563         type_info.class_size = sizeof (ESourceCamelClass);
564         type_info.class_init = subclass_class_init;
565         type_info.instance_size = sizeof (ESourceCamel);
566         type_info.instance_init = subclass_instance_init;
567
568         parent_type = E_TYPE_SOURCE_CAMEL;
569         type = g_type_register_static (parent_type, type_name, &type_info, 0);
570
571         /* Since we have first access to the newly registered GType, and
572          * because initializing its class structure requires some of the
573          * arguments we were passed, we'll complete class initialization
574          * here rather than trying to do it all in subclass_init(). */
575
576         class = g_type_class_ref (type);
577         settings_class = g_type_class_ref (settings_type);
578
579         /* Initialize more class members. */
580         class->settings_type = G_OBJECT_CLASS_TYPE (settings_class);
581         class->parent_class.name = g_intern_string (extension_name);
582
583         /* For each property in the CamelSettings class, register
584          * an equivalent GObject property in this class and add an
585          * E_SOURCE_PARAM_SETTING flag so the value gets written to
586          * the ESource's key file. */
587
588         properties = g_object_class_list_properties (
589                 settings_class, &n_properties);
590
591         for (ii = 0; ii < n_properties; ii++) {
592                 GParamSpec *pspec;
593
594                 /* Some properties in CamelSettings may be covered
595                  * by other ESourceExtensions.  Skip them here. */
596                 if (subclass_get_binding_index (properties[ii]) >= 0)
597                         continue;
598
599                 pspec = param_spec_clone (properties[ii]);
600                 pspec->flags |= E_SOURCE_PARAM_SETTING;
601
602                 /* Clear the G_PARAM_CONSTRUCT flag.  We apply default
603                  * property values to our GValue array during instance
604                  * initialization. */
605                 pspec->flags &= ~G_PARAM_CONSTRUCT;
606
607                 g_object_class_install_property (
608                         G_OBJECT_CLASS (class), prop_id++, pspec);
609         }
610
611         g_free (properties);
612
613         g_type_class_unref (class);
614         g_type_class_unref (settings_class);
615
616         return type;
617 }
618
619 /**
620  * e_source_camel_get_settings:
621  * @extension: an #ESourceCamel
622  *
623  * Returns @extension's #ESourceCamel:settings instance, pre-configured
624  * from the #ESource to which @extension belongs.  Changes to the #ESource
625  * will automatically propagate to the #ESourceCamel:settings instance and
626  * vice versa.
627  *
628  * This is essentially the glue that binds #ESource to #CamelService.
629  * See e_source_camel_configure_service().
630  *
631  * Returns: a configured #CamelSettings instance
632  *
633  * Since: 3.6
634  **/
635 CamelSettings *
636 e_source_camel_get_settings (ESourceCamel *extension)
637 {
638         g_return_val_if_fail (E_IS_SOURCE_CAMEL (extension), NULL);
639
640         return extension->priv->settings;
641 }
642
643 /**
644  * e_source_camel_get_type_name:
645  * @protocol: a #CamelProvider protocol
646  *
647  * Returns the #GType name of the registered #ESourceCamel subtype for
648  * @protocol.
649  *
650  * For example, given a protocol named "imap" the function would return
651  * "ESourceCamelImap".
652  *
653  * Returns: the #ESourceCamel type name for @protocol
654  *
655  * Since: 3.6
656  **/
657 const gchar *
658 e_source_camel_get_type_name (const gchar *protocol)
659 {
660         gchar *buffer;
661
662         g_return_val_if_fail (protocol != NULL, NULL);
663
664         buffer = g_alloca (strlen (protocol) + 16);
665         g_sprintf (buffer, "ESourceCamel%s", protocol);
666         buffer[12] = g_ascii_toupper (buffer[12]);
667
668         return g_intern_string (buffer);
669 }
670
671 /**
672  * e_source_camel_get_extension_name:
673  * @protocol: a #CamelProvider protocol
674  *
675  * Returns the extension name for the #ESourceCamel subtype for @protocol.
676  * The extension name can then be passed to e_source_get_extension() to
677  * obtain an instance of the #ESourceCamel subtype.
678  *
679  * For example, given a protocol named "imap" the function would return
680  * "Imap Backend".
681  *
682  * Returns: the #ESourceCamel extension name for @protocol
683  *
684  * Since: 3.6
685  **/
686 const gchar *
687 e_source_camel_get_extension_name (const gchar *protocol)
688 {
689         gchar *buffer;
690
691         g_return_val_if_fail (protocol != NULL, NULL);
692
693         /* Use the term "backend" for consistency with other
694          * calendar and address book backend extension names. */
695         buffer = g_alloca (strlen (protocol) + 16);
696         g_sprintf (buffer, "%s Backend", protocol);
697         buffer[0] = g_ascii_toupper (buffer[0]);
698
699         return g_intern_string (buffer);
700 }
701
702 /**
703  * e_source_camel_configure_service:
704  * @source: an #ESource
705  * @service: a #CamelService
706  *
707  * This function essentially glues together @source and @serivce so their
708  * configuration settings stay synchronized.  The glue itself is a shared
709  * #CamelSettings instance.
710  *
711  * Call this function immediately after creating a new #CamelService with
712  * camel_session_add_service().
713  *
714  * Since: 3.6
715  **/
716 void
717 e_source_camel_configure_service (ESource *source,
718                                   CamelService *service)
719 {
720         ESourceCamel *extension;
721         CamelProvider *provider;
722         CamelSettings *settings;
723         const gchar *extension_name;
724
725         g_return_if_fail (E_IS_SOURCE (source));
726         g_return_if_fail (CAMEL_IS_SERVICE (service));
727
728         provider = camel_service_get_provider (service);
729         g_return_if_fail (provider != NULL);
730
731         extension_name =
732                 e_source_camel_get_extension_name (provider->protocol);
733         extension = e_source_get_extension (source, extension_name);
734
735         settings = e_source_camel_get_settings (extension);
736         camel_service_set_settings (service, settings);
737 }
738